summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/database.cc
blob: 71927f6b8e921445af490804971b8d26cf48e94e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 *  database.cc
 *  Crawl
 *
 *  Created by Peter Berger on 4/15/07.
 *  Copyright 2007 __MyCompanyName__. All rights reserved.
 *
 */

#ifdef UNIX
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#endif
#include <stdlib.h>
#include "database.h"
#include "files.h"

// Convenience functions for (read-only) access to generic
// berkeley DB databases.

#define nil 0

static bool databaseIsInitted = false;
dbList_t *openDBList;
DBM      *descriptionDB;

struct dbList_s {
    DBM         *dbPtr;
    dbList_s    *next;
} dbList_s;


void databaseSystemInit() {
    if (!databaseIsInitted) {
        databaseIsInitted = true;
        openDBList = nil;
        std::string descriptionPath = datafile_path("descriptions.db");
        descriptionPath.erase(descriptionPath.length() - 3, descriptionPath.length());
        descriptionDB = openDB(descriptionPath.c_str());
    }
}

void databaseSystemShutdown() {
    if (!databaseIsInitted) {
        // All done.
        return;
    }
    dbList_t *current = openDBList;
    dbList_t *prev = nil;
    while (current) {
        dbm_close(current->dbPtr);
        prev = current;
        current = current->next;
        free(prev);
    }
}

// This is here, and is external, just for future expansion -- if we
// want to allow external modules to manage their own DB, they can
// use this for the sake of convenience.  It's arguable that it's
// morally wrong to have the database module manage the memory here.
// But hey, life is hard and you can write your own berkeley DB
// calls if you like.
DBM   *openDB(const char *dbFilename) {
    if (!databaseIsInitted) {
        return nil;
    }
    DBM *dbToReturn = dbm_open(dbFilename, O_RDONLY, 0660);
    if (dbToReturn) {
        if (openDBList) {
            dbList_t *endOfDBList = openDBList; 
            while (openDBList->next) {
                endOfDBList = openDBList->next;
            }
            endOfDBList->next = (dbList_t *)malloc(sizeof(dbList_t));
            endOfDBList = endOfDBList->next;
            endOfDBList->next = nil;
            endOfDBList->dbPtr = dbToReturn;
            
        } else {
            openDBList = (dbList_t *)malloc(sizeof(dbList_t));
            openDBList->next = nil;
            openDBList->dbPtr = dbToReturn;
        }
    } else {
        dbToReturn = nil;
    }
    return dbToReturn;
}

datum database_fetch(DBM *database, const char *key) {
    datum result;
    result.dptr = nil;
    result.dsize = 0;
    if (!databaseIsInitted) {
        return result;
    }
    datum dbKey;
    
    dbKey.dptr = (void *)key;
    dbKey.dsize = strlen(key); 
    
    result = dbm_fetch(database, dbKey);
    
    return result;
}

char *private_strlwr(char *string) {
    int i;
    for (i = 0; string[i]; i++) {
        string[i] = tolower(string[i]);
    }
    return string;
} 

std::string getLongDescription(const char *key) {
    if (!databaseIsInitted) {
        return nil;
    }
    // We have to canonicalize the key (in case the user typed it
    // in and got the case wrong.
    int len = strlen(key);
    char *lowercaseKey = (char *)malloc(len+1);
    (void) strncpy(lowercaseKey, key, len+1);
    lowercaseKey = private_strlwr(lowercaseKey);
    
    // Query the DB.
    datum result = database_fetch(descriptionDB, (const char *)lowercaseKey);
    
    // Cons up a (C++) string to return.  The caller must release it.
    std::string stringToReturn((const char *)result.dptr, result.dsize);
    // free the result...
    free(lowercaseKey);
    
    return stringToReturn;
}