| @@ -1,640 +1,643 @@ | | | @@ -1,640 +1,643 @@ |
1 | /**************************************************************** | | 1 | /**************************************************************** |
2 | Copyright (C) Lucent Technologies 1997 | | 2 | Copyright (C) Lucent Technologies 1997 |
3 | All Rights Reserved | | 3 | All Rights Reserved |
4 | | | 4 | |
5 | Permission to use, copy, modify, and distribute this software and | | 5 | Permission to use, copy, modify, and distribute this software and |
6 | its documentation for any purpose and without fee is hereby | | 6 | its documentation for any purpose and without fee is hereby |
7 | granted, provided that the above copyright notice appear in all | | 7 | granted, provided that the above copyright notice appear in all |
8 | copies and that both that the copyright notice and this | | 8 | copies and that both that the copyright notice and this |
9 | permission notice and warranty disclaimer appear in supporting | | 9 | permission notice and warranty disclaimer appear in supporting |
10 | documentation, and that the name Lucent Technologies or any of | | 10 | documentation, and that the name Lucent Technologies or any of |
11 | its entities not be used in advertising or publicity pertaining | | 11 | its entities not be used in advertising or publicity pertaining |
12 | to distribution of the software without specific, written prior | | 12 | to distribution of the software without specific, written prior |
13 | permission. | | 13 | permission. |
14 | | | 14 | |
15 | LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | | 15 | LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
16 | INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. | | 16 | INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. |
17 | IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY | | 17 | IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY |
18 | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 18 | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
19 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | | 19 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER |
20 | IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | | 20 | IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
21 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | | 21 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF |
22 | THIS SOFTWARE. | | 22 | THIS SOFTWARE. |
23 | ****************************************************************/ | | 23 | ****************************************************************/ |
24 | | | 24 | |
25 | #if HAVE_NBTOOL_CONFIG_H | | 25 | #if HAVE_NBTOOL_CONFIG_H |
26 | #include "nbtool_config.h" | | 26 | #include "nbtool_config.h" |
27 | #endif | | 27 | #endif |
28 | | | 28 | |
29 | #define DEBUG | | 29 | #define DEBUG |
30 | #include <stdio.h> | | 30 | #include <stdio.h> |
31 | #include <math.h> | | 31 | #include <math.h> |
32 | #include <ctype.h> | | 32 | #include <ctype.h> |
33 | #include <string.h> | | 33 | #include <string.h> |
34 | #include <stdlib.h> | | 34 | #include <stdlib.h> |
35 | #include "awk.h" | | 35 | #include "awk.h" |
36 | #include "awkgram.h" | | 36 | #include "awkgram.h" |
37 | | | 37 | |
38 | #define FULLTAB 2 /* rehash when table gets this x full */ | | 38 | #define FULLTAB 2 /* rehash when table gets this x full */ |
39 | #define GROWTAB 4 /* grow table by this factor */ | | 39 | #define GROWTAB 4 /* grow table by this factor */ |
40 | | | 40 | |
41 | Array *symtab; /* main symbol table */ | | 41 | Array *symtab; /* main symbol table */ |
42 | | | 42 | |
43 | char **FS; /* initial field sep */ | | 43 | char **FS; /* initial field sep */ |
44 | char **RS; /* initial record sep */ | | 44 | char **RS; /* initial record sep */ |
45 | char **OFS; /* output field sep */ | | 45 | char **OFS; /* output field sep */ |
46 | char **ORS; /* output record sep */ | | 46 | char **ORS; /* output record sep */ |
47 | char **OFMT; /* output format for numbers */ | | 47 | char **OFMT; /* output format for numbers */ |
48 | char **CONVFMT; /* format for conversions in getsval */ | | 48 | char **CONVFMT; /* format for conversions in getsval */ |
49 | Awkfloat *NF; /* number of fields in current record */ | | 49 | Awkfloat *NF; /* number of fields in current record */ |
50 | Awkfloat *NR; /* number of current record */ | | 50 | Awkfloat *NR; /* number of current record */ |
51 | Awkfloat *FNR; /* number of current record in current file */ | | 51 | Awkfloat *FNR; /* number of current record in current file */ |
52 | char **FILENAME; /* current filename argument */ | | 52 | char **FILENAME; /* current filename argument */ |
53 | Awkfloat *ARGC; /* number of arguments from command line */ | | 53 | Awkfloat *ARGC; /* number of arguments from command line */ |
54 | char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ | | 54 | char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ |
55 | Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ | | 55 | Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ |
56 | Awkfloat *RLENGTH; /* length of same */ | | 56 | Awkfloat *RLENGTH; /* length of same */ |
57 | | | 57 | |
58 | Cell *fsloc; /* FS */ | | 58 | Cell *fsloc; /* FS */ |
59 | Cell *nrloc; /* NR */ | | 59 | Cell *nrloc; /* NR */ |
60 | Cell *nfloc; /* NF */ | | 60 | Cell *nfloc; /* NF */ |
61 | Cell *fnrloc; /* FNR */ | | 61 | Cell *fnrloc; /* FNR */ |
62 | Cell *ofsloc; /* OFS */ | | 62 | Cell *ofsloc; /* OFS */ |
63 | Cell *orsloc; /* ORS */ | | 63 | Cell *orsloc; /* ORS */ |
64 | Cell *rsloc; /* RS */ | | 64 | Cell *rsloc; /* RS */ |
65 | Array *ARGVtab; /* symbol table containing ARGV[...] */ | | 65 | Array *ARGVtab; /* symbol table containing ARGV[...] */ |
66 | Array *ENVtab; /* symbol table containing ENVIRON[...] */ | | 66 | Array *ENVtab; /* symbol table containing ENVIRON[...] */ |
67 | Cell *rstartloc; /* RSTART */ | | 67 | Cell *rstartloc; /* RSTART */ |
68 | Cell *rlengthloc; /* RLENGTH */ | | 68 | Cell *rlengthloc; /* RLENGTH */ |
69 | Cell *subseploc; /* SUBSEP */ | | 69 | Cell *subseploc; /* SUBSEP */ |
70 | Cell *symtabloc; /* SYMTAB */ | | 70 | Cell *symtabloc; /* SYMTAB */ |
71 | | | 71 | |
72 | Cell *nullloc; /* a guaranteed empty cell */ | | 72 | Cell *nullloc; /* a guaranteed empty cell */ |
73 | Node *nullnode; /* zero&null, converted into a node for comparisons */ | | 73 | Node *nullnode; /* zero&null, converted into a node for comparisons */ |
74 | Cell *literal0; | | 74 | Cell *literal0; |
75 | | | 75 | |
76 | extern Cell **fldtab; | | 76 | extern Cell **fldtab; |
77 | | | 77 | |
78 | static void | | 78 | static void |
79 | setfree(Cell *vp) | | 79 | setfree(Cell *vp) |
80 | { | | 80 | { |
81 | if (&vp->sval == FS || &vp->sval == RS || | | 81 | if (&vp->sval == FS || &vp->sval == RS || |
82 | &vp->sval == OFS || &vp->sval == ORS || | | 82 | &vp->sval == OFS || &vp->sval == ORS || |
83 | &vp->sval == OFMT || &vp->sval == CONVFMT || | | 83 | &vp->sval == OFMT || &vp->sval == CONVFMT || |
84 | &vp->sval == FILENAME || &vp->sval == SUBSEP) | | 84 | &vp->sval == FILENAME || &vp->sval == SUBSEP) |
85 | vp->tval |= DONTFREE; | | 85 | vp->tval |= DONTFREE; |
86 | else | | 86 | else |
87 | vp->tval &= ~DONTFREE; | | 87 | vp->tval &= ~DONTFREE; |
88 | } | | 88 | } |
89 | | | 89 | |
90 | void syminit(void) /* initialize symbol table with builtin vars */ | | 90 | void syminit(void) /* initialize symbol table with builtin vars */ |
91 | { | | 91 | { |
92 | literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); | | 92 | literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); |
93 | /* this is used for if(x)... tests: */ | | 93 | /* this is used for if(x)... tests: */ |
94 | nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); | | 94 | nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); |
95 | nullnode = celltonode(nullloc, CCON); | | 95 | nullnode = celltonode(nullloc, CCON); |
96 | | | 96 | |
97 | fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab); | | 97 | fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab); |
98 | FS = &fsloc->sval; | | 98 | FS = &fsloc->sval; |
99 | rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab); | | 99 | rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab); |
100 | RS = &rsloc->sval; | | 100 | RS = &rsloc->sval; |
101 | ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab); | | 101 | ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab); |
102 | OFS = &ofsloc->sval; | | 102 | OFS = &ofsloc->sval; |
103 | orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab); | | 103 | orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab); |
104 | ORS = &orsloc->sval; | | 104 | ORS = &orsloc->sval; |
105 | OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; | | 105 | OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; |
106 | CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; | | 106 | CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; |
107 | FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; | | 107 | FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; |
108 | nfloc = setsymtab("NF", "", 0.0, NUM, symtab); | | 108 | nfloc = setsymtab("NF", "", 0.0, NUM, symtab); |
109 | NF = &nfloc->fval; | | 109 | NF = &nfloc->fval; |
110 | nrloc = setsymtab("NR", "", 0.0, NUM, symtab); | | 110 | nrloc = setsymtab("NR", "", 0.0, NUM, symtab); |
111 | NR = &nrloc->fval; | | 111 | NR = &nrloc->fval; |
112 | fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); | | 112 | fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); |
113 | FNR = &fnrloc->fval; | | 113 | FNR = &fnrloc->fval; |
114 | subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab); | | 114 | subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab); |
115 | SUBSEP = &subseploc->sval; | | 115 | SUBSEP = &subseploc->sval; |
116 | rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); | | 116 | rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); |
117 | RSTART = &rstartloc->fval; | | 117 | RSTART = &rstartloc->fval; |
118 | rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); | | 118 | rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); |
119 | RLENGTH = &rlengthloc->fval; | | 119 | RLENGTH = &rlengthloc->fval; |
120 | symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); | | 120 | symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); |
121 | free(symtabloc->sval); | | 121 | free(symtabloc->sval); |
122 | symtabloc->sval = (char *) symtab; | | 122 | symtabloc->sval = (char *) symtab; |
123 | } | | 123 | } |
124 | | | 124 | |
125 | void arginit(int ac, char **av) /* set up ARGV and ARGC */ | | 125 | void arginit(int ac, char **av) /* set up ARGV and ARGC */ |
126 | { | | 126 | { |
127 | Cell *cp; | | 127 | Cell *cp; |
128 | int i; | | 128 | int i; |
129 | char temp[50]; | | 129 | char temp[50]; |
130 | | | 130 | |
131 | ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; | | 131 | ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; |
132 | cp = setsymtab("ARGV", "", 0.0, ARR, symtab); | | 132 | cp = setsymtab("ARGV", "", 0.0, ARR, symtab); |
133 | ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ | | 133 | ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ |
134 | free(cp->sval); | | 134 | free(cp->sval); |
135 | cp->sval = (char *) ARGVtab; | | 135 | cp->sval = (char *) ARGVtab; |
136 | for (i = 0; i < ac; i++) { | | 136 | for (i = 0; i < ac; i++) { |
137 | sprintf(temp, "%d", i); | | 137 | sprintf(temp, "%d", i); |
138 | if (is_number(*av)) | | 138 | if (is_number(*av)) |
139 | setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); | | 139 | setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); |
140 | else | | 140 | else |
141 | setsymtab(temp, *av, 0.0, STR, ARGVtab); | | 141 | setsymtab(temp, *av, 0.0, STR, ARGVtab); |
142 | av++; | | 142 | av++; |
143 | } | | 143 | } |
144 | } | | 144 | } |
145 | | | 145 | |
146 | void envinit(char **envp) /* set up ENVIRON variable */ | | 146 | void envinit(char **envp) /* set up ENVIRON variable */ |
147 | { | | 147 | { |
148 | Cell *cp; | | 148 | Cell *cp; |
149 | char *p; | | 149 | char *p; |
150 | | | 150 | |
151 | cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); | | 151 | cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); |
152 | ENVtab = makesymtab(NSYMTAB); | | 152 | ENVtab = makesymtab(NSYMTAB); |
153 | free(cp->sval); | | 153 | free(cp->sval); |
154 | cp->sval = (char *) ENVtab; | | 154 | cp->sval = (char *) ENVtab; |
155 | for ( ; *envp; envp++) { | | 155 | for ( ; *envp; envp++) { |
156 | if ((p = strchr(*envp, '=')) == NULL) | | 156 | if ((p = strchr(*envp, '=')) == NULL) |
157 | continue; | | 157 | continue; |
158 | if( p == *envp ) /* no left hand side name in env string */ | | 158 | if( p == *envp ) /* no left hand side name in env string */ |
159 | continue; | | 159 | continue; |
160 | *p++ = 0; /* split into two strings at = */ | | 160 | *p++ = 0; /* split into two strings at = */ |
161 | if (is_number(p)) | | 161 | if (is_number(p)) |
162 | setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); | | 162 | setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); |
163 | else | | 163 | else |
164 | setsymtab(*envp, p, 0.0, STR, ENVtab); | | 164 | setsymtab(*envp, p, 0.0, STR, ENVtab); |
165 | p[-1] = '='; /* restore in case env is passed down to a shell */ | | 165 | p[-1] = '='; /* restore in case env is passed down to a shell */ |
166 | } | | 166 | } |
167 | } | | 167 | } |
168 | | | 168 | |
169 | Array *makesymtab(int n) /* make a new symbol table */ | | 169 | Array *makesymtab(int n) /* make a new symbol table */ |
170 | { | | 170 | { |
171 | Array *ap; | | 171 | Array *ap; |
172 | Cell **tp; | | 172 | Cell **tp; |
173 | | | 173 | |
174 | ap = malloc(sizeof(*ap)); | | 174 | ap = malloc(sizeof(*ap)); |
175 | tp = calloc(n, sizeof(*tp)); | | 175 | tp = calloc(n, sizeof(*tp)); |
176 | if (ap == NULL || tp == NULL) | | 176 | if (ap == NULL || tp == NULL) |
177 | FATAL("out of space in makesymtab"); | | 177 | FATAL("out of space in makesymtab"); |
178 | ap->nelem = 0; | | 178 | ap->nelem = 0; |
179 | ap->size = n; | | 179 | ap->size = n; |
180 | ap->tab = tp; | | 180 | ap->tab = tp; |
181 | return(ap); | | 181 | return(ap); |
182 | } | | 182 | } |
183 | | | 183 | |
184 | void freesymtab(Cell *ap) /* free a symbol table */ | | 184 | void freesymtab(Cell *ap) /* free a symbol table */ |
185 | { | | 185 | { |
186 | Cell *cp, *temp; | | 186 | Cell *cp, *temp; |
187 | Array *tp; | | 187 | Array *tp; |
188 | int i; | | 188 | int i; |
189 | | | 189 | |
190 | if (!isarr(ap)) | | 190 | if (!isarr(ap)) |
191 | return; | | 191 | return; |
192 | tp = (Array *) ap->sval; | | 192 | tp = (Array *) ap->sval; |
193 | if (tp == NULL) | | 193 | if (tp == NULL) |
194 | return; | | 194 | return; |
195 | for (i = 0; i < tp->size; i++) { | | 195 | for (i = 0; i < tp->size; i++) { |
196 | for (cp = tp->tab[i]; cp != NULL; cp = temp) { | | 196 | for (cp = tp->tab[i]; cp != NULL; cp = temp) { |
197 | xfree(cp->nval); | | 197 | xfree(cp->nval); |
198 | if (freeable(cp)) | | 198 | if (freeable(cp)) |
199 | xfree(cp->sval); | | 199 | xfree(cp->sval); |
200 | temp = cp->cnext; /* avoids freeing then using */ | | 200 | temp = cp->cnext; /* avoids freeing then using */ |
201 | free(cp); | | 201 | free(cp); |
202 | tp->nelem--; | | 202 | tp->nelem--; |
203 | } | | 203 | } |
204 | tp->tab[i] = NULL; | | 204 | tp->tab[i] = NULL; |
205 | } | | 205 | } |
206 | if (tp->nelem != 0) | | 206 | if (tp->nelem != 0) |
207 | WARNING("can't happen: inconsistent element count freeing %s", ap->nval); | | 207 | WARNING("can't happen: inconsistent element count freeing %s", ap->nval); |
208 | free(tp->tab); | | 208 | free(tp->tab); |
209 | free(tp); | | 209 | free(tp); |
210 | } | | 210 | } |
211 | | | 211 | |
212 | void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ | | 212 | void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ |
213 | { | | 213 | { |
214 | Array *tp; | | 214 | Array *tp; |
215 | Cell *p, *prev = NULL; | | 215 | Cell *p, *prev = NULL; |
216 | int h; | | 216 | int h; |
217 | | | 217 | |
218 | tp = (Array *) ap->sval; | | 218 | tp = (Array *) ap->sval; |
219 | h = hash(s, tp->size); | | 219 | h = hash(s, tp->size); |
220 | for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) | | 220 | for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) |
221 | if (strcmp(s, p->nval) == 0) { | | 221 | if (strcmp(s, p->nval) == 0) { |
222 | if (prev == NULL) /* 1st one */ | | 222 | if (prev == NULL) /* 1st one */ |
223 | tp->tab[h] = p->cnext; | | 223 | tp->tab[h] = p->cnext; |
224 | else /* middle somewhere */ | | 224 | else /* middle somewhere */ |
225 | prev->cnext = p->cnext; | | 225 | prev->cnext = p->cnext; |
226 | if (freeable(p)) | | 226 | if (freeable(p)) |
227 | xfree(p->sval); | | 227 | xfree(p->sval); |
228 | free(p->nval); | | 228 | free(p->nval); |
229 | free(p); | | 229 | free(p); |
230 | tp->nelem--; | | 230 | tp->nelem--; |
231 | return; | | 231 | return; |
232 | } | | 232 | } |
233 | } | | 233 | } |
234 | | | 234 | |
235 | Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) | | 235 | Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) |
236 | { | | 236 | { |
237 | int h; | | 237 | int h; |
238 | Cell *p; | | 238 | Cell *p; |
239 | | | 239 | |
240 | if (n != NULL && (p = lookup(n, tp)) != NULL) { | | 240 | if (n != NULL && (p = lookup(n, tp)) != NULL) { |
241 | dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", | | 241 | dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", |
242 | (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); | | 242 | (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); |
243 | return(p); | | 243 | return(p); |
244 | } | | 244 | } |
245 | p = malloc(sizeof(*p)); | | 245 | p = malloc(sizeof(*p)); |
246 | if (p == NULL) | | 246 | if (p == NULL) |
247 | FATAL("out of space for symbol table at %s", n); | | 247 | FATAL("out of space for symbol table at %s", n); |
248 | p->nval = tostring(n); | | 248 | p->nval = tostring(n); |
249 | p->sval = s ? tostring(s) : tostring(""); | | 249 | p->sval = s ? tostring(s) : tostring(""); |
250 | p->fval = f; | | 250 | p->fval = f; |
251 | p->tval = t; | | 251 | p->tval = t; |
252 | p->csub = CUNK; | | 252 | p->csub = CUNK; |
253 | p->ctype = OCELL; | | 253 | p->ctype = OCELL; |
254 | tp->nelem++; | | 254 | tp->nelem++; |
255 | if (tp->nelem > FULLTAB * tp->size) | | 255 | if (tp->nelem > FULLTAB * tp->size) |
256 | rehash(tp); | | 256 | rehash(tp); |
257 | h = hash(n, tp->size); | | 257 | h = hash(n, tp->size); |
258 | p->cnext = tp->tab[h]; | | 258 | p->cnext = tp->tab[h]; |
259 | tp->tab[h] = p; | | 259 | tp->tab[h] = p; |
260 | dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", | | 260 | dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", |
261 | (void*)p, p->nval, p->sval, p->fval, p->tval) ); | | 261 | (void*)p, p->nval, p->sval, p->fval, p->tval) ); |
262 | return(p); | | 262 | return(p); |
263 | } | | 263 | } |
264 | | | 264 | |
265 | int hash(const char *s, int n) /* form hash value for string s */ | | 265 | int hash(const char *s, int n) /* form hash value for string s */ |
266 | { | | 266 | { |
267 | unsigned hashval; | | 267 | unsigned hashval; |
268 | | | 268 | |
269 | for (hashval = 0; *s != '\0'; s++) | | 269 | for (hashval = 0; *s != '\0'; s++) |
270 | hashval = (*s + 31 * hashval); | | 270 | hashval = (*s + 31 * hashval); |
271 | return hashval % n; | | 271 | return hashval % n; |
272 | } | | 272 | } |
273 | | | 273 | |
274 | void rehash(Array *tp) /* rehash items in small table into big one */ | | 274 | void rehash(Array *tp) /* rehash items in small table into big one */ |
275 | { | | 275 | { |
276 | int i, nh, nsz; | | 276 | int i, nh, nsz; |
277 | Cell *cp, *op, **np; | | 277 | Cell *cp, *op, **np; |
278 | | | 278 | |
279 | nsz = GROWTAB * tp->size; | | 279 | nsz = GROWTAB * tp->size; |
280 | np = calloc(nsz, sizeof(*np)); | | 280 | np = calloc(nsz, sizeof(*np)); |
281 | if (np == NULL) /* can't do it, but can keep running. */ | | 281 | if (np == NULL) /* can't do it, but can keep running. */ |
282 | return; /* someone else will run out later. */ | | 282 | return; /* someone else will run out later. */ |
283 | for (i = 0; i < tp->size; i++) { | | 283 | for (i = 0; i < tp->size; i++) { |
284 | for (cp = tp->tab[i]; cp; cp = op) { | | 284 | for (cp = tp->tab[i]; cp; cp = op) { |
285 | op = cp->cnext; | | 285 | op = cp->cnext; |
286 | nh = hash(cp->nval, nsz); | | 286 | nh = hash(cp->nval, nsz); |
287 | cp->cnext = np[nh]; | | 287 | cp->cnext = np[nh]; |
288 | np[nh] = cp; | | 288 | np[nh] = cp; |
289 | } | | 289 | } |
290 | } | | 290 | } |
291 | free(tp->tab); | | 291 | free(tp->tab); |
292 | tp->tab = np; | | 292 | tp->tab = np; |
293 | tp->size = nsz; | | 293 | tp->size = nsz; |
294 | } | | 294 | } |
295 | | | 295 | |
296 | Cell *lookup(const char *s, Array *tp) /* look for s in tp */ | | 296 | Cell *lookup(const char *s, Array *tp) /* look for s in tp */ |
297 | { | | 297 | { |
298 | Cell *p; | | 298 | Cell *p; |
299 | int h; | | 299 | int h; |
300 | | | 300 | |
301 | h = hash(s, tp->size); | | 301 | h = hash(s, tp->size); |
302 | for (p = tp->tab[h]; p != NULL; p = p->cnext) | | 302 | for (p = tp->tab[h]; p != NULL; p = p->cnext) |
303 | if (strcmp(s, p->nval) == 0) | | 303 | if (strcmp(s, p->nval) == 0) |
304 | return(p); /* found it */ | | 304 | return(p); /* found it */ |
305 | return(NULL); /* not found */ | | 305 | return(NULL); /* not found */ |
306 | } | | 306 | } |
307 | | | 307 | |
308 | Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ | | 308 | Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ |
309 | { | | 309 | { |
310 | int fldno; | | 310 | int fldno; |
311 | | | 311 | |
312 | f += 0.0; /* normalise negative zero to positive zero */ | | 312 | f += 0.0; /* normalise negative zero to positive zero */ |
313 | if ((vp->tval & (NUM | STR)) == 0) | | 313 | if ((vp->tval & (NUM | STR)) == 0) |
314 | funnyvar(vp, "assign to"); | | 314 | funnyvar(vp, "assign to"); |
315 | if (isfld(vp)) { | | 315 | if (isfld(vp)) { |
316 | donerec = false; /* mark $0 invalid */ | | 316 | donerec = false; /* mark $0 invalid */ |
317 | fldno = atoi(vp->nval); | | 317 | fldno = atoi(vp->nval); |
318 | if (fldno > *NF) | | 318 | if (fldno > *NF) |
319 | newfld(fldno); | | 319 | newfld(fldno); |
320 | dprintf( ("setting field %d to %g\n", fldno, f) ); | | 320 | dprintf( ("setting field %d to %g\n", fldno, f) ); |
321 | } else if (&vp->fval == NF) { | | 321 | } else if (&vp->fval == NF) { |
322 | donerec = false; /* mark $0 invalid */ | | 322 | donerec = false; /* mark $0 invalid */ |
323 | setlastfld(f); | | 323 | setlastfld(f); |
324 | dprintf( ("setting NF to %g\n", f) ); | | 324 | dprintf( ("setting NF to %g\n", f) ); |
325 | } else if (isrec(vp)) { | | 325 | } else if (isrec(vp)) { |
326 | donefld = false; /* mark $1... invalid */ | | 326 | donefld = false; /* mark $1... invalid */ |
327 | donerec = true; | | 327 | donerec = true; |
328 | savefs(); | | 328 | savefs(); |
329 | } else if (vp == ofsloc) { | | 329 | } else if (vp == ofsloc) { |
330 | if (!donerec) | | 330 | if (!donerec) |
331 | recbld(); | | 331 | recbld(); |
332 | } | | 332 | } |
333 | if (freeable(vp)) | | 333 | if (freeable(vp)) |
334 | xfree(vp->sval); /* free any previous string */ | | 334 | xfree(vp->sval); /* free any previous string */ |
335 | vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */ | | 335 | vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */ |
336 | vp->fmt = NULL; | | 336 | vp->fmt = NULL; |
337 | vp->tval |= NUM; /* mark number ok */ | | 337 | vp->tval |= NUM; /* mark number ok */ |
338 | if (f == -0) /* who would have thought this possible? */ | | 338 | if (f == -0) /* who would have thought this possible? */ |
339 | f = 0; | | 339 | f = 0; |
340 | dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) ); | | 340 | dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) ); |
341 | return vp->fval = f; | | 341 | return vp->fval = f; |
342 | } | | 342 | } |
343 | | | 343 | |
344 | void funnyvar(Cell *vp, const char *rw) | | 344 | void funnyvar(Cell *vp, const char *rw) |
345 | { | | 345 | { |
346 | if (isarr(vp)) | | 346 | if (isarr(vp)) |
347 | FATAL("can't %s %s; it's an array name.", rw, vp->nval); | | 347 | FATAL("can't %s %s; it's an array name.", rw, vp->nval); |
348 | if (vp->tval & FCN) | | 348 | if (vp->tval & FCN) |
349 | FATAL("can't %s %s; it's a function.", rw, vp->nval); | | 349 | FATAL("can't %s %s; it's a function.", rw, vp->nval); |
350 | WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", | | 350 | WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", |
351 | (void *)vp, vp->nval, vp->sval, vp->fval, vp->tval); | | 351 | (void *)vp, vp->nval, vp->sval, vp->fval, vp->tval); |
352 | } | | 352 | } |
353 | | | 353 | |
354 | char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ | | 354 | char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ |
355 | { | | 355 | { |
356 | char *t; | | 356 | char *t; |
357 | int fldno; | | 357 | int fldno; |
358 | Awkfloat f; | | 358 | Awkfloat f; |
359 | | | 359 | |
360 | dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", | | 360 | dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", |
361 | (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); | | 361 | (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); |
362 | if ((vp->tval & (NUM | STR)) == 0) | | 362 | if ((vp->tval & (NUM | STR)) == 0) |
363 | funnyvar(vp, "assign to"); | | 363 | funnyvar(vp, "assign to"); |
364 | if (isfld(vp)) { | | 364 | if (isfld(vp)) { |
365 | donerec = false; /* mark $0 invalid */ | | 365 | donerec = false; /* mark $0 invalid */ |
366 | fldno = atoi(vp->nval); | | 366 | fldno = atoi(vp->nval); |
367 | if (fldno > *NF) | | 367 | if (fldno > *NF) |
368 | newfld(fldno); | | 368 | newfld(fldno); |
369 | dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); | | 369 | dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); |
370 | } else if (isrec(vp)) { | | 370 | } else if (isrec(vp)) { |
371 | donefld = false; /* mark $1... invalid */ | | 371 | donefld = false; /* mark $1... invalid */ |
372 | donerec = true; | | 372 | donerec = true; |
373 | savefs(); | | 373 | savefs(); |
374 | } else if (vp == ofsloc) { | | 374 | } else if (vp == ofsloc) { |
375 | if (!donerec) | | 375 | if (!donerec) |
376 | recbld(); | | 376 | recbld(); |
377 | } | | 377 | } |
378 | t = s ? tostring(s) : tostring(""); /* in case it's self-assign */ | | 378 | t = s ? tostring(s) : tostring(""); /* in case it's self-assign */ |
379 | if (freeable(vp)) | | 379 | if (freeable(vp)) |
380 | xfree(vp->sval); | | 380 | xfree(vp->sval); |
381 | vp->tval &= ~(NUM|CONVC|CONVO); | | 381 | vp->tval &= ~(NUM|CONVC|CONVO); |
382 | vp->tval |= STR; | | 382 | vp->tval |= STR; |
383 | vp->fmt = NULL; | | 383 | vp->fmt = NULL; |
384 | setfree(vp); | | 384 | setfree(vp); |
385 | dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", | | 385 | dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", |
386 | (void*)vp, NN(vp->nval), t, t, vp->tval, donerec, donefld) ); | | 386 | (void*)vp, NN(vp->nval), t, t, vp->tval, donerec, donefld) ); |
387 | vp->sval = t; | | 387 | vp->sval = t; |
388 | if (&vp->fval == NF) { | | 388 | if (&vp->fval == NF) { |
389 | donerec = false; /* mark $0 invalid */ | | 389 | donerec = false; /* mark $0 invalid */ |
390 | f = getfval(vp); | | 390 | f = getfval(vp); |
391 | setlastfld(f); | | 391 | setlastfld(f); |
392 | dprintf( ("setting NF to %g\n", f) ); | | 392 | dprintf( ("setting NF to %g\n", f) ); |
393 | } | | 393 | } |
394 | | | 394 | |
395 | return(vp->sval); | | 395 | return(vp->sval); |
396 | } | | 396 | } |
397 | | | 397 | |
398 | Awkfloat getfval(Cell *vp) /* get float val of a Cell */ | | 398 | Awkfloat getfval(Cell *vp) /* get float val of a Cell */ |
399 | { | | 399 | { |
400 | if ((vp->tval & (NUM | STR)) == 0) | | 400 | if ((vp->tval & (NUM | STR)) == 0) |
401 | funnyvar(vp, "read value of"); | | 401 | funnyvar(vp, "read value of"); |
402 | if (isfld(vp) && !donefld) | | 402 | if (isfld(vp) && !donefld) |
403 | fldbld(); | | 403 | fldbld(); |
404 | else if (isrec(vp) && !donerec) | | 404 | else if (isrec(vp) && !donerec) |
405 | recbld(); | | 405 | recbld(); |
406 | if (!isnum(vp)) { /* not a number */ | | 406 | if (!isnum(vp)) { /* not a number */ |
407 | vp->fval = atof(vp->sval); /* best guess */ | | 407 | if (is_number(vp->sval) && !(vp->tval&CON)) { |
408 | if (is_number(vp->sval) && !(vp->tval&CON)) | | 408 | vp->fval = atof(vp->sval); /* best guess */ |
409 | vp->tval |= NUM; /* make NUM only sparingly */ | | 409 | vp->tval |= NUM; /* make NUM only sparingly */ |
| | | 410 | } else { |
| | | 411 | vp->fval = 0; |
| | | 412 | } |
410 | } | | 413 | } |
411 | dprintf( ("getfval %p: %s = %g, t=%o\n", | | 414 | dprintf( ("getfval %p: %s = %g, t=%o\n", |
412 | (void*)vp, NN(vp->nval), vp->fval, vp->tval) ); | | 415 | (void*)vp, NN(vp->nval), vp->fval, vp->tval) ); |
413 | return(vp->fval); | | 416 | return(vp->fval); |
414 | } | | 417 | } |
415 | | | 418 | |
416 | static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ | | 419 | static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ |
417 | { | | 420 | { |
418 | char s[256]; | | 421 | char s[256]; |
419 | double dtemp; | | 422 | double dtemp; |
420 | | | 423 | |
421 | if ((vp->tval & (NUM | STR)) == 0) | | 424 | if ((vp->tval & (NUM | STR)) == 0) |
422 | funnyvar(vp, "read value of"); | | 425 | funnyvar(vp, "read value of"); |
423 | if (isfld(vp) && ! donefld) | | 426 | if (isfld(vp) && ! donefld) |
424 | fldbld(); | | 427 | fldbld(); |
425 | else if (isrec(vp) && ! donerec) | | 428 | else if (isrec(vp) && ! donerec) |
426 | recbld(); | | 429 | recbld(); |
427 | | | 430 | |
428 | /* | | 431 | /* |
429 | * ADR: This is complicated and more fragile than is desirable. | | 432 | * ADR: This is complicated and more fragile than is desirable. |
430 | * Retrieving a string value for a number associates the string | | 433 | * Retrieving a string value for a number associates the string |
431 | * value with the scalar. Previously, the string value was | | 434 | * value with the scalar. Previously, the string value was |
432 | * sticky, meaning if converted via OFMT that became the value | | 435 | * sticky, meaning if converted via OFMT that became the value |
433 | * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT | | 436 | * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT |
434 | * changed after a string value was retrieved, the original value | | 437 | * changed after a string value was retrieved, the original value |
435 | * was maintained and used. Also not per POSIX. | | 438 | * was maintained and used. Also not per POSIX. |
436 | * | | 439 | * |
437 | * We work around this design by adding two additional flags, | | 440 | * We work around this design by adding two additional flags, |
438 | * CONVC and CONVO, indicating how the string value was | | 441 | * CONVC and CONVO, indicating how the string value was |
439 | * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy | | 442 | * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy |
440 | * of the pointer to the xFMT format string used for the | | 443 | * of the pointer to the xFMT format string used for the |
441 | * conversion. This pointer is only read, **never** dereferenced. | | 444 | * conversion. This pointer is only read, **never** dereferenced. |
442 | * The next time we do a conversion, if it's coming from the same | | 445 | * The next time we do a conversion, if it's coming from the same |
443 | * xFMT as last time, and the pointer value is different, we | | 446 | * xFMT as last time, and the pointer value is different, we |
444 | * know that the xFMT format string changed, and we need to | | 447 | * know that the xFMT format string changed, and we need to |
445 | * redo the conversion. If it's the same, we don't have to. | | 448 | * redo the conversion. If it's the same, we don't have to. |
446 | * | | 449 | * |
447 | * There are also several cases where we don't do a conversion, | | 450 | * There are also several cases where we don't do a conversion, |
448 | * such as for a field (see the checks below). | | 451 | * such as for a field (see the checks below). |
449 | */ | | 452 | */ |
450 | | | 453 | |
451 | /* Don't duplicate the code for actually updating the value */ | | 454 | /* Don't duplicate the code for actually updating the value */ |
452 | #define update_str_val(vp) \ | | 455 | #define update_str_val(vp) \ |
453 | { \ | | 456 | { \ |
454 | if (freeable(vp)) \ | | 457 | if (freeable(vp)) \ |
455 | xfree(vp->sval); \ | | 458 | xfree(vp->sval); \ |
456 | if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ | | 459 | if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ |
457 | snprintf(s, sizeof (s), "%.30g", vp->fval); \ | | 460 | snprintf(s, sizeof (s), "%.30g", vp->fval); \ |
458 | else \ | | 461 | else \ |
459 | snprintf(s, sizeof (s), *fmt, vp->fval); \ | | 462 | snprintf(s, sizeof (s), *fmt, vp->fval); \ |
460 | vp->sval = tostring(s); \ | | 463 | vp->sval = tostring(s); \ |
461 | vp->tval &= ~DONTFREE; \ | | 464 | vp->tval &= ~DONTFREE; \ |
462 | vp->tval |= STR; \ | | 465 | vp->tval |= STR; \ |
463 | } | | 466 | } |
464 | | | 467 | |
465 | if (isstr(vp) == 0) { | | 468 | if (isstr(vp) == 0) { |
466 | update_str_val(vp); | | 469 | update_str_val(vp); |
467 | if (fmt == OFMT) { | | 470 | if (fmt == OFMT) { |
468 | vp->tval &= ~CONVC; | | 471 | vp->tval &= ~CONVC; |
469 | vp->tval |= CONVO; | | 472 | vp->tval |= CONVO; |
470 | } else { | | 473 | } else { |
471 | /* CONVFMT */ | | 474 | /* CONVFMT */ |
472 | vp->tval &= ~CONVO; | | 475 | vp->tval &= ~CONVO; |
473 | vp->tval |= CONVC; | | 476 | vp->tval |= CONVC; |
474 | } | | 477 | } |
475 | vp->fmt = *fmt; | | 478 | vp->fmt = *fmt; |
476 | } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) { | | 479 | } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) { |
477 | goto done; | | 480 | goto done; |
478 | } else if (isstr(vp)) { | | 481 | } else if (isstr(vp)) { |
479 | if (fmt == OFMT) { | | 482 | if (fmt == OFMT) { |
480 | if ((vp->tval & CONVC) != 0 | | 483 | if ((vp->tval & CONVC) != 0 |
481 | || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) { | | 484 | || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) { |
482 | update_str_val(vp); | | 485 | update_str_val(vp); |
483 | vp->tval &= ~CONVC; | | 486 | vp->tval &= ~CONVC; |
484 | vp->tval |= CONVO; | | 487 | vp->tval |= CONVO; |
485 | vp->fmt = *fmt; | | 488 | vp->fmt = *fmt; |
486 | } | | 489 | } |
487 | } else { | | 490 | } else { |
488 | /* CONVFMT */ | | 491 | /* CONVFMT */ |
489 | if ((vp->tval & CONVO) != 0 | | 492 | if ((vp->tval & CONVO) != 0 |
490 | || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) { | | 493 | || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) { |
491 | update_str_val(vp); | | 494 | update_str_val(vp); |
492 | vp->tval &= ~CONVO; | | 495 | vp->tval &= ~CONVO; |
493 | vp->tval |= CONVC; | | 496 | vp->tval |= CONVC; |
494 | vp->fmt = *fmt; | | 497 | vp->fmt = *fmt; |
495 | } | | 498 | } |
496 | } | | 499 | } |
497 | } | | 500 | } |
498 | done: | | 501 | done: |
499 | dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", | | 502 | dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", |
500 | (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); | | 503 | (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); |
501 | return(vp->sval); | | 504 | return(vp->sval); |
502 | } | | 505 | } |
503 | | | 506 | |
504 | char *getsval(Cell *vp) /* get string val of a Cell */ | | 507 | char *getsval(Cell *vp) /* get string val of a Cell */ |
505 | { | | 508 | { |
506 | return get_str_val(vp, CONVFMT); | | 509 | return get_str_val(vp, CONVFMT); |
507 | } | | 510 | } |
508 | | | 511 | |
509 | char *getpssval(Cell *vp) /* get string val of a Cell for print */ | | 512 | char *getpssval(Cell *vp) /* get string val of a Cell for print */ |
510 | { | | 513 | { |
511 | return get_str_val(vp, OFMT); | | 514 | return get_str_val(vp, OFMT); |
512 | } | | 515 | } |
513 | | | 516 | |
514 | | | 517 | |
515 | char *tostring(const char *s) /* make a copy of string s */ | | 518 | char *tostring(const char *s) /* make a copy of string s */ |
516 | { | | 519 | { |
517 | char *p = strdup(s); | | 520 | char *p = strdup(s); |
518 | if (p == NULL) | | 521 | if (p == NULL) |
519 | FATAL("out of space in tostring on %s", s); | | 522 | FATAL("out of space in tostring on %s", s); |
520 | return(p); | | 523 | return(p); |
521 | } | | 524 | } |
522 | | | 525 | |
523 | char *tostringN(const char *s, size_t n) /* make a copy of string s */ | | 526 | char *tostringN(const char *s, size_t n) /* make a copy of string s */ |
524 | { | | 527 | { |
525 | char *p; | | 528 | char *p; |
526 | | | 529 | |
527 | p = malloc(n); | | 530 | p = malloc(n); |
528 | if (p == NULL) | | 531 | if (p == NULL) |
529 | FATAL("out of space in tostring on %s", s); | | 532 | FATAL("out of space in tostring on %s", s); |
530 | strcpy(p, s); | | 533 | strcpy(p, s); |
531 | return(p); | | 534 | return(p); |
532 | } | | 535 | } |
533 | | | 536 | |
534 | Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */ | | 537 | Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */ |
535 | { | | 538 | { |
536 | Cell *c; | | 539 | Cell *c; |
537 | char *p; | | 540 | char *p; |
538 | char *sa = getsval(a); | | 541 | char *sa = getsval(a); |
539 | char *sb = getsval(b); | | 542 | char *sb = getsval(b); |
540 | size_t l = strlen(sa) + strlen(sb) + 1; | | 543 | size_t l = strlen(sa) + strlen(sb) + 1; |
541 | p = malloc(l); | | 544 | p = malloc(l); |
542 | if (p == NULL) | | 545 | if (p == NULL) |
543 | FATAL("out of space concatenating %s and %s", sa, sb); | | 546 | FATAL("out of space concatenating %s and %s", sa, sb); |
544 | snprintf(p, l, "%s%s", sa, sb); | | 547 | snprintf(p, l, "%s%s", sa, sb); |
545 | | | 548 | |
546 | l++; // add room for ' ' | | 549 | l++; // add room for ' ' |
547 | char *newbuf = malloc(l); | | 550 | char *newbuf = malloc(l); |
548 | if (newbuf == NULL) | | 551 | if (newbuf == NULL) |
549 | FATAL("out of space concatenating %s and %s", sa, sb); | | 552 | FATAL("out of space concatenating %s and %s", sa, sb); |
550 | // See string() in lex.c; a string "xx" is stored in the symbol | | 553 | // See string() in lex.c; a string "xx" is stored in the symbol |
551 | // table as "xx ". | | 554 | // table as "xx ". |
552 | snprintf(newbuf, l, "%s ", p); | | 555 | snprintf(newbuf, l, "%s ", p); |
553 | c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab); | | 556 | c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab); |
554 | free(p); | | 557 | free(p); |
555 | free(newbuf); | | 558 | free(newbuf); |
556 | return c; | | 559 | return c; |
557 | } | | 560 | } |
558 | | | 561 | |
559 | char *qstring(const char *is, int delim) /* collect string up to next delim */ | | 562 | char *qstring(const char *is, int delim) /* collect string up to next delim */ |
560 | { | | 563 | { |
561 | const char *os = is; | | 564 | const char *os = is; |
562 | int c, n; | | 565 | int c, n; |
563 | const uschar *s = (const uschar *) is; | | 566 | const uschar *s = (const uschar *) is; |
564 | uschar *buf, *bp; | | 567 | uschar *buf, *bp; |
565 | | | 568 | |
566 | if ((buf = malloc(strlen(is)+3)) == NULL) | | 569 | if ((buf = malloc(strlen(is)+3)) == NULL) |
567 | FATAL( "out of space in qstring(%s)", s); | | 570 | FATAL( "out of space in qstring(%s)", s); |
568 | for (bp = buf; (c = *s) != delim; s++) { | | 571 | for (bp = buf; (c = *s) != delim; s++) { |
569 | if (c == '\n') | | 572 | if (c == '\n') |
570 | SYNTAX( "newline in string %.20s...", os ); | | 573 | SYNTAX( "newline in string %.20s...", os ); |
571 | else if (c != '\\') | | 574 | else if (c != '\\') |
572 | *bp++ = c; | | 575 | *bp++ = c; |
573 | else { /* \something */ | | 576 | else { /* \something */ |
574 | c = *++s; | | 577 | c = *++s; |
575 | if (c == 0) { /* \ at end */ | | 578 | if (c == 0) { /* \ at end */ |
576 | *bp++ = '\\'; | | 579 | *bp++ = '\\'; |
577 | break; /* for loop */ | | 580 | break; /* for loop */ |
578 | } | | 581 | } |
579 | switch (c) { | | 582 | switch (c) { |
580 | case '\\': *bp++ = '\\'; break; | | 583 | case '\\': *bp++ = '\\'; break; |
581 | case 'n': *bp++ = '\n'; break; | | 584 | case 'n': *bp++ = '\n'; break; |
582 | case 't': *bp++ = '\t'; break; | | 585 | case 't': *bp++ = '\t'; break; |
583 | case 'b': *bp++ = '\b'; break; | | 586 | case 'b': *bp++ = '\b'; break; |
584 | case 'f': *bp++ = '\f'; break; | | 587 | case 'f': *bp++ = '\f'; break; |
585 | case 'r': *bp++ = '\r'; break; | | 588 | case 'r': *bp++ = '\r'; break; |
586 | case 'v': *bp++ = '\v'; break; | | 589 | case 'v': *bp++ = '\v'; break; |
587 | case 'a': *bp++ = '\a'; break; | | 590 | case 'a': *bp++ = '\a'; break; |
588 | default: | | 591 | default: |
589 | if (!isdigit(c)) { | | 592 | if (!isdigit(c)) { |
590 | *bp++ = c; | | 593 | *bp++ = c; |
591 | break; | | 594 | break; |
592 | } | | 595 | } |
593 | n = c - '0'; | | 596 | n = c - '0'; |
594 | if (isdigit(s[1])) { | | 597 | if (isdigit(s[1])) { |
595 | n = 8 * n + *++s - '0'; | | 598 | n = 8 * n + *++s - '0'; |
596 | if (isdigit(s[1])) | | 599 | if (isdigit(s[1])) |
597 | n = 8 * n + *++s - '0'; | | 600 | n = 8 * n + *++s - '0'; |
598 | } | | 601 | } |
599 | *bp++ = n; | | 602 | *bp++ = n; |
600 | break; | | 603 | break; |
601 | } | | 604 | } |
602 | } | | 605 | } |
603 | } | | 606 | } |
604 | *bp++ = 0; | | 607 | *bp++ = 0; |
605 | return (char *) buf; | | 608 | return (char *) buf; |
606 | } | | 609 | } |
607 | | | 610 | |
608 | const char *flags2str(int flags) | | 611 | const char *flags2str(int flags) |
609 | { | | 612 | { |
610 | static const struct ftab { | | 613 | static const struct ftab { |
611 | const char *name; | | 614 | const char *name; |
612 | int value; | | 615 | int value; |
613 | } flagtab[] = { | | 616 | } flagtab[] = { |
614 | { "NUM", NUM }, | | 617 | { "NUM", NUM }, |
615 | { "STR", STR }, | | 618 | { "STR", STR }, |
616 | { "DONTFREE", DONTFREE }, | | 619 | { "DONTFREE", DONTFREE }, |
617 | { "CON", CON }, | | 620 | { "CON", CON }, |
618 | { "ARR", ARR }, | | 621 | { "ARR", ARR }, |
619 | { "FCN", FCN }, | | 622 | { "FCN", FCN }, |
620 | { "FLD", FLD }, | | 623 | { "FLD", FLD }, |
621 | { "REC", REC }, | | 624 | { "REC", REC }, |
622 | { "CONVC", CONVC }, | | 625 | { "CONVC", CONVC }, |
623 | { "CONVO", CONVO }, | | 626 | { "CONVO", CONVO }, |
624 | { NULL, 0 } | | 627 | { NULL, 0 } |
625 | }; | | 628 | }; |
626 | static char buf[100]; | | 629 | static char buf[100]; |
627 | int i; | | 630 | int i; |
628 | char *cp = buf; | | 631 | char *cp = buf; |
629 | | | 632 | |
630 | for (i = 0; flagtab[i].name != NULL; i++) { | | 633 | for (i = 0; flagtab[i].name != NULL; i++) { |
631 | if ((flags & flagtab[i].value) != 0) { | | 634 | if ((flags & flagtab[i].value) != 0) { |
632 | if (cp > buf) | | 635 | if (cp > buf) |
633 | *cp++ = '|'; | | 636 | *cp++ = '|'; |
634 | strcpy(cp, flagtab[i].name); | | 637 | strcpy(cp, flagtab[i].name); |
635 | cp += strlen(cp); | | 638 | cp += strlen(cp); |
636 | } | | 639 | } |
637 | } | | 640 | } |
638 | | | 641 | |
639 | return buf; | | 642 | return buf; |
640 | } | | 643 | } |