semi-ported to msys2
[laserbrain_demo] / src / datamap.cc
index bf8854c..dcbae78 100644 (file)
-#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;
 }