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