1 /* -*- c-file-style: "java"; indent-tabs-mode: nil; tab-width: 4; fill-column: 78 -*-
2  *
3  * Copyright 2005 Google Inc.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
18  * USA.
19  */
20 
21 #include <config.h>
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <assert.h>
28 
29 #include "stringmap.h"
30 
31 #ifndef NULL
32 #define NULL 0
33 #endif
34 
35 #ifndef PATH_MAX
36 #define PATH_MAX 4096
37 #endif
38 
39 /* Load the given list of strings into the key/value map.
40  * The key for each string is the numFinalWordsToMatch of the string;
41  * the value for each string is the entire string.
42  * FIXME: doesn't work for utf-8 strings, since it scans raw chars for /
43  */
stringmap_load(const char * filename,int numFinalWordsToMatch)44 stringmap_t *stringmap_load(const char *filename, int numFinalWordsToMatch)
45 {
46     stringmap_t *result;
47     FILE *fp;
48     char buf[2*PATH_MAX];
49     int n;
50 
51     result = calloc(1, sizeof(*result));
52     if (!result)
53         return NULL;
54     result->numFinalWordsToMatch = numFinalWordsToMatch;
55     fp = fopen(filename, "r");
56     if (!fp) {
57         free(result);
58         return NULL;
59     }
60     n=0;
61     while (fgets(buf, sizeof(buf), fp))
62         n++;
63     result->n = n;
64     result->map = malloc(n * sizeof(result->map[0]));
65 
66     rewind(fp);
67     n=0;
68     while (fgets(buf, sizeof(buf), fp)) {
69         int pos, w;
70 
71         int len = strlen(buf);
72         /* strip trailing \n */
73         if (len > 0 && buf[len-1] == '\n') {
74             buf[len-1] = 0;
75             len--;
76         }
77         /* set pos to the start of the significant part of the string */
78         for (pos=len-1, w=0; pos>0; pos--) {
79             if (buf[pos] == '/') {
80                 w++;
81                 if (w >= numFinalWordsToMatch) {
82                     pos++;
83                     break;
84                 }
85             }
86         }
87 
88         result->map[n].value = strdup(buf);
89         result->map[n].key = strdup(buf+pos);
90         n++;
91     } fclose(fp);
92     return result;
93 }
94 
stringmap_lookup(const stringmap_t * map,const char * string)95 const char *stringmap_lookup(const stringmap_t *map, const char *string)
96 {
97     int i, w;
98     int len = strlen(string);
99     int pos;
100     for (pos=len-1, w=0; pos>0; pos--) {
101         if (string[pos] == '/') {
102             w++;
103             if (w >= map->numFinalWordsToMatch) {
104                 pos++;
105                 break;
106             }
107         }
108     }
109     for (i=0; i<map->n; i++) {
110         /*printf("Comparing %s and %s\n", map->map[i].key, string+pos);*/
111         if (!strcmp(map->map[i].key, string+pos))
112             return map->map[i].value;
113     }
114     return NULL;
115 }
116 
117 #if 0
118 
119 void dumpMap(stringmap_t *sm)
120 {
121     int i;
122     printf("map has %d elements, and numFinalWordsToMatch is %d\n", sm->n, sm->numFinalWordsToMatch);
123     for (i=0; i < sm->n; i++) {
124         printf("row %d: key %s, value %s\n", i, sm->map[i].key, sm->map[i].value);
125     }
126 }
127 
128 #define verifyMap(sm, a, b) { \
129     const char *c = stringmap_lookup(sm, a); \
130     if (!b) \
131         assert(!c); \
132     else { \
133         assert(c); \
134         assert(!strcmp(b, c)); } }
135 
136 int main(int argc, char **argv)
137 {
138     FILE *fp;
139     stringmap_t *sm;
140 
141     fp = fopen("stringmap_test.dat", "w");
142     fprintf(fp, "/foo/bar/bletch\n");
143     fclose(fp);
144     sm = stringmap_load("stringmap_test.dat", 1);
145     dumpMap(sm);
146     verifyMap(sm, "/bar/bletch", "/foo/bar/bletch");
147     verifyMap(sm, "bletch", "/foo/bar/bletch");
148     verifyMap(sm, "/whatever/bletch", "/foo/bar/bletch");
149     verifyMap(sm, "baz", NULL);
150     verifyMap(sm, "/foo/bar/bletch", "/foo/bar/bletch");
151 
152     fp = fopen("stringmap_test.dat", "w");
153     fprintf(fp, "/usr/bin/gcc\n");
154     fprintf(fp, "/usr/bin/cc\n");
155     fclose(fp);
156     sm = stringmap_load("stringmap_test.dat", 1);
157     dumpMap(sm);
158     verifyMap(sm, "/usr/bin/gcc", "/usr/bin/gcc");
159     verifyMap(sm, "/usr/bin/cc", "/usr/bin/cc");
160     verifyMap(sm, "gcc", "/usr/bin/gcc");
161     verifyMap(sm, "cc", "/usr/bin/cc");
162     verifyMap(sm, "g77", NULL);
163 
164     fp = fopen("stringmap_test.dat", "w");
165     fprintf(fp, "/usr/bin/i686-blah-blah/gcc\n");
166     fprintf(fp, "/usr/bin/i386-blah-blah/gcc\n");
167     fclose(fp);
168     sm = stringmap_load("stringmap_test.dat", 2);
169     dumpMap(sm);
170     verifyMap(sm, "/usr/bin/i686-blah-blah/gcc",
171                       "/usr/bin/i686-blah-blah/gcc");
172     verifyMap(sm, "/usr/bin/i386-blah-blah/gcc",
173                       "/usr/bin/i386-blah-blah/gcc");
174     verifyMap(sm, "i686-blah-blah/gcc", "/usr/bin/i686-blah-blah/gcc");
175     verifyMap(sm, "i386-blah-blah/gcc", "/usr/bin/i386-blah-blah/gcc");
176     verifyMap(sm, "gcc", NULL);
177     verifyMap(sm, "g77", NULL);
178 
179         return 0;
180 }
181 
182 #endif
183