1 /*
2  * hasstr.c
3  *
4  * 2 char * hash tables
5  * Copyright (c) 1988, 89, 90, 91, 92, 93 Miguel Santana
6  * Copyright (c) 1995, 96, 97, 98, 99 Akim Demaille, Miguel Santana
7  */
8 
9 /*
10  * This file is part of a2ps.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; see the file COPYING.  If not, write to
24  * the Free Software Foundation, 59 Temple Place - Suite 330,
25  * Boston, MA 02111-1307, USA.
26  */
27 
28 /*
29  * $Id: pair_ht.c,v 1.11 1998/03/03 15:51:20 demaille Exp $
30  */
31 #include "a2ps.h"
32 
33 /* Hack! */
34 #define hash_table_s pair_htable
35 
36 #include "hashtab.h"
37 #include "message.h"
38 #include "pair_ht.h"
39 #include "getshline.h"
40 #include "lister.h"
41 #include "quotearg.h"
42 #include "routines.h"
43 
44 /************************************************************************
45  * hash tables with two char * fields					*
46  ************************************************************************/
47 /* Definition of the hash structure */
48 struct pair
49 {
50   char * key;
51   char * value;
52 };
53 
54 /*
55  * Basic routines
56  */
57 static unsigned long
pair_hash_1(struct pair * pair)58 pair_hash_1 (struct pair *pair)
59 {
60   return_STRING_HASH_1 (pair->key);
61 }
62 
63 static unsigned long
pair_hash_2(struct pair * pair)64 pair_hash_2 (struct pair *pair)
65 {
66   return_STRING_HASH_2 (pair->key);
67 }
68 
69 static int
pair_hash_cmp(struct pair * x,struct pair * y)70 pair_hash_cmp (struct pair *x, struct pair *y)
71 {
72   return_STRING_COMPARE (x->key, y->key);
73 }
74 
75 /*
76  * For sorting them in alpha order
77  */
78 static int
pair_hash_qcmp(struct pair ** x,struct pair ** y)79 pair_hash_qcmp (struct pair **x, struct pair **y)
80 {
81   return_STRING_COMPARE ((*x)->key, (*y)->key);
82 }
83 
84 /*
85  * Free a pair, and its content
86  */
87 static void
pair_free(struct pair * pair)88 pair_free (struct pair * pair)
89 {
90   XFREE (pair->key);
91   XFREE (pair->value);
92   XFREE (pair);
93 }
94 
95 /* Return the length of the key of PAIR */
96 
97 static size_t
pair_key_len(struct pair * pair)98 pair_key_len (struct pair * pair)
99 {
100   return strlen (pair->key);
101 }
102 
103 /* Fputs the key of PAIR to STREAM */
104 static void
pair_key_fputs(struct pair * pair,FILE * stream)105 pair_key_fputs (struct pair * pair, FILE * stream)
106 {
107   fputs (pair->key, stream);
108 }
109 
110 
111 
112 /*
113  * Create the structure that stores the list of pairs
114  */
115 struct hash_table_s *
pair_table_new(void)116 pair_table_new (void)
117 {
118   struct hash_table_s * res;
119 
120   res = XMALLOC (struct hash_table_s, 1);
121   hash_init (res, 8,
122 	     (hash_func_t) pair_hash_1,
123 	     (hash_func_t) pair_hash_2,
124 	     (hash_cmp_func_t) pair_hash_cmp);
125   return res;
126 }
127 
128 /*
129  * Free the whole structure
130  */
131 void
pair_table_free(struct hash_table_s * table)132 pair_table_free (struct hash_table_s * table)
133 {
134   hash_free (table, (hash_map_func_t) pair_free);
135   free (table);
136 }
137 
138 /*
139  *  Add a pair, with your own allocation for them.
140  * It KEY is yet used, override its value with VALUE
141  */
142 void
pair_add(struct hash_table_s * table,const char * key,const char * value)143 pair_add (struct hash_table_s * table,
144 	  const char * key, const char * value)
145 {
146   struct pair * item, token;
147 
148   token.key = (char *) key;
149   item = (struct pair *) hash_find_item (table, &token);
150 
151   if (item) {
152     if (item->value)
153       free (item->value);
154   } else {
155     item = XMALLOC (struct pair, 1);
156     item->key = xstrdup(key);
157   }
158 
159   if (value)
160     item->value = xstrdup (value);
161   else
162     item->value = NULL;
163 
164   hash_insert (table, item);
165 }
166 
167 /*
168  * Remove a pair and free it.
169  * It KEY is yet used, override its value with VALUE
170  */
171 void
pair_delete(struct hash_table_s * table,const char * key)172 pair_delete (struct hash_table_s * table, const char * key)
173 {
174   struct pair * item, token;
175 
176   token.key = (char *) key;
177   item = (struct pair *) hash_find_item (table, &token);
178 
179   if (item) {
180     hash_delete (table, item);
181     pair_free (item);
182   }
183 }
184 
185 /*
186  * Get the value associated to KEY in TABLE
187  * Return NULL upon error (this means that it is not
188  * valid to enter NULL as a value)
189  */
190 char *
pair_get(struct hash_table_s * table,const char * key)191 pair_get (struct hash_table_s * table, const char * key)
192 {
193   struct pair * item, token;
194 
195   token.key = (char *) key;
196   item = (struct pair *) hash_find_item (table, &token);
197 
198   if (item)
199     return item->value;
200   else
201     return NULL;
202 }
203 
204 /*
205  * Return the content of the hash table, ordered
206  */
207 void
pair_table_map(struct hash_table_s * table,pair_ht_map_fn_t map_fn,pair_ht_select_fn_t select_fn,void const * arg)208 pair_table_map (struct hash_table_s * table,
209 		pair_ht_map_fn_t map_fn,
210 		pair_ht_select_fn_t select_fn,
211 		void const * arg)
212 {
213   int i, num = 0;
214   struct pair ** entries;
215   entries = (struct pair **)
216     hash_dump (table, NULL,
217 	       (hash_cmp_func_t) pair_hash_qcmp);
218 
219   for (i = 0 ; entries[i] ; i++) {
220     if (!select_fn
221 	|| select_fn (entries[i]-> key, entries[i]->value))
222       {
223 	map_fn (num, entries[i]-> key, entries[i]->value, arg);
224 	num++;
225       }
226   }
227 
228   free (entries);
229 }
230 
231 /*
232  * For typically for --list-features
233  */
234 void
pair_table_list_short(struct hash_table_s * table,FILE * stream)235 pair_table_list_short (struct hash_table_s * table, FILE * stream)
236 {
237   struct pair ** entries;
238   entries = (struct pair **)
239     hash_dump (table, NULL,
240 	       (hash_cmp_func_t) pair_hash_qcmp);
241 
242   lister_fprint_vertical (NULL, stream,
243 			  (void **) entries, (size_t) -1,
244 			  (lister_width_t) pair_key_len,
245 			  (lister_print_t) pair_key_fputs);
246   free (entries);
247 }
248 
249 /*
250  * For typically for --list-<something>
251  */
252 void
pair_table_list_long(struct hash_table_s * table,FILE * stream)253 pair_table_list_long (struct hash_table_s * table, FILE * stream)
254 {
255   int i;
256   struct pair ** entries;
257   entries = (struct pair **)
258     hash_dump (table, NULL,
259 	       (hash_cmp_func_t) pair_hash_qcmp);
260 
261   for (i = 0 ; entries[i] ; i++)
262     fprintf (stream, "%-16s = %s\n",
263 	     entries[i]->key,
264 	     entries[i]->value ? entries[i]->value : "<NULL>");
265 
266   putc ('\n', stream);
267   free (entries);
268 }
269 
270 /*
271  * Mostly for debbuging
272  */
273 void
pair_table_self_print(struct hash_table_s * table,FILE * stream)274 pair_table_self_print (struct hash_table_s * table, FILE * stream)
275 {
276   int i;
277   struct pair ** entries;
278   entries = (struct pair **)
279     hash_dump (table, NULL,
280 	       (hash_cmp_func_t) pair_hash_qcmp);
281 
282   for (i = 0 ; entries[i] ; i++)
283     fprintf (stream, "%s:%s\n",
284 	     entries[i]->key,
285 	     entries[i]->value ? entries[i]->value : "<NULL>");
286 
287   putc ('\n', stream);
288   free (entries);
289 }
290 
291 #define GET_TOKEN(from) (strtok ((from), " \t\n"))
292 #define GET_LINE_TOKEN(from) (strtok ((from), "\n"))
293 #define CHECK_TOKEN() 							\
294   if (token2 == NULL) 							\
295     error_at_line (1, 0, file, firstline, 				\
296 		   _("missing argument for `%s'"), quotearg (token));
297 
298 /*
299  * Read from a FILE
300  */
301 int
pair_table_load(struct hash_table_s * table,const char * file)302 pair_table_load (struct hash_table_s * table, const char *file)
303 {
304   FILE * fp;
305   char *buf = NULL;
306   size_t bufsiz = 0;
307   char * token, * token2;
308   int firstline = 0, lastline = 0;
309 
310   message (msg_file,
311 	   (stderr, "Loading map file `%s'\n", quotearg (file)));
312   fp = xrfopen (file);
313 
314   while (getshline_numbered (&firstline, &lastline, &buf, &bufsiz, fp) != -1)
315     {
316       token = GET_TOKEN (buf);
317 
318       if (!token)
319 	/* Blank but not empty */
320 	continue;
321 
322       if (strequ (token, "***"))
323 	{
324 	  /* Load another map file */
325 	  token2 = GET_TOKEN (NULL);	/* A map file path	*/
326 	  CHECK_TOKEN ();
327 	  pair_table_load (table, token2);
328 	}
329       else
330 	{
331 	  token2 = GET_TOKEN (NULL);	/* key		*/
332 	  CHECK_TOKEN ();
333 	  pair_add (table, token, token2);
334 	}
335     }
336 
337   free (buf);
338   fclose (fp);
339   return 1;
340 }
341