19aaf44c95e788ef85f42fe753dd708810d55c5a
[laserbrain_demo] / src / datamap.cc
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <vector>
5 #include <map>
6 #include <string>
7 //#include <regex>
8 #include "datamap.h"
9
10 #ifdef WIN32
11 #include <malloc.h>
12 #else
13 #include <alloca.h>
14 #endif
15
16 static char *clean_line(char *s);
17
18 //static std::vector<std::pair<std::regex, std::string>> dmap;
19 static std::vector<std::pair<std::string, std::string>> dmap;
20 static std::map<std::string, std::string> cache;
21 static std::string root;
22
23 void datamap_reset()
24 {
25         dmap.clear();
26         cache.clear();
27 }
28
29 void datamap_set_path(const char *path)
30 {
31         root = std::string(path);
32 }
33
34 bool datamap_load_map(const char *fname)
35 {
36         std::string path = root.empty() ? fname : root + std::string("/") + fname;
37         fname = path.c_str();
38
39         FILE *fp = fopen(fname, "r");
40         if(!fp) {
41                 fprintf(stderr, "failed to open data map: %s\n", fname);
42                 return false;
43         }
44
45         char buf[256];
46         if(fread(buf, 1, 8, fp) < 8 || memcmp(buf, "DATAMAP0", 8) != 0) {
47                 fprintf(stderr, "invalid datamap file: %s\n", fname);
48                 fclose(fp);
49                 return false;
50         }
51
52         datamap_reset();
53
54         char *line;
55         int nline = 0;
56         while(fgets(buf, sizeof buf, fp)) {
57                 ++nline;
58                 line = clean_line(buf);
59                 if(!line || !*line) continue;
60
61                 char *colon = strchr(line, ':');
62                 if(!colon) {
63                         goto err;
64                 }
65                 *colon = 0;
66
67                 //std::pair<std::regex, std::string> pair;
68                 //pair.first = std::regex(line);
69                 std::pair<std::string, std::string> pair;
70                 pair.first = std::string(line);
71
72                 char *value = clean_line(colon + 1);
73                 if(!value || !*value) {
74                         goto err;
75                 }
76                 pair.second = std::string(value);
77                 dmap.push_back(pair);
78         }
79         fclose(fp);
80
81         printf("loaded datamap %s: %d mappings\n", fname, (int)dmap.size());
82         return true;
83
84 err:
85         fprintf(stderr, "error while parsing %s, invalid line %d: %s\n", fname, nline, line);
86         datamap_reset();
87         fclose(fp);
88         return false;
89 }
90
91 void datamap_map(const char *re, const char *path)
92 {
93         //std::pair<std::regex, std::string> mapping;
94         //mapping.first = std::regex(re);
95         std::pair<std::string, std::string> mapping;
96         mapping.first = std::string(re);
97         mapping.second = std::string(path);
98         dmap.push_back(std::move(mapping));
99 }
100
101 int datamap_lookup(const char *in, char *buf, int bsz)
102 {
103         std::string res;
104
105         char *inbuf = (char*)alloca(strlen(in) + 1);
106         strcpy(inbuf, in);
107         in = clean_line(inbuf);
108
109         // first check the cache
110         std::map<std::string, std::string>::iterator it = cache.find(in);
111         if(it != cache.end()) {
112                 res = it->second;
113         } else {
114                 // try matching with the available mappings
115                 res = std::string(in);
116
117                 int num = dmap.size();
118                 for(int i=0; i<num; i++) {
119                         //if(std::regex_search(in, dmap[i].first)) {
120                         if(strstr(in, dmap[i].first.c_str())) {
121                                 res = root.empty() ? dmap[i].second : root + "/" + dmap[i].second;
122                                 cache[in] = res;        // add it to the cache
123                                 break;
124                         }
125                 }
126         }
127
128         // copy result in buf, truncating if necessary and return the size of the
129         // buffer required to hold it
130         if(buf) {
131                 int n = std::min(bsz - 1, (int)res.length());
132                 memcpy(buf, res.c_str(), n);
133                 buf[bsz - 1] = 0; // make sure it's null-terminated even if it got truncated
134         }
135         return res.length() + 1;
136 }
137
138 int datamap_path_size(const char *in)
139 {
140         return datamap_lookup(in, 0, 0);
141 }
142
143 static char *clean_line(char *s)
144 {
145         while(*s && isspace(*s)) ++s;
146         if(!*s) return 0;
147
148         char *end;
149         if(!(end = strchr(s, '#'))) {
150                 end = s + strlen(s) - 1;
151         }
152         while(end > s && isspace(*end)) --end;
153         if(s == end) return 0;
154         end[1] = 0;
155
156         // app-specific: convert backslashes
157         char *c = s;
158         while(*c) {
159                 if(*c == '\\') *c = '/';
160                 ++c;
161         }
162
163         return s;
164 }