-#include <vector>
-#include <map>
-#include <string>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
#include "datamap.h"
-static std::vector<std::pair<std::string, std::string>> dmap;
-static std::map<std::string, std::string> cache;
-static std::string root;
+#if defined(WIN32) || defined(__WIN32__)
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
-void datmap_reset()
+static char *clean_line(char *s);
+
+DataMap::DataMap()
+{
+ strip_paths = false;
+}
+
+void DataMap::clear()
{
- root.clear();
dmap.clear();
cache.clear();
}
-void datmap_set_path(const char *path)
+void DataMap::set_path(const char *path)
{
root = std::string(path);
}
-bool datmap_load_map(const char *fname)
+void DataMap::set_strip(bool s)
+{
+ strip_paths = s;
+}
+
+bool DataMap::load_map(const char *fname)
{
std::string path = root.empty() ? fname : root + std::string("/") + fname;
- return false; // TODO cont...
+ fname = path.c_str();
+
+ FILE *fp = fopen(fname, "r");
+ if(!fp) {
+ fprintf(stderr, "failed to open data map: %s\n", fname);
+ return false;
+ }
+
+ char buf[256];
+ if(fread(buf, 1, 8, fp) < 8 || memcmp(buf, "DATAMAP0", 8) != 0) {
+ fprintf(stderr, "invalid datamap file: %s\n", fname);
+ fclose(fp);
+ return false;
+ }
+
+ clear();
+
+ char *line;
+ int nline = 0;
+ while(fgets(buf, sizeof buf, fp)) {
+ ++nline;
+ line = clean_line(buf);
+ if(!line || !*line) continue;
+
+ char *colon = strchr(line, ':');
+ if(!colon) {
+ goto err;
+ }
+ *colon = 0;
+
+ //std::pair<std::regex, std::string> pair;
+ //pair.first = std::regex(line);
+ std::pair<std::string, std::string> pair;
+ pair.first = std::string(line);
+
+ char *value = clean_line(colon + 1);
+ if(!value || !*value) {
+ goto err;
+ }
+ pair.second = std::string(value);
+ dmap.push_back(pair);
+ }
+ fclose(fp);
+
+ printf("loaded datamap %s: %d mappings\n", fname, (int)dmap.size());
+ return true;
+
+err:
+ fprintf(stderr, "error while parsing %s, invalid line %d: %s\n", fname, nline, line);
+ clear();
+ fclose(fp);
+ return false;
}
-void datmap_map(const char *re, const char *path)
+void DataMap::map(const char *match, const char *path)
{
std::pair<std::string, std::string> mapping;
- mapping.first = std::string(re);
+ mapping.first = std::string(match);
mapping.second = std::string(path);
- dmap.push_back(mapping);
+ dmap.push_back(std::move(mapping));
}
-int datmap_lookup(const char *in, char *buf, int bsz)
+int DataMap::lookup(const char *in, char *buf, int bsz) const
{
- return -1; // TODO
+ std::string res;
+
+ if(strip_paths) {
+ const char *ptr = strrchr(in, '/');
+ if(ptr) {
+ in = ptr + 1;
+ }
+ }
+
+ char *inbuf = (char*)alloca(strlen(in) + 1);
+ strcpy(inbuf, in);
+ in = clean_line(inbuf);
+
+ // first check the cache
+ std::map<std::string, std::string>::iterator it = cache.find(in);
+ if(it != cache.end()) {
+ res = it->second;
+ } else {
+ // try matching with the available mappings
+ res = root.empty() ? std::string(in) : root + "/" + std::string(in);
+
+ int num = dmap.size();
+ for(int i=0; i<num; i++) {
+ //if(std::regex_search(in, dmap[i].first)) {
+ if(strstr(in, dmap[i].first.c_str())) {
+ res = root.empty() ? dmap[i].second : root + "/" + dmap[i].second;
+ cache[in] = res; // add it to the cache
+ break;
+ }
+ }
+ }
+
+ // copy result in buf, truncating if necessary and return the size of the
+ // buffer required to hold it
+ if(buf) {
+ int n = std::min(bsz - 1, (int)res.length());
+ memcpy(buf, res.c_str(), n);
+ buf[n] = 0; // make sure it's null-terminated even if it got truncated
+ }
+ return res.length() + 1;
}
-int datmap_path_size(const char *in)
+int DataMap::path_size(const char *in) const
{
- return datmap_lookup(in, 0, 0);
+ return lookup(in, 0, 0);
+}
+
+static char *clean_line(char *s)
+{
+ while(*s && isspace(*s)) ++s;
+ if(!*s) return 0;
+
+ char *end;
+ if(!(end = strchr(s, '#'))) {
+ end = s + strlen(s) - 1;
+ }
+ while(end > s && isspace(*end)) --end;
+ if(s == end) return 0;
+ end[1] = 0;
+
+ // app-specific: convert backslashes
+ char *c = s;
+ while(*c) {
+ if(*c == '\\') *c = '/';
+ ++c;
+ }
+
+ return s;
}