16 static char *clean_line(char *s);
18 static std::vector<std::pair<std::regex, std::string>> dmap;
19 static std::map<std::string, std::string> cache;
20 static std::string root;
29 void datamap_set_path(const char *path)
31 root = std::string(path);
34 bool datamap_load_map(const char *fname)
36 std::string path = root.empty() ? fname : root + std::string("/") + fname;
39 FILE *fp = fopen(fname, "r");
41 fprintf(stderr, "failed to open data map: %s\n", fname);
46 if(fread(buf, 1, 8, fp) < 8 || memcmp(buf, "DATAMAP0", 8) != 0) {
47 fprintf(stderr, "invalid datamap file: %s\n", fname);
56 while(fgets(buf, sizeof buf, fp)) {
58 line = clean_line(buf);
59 if(!line || !*line) continue;
61 char *colon = strchr(line, ':');
67 std::pair<std::regex, std::string> pair;
68 pair.first = std::regex(line);
70 char *value = clean_line(colon + 1);
71 if(!value || !*value) {
74 pair.second = std::string(value);
79 printf("loaded datamap %s: %d mappings\n", fname, (int)dmap.size());
83 fprintf(stderr, "error while parsing %s, invalid line %d: %s\n", fname, nline, line);
89 void datamap_map(const char *re, const char *path)
91 std::pair<std::regex, std::string> mapping;
92 mapping.first = std::regex(re);
93 mapping.second = std::string(path);
94 dmap.push_back(std::move(mapping));
97 int datamap_lookup(const char *in, char *buf, int bsz)
101 char *inbuf = (char*)alloca(strlen(in) + 1);
103 in = clean_line(inbuf);
105 // first check the cache
106 std::map<std::string, std::string>::iterator it = cache.find(in);
107 if(it != cache.end()) {
110 // try matching with the available mappings
111 int num = dmap.size();
112 for(int i=0; i<num; i++) {
113 if(std::regex_match(in, dmap[i].first)) {
114 res = root.empty() ? dmap[i].second : root + "/" + dmap[i].second;
115 cache[in] = res; // add it to the cache
122 // copy result in buf, truncating if necessary and return the size of the
123 // buffer required to hold it
125 int n = std::min(bsz - 1, (int)res.length());
126 memcpy(buf, res.c_str(), n);
127 buf[bsz - 1] = 0; // make sure it's null-terminated even if it got truncated
129 return res.length() + 1;
132 int datamap_path_size(const char *in)
134 return datamap_lookup(in, 0, 0);
137 static char *clean_line(char *s)
139 while(*s && isspace(*s)) ++s;
143 if(!(end = strchr(s, '#'))) {
144 end = s + strlen(s) - 1;
146 while(end > s && isspace(*end)) --end;
147 if(s == end) return 0;
150 // app-specific: convert backslashes
153 if(*c == '\\') *c = '/';