| @@ -1,661 +1,663 @@ | | | @@ -1,661 +1,663 @@ |
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 | static int checkstr(const char *s, const char *v) | | 398 | static int checkstr(const char *s, const char *v) |
399 | { | | 399 | { |
400 | while (*s && tolower((unsigned char)*s) == *v) | | 400 | while (*s && tolower((unsigned char)*s) == *v) |
401 | s++, v++; | | 401 | s++, v++; |
402 | return !(*s || *v); | | 402 | return !(*s || *v); |
403 | } | | 403 | } |
404 | | | 404 | |
405 | static int checkinfnan(const char *s) | | 405 | static int checkinfnan(const char *s) |
406 | { | | 406 | { |
| | | 407 | if (*s == '+' || *s == '-') |
| | | 408 | s++; |
407 | switch (tolower((unsigned char)*s)) { | | 409 | switch (tolower((unsigned char)*s)) { |
408 | case 'i': | | 410 | case 'i': |
409 | return checkstr(s, "inf") || checkstr(s, "infinity"); | | 411 | return checkstr(s, "inf") || checkstr(s, "infinity"); |
410 | case 'n': | | 412 | case 'n': |
411 | return checkstr(s, "nan"); | | 413 | return checkstr(s, "nan"); |
412 | default: | | 414 | default: |
413 | return 1; | | 415 | return 1; |
414 | } | | 416 | } |
415 | } | | 417 | } |
416 | | | 418 | |
417 | Awkfloat getfval(Cell *vp) /* get float val of a Cell */ | | 419 | Awkfloat getfval(Cell *vp) /* get float val of a Cell */ |
418 | { | | 420 | { |
419 | if ((vp->tval & (NUM | STR)) == 0) | | 421 | if ((vp->tval & (NUM | STR)) == 0) |
420 | funnyvar(vp, "read value of"); | | 422 | funnyvar(vp, "read value of"); |
421 | if (isfld(vp) && !donefld) | | 423 | if (isfld(vp) && !donefld) |
422 | fldbld(); | | 424 | fldbld(); |
423 | else if (isrec(vp) && !donerec) | | 425 | else if (isrec(vp) && !donerec) |
424 | recbld(); | | 426 | recbld(); |
425 | if (!isnum(vp)) { /* not a number */ | | 427 | if (!isnum(vp)) { /* not a number */ |
426 | if (checkinfnan(vp->sval)) | | 428 | if (checkinfnan(vp->sval)) |
427 | vp->fval = atof(vp->sval); /* best guess */ | | 429 | vp->fval = atof(vp->sval); /* best guess */ |
428 | if (is_number(vp->sval) && !(vp->tval&CON)) { | | 430 | if (is_number(vp->sval) && !(vp->tval&CON)) { |
429 | vp->tval |= NUM; /* make NUM only sparingly */ | | 431 | vp->tval |= NUM; /* make NUM only sparingly */ |
430 | } | | 432 | } |
431 | } | | 433 | } |
432 | dprintf( ("getfval %p: %s = %g, t=%o\n", | | 434 | dprintf( ("getfval %p: %s = %g, t=%o\n", |
433 | (void*)vp, NN(vp->nval), vp->fval, vp->tval) ); | | 435 | (void*)vp, NN(vp->nval), vp->fval, vp->tval) ); |
434 | return(vp->fval); | | 436 | return(vp->fval); |
435 | } | | 437 | } |
436 | | | 438 | |
437 | static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ | | 439 | static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ |
438 | { | | 440 | { |
439 | char s[256]; | | 441 | char s[256]; |
440 | double dtemp; | | 442 | double dtemp; |
441 | | | 443 | |
442 | if ((vp->tval & (NUM | STR)) == 0) | | 444 | if ((vp->tval & (NUM | STR)) == 0) |
443 | funnyvar(vp, "read value of"); | | 445 | funnyvar(vp, "read value of"); |
444 | if (isfld(vp) && ! donefld) | | 446 | if (isfld(vp) && ! donefld) |
445 | fldbld(); | | 447 | fldbld(); |
446 | else if (isrec(vp) && ! donerec) | | 448 | else if (isrec(vp) && ! donerec) |
447 | recbld(); | | 449 | recbld(); |
448 | | | 450 | |
449 | /* | | 451 | /* |
450 | * ADR: This is complicated and more fragile than is desirable. | | 452 | * ADR: This is complicated and more fragile than is desirable. |
451 | * Retrieving a string value for a number associates the string | | 453 | * Retrieving a string value for a number associates the string |
452 | * value with the scalar. Previously, the string value was | | 454 | * value with the scalar. Previously, the string value was |
453 | * sticky, meaning if converted via OFMT that became the value | | 455 | * sticky, meaning if converted via OFMT that became the value |
454 | * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT | | 456 | * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT |
455 | * changed after a string value was retrieved, the original value | | 457 | * changed after a string value was retrieved, the original value |
456 | * was maintained and used. Also not per POSIX. | | 458 | * was maintained and used. Also not per POSIX. |
457 | * | | 459 | * |
458 | * We work around this design by adding two additional flags, | | 460 | * We work around this design by adding two additional flags, |
459 | * CONVC and CONVO, indicating how the string value was | | 461 | * CONVC and CONVO, indicating how the string value was |
460 | * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy | | 462 | * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy |
461 | * of the pointer to the xFMT format string used for the | | 463 | * of the pointer to the xFMT format string used for the |
462 | * conversion. This pointer is only read, **never** dereferenced. | | 464 | * conversion. This pointer is only read, **never** dereferenced. |
463 | * The next time we do a conversion, if it's coming from the same | | 465 | * The next time we do a conversion, if it's coming from the same |
464 | * xFMT as last time, and the pointer value is different, we | | 466 | * xFMT as last time, and the pointer value is different, we |
465 | * know that the xFMT format string changed, and we need to | | 467 | * know that the xFMT format string changed, and we need to |
466 | * redo the conversion. If it's the same, we don't have to. | | 468 | * redo the conversion. If it's the same, we don't have to. |
467 | * | | 469 | * |
468 | * There are also several cases where we don't do a conversion, | | 470 | * There are also several cases where we don't do a conversion, |
469 | * such as for a field (see the checks below). | | 471 | * such as for a field (see the checks below). |
470 | */ | | 472 | */ |
471 | | | 473 | |
472 | /* Don't duplicate the code for actually updating the value */ | | 474 | /* Don't duplicate the code for actually updating the value */ |
473 | #define update_str_val(vp) \ | | 475 | #define update_str_val(vp) \ |
474 | { \ | | 476 | { \ |
475 | if (freeable(vp)) \ | | 477 | if (freeable(vp)) \ |
476 | xfree(vp->sval); \ | | 478 | xfree(vp->sval); \ |
477 | if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ | | 479 | if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ |
478 | snprintf(s, sizeof (s), "%.30g", vp->fval); \ | | 480 | snprintf(s, sizeof (s), "%.30g", vp->fval); \ |
479 | else \ | | 481 | else \ |
480 | snprintf(s, sizeof (s), *fmt, vp->fval); \ | | 482 | snprintf(s, sizeof (s), *fmt, vp->fval); \ |
481 | vp->sval = tostring(s); \ | | 483 | vp->sval = tostring(s); \ |
482 | vp->tval &= ~DONTFREE; \ | | 484 | vp->tval &= ~DONTFREE; \ |
483 | vp->tval |= STR; \ | | 485 | vp->tval |= STR; \ |
484 | } | | 486 | } |
485 | | | 487 | |
486 | if (isstr(vp) == 0) { | | 488 | if (isstr(vp) == 0) { |
487 | update_str_val(vp); | | 489 | update_str_val(vp); |
488 | if (fmt == OFMT) { | | 490 | if (fmt == OFMT) { |
489 | vp->tval &= ~CONVC; | | 491 | vp->tval &= ~CONVC; |
490 | vp->tval |= CONVO; | | 492 | vp->tval |= CONVO; |
491 | } else { | | 493 | } else { |
492 | /* CONVFMT */ | | 494 | /* CONVFMT */ |
493 | vp->tval &= ~CONVO; | | 495 | vp->tval &= ~CONVO; |
494 | vp->tval |= CONVC; | | 496 | vp->tval |= CONVC; |
495 | } | | 497 | } |
496 | vp->fmt = *fmt; | | 498 | vp->fmt = *fmt; |
497 | } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) { | | 499 | } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) { |
498 | goto done; | | 500 | goto done; |
499 | } else if (isstr(vp)) { | | 501 | } else if (isstr(vp)) { |
500 | if (fmt == OFMT) { | | 502 | if (fmt == OFMT) { |
501 | if ((vp->tval & CONVC) != 0 | | 503 | if ((vp->tval & CONVC) != 0 |
502 | || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) { | | 504 | || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) { |
503 | update_str_val(vp); | | 505 | update_str_val(vp); |
504 | vp->tval &= ~CONVC; | | 506 | vp->tval &= ~CONVC; |
505 | vp->tval |= CONVO; | | 507 | vp->tval |= CONVO; |
506 | vp->fmt = *fmt; | | 508 | vp->fmt = *fmt; |
507 | } | | 509 | } |
508 | } else { | | 510 | } else { |
509 | /* CONVFMT */ | | 511 | /* CONVFMT */ |
510 | if ((vp->tval & CONVO) != 0 | | 512 | if ((vp->tval & CONVO) != 0 |
511 | || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) { | | 513 | || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) { |
512 | update_str_val(vp); | | 514 | update_str_val(vp); |
513 | vp->tval &= ~CONVO; | | 515 | vp->tval &= ~CONVO; |
514 | vp->tval |= CONVC; | | 516 | vp->tval |= CONVC; |
515 | vp->fmt = *fmt; | | 517 | vp->fmt = *fmt; |
516 | } | | 518 | } |
517 | } | | 519 | } |
518 | } | | 520 | } |
519 | done: | | 521 | done: |
520 | dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", | | 522 | dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", |
521 | (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); | | 523 | (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); |
522 | return(vp->sval); | | 524 | return(vp->sval); |
523 | } | | 525 | } |
524 | | | 526 | |
525 | char *getsval(Cell *vp) /* get string val of a Cell */ | | 527 | char *getsval(Cell *vp) /* get string val of a Cell */ |
526 | { | | 528 | { |
527 | return get_str_val(vp, CONVFMT); | | 529 | return get_str_val(vp, CONVFMT); |
528 | } | | 530 | } |
529 | | | 531 | |
530 | char *getpssval(Cell *vp) /* get string val of a Cell for print */ | | 532 | char *getpssval(Cell *vp) /* get string val of a Cell for print */ |
531 | { | | 533 | { |
532 | return get_str_val(vp, OFMT); | | 534 | return get_str_val(vp, OFMT); |
533 | } | | 535 | } |
534 | | | 536 | |
535 | | | 537 | |
536 | char *tostring(const char *s) /* make a copy of string s */ | | 538 | char *tostring(const char *s) /* make a copy of string s */ |
537 | { | | 539 | { |
538 | char *p = strdup(s); | | 540 | char *p = strdup(s); |
539 | if (p == NULL) | | 541 | if (p == NULL) |
540 | FATAL("out of space in tostring on %s", s); | | 542 | FATAL("out of space in tostring on %s", s); |
541 | return(p); | | 543 | return(p); |
542 | } | | 544 | } |
543 | | | 545 | |
544 | char *tostringN(const char *s, size_t n) /* make a copy of string s */ | | 546 | char *tostringN(const char *s, size_t n) /* make a copy of string s */ |
545 | { | | 547 | { |
546 | char *p; | | 548 | char *p; |
547 | | | 549 | |
548 | p = malloc(n); | | 550 | p = malloc(n); |
549 | if (p == NULL) | | 551 | if (p == NULL) |
550 | FATAL("out of space in tostring on %s", s); | | 552 | FATAL("out of space in tostring on %s", s); |
551 | strcpy(p, s); | | 553 | strcpy(p, s); |
552 | return(p); | | 554 | return(p); |
553 | } | | 555 | } |
554 | | | 556 | |
555 | Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */ | | 557 | Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */ |
556 | { | | 558 | { |
557 | Cell *c; | | 559 | Cell *c; |
558 | char *p; | | 560 | char *p; |
559 | char *sa = getsval(a); | | 561 | char *sa = getsval(a); |
560 | char *sb = getsval(b); | | 562 | char *sb = getsval(b); |
561 | size_t l = strlen(sa) + strlen(sb) + 1; | | 563 | size_t l = strlen(sa) + strlen(sb) + 1; |
562 | p = malloc(l); | | 564 | p = malloc(l); |
563 | if (p == NULL) | | 565 | if (p == NULL) |
564 | FATAL("out of space concatenating %s and %s", sa, sb); | | 566 | FATAL("out of space concatenating %s and %s", sa, sb); |
565 | snprintf(p, l, "%s%s", sa, sb); | | 567 | snprintf(p, l, "%s%s", sa, sb); |
566 | | | 568 | |
567 | l++; // add room for ' ' | | 569 | l++; // add room for ' ' |
568 | char *newbuf = malloc(l); | | 570 | char *newbuf = malloc(l); |
569 | if (newbuf == NULL) | | 571 | if (newbuf == NULL) |
570 | FATAL("out of space concatenating %s and %s", sa, sb); | | 572 | FATAL("out of space concatenating %s and %s", sa, sb); |
571 | // See string() in lex.c; a string "xx" is stored in the symbol | | 573 | // See string() in lex.c; a string "xx" is stored in the symbol |
572 | // table as "xx ". | | 574 | // table as "xx ". |
573 | snprintf(newbuf, l, "%s ", p); | | 575 | snprintf(newbuf, l, "%s ", p); |
574 | c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab); | | 576 | c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab); |
575 | free(p); | | 577 | free(p); |
576 | free(newbuf); | | 578 | free(newbuf); |
577 | return c; | | 579 | return c; |
578 | } | | 580 | } |
579 | | | 581 | |
580 | char *qstring(const char *is, int delim) /* collect string up to next delim */ | | 582 | char *qstring(const char *is, int delim) /* collect string up to next delim */ |
581 | { | | 583 | { |
582 | const char *os = is; | | 584 | const char *os = is; |
583 | int c, n; | | 585 | int c, n; |
584 | const uschar *s = (const uschar *) is; | | 586 | const uschar *s = (const uschar *) is; |
585 | uschar *buf, *bp; | | 587 | uschar *buf, *bp; |
586 | | | 588 | |
587 | if ((buf = malloc(strlen(is)+3)) == NULL) | | 589 | if ((buf = malloc(strlen(is)+3)) == NULL) |
588 | FATAL( "out of space in qstring(%s)", s); | | 590 | FATAL( "out of space in qstring(%s)", s); |
589 | for (bp = buf; (c = *s) != delim; s++) { | | 591 | for (bp = buf; (c = *s) != delim; s++) { |
590 | if (c == '\n') | | 592 | if (c == '\n') |
591 | SYNTAX( "newline in string %.20s...", os ); | | 593 | SYNTAX( "newline in string %.20s...", os ); |
592 | else if (c != '\\') | | 594 | else if (c != '\\') |
593 | *bp++ = c; | | 595 | *bp++ = c; |
594 | else { /* \something */ | | 596 | else { /* \something */ |
595 | c = *++s; | | 597 | c = *++s; |
596 | if (c == 0) { /* \ at end */ | | 598 | if (c == 0) { /* \ at end */ |
597 | *bp++ = '\\'; | | 599 | *bp++ = '\\'; |
598 | break; /* for loop */ | | 600 | break; /* for loop */ |
599 | } | | 601 | } |
600 | switch (c) { | | 602 | switch (c) { |
601 | case '\\': *bp++ = '\\'; break; | | 603 | case '\\': *bp++ = '\\'; break; |
602 | case 'n': *bp++ = '\n'; break; | | 604 | case 'n': *bp++ = '\n'; break; |
603 | case 't': *bp++ = '\t'; break; | | 605 | case 't': *bp++ = '\t'; break; |
604 | case 'b': *bp++ = '\b'; break; | | 606 | case 'b': *bp++ = '\b'; break; |
605 | case 'f': *bp++ = '\f'; break; | | 607 | case 'f': *bp++ = '\f'; break; |
606 | case 'r': *bp++ = '\r'; break; | | 608 | case 'r': *bp++ = '\r'; break; |
607 | case 'v': *bp++ = '\v'; break; | | 609 | case 'v': *bp++ = '\v'; break; |
608 | case 'a': *bp++ = '\a'; break; | | 610 | case 'a': *bp++ = '\a'; break; |
609 | default: | | 611 | default: |
610 | if (!isdigit(c)) { | | 612 | if (!isdigit(c)) { |
611 | *bp++ = c; | | 613 | *bp++ = c; |
612 | break; | | 614 | break; |
613 | } | | 615 | } |
614 | n = c - '0'; | | 616 | n = c - '0'; |
615 | if (isdigit(s[1])) { | | 617 | if (isdigit(s[1])) { |
616 | n = 8 * n + *++s - '0'; | | 618 | n = 8 * n + *++s - '0'; |
617 | if (isdigit(s[1])) | | 619 | if (isdigit(s[1])) |
618 | n = 8 * n + *++s - '0'; | | 620 | n = 8 * n + *++s - '0'; |
619 | } | | 621 | } |
620 | *bp++ = n; | | 622 | *bp++ = n; |
621 | break; | | 623 | break; |
622 | } | | 624 | } |
623 | } | | 625 | } |
624 | } | | 626 | } |
625 | *bp++ = 0; | | 627 | *bp++ = 0; |
626 | return (char *) buf; | | 628 | return (char *) buf; |
627 | } | | 629 | } |
628 | | | 630 | |
629 | const char *flags2str(int flags) | | 631 | const char *flags2str(int flags) |
630 | { | | 632 | { |
631 | static const struct ftab { | | 633 | static const struct ftab { |
632 | const char *name; | | 634 | const char *name; |
633 | int value; | | 635 | int value; |
634 | } flagtab[] = { | | 636 | } flagtab[] = { |
635 | { "NUM", NUM }, | | 637 | { "NUM", NUM }, |
636 | { "STR", STR }, | | 638 | { "STR", STR }, |
637 | { "DONTFREE", DONTFREE }, | | 639 | { "DONTFREE", DONTFREE }, |
638 | { "CON", CON }, | | 640 | { "CON", CON }, |
639 | { "ARR", ARR }, | | 641 | { "ARR", ARR }, |
640 | { "FCN", FCN }, | | 642 | { "FCN", FCN }, |
641 | { "FLD", FLD }, | | 643 | { "FLD", FLD }, |
642 | { "REC", REC }, | | 644 | { "REC", REC }, |
643 | { "CONVC", CONVC }, | | 645 | { "CONVC", CONVC }, |
644 | { "CONVO", CONVO }, | | 646 | { "CONVO", CONVO }, |
645 | { NULL, 0 } | | 647 | { NULL, 0 } |
646 | }; | | 648 | }; |
647 | static char buf[100]; | | 649 | static char buf[100]; |
648 | int i; | | 650 | int i; |
649 | char *cp = buf; | | 651 | char *cp = buf; |
650 | | | 652 | |
651 | for (i = 0; flagtab[i].name != NULL; i++) { | | 653 | for (i = 0; flagtab[i].name != NULL; i++) { |
652 | if ((flags & flagtab[i].value) != 0) { | | 654 | if ((flags & flagtab[i].value) != 0) { |
653 | if (cp > buf) | | 655 | if (cp > buf) |
654 | *cp++ = '|'; | | 656 | *cp++ = '|'; |
655 | strcpy(cp, flagtab[i].name); | | 657 | strcpy(cp, flagtab[i].name); |
656 | cp += strlen(cp); | | 658 | cp += strlen(cp); |
657 | } | | 659 | } |
658 | } | | 660 | } |
659 | | | 661 | |
660 | return buf; | | 662 | return buf; |
661 | } | | 663 | } |