source: git/src/ini.c @ 0804fbe

RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-data
Last change on this file since 0804fbe was 0804fbe, checked in by Olly Betts <olly@…>, 12 years ago

lib/,src/: Use curly double quotes instead of "`" and "'" to
quote literals and filenames in messages.

git-svn-id: file:///home/survex-svn/survex/trunk@3897 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 5.6 KB
Line 
1/* ini.c
2 * .ini file routines
3 * Copyright (C) 1995-2001,2003,2010 Olly Betts
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (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 St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28
29#include "debug.h"
30#include "filename.h"
31#include "hash.h"
32#include "ini.h"
33#include "message.h"
34#include "useful.h"
35
36/* for testing separately from Survex */
37#ifdef TEST_ALONE
38/* says when two distinct strings hash to same value */
39#define REPORT_COLLISION
40
41/* good enough for testing */
42#define strcasecmp(x,y) strcmp((x),(y))
43
44char *
45osstrdup(char *s)
46{
47   char *t;
48   t = malloc(strlen(s) + 1);
49   if (!t) {
50      printf("out of memory\n");
51      exit(1);
52   }
53   strcpy(t, s);
54   return t;
55}
56#include <assert.h>
57#define SVX_ASSERT(M) assert(M)
58#endif
59
60#if 0
61void
62ini_write(const char *section, const char *var, const char *value)
63{
64   FILE *fh = stdout;
65   scan_for(section, var);
66
67   static char *last_section = NULL;
68   if (!last_section || strcasecmp(last_section, section) != 0) {
69      if (last_section) PUTC('\n', fh);
70      fprintf(fh, "[%s]\n", section);
71      last_section = section;
72   }
73   fprintf(stdout, "%s=%s\n", var, value);
74}
75#endif
76
77char **
78ini_read(FILE **fh_list, const char *section, const char **vars)
79{
80   int n, c;
81   char **vals;
82   int *hash_tab;
83
84   SVX_ASSERT(fh_list != NULL);
85   SVX_ASSERT(section != NULL);
86   SVX_ASSERT(vars != NULL);
87
88   /* count how many variables to look up */
89   n = 0;
90   while (vars[n]) n++;
91
92   hash_tab = malloc(n * sizeof(int));
93   vals = malloc(n * sizeof(char*));
94   if (!hash_tab || !vals) {
95      free(hash_tab);
96      return NULL;
97   }
98
99   /* calculate hashes (to save on strcmp-s) */
100   for (c = 0; vars[c]; c++) {
101      hash_tab[c] = hash_lc_string(vars[c]);
102      vals[c] = NULL;
103   }
104
105   SVX_ASSERT(c == n); /* counted vars[] twice and got different answers! */
106
107   while (1) {
108      char *p, *var, *val;
109      char buf[1024];
110      int hash;
111
112      int fInSection = 0;
113
114      FILE *fh = *fh_list++;
115
116      if (!fh) break;
117      rewind(fh);
118      while (1) {
119         if (feof(fh)) {
120            /* if (fWrite) { insert_section(); insert_lines(); fDone=1; } */
121            break;
122         }
123
124         /* read line and sort out terminator */
125         if (!fgets(buf, 1024, fh)) break;
126         p = strpbrk(buf, "\n\r");
127         if (p) *p = '\0';
128
129         /* skip blank lines */
130         if (buf[0] == '\0') continue;
131
132         /* deal with a section heading */
133         if (buf[0] == '[' && buf[strlen(buf) - 1] == ']') {
134            buf[strlen(buf) - 1] = '\0';
135            if (fInSection) {
136               /* if (fWrite) { insert_lines(); fDone=1; } */
137               /* now leaving wanted section, so stop on this file */
138               break;
139            }
140            /*         printf("[%s] [%s]\n", section, buf + 1);*/
141            if (!strcasecmp(section, buf + 1)) fInSection = 1;
142            continue;
143         }
144
145         if (!fInSection) continue;
146
147         p = strchr(buf, '=');
148         if (!p) continue; /* non-blank line with no = sign! */
149
150         *p = '\0';
151         var = buf;
152         val = p + 1;
153
154         /* hash the variable name and see if it's in the list passed in */
155         hash = hash_lc_string(var);
156         for (c = n - 1; c >= 0; c--) {
157            if (hash == hash_tab[c]) {
158               if (strcasecmp(var, vars[c]) == 0) {
159                  /* if (fWrite) { replace_line(); hash_tab[c]=-1; } else */
160                  vals[c] = osstrdup(val);
161                  /* set to value hash can't generate to ignore further matches */
162                  hash_tab[c] = -1;
163               } else {
164#ifdef REPORT_COLLISION
165                  printf("“%s” and “%s” both hash to %d!\n",var,vars[c],hash);
166#endif
167               }
168            }
169         }
170      }
171   }
172
173   free(hash_tab);
174   return vals;
175}
176
177char **
178ini_read_hier(FILE **fh_list, const char *section, const char **v)
179{
180   int i, j;
181   char **vals;
182   int *to;
183   char **vars;
184
185   SVX_ASSERT(fh_list != NULL);
186   SVX_ASSERT(section != NULL);
187   SVX_ASSERT(v != NULL);
188
189   vals = ini_read(fh_list, section, v);
190   if (!vals) return NULL;
191
192/*{int i; printf("[%s]\n",section);for(i=0;v[i];i++)printf("%d:%s\"%s\"\n",i,v[i],vals[i]?vals[i]:"(null)");}*/
193   i = 0;
194   while (v[i]) i++;
195   vars = malloc((i + 1) * sizeof(char*)); /* + 1 to include NULL */
196   to = malloc(i * sizeof(int));
197   if (!vars || !to) {
198      free(vars);
199      free(to);
200      free(vals);
201      return NULL;
202   }
203   memcpy(vars, v, (i + 1) * sizeof(char*));
204
205   for (i = 1, j = 1; vars[i]; i++) {
206/*      printf("%s: %s %d\n",vars[i],vals[i]?vals[i]:"(null)",to[i]);*/
207      if (!vals[i]) {
208         vars[j] = vars[i];
209         to[j] = i;
210         j++;
211      }
212   }
213
214   while (vals[0] && j > 1) {
215      char **x;
216
217      vars[j] = NULL;
218
219      x = ini_read(fh_list, vals[0], (const char **)vars);
220      if (!x) {
221         free(vals);
222         vals = NULL;
223         break;
224      }
225
226/*{int i; printf("[%s]\n",vals[0]);for(i=0;vars[i];i++)printf("%d:%s\"%s\"\n",i,vars[i],vals[i]?vals[i]:"(null)");}*/
227
228      free(vals[0]);
229      vals[0] = x[0];
230
231      for (i = 1, j = 1; vars[i]; i++) {
232/*         printf("%s: %s %d\n",vars[i],vals[i]?vals[i]:"(null)",to[i]);*/
233         if (x[i]) {
234            if (x) vals[to[i]] = x[i];
235         } else {
236            vars[j] = vars[i];
237            to[j] = to[i];
238            j++;
239         }
240      }
241      free(x);
242   }
243
244   free(vals[0]);
245   vals[0] = NULL;
246   free(vars);
247   free(to);
248
249   return vals;
250}
Note: See TracBrowser for help on using the repository browser.