Commit | Line | Data |
27e2fb84 |
1 | /* $Header: str.c,v 3.0.1.12 91/01/11 18:26:54 lwall Locked $ |
a687059c |
2 | * |
3 | * Copyright (c) 1989, Larry Wall |
4 | * |
5 | * You may distribute under the terms of the GNU General Public License |
6 | * as specified in the README file that comes with the perl 3.0 kit. |
8d063cd8 |
7 | * |
8 | * $Log: str.c,v $ |
27e2fb84 |
9 | * Revision 3.0.1.12 91/01/11 18:26:54 lwall |
10 | * patch42: s/^foo/bar/ occasionally brought on core dumps |
11 | * patch42: undid unwarranted assumptions about memcmp() return value |
12 | * patch42: ('a' .. 'z') could lose its value in a loop |
13 | * |
4e8eb4f0 |
14 | * Revision 3.0.1.11 90/11/13 15:27:14 lwall |
15 | * patch41: fixed a couple of malloc/free problems |
16 | * |
34de22dd |
17 | * Revision 3.0.1.10 90/11/10 02:06:29 lwall |
18 | * patch38: temp string values are now copied less often |
19 | * patch38: array slurps are now faster and take less memory |
20 | * patch38: fixed a memory leakage on local(*foo) |
21 | * |
395c3793 |
22 | * Revision 3.0.1.9 90/10/16 10:41:21 lwall |
23 | * patch29: the undefined value could get defined by devious means |
24 | * patch29: undefined values compared inconsistently |
25 | * patch29: taintperl now checks for world writable PATH components |
26 | * |
e929a76b |
27 | * Revision 3.0.1.8 90/08/09 05:22:18 lwall |
28 | * patch19: the number to string converter wasn't allocating enough space |
29 | * patch19: tainting didn't work on setgid scripts |
30 | * |
0f85fab0 |
31 | * Revision 3.0.1.7 90/03/27 16:24:11 lwall |
32 | * patch16: strings with prefix chopped off sometimes freed wrong |
33 | * patch16: taint check blows up on undefined array element |
34 | * |
79a0689e |
35 | * Revision 3.0.1.6 90/03/12 17:02:14 lwall |
36 | * patch13: substr as lvalue didn't invalidate old numeric value |
37 | * |
9f68db38 |
38 | * Revision 3.0.1.5 90/02/28 18:30:38 lwall |
39 | * patch9: you may now undef $/ to have no input record separator |
40 | * patch9: nested evals clobbered their longjmp environment |
41 | * patch9: sometimes perl thought ordinary data was a symbol table entry |
42 | * patch9: insufficient space allocated for numeric string on sun4 |
43 | * patch9: underscore in an array name in a double-quoted string not recognized |
44 | * patch9: "@foo{}" not recognized unless %foo defined |
45 | * patch9: "$foo[$[]" gives error |
46 | * |
663a0e37 |
47 | * Revision 3.0.1.4 89/12/21 20:21:35 lwall |
48 | * patch7: errno may now be a macro with an lvalue |
49 | * patch7: made nested or recursive foreach work right |
50 | * |
ffed7fef |
51 | * Revision 3.0.1.3 89/11/17 15:38:23 lwall |
52 | * patch5: some machines typedef unchar too |
53 | * patch5: substitution on leading components occasionally caused <> corruption |
54 | * |
ae986130 |
55 | * Revision 3.0.1.2 89/11/11 04:56:22 lwall |
56 | * patch2: uchar gives Crays fits |
57 | * |
03a14243 |
58 | * Revision 3.0.1.1 89/10/26 23:23:41 lwall |
59 | * patch1: string ordering tests were wrong |
60 | * patch1: $/ now works even when STDSTDIO undefined |
61 | * |
a687059c |
62 | * Revision 3.0 89/10/18 15:23:38 lwall |
63 | * 3.0 baseline |
8d063cd8 |
64 | * |
65 | */ |
66 | |
8d063cd8 |
67 | #include "EXTERN.h" |
8d063cd8 |
68 | #include "perl.h" |
a687059c |
69 | #include "perly.h" |
8d063cd8 |
70 | |
a687059c |
71 | extern char **environ; |
72 | |
73 | #ifndef str_get |
74 | char * |
75 | str_get(str) |
76 | STR *str; |
8d063cd8 |
77 | { |
a687059c |
78 | #ifdef TAINT |
79 | tainted |= str->str_tainted; |
80 | #endif |
81 | return str->str_pok ? str->str_ptr : str_2ptr(str); |
82 | } |
83 | #endif |
8d063cd8 |
84 | |
a687059c |
85 | /* dlb ... guess we have a "crippled cc". |
86 | * dlb the following functions are usually macros. |
87 | */ |
88 | #ifndef str_true |
89 | str_true(Str) |
90 | STR *Str; |
91 | { |
92 | if (Str->str_pok) { |
93 | if (*Str->str_ptr > '0' || |
94 | Str->str_cur > 1 || |
95 | (Str->str_cur && *Str->str_ptr != '0')) |
96 | return 1; |
97 | return 0; |
8d063cd8 |
98 | } |
a687059c |
99 | if (Str->str_nok) |
100 | return (Str->str_u.str_nval != 0.0); |
101 | return 0; |
102 | } |
103 | #endif /* str_true */ |
8d063cd8 |
104 | |
a687059c |
105 | #ifndef str_gnum |
106 | double str_gnum(Str) |
107 | STR *Str; |
108 | { |
109 | #ifdef TAINT |
110 | tainted |= Str->str_tainted; |
111 | #endif /* TAINT*/ |
112 | if (Str->str_nok) |
113 | return Str->str_u.str_nval; |
114 | return str_2num(Str); |
115 | } |
116 | #endif /* str_gnum */ |
117 | /* dlb ... end of crutch */ |
8d063cd8 |
118 | |
a687059c |
119 | char * |
120 | str_grow(str,newlen) |
121 | register STR *str; |
e929a76b |
122 | #ifndef MSDOS |
a687059c |
123 | register int newlen; |
e929a76b |
124 | #else |
125 | unsigned long newlen; |
126 | #endif |
a687059c |
127 | { |
128 | register char *s = str->str_ptr; |
129 | |
e929a76b |
130 | #ifdef MSDOS |
131 | if (newlen >= 0x10000) { |
132 | fprintf(stderr, "Allocation too large: %lx\n", newlen); |
133 | exit(1); |
134 | } |
135 | #endif /* MSDOS */ |
a687059c |
136 | if (str->str_state == SS_INCR) { /* data before str_ptr? */ |
137 | str->str_len += str->str_u.str_useful; |
138 | str->str_ptr -= str->str_u.str_useful; |
139 | str->str_u.str_useful = 0L; |
140 | bcopy(s, str->str_ptr, str->str_cur+1); |
141 | s = str->str_ptr; |
142 | str->str_state = SS_NORM; /* normal again */ |
143 | if (newlen > str->str_len) |
144 | newlen += 10 * (newlen - str->str_cur); /* avoid copy each time */ |
145 | } |
146 | if (newlen > str->str_len) { /* need more room? */ |
147 | if (str->str_len) |
148 | Renew(s,newlen,char); |
149 | else |
150 | New(703,s,newlen,char); |
151 | str->str_ptr = s; |
152 | str->str_len = newlen; |
8d063cd8 |
153 | } |
a687059c |
154 | return s; |
8d063cd8 |
155 | } |
156 | |
157 | str_numset(str,num) |
158 | register STR *str; |
159 | double num; |
160 | { |
0f85fab0 |
161 | if (str->str_pok) { |
162 | str->str_pok = 0; /* invalidate pointer */ |
163 | if (str->str_state == SS_INCR) |
e929a76b |
164 | Str_Grow(str,0); |
0f85fab0 |
165 | } |
a687059c |
166 | str->str_u.str_nval = num; |
167 | str->str_state = SS_NORM; |
a687059c |
168 | str->str_nok = 1; /* validate number */ |
169 | #ifdef TAINT |
170 | str->str_tainted = tainted; |
171 | #endif |
8d063cd8 |
172 | } |
173 | |
174 | char * |
175 | str_2ptr(str) |
176 | register STR *str; |
177 | { |
178 | register char *s; |
378cc40b |
179 | int olderrno; |
8d063cd8 |
180 | |
181 | if (!str) |
182 | return ""; |
8d063cd8 |
183 | if (str->str_nok) { |
9f68db38 |
184 | STR_GROW(str, 30); |
a687059c |
185 | s = str->str_ptr; |
378cc40b |
186 | olderrno = errno; /* some Xenix systems wipe out errno here */ |
187 | #if defined(scs) && defined(ns32000) |
a687059c |
188 | gcvt(str->str_u.str_nval,20,s); |
378cc40b |
189 | #else |
190 | #ifdef apollo |
a687059c |
191 | if (str->str_u.str_nval == 0.0) |
192 | (void)strcpy(s,"0"); |
378cc40b |
193 | else |
194 | #endif /*apollo*/ |
a687059c |
195 | (void)sprintf(s,"%.20g",str->str_u.str_nval); |
378cc40b |
196 | #endif /*scs*/ |
197 | errno = olderrno; |
8d063cd8 |
198 | while (*s) s++; |
9f68db38 |
199 | #ifdef hcx |
200 | if (s[-1] == '.') |
201 | s--; |
202 | #endif |
8d063cd8 |
203 | } |
a687059c |
204 | else { |
205 | if (str == &str_undef) |
206 | return No; |
207 | if (dowarn) |
208 | warn("Use of uninitialized variable"); |
9f68db38 |
209 | STR_GROW(str, 30); |
a687059c |
210 | s = str->str_ptr; |
211 | } |
8d063cd8 |
212 | *s = '\0'; |
213 | str->str_cur = s - str->str_ptr; |
214 | str->str_pok = 1; |
215 | #ifdef DEBUGGING |
216 | if (debug & 32) |
217 | fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr); |
218 | #endif |
219 | return str->str_ptr; |
220 | } |
221 | |
222 | double |
223 | str_2num(str) |
224 | register STR *str; |
225 | { |
226 | if (!str) |
227 | return 0.0; |
0f85fab0 |
228 | if (str->str_state == SS_INCR) |
e929a76b |
229 | Str_Grow(str,0); /* just force copy down */ |
a687059c |
230 | str->str_state = SS_NORM; |
8d063cd8 |
231 | if (str->str_len && str->str_pok) |
a687059c |
232 | str->str_u.str_nval = atof(str->str_ptr); |
233 | else { |
234 | if (str == &str_undef) |
235 | return 0.0; |
378cc40b |
236 | if (dowarn) |
a687059c |
237 | warn("Use of uninitialized variable"); |
238 | str->str_u.str_nval = 0.0; |
378cc40b |
239 | } |
8d063cd8 |
240 | str->str_nok = 1; |
241 | #ifdef DEBUGGING |
242 | if (debug & 32) |
a687059c |
243 | fprintf(stderr,"0x%lx num(%g)\n",str,str->str_u.str_nval); |
8d063cd8 |
244 | #endif |
a687059c |
245 | return str->str_u.str_nval; |
8d063cd8 |
246 | } |
247 | |
34de22dd |
248 | /* Note: str_sset() should not be called with a source string that needs |
249 | * be reused, since it may destroy the source string if it is marked |
250 | * as temporary. |
251 | */ |
252 | |
8d063cd8 |
253 | str_sset(dstr,sstr) |
254 | STR *dstr; |
255 | register STR *sstr; |
256 | { |
a687059c |
257 | #ifdef TAINT |
0f85fab0 |
258 | if (sstr) |
259 | tainted |= sstr->str_tainted; |
a687059c |
260 | #endif |
395c3793 |
261 | if (sstr == dstr || dstr == &str_undef) |
9f68db38 |
262 | return; |
8d063cd8 |
263 | if (!sstr) |
a687059c |
264 | dstr->str_pok = dstr->str_nok = 0; |
265 | else if (sstr->str_pok) { |
34de22dd |
266 | |
267 | /* |
268 | * Check to see if we can just swipe the string. If so, it's a |
269 | * possible small lose on short strings, but a big win on long ones. |
4e8eb4f0 |
270 | * It might even be a win on short strings if dstr->str_ptr |
271 | * has to be allocated and sstr->str_ptr has to be freed. |
34de22dd |
272 | */ |
273 | |
274 | if (sstr->str_pok & SP_TEMP) { /* slated for free anyway? */ |
4e8eb4f0 |
275 | if (dstr->str_ptr) { |
276 | if (dstr->str_state == SS_INCR) |
277 | dstr->str_ptr -= dstr->str_u.str_useful; |
34de22dd |
278 | Safefree(dstr->str_ptr); |
4e8eb4f0 |
279 | } |
280 | dstr->str_ptr = sstr->str_ptr; |
281 | dstr->str_len = sstr->str_len; |
282 | dstr->str_cur = sstr->str_cur; |
283 | dstr->str_state = sstr->str_state; |
284 | dstr->str_pok = sstr->str_pok & ~SP_TEMP; |
285 | #ifdef TAINT |
286 | dstr->str_tainted = sstr->str_tainted; |
34de22dd |
287 | #endif |
4e8eb4f0 |
288 | sstr->str_ptr = Nullch; |
289 | sstr->str_len = 0; |
290 | sstr->str_pok = 0; /* wipe out any weird flags */ |
291 | sstr->str_state = 0; /* so sstr frees uneventfully */ |
a687059c |
292 | } |
27e2fb84 |
293 | else { /* have to copy actual string */ |
294 | if (dstr->str_ptr) { |
295 | if (dstr->str_state == SS_INCR) { |
296 | Str_Grow(dstr,0); |
297 | } |
298 | } |
34de22dd |
299 | str_nset(dstr,sstr->str_ptr,sstr->str_cur); |
27e2fb84 |
300 | } |
4e8eb4f0 |
301 | if (dstr->str_nok = sstr->str_nok) |
302 | dstr->str_u.str_nval = sstr->str_u.str_nval; |
303 | else { |
304 | #ifdef STRUCTCOPY |
305 | dstr->str_u = sstr->str_u; |
306 | #else |
307 | dstr->str_u.str_nval = sstr->str_u.str_nval; |
308 | #endif |
309 | if (dstr->str_cur == sizeof(STBP)) { |
310 | char *tmps = dstr->str_ptr; |
a687059c |
311 | |
34de22dd |
312 | if (*tmps == 'S' && bcmp(tmps,"StB",4) == 0) { |
313 | if (!dstr->str_magic) { |
314 | dstr->str_magic = str_smake(sstr->str_magic); |
315 | dstr->str_magic->str_rare = 'X'; |
316 | } |
395c3793 |
317 | } |
a687059c |
318 | } |
319 | } |
320 | } |
321 | else if (sstr->str_nok) |
322 | str_numset(dstr,sstr->str_u.str_nval); |
663a0e37 |
323 | else { |
0f85fab0 |
324 | if (dstr->str_state == SS_INCR) |
e929a76b |
325 | Str_Grow(dstr,0); /* just force copy down */ |
0f85fab0 |
326 | |
663a0e37 |
327 | #ifdef STRUCTCOPY |
328 | dstr->str_u = sstr->str_u; |
329 | #else |
330 | dstr->str_u.str_nval = sstr->str_u.str_nval; |
331 | #endif |
a687059c |
332 | dstr->str_pok = dstr->str_nok = 0; |
663a0e37 |
333 | } |
8d063cd8 |
334 | } |
335 | |
336 | str_nset(str,ptr,len) |
337 | register STR *str; |
338 | register char *ptr; |
e929a76b |
339 | register STRLEN len; |
8d063cd8 |
340 | { |
395c3793 |
341 | if (str == &str_undef) |
342 | return; |
a687059c |
343 | STR_GROW(str, len + 1); |
0f85fab0 |
344 | if (ptr) |
345 | (void)bcopy(ptr,str->str_ptr,len); |
8d063cd8 |
346 | str->str_cur = len; |
347 | *(str->str_ptr+str->str_cur) = '\0'; |
348 | str->str_nok = 0; /* invalidate number */ |
349 | str->str_pok = 1; /* validate pointer */ |
a687059c |
350 | #ifdef TAINT |
351 | str->str_tainted = tainted; |
352 | #endif |
8d063cd8 |
353 | } |
354 | |
355 | str_set(str,ptr) |
356 | register STR *str; |
357 | register char *ptr; |
358 | { |
e929a76b |
359 | register STRLEN len; |
8d063cd8 |
360 | |
395c3793 |
361 | if (str == &str_undef) |
362 | return; |
8d063cd8 |
363 | if (!ptr) |
364 | ptr = ""; |
365 | len = strlen(ptr); |
a687059c |
366 | STR_GROW(str, len + 1); |
367 | (void)bcopy(ptr,str->str_ptr,len+1); |
8d063cd8 |
368 | str->str_cur = len; |
369 | str->str_nok = 0; /* invalidate number */ |
370 | str->str_pok = 1; /* validate pointer */ |
a687059c |
371 | #ifdef TAINT |
372 | str->str_tainted = tainted; |
373 | #endif |
8d063cd8 |
374 | } |
375 | |
376 | str_chop(str,ptr) /* like set but assuming ptr is in str */ |
377 | register STR *str; |
378 | register char *ptr; |
379 | { |
e929a76b |
380 | register STRLEN delta; |
a687059c |
381 | |
8d063cd8 |
382 | if (!(str->str_pok)) |
a687059c |
383 | fatal("str_chop: internal inconsistency"); |
384 | delta = ptr - str->str_ptr; |
385 | str->str_len -= delta; |
386 | str->str_cur -= delta; |
387 | str->str_ptr += delta; |
388 | if (str->str_state == SS_INCR) |
389 | str->str_u.str_useful += delta; |
390 | else { |
391 | str->str_u.str_useful = delta; |
392 | str->str_state = SS_INCR; |
393 | } |
8d063cd8 |
394 | str->str_nok = 0; /* invalidate number */ |
a687059c |
395 | str->str_pok = 1; /* validate pointer (and unstudy str) */ |
8d063cd8 |
396 | } |
397 | |
398 | str_ncat(str,ptr,len) |
399 | register STR *str; |
400 | register char *ptr; |
e929a76b |
401 | register STRLEN len; |
8d063cd8 |
402 | { |
395c3793 |
403 | if (str == &str_undef) |
404 | return; |
8d063cd8 |
405 | if (!(str->str_pok)) |
a687059c |
406 | (void)str_2ptr(str); |
407 | STR_GROW(str, str->str_cur + len + 1); |
408 | (void)bcopy(ptr,str->str_ptr+str->str_cur,len); |
8d063cd8 |
409 | str->str_cur += len; |
410 | *(str->str_ptr+str->str_cur) = '\0'; |
411 | str->str_nok = 0; /* invalidate number */ |
412 | str->str_pok = 1; /* validate pointer */ |
a687059c |
413 | #ifdef TAINT |
414 | str->str_tainted |= tainted; |
415 | #endif |
8d063cd8 |
416 | } |
417 | |
418 | str_scat(dstr,sstr) |
419 | STR *dstr; |
420 | register STR *sstr; |
421 | { |
a687059c |
422 | #ifdef TAINT |
423 | tainted |= sstr->str_tainted; |
424 | #endif |
378cc40b |
425 | if (!sstr) |
426 | return; |
8d063cd8 |
427 | if (!(sstr->str_pok)) |
a687059c |
428 | (void)str_2ptr(sstr); |
8d063cd8 |
429 | if (sstr) |
430 | str_ncat(dstr,sstr->str_ptr,sstr->str_cur); |
431 | } |
432 | |
433 | str_cat(str,ptr) |
434 | register STR *str; |
435 | register char *ptr; |
436 | { |
e929a76b |
437 | register STRLEN len; |
8d063cd8 |
438 | |
395c3793 |
439 | if (str == &str_undef) |
440 | return; |
8d063cd8 |
441 | if (!ptr) |
442 | return; |
443 | if (!(str->str_pok)) |
a687059c |
444 | (void)str_2ptr(str); |
8d063cd8 |
445 | len = strlen(ptr); |
a687059c |
446 | STR_GROW(str, str->str_cur + len + 1); |
447 | (void)bcopy(ptr,str->str_ptr+str->str_cur,len+1); |
8d063cd8 |
448 | str->str_cur += len; |
449 | str->str_nok = 0; /* invalidate number */ |
450 | str->str_pok = 1; /* validate pointer */ |
a687059c |
451 | #ifdef TAINT |
452 | str->str_tainted |= tainted; |
453 | #endif |
8d063cd8 |
454 | } |
455 | |
456 | char * |
a687059c |
457 | str_append_till(str,from,fromend,delim,keeplist) |
8d063cd8 |
458 | register STR *str; |
459 | register char *from; |
a687059c |
460 | register char *fromend; |
8d063cd8 |
461 | register int delim; |
462 | char *keeplist; |
463 | { |
464 | register char *to; |
e929a76b |
465 | register STRLEN len; |
8d063cd8 |
466 | |
395c3793 |
467 | if (str == &str_undef) |
468 | return Nullch; |
8d063cd8 |
469 | if (!from) |
470 | return Nullch; |
a687059c |
471 | len = fromend - from; |
472 | STR_GROW(str, str->str_cur + len + 1); |
8d063cd8 |
473 | str->str_nok = 0; /* invalidate number */ |
474 | str->str_pok = 1; /* validate pointer */ |
475 | to = str->str_ptr+str->str_cur; |
a687059c |
476 | for (; from < fromend; from++,to++) { |
477 | if (*from == '\\' && from+1 < fromend && delim != '\\') { |
8d063cd8 |
478 | if (!keeplist) { |
479 | if (from[1] == delim || from[1] == '\\') |
480 | from++; |
481 | else |
482 | *to++ = *from++; |
483 | } |
a687059c |
484 | else if (from[1] && index(keeplist,from[1])) |
8d063cd8 |
485 | *to++ = *from++; |
486 | else |
487 | from++; |
488 | } |
489 | else if (*from == delim) |
490 | break; |
491 | *to = *from; |
492 | } |
493 | *to = '\0'; |
494 | str->str_cur = to - str->str_ptr; |
495 | return from; |
496 | } |
497 | |
498 | STR * |
a687059c |
499 | #ifdef LEAKTEST |
500 | str_new(x,len) |
501 | int x; |
502 | #else |
8d063cd8 |
503 | str_new(len) |
a687059c |
504 | #endif |
e929a76b |
505 | STRLEN len; |
8d063cd8 |
506 | { |
507 | register STR *str; |
508 | |
509 | if (freestrroot) { |
510 | str = freestrroot; |
a687059c |
511 | freestrroot = str->str_magic; |
512 | str->str_magic = Nullstr; |
513 | str->str_state = SS_NORM; |
8d063cd8 |
514 | } |
515 | else { |
a687059c |
516 | Newz(700+x,str,1,STR); |
8d063cd8 |
517 | } |
518 | if (len) |
a687059c |
519 | STR_GROW(str, len + 1); |
8d063cd8 |
520 | return str; |
521 | } |
522 | |
523 | void |
a687059c |
524 | str_magic(str, stab, how, name, namlen) |
8d063cd8 |
525 | register STR *str; |
a687059c |
526 | STAB *stab; |
527 | int how; |
528 | char *name; |
e929a76b |
529 | STRLEN namlen; |
a687059c |
530 | { |
395c3793 |
531 | if (str == &str_undef || str->str_magic) |
a687059c |
532 | return; |
533 | str->str_magic = Str_new(75,namlen); |
534 | str = str->str_magic; |
535 | str->str_u.str_stab = stab; |
536 | str->str_rare = how; |
537 | if (name) |
538 | str_nset(str,name,namlen); |
539 | } |
540 | |
541 | void |
542 | str_insert(bigstr,offset,len,little,littlelen) |
543 | STR *bigstr; |
e929a76b |
544 | STRLEN offset; |
545 | STRLEN len; |
a687059c |
546 | char *little; |
e929a76b |
547 | STRLEN littlelen; |
8d063cd8 |
548 | { |
a687059c |
549 | register char *big; |
550 | register char *mid; |
551 | register char *midend; |
552 | register char *bigend; |
553 | register int i; |
554 | |
395c3793 |
555 | if (bigstr == &str_undef) |
556 | return; |
79a0689e |
557 | bigstr->str_nok = 0; |
558 | bigstr->str_pok = SP_VALID; /* disable possible screamer */ |
559 | |
a687059c |
560 | i = littlelen - len; |
561 | if (i > 0) { /* string might grow */ |
562 | STR_GROW(bigstr, bigstr->str_cur + i + 1); |
563 | big = bigstr->str_ptr; |
564 | mid = big + offset + len; |
565 | midend = bigend = big + bigstr->str_cur; |
566 | bigend += i; |
567 | *bigend = '\0'; |
568 | while (midend > mid) /* shove everything down */ |
569 | *--bigend = *--midend; |
570 | (void)bcopy(little,big+offset,littlelen); |
571 | bigstr->str_cur += i; |
572 | return; |
573 | } |
574 | else if (i == 0) { |
575 | (void)bcopy(little,bigstr->str_ptr+offset,len); |
576 | return; |
577 | } |
578 | |
579 | big = bigstr->str_ptr; |
580 | mid = big + offset; |
581 | midend = mid + len; |
582 | bigend = big + bigstr->str_cur; |
583 | |
584 | if (midend > bigend) |
585 | fatal("panic: str_insert"); |
586 | |
a687059c |
587 | if (mid - big > bigend - midend) { /* faster to shorten from end */ |
588 | if (littlelen) { |
589 | (void)bcopy(little, mid, littlelen); |
590 | mid += littlelen; |
591 | } |
592 | i = bigend - midend; |
593 | if (i > 0) { |
594 | (void)bcopy(midend, mid, i); |
595 | mid += i; |
596 | } |
597 | *mid = '\0'; |
598 | bigstr->str_cur = mid - big; |
599 | } |
600 | else if (i = mid - big) { /* faster from front */ |
601 | midend -= littlelen; |
602 | mid = midend; |
603 | str_chop(bigstr,midend-i); |
604 | big += i; |
605 | while (i--) |
606 | *--midend = *--big; |
607 | if (littlelen) |
608 | (void)bcopy(little, mid, littlelen); |
609 | } |
610 | else if (littlelen) { |
611 | midend -= littlelen; |
612 | str_chop(bigstr,midend); |
613 | (void)bcopy(little,midend,littlelen); |
614 | } |
615 | else { |
616 | str_chop(bigstr,midend); |
617 | } |
618 | STABSET(bigstr); |
8d063cd8 |
619 | } |
620 | |
621 | /* make str point to what nstr did */ |
622 | |
623 | void |
624 | str_replace(str,nstr) |
625 | register STR *str; |
626 | register STR *nstr; |
627 | { |
395c3793 |
628 | if (str == &str_undef) |
629 | return; |
a687059c |
630 | if (str->str_state == SS_INCR) |
e929a76b |
631 | Str_Grow(str,0); /* just force copy down */ |
a687059c |
632 | if (nstr->str_state == SS_INCR) |
e929a76b |
633 | Str_Grow(nstr,0); |
a687059c |
634 | if (str->str_ptr) |
635 | Safefree(str->str_ptr); |
8d063cd8 |
636 | str->str_ptr = nstr->str_ptr; |
637 | str->str_len = nstr->str_len; |
638 | str->str_cur = nstr->str_cur; |
639 | str->str_pok = nstr->str_pok; |
a687059c |
640 | str->str_nok = nstr->str_nok; |
641 | #ifdef STRUCTCOPY |
642 | str->str_u = nstr->str_u; |
643 | #else |
644 | str->str_u.str_nval = nstr->str_u.str_nval; |
645 | #endif |
646 | #ifdef TAINT |
647 | str->str_tainted = nstr->str_tainted; |
648 | #endif |
34de22dd |
649 | if (nstr->str_magic) |
650 | str_free(nstr->str_magic); |
a687059c |
651 | Safefree(nstr); |
8d063cd8 |
652 | } |
653 | |
654 | void |
655 | str_free(str) |
656 | register STR *str; |
657 | { |
395c3793 |
658 | if (!str || str == &str_undef) |
8d063cd8 |
659 | return; |
a687059c |
660 | if (str->str_state) { |
661 | if (str->str_state == SS_FREE) /* already freed */ |
662 | return; |
663 | if (str->str_state == SS_INCR && !(str->str_pok & 2)) { |
664 | str->str_ptr -= str->str_u.str_useful; |
665 | str->str_len += str->str_u.str_useful; |
666 | } |
667 | } |
668 | if (str->str_magic) |
669 | str_free(str->str_magic); |
670 | #ifdef LEAKTEST |
8d063cd8 |
671 | if (str->str_len) |
a687059c |
672 | Safefree(str->str_ptr); |
673 | if ((str->str_pok & SP_INTRP) && str->str_u.str_args) |
674 | arg_free(str->str_u.str_args); |
675 | Safefree(str); |
676 | #else /* LEAKTEST */ |
677 | if (str->str_len) { |
678 | if (str->str_len > 127) { /* next user not likely to want more */ |
679 | Safefree(str->str_ptr); /* so give it back to malloc */ |
680 | str->str_ptr = Nullch; |
681 | str->str_len = 0; |
682 | } |
683 | else |
684 | str->str_ptr[0] = '\0'; |
685 | } |
686 | if ((str->str_pok & SP_INTRP) && str->str_u.str_args) |
687 | arg_free(str->str_u.str_args); |
8d063cd8 |
688 | str->str_cur = 0; |
689 | str->str_nok = 0; |
690 | str->str_pok = 0; |
a687059c |
691 | str->str_state = SS_FREE; |
692 | #ifdef TAINT |
693 | str->str_tainted = 0; |
694 | #endif |
695 | str->str_magic = freestrroot; |
8d063cd8 |
696 | freestrroot = str; |
a687059c |
697 | #endif /* LEAKTEST */ |
8d063cd8 |
698 | } |
699 | |
e929a76b |
700 | STRLEN |
8d063cd8 |
701 | str_len(str) |
702 | register STR *str; |
703 | { |
704 | if (!str) |
705 | return 0; |
706 | if (!(str->str_pok)) |
a687059c |
707 | (void)str_2ptr(str); |
708 | if (str->str_ptr) |
8d063cd8 |
709 | return str->str_cur; |
710 | else |
711 | return 0; |
712 | } |
713 | |
a687059c |
714 | str_eq(str1,str2) |
715 | register STR *str1; |
716 | register STR *str2; |
717 | { |
395c3793 |
718 | if (!str1 || str1 == &str_undef) |
719 | return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur); |
720 | if (!str2 || str2 == &str_undef) |
721 | return !str1->str_cur; |
a687059c |
722 | |
723 | if (!str1->str_pok) |
724 | (void)str_2ptr(str1); |
725 | if (!str2->str_pok) |
726 | (void)str_2ptr(str2); |
727 | |
728 | if (str1->str_cur != str2->str_cur) |
729 | return 0; |
730 | |
731 | return !bcmp(str1->str_ptr, str2->str_ptr, str1->str_cur); |
732 | } |
733 | |
734 | str_cmp(str1,str2) |
735 | register STR *str1; |
736 | register STR *str2; |
737 | { |
738 | int retval; |
739 | |
395c3793 |
740 | if (!str1 || str1 == &str_undef) |
741 | return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur)?0:-1; |
742 | if (!str2 || str2 == &str_undef) |
743 | return str1->str_cur != 0; |
a687059c |
744 | |
745 | if (!str1->str_pok) |
746 | (void)str_2ptr(str1); |
747 | if (!str2->str_pok) |
748 | (void)str_2ptr(str2); |
749 | |
750 | if (str1->str_cur < str2->str_cur) { |
751 | if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur)) |
27e2fb84 |
752 | return retval < 0 ? -1 : 1; |
a687059c |
753 | else |
03a14243 |
754 | return -1; |
a687059c |
755 | } |
756 | else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur)) |
27e2fb84 |
757 | return retval < 0 ? -1 : 1; |
a687059c |
758 | else if (str1->str_cur == str2->str_cur) |
759 | return 0; |
760 | else |
03a14243 |
761 | return 1; |
a687059c |
762 | } |
763 | |
8d063cd8 |
764 | char * |
a687059c |
765 | str_gets(str,fp,append) |
8d063cd8 |
766 | register STR *str; |
767 | register FILE *fp; |
a687059c |
768 | int append; |
8d063cd8 |
769 | { |
8d063cd8 |
770 | register char *bp; /* we're going to steal some values */ |
771 | register int cnt; /* from the stdio struct and put EVERYTHING */ |
36ce8bec |
772 | register STDCHAR *ptr; /* in the innermost loop into registers */ |
9f68db38 |
773 | register int newline = record_separator;/* (assuming >= 6 registers) */ |
8d063cd8 |
774 | int i; |
e929a76b |
775 | STRLEN bpx; |
776 | STRLEN obpx; |
8d063cd8 |
777 | register int get_paragraph; |
778 | register char *oldbp; |
34de22dd |
779 | int shortbuffered; |
8d063cd8 |
780 | |
395c3793 |
781 | if (str == &str_undef) |
782 | return Nullch; |
a687059c |
783 | if (get_paragraph = !rslen) { /* yes, that's an assignment */ |
8d063cd8 |
784 | newline = '\n'; |
785 | oldbp = Nullch; /* remember last \n position (none) */ |
786 | } |
03a14243 |
787 | #ifdef STDSTDIO /* Here is some breathtakingly efficient cheating */ |
8d063cd8 |
788 | cnt = fp->_cnt; /* get count into register */ |
789 | str->str_nok = 0; /* invalidate number */ |
790 | str->str_pok = 1; /* validate pointer */ |
34de22dd |
791 | if (str->str_len <= cnt + 1) { /* make sure we have the room */ |
792 | if (cnt > 80 && str->str_len > 0) { |
4e8eb4f0 |
793 | shortbuffered = cnt - str->str_len + 1; |
794 | cnt = str->str_len - 1; |
34de22dd |
795 | } |
796 | else { |
797 | shortbuffered = 0; |
798 | STR_GROW(str, append+cnt+2);/* (remembering cnt can be -1) */ |
799 | } |
800 | } |
801 | else |
802 | shortbuffered = 0; |
a687059c |
803 | bp = str->str_ptr + append; /* move these two too to registers */ |
8d063cd8 |
804 | ptr = fp->_ptr; |
805 | for (;;) { |
806 | screamer: |
807 | while (--cnt >= 0) { /* this */ /* eat */ |
808 | if ((*bp++ = *ptr++) == newline) /* really */ /* dust */ |
809 | goto thats_all_folks; /* screams */ /* sed :-) */ |
810 | } |
811 | |
34de22dd |
812 | if (shortbuffered) { /* oh well, must extend */ |
813 | cnt = shortbuffered; |
814 | shortbuffered = 0; |
815 | if (get_paragraph && oldbp) |
816 | obpx = oldbp - str->str_ptr; |
817 | bpx = bp - str->str_ptr; /* prepare for possible relocation */ |
27e2fb84 |
818 | str->str_cur = bpx; |
34de22dd |
819 | STR_GROW(str, str->str_len + append + cnt + 2); |
820 | bp = str->str_ptr + bpx; /* reconstitute our pointer */ |
821 | if (get_paragraph && oldbp) |
822 | oldbp = str->str_ptr + obpx; |
823 | continue; |
824 | } |
825 | |
8d063cd8 |
826 | fp->_cnt = cnt; /* deregisterize cnt and ptr */ |
827 | fp->_ptr = ptr; |
828 | i = _filbuf(fp); /* get more characters */ |
829 | cnt = fp->_cnt; |
830 | ptr = fp->_ptr; /* reregisterize cnt and ptr */ |
831 | |
832 | bpx = bp - str->str_ptr; /* prepare for possible relocation */ |
833 | if (get_paragraph && oldbp) |
834 | obpx = oldbp - str->str_ptr; |
ffed7fef |
835 | str->str_cur = bpx; |
a687059c |
836 | STR_GROW(str, bpx + cnt + 2); |
8d063cd8 |
837 | bp = str->str_ptr + bpx; /* reconstitute our pointer */ |
838 | if (get_paragraph && oldbp) |
839 | oldbp = str->str_ptr + obpx; |
840 | |
841 | if (i == newline) { /* all done for now? */ |
842 | *bp++ = i; |
843 | goto thats_all_folks; |
844 | } |
845 | else if (i == EOF) /* all done for ever? */ |
846 | goto thats_really_all_folks; |
847 | *bp++ = i; /* now go back to screaming loop */ |
848 | } |
849 | |
850 | thats_all_folks: |
851 | if (get_paragraph && bp - 1 != oldbp) { |
852 | oldbp = bp; /* remember where this newline was */ |
853 | goto screamer; /* and go back to the fray */ |
854 | } |
855 | thats_really_all_folks: |
34de22dd |
856 | if (shortbuffered) |
857 | cnt += shortbuffered; |
8d063cd8 |
858 | fp->_cnt = cnt; /* put these back or we're in trouble */ |
859 | fp->_ptr = ptr; |
860 | *bp = '\0'; |
861 | str->str_cur = bp - str->str_ptr; /* set length */ |
862 | |
863 | #else /* !STDSTDIO */ /* The big, slow, and stupid way */ |
864 | |
03a14243 |
865 | { |
866 | static char buf[8192]; |
867 | char * bpe = buf + sizeof(buf) - 3; |
868 | |
869 | screamer: |
870 | bp = buf; |
871 | filler: |
872 | while ((i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe); |
873 | if (i == newline && get_paragraph && |
874 | (i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe) |
875 | goto filler; |
8d063cd8 |
876 | |
03a14243 |
877 | *bp = '\0'; |
a687059c |
878 | if (append) |
879 | str_cat(str, buf); |
880 | else |
881 | str_set(str, buf); |
03a14243 |
882 | if (i != newline && i != EOF) { |
883 | append = -1; |
884 | goto screamer; |
885 | } |
a687059c |
886 | } |
8d063cd8 |
887 | |
888 | #endif /* STDSTDIO */ |
889 | |
a687059c |
890 | return str->str_cur - append ? str->str_ptr : Nullch; |
8d063cd8 |
891 | } |
892 | |
a687059c |
893 | ARG * |
894 | parselist(str) |
895 | STR *str; |
896 | { |
897 | register CMD *cmd; |
898 | register ARG *arg; |
e929a76b |
899 | CMD *oldcurcmd = curcmd; |
395c3793 |
900 | int oldperldb = perldb; |
a687059c |
901 | int retval; |
8d063cd8 |
902 | |
395c3793 |
903 | perldb = 0; |
a687059c |
904 | str_sset(linestr,str); |
905 | in_eval++; |
906 | oldoldbufptr = oldbufptr = bufptr = str_get(linestr); |
907 | bufend = bufptr + linestr->str_cur; |
9f68db38 |
908 | if (++loop_ptr >= loop_max) { |
909 | loop_max += 128; |
910 | Renew(loop_stack, loop_max, struct loop); |
911 | } |
912 | loop_stack[loop_ptr].loop_label = "_EVAL_"; |
913 | loop_stack[loop_ptr].loop_sp = 0; |
914 | #ifdef DEBUGGING |
915 | if (debug & 4) { |
916 | deb("(Pushing label #%d _EVAL_)\n", loop_ptr); |
917 | } |
918 | #endif |
919 | if (setjmp(loop_stack[loop_ptr].loop_env)) { |
920 | in_eval--; |
921 | loop_ptr--; |
395c3793 |
922 | perldb = oldperldb; |
a687059c |
923 | fatal("%s\n",stab_val(stabent("@",TRUE))->str_ptr); |
924 | } |
9f68db38 |
925 | #ifdef DEBUGGING |
926 | if (debug & 4) { |
e929a76b |
927 | char *tmps = loop_stack[loop_ptr].loop_label; |
9f68db38 |
928 | deb("(Popping label #%d %s)\n",loop_ptr, |
929 | tmps ? tmps : "" ); |
930 | } |
931 | #endif |
932 | loop_ptr--; |
a687059c |
933 | error_count = 0; |
e929a76b |
934 | curcmd = &compiling; |
935 | curcmd->c_line = oldcurcmd->c_line; |
a687059c |
936 | retval = yyparse(); |
e929a76b |
937 | curcmd = oldcurcmd; |
395c3793 |
938 | perldb = oldperldb; |
a687059c |
939 | in_eval--; |
940 | if (retval || error_count) |
941 | fatal("Invalid component in string or format"); |
942 | cmd = eval_root; |
943 | arg = cmd->c_expr; |
944 | if (cmd->c_type != C_EXPR || cmd->c_next || arg->arg_type != O_LIST) |
945 | fatal("panic: error in parselist %d %x %d", cmd->c_type, |
946 | cmd->c_next, arg ? arg->arg_type : -1); |
a687059c |
947 | Safefree(cmd); |
948 | return arg; |
949 | } |
950 | |
951 | void |
952 | intrpcompile(src) |
953 | STR *src; |
8d063cd8 |
954 | { |
a687059c |
955 | register char *s = str_get(src); |
956 | register char *send = s + src->str_cur; |
957 | register STR *str; |
958 | register char *t; |
959 | STR *toparse; |
e929a76b |
960 | STRLEN len; |
a687059c |
961 | register int brackets; |
962 | register char *d; |
963 | STAB *stab; |
964 | char *checkpoint; |
8d063cd8 |
965 | |
a687059c |
966 | toparse = Str_new(76,0); |
967 | str = Str_new(77,0); |
968 | |
969 | str_nset(str,"",0); |
970 | str_nset(toparse,"",0); |
971 | t = s; |
972 | while (s < send) { |
973 | if (*s == '\\' && s[1] && index("$@[{\\]}",s[1])) { |
974 | str_ncat(str, t, s - t); |
975 | ++s; |
976 | if (*nointrp && s+1 < send) |
977 | if (*s != '@' && (*s != '$' || index(nointrp,s[1]))) |
978 | str_ncat(str,s-1,1); |
979 | str_ncat(str, "$b", 2); |
980 | str_ncat(str, s, 1); |
981 | ++s; |
982 | t = s; |
8d063cd8 |
983 | } |
a687059c |
984 | else if ((*s == '@' || (*s == '$' && !index(nointrp,s[1]))) && |
985 | s+1 < send) { |
8d063cd8 |
986 | str_ncat(str,t,s-t); |
8d063cd8 |
987 | t = s; |
9f68db38 |
988 | if (*s == '$' && s[1] == '#' && (isalpha(s[2]) || s[2] == '_')) |
a687059c |
989 | s++; |
990 | s = scanreg(s,send,tokenbuf); |
991 | if (*t == '@' && |
9f68db38 |
992 | (!(stab = stabent(tokenbuf,FALSE)) || |
993 | (*s == '{' ? !stab_xhash(stab) : !stab_xarray(stab)) )) { |
a687059c |
994 | str_ncat(str,"@",1); |
995 | s = ++t; |
996 | continue; /* grandfather @ from old scripts */ |
997 | } |
998 | str_ncat(str,"$a",2); |
999 | str_ncat(toparse,",",1); |
1000 | if (t[1] != '{' && (*s == '[' || *s == '{' /* }} */ ) && |
1001 | (stab = stabent(tokenbuf,FALSE)) && |
1002 | ((*s == '[') ? (stab_xarray(stab) != 0) : (stab_xhash(stab) != 0)) ) { |
1003 | brackets = 0; |
1004 | checkpoint = s; |
1005 | do { |
1006 | switch (*s) { |
9f68db38 |
1007 | case '[': |
1008 | if (s[-1] != '$') |
1009 | brackets++; |
1010 | break; |
1011 | case '{': |
a687059c |
1012 | brackets++; |
1013 | break; |
9f68db38 |
1014 | case ']': |
1015 | if (s[-1] != '$') |
1016 | brackets--; |
1017 | break; |
1018 | case '}': |
a687059c |
1019 | brackets--; |
1020 | break; |
1021 | case '\'': |
1022 | case '"': |
1023 | if (s[-1] != '$') { |
1024 | s = cpytill(tokenbuf,s+1,send,*s,&len); |
1025 | if (s >= send) |
1026 | fatal("Unterminated string"); |
1027 | } |
1028 | break; |
1029 | } |
1030 | s++; |
1031 | } while (brackets > 0 && s < send); |
1032 | if (s > send) |
1033 | fatal("Unmatched brackets in string"); |
1034 | if (*nointrp) { /* we're in a regular expression */ |
1035 | d = checkpoint; |
1036 | if (*d == '{' && s[-1] == '}') { /* maybe {n,m} */ |
1037 | ++d; |
1038 | if (isdigit(*d)) { /* matches /^{\d,?\d*}$/ */ |
1039 | if (*++d == ',') |
1040 | ++d; |
1041 | while (isdigit(*d)) |
1042 | d++; |
1043 | if (d == s - 1) |
1044 | s = checkpoint; /* Is {n,m}! Backoff! */ |
1045 | } |
1046 | } |
1047 | else if (*d == '[' && s[-1] == ']') { /* char class? */ |
1048 | int weight = 2; /* let's weigh the evidence */ |
1049 | char seen[256]; |
ffed7fef |
1050 | unsigned char un_char = 0, last_un_char; |
a687059c |
1051 | |
1052 | Zero(seen,256,char); |
1053 | *--s = '\0'; |
1054 | if (d[1] == '^') |
1055 | weight += 150; |
1056 | else if (d[1] == '$') |
1057 | weight -= 3; |
1058 | if (isdigit(d[1])) { |
1059 | if (d[2]) { |
1060 | if (isdigit(d[2]) && !d[3]) |
1061 | weight -= 10; |
1062 | } |
1063 | else |
1064 | weight -= 100; |
1065 | } |
1066 | for (d++; d < s; d++) { |
ffed7fef |
1067 | last_un_char = un_char; |
1068 | un_char = (unsigned char)*d; |
a687059c |
1069 | switch (*d) { |
1070 | case '&': |
1071 | case '$': |
ffed7fef |
1072 | weight -= seen[un_char] * 10; |
a687059c |
1073 | if (isalpha(d[1]) || isdigit(d[1]) || |
1074 | d[1] == '_') { |
1075 | d = scanreg(d,s,tokenbuf); |
1076 | if (stabent(tokenbuf,FALSE)) |
1077 | weight -= 100; |
1078 | else |
1079 | weight -= 10; |
1080 | } |
1081 | else if (*d == '$' && d[1] && |
1082 | index("[#!%*<>()-=",d[1])) { |
1083 | if (!d[2] || /*{*/ index("])} =",d[2])) |
1084 | weight -= 10; |
1085 | else |
1086 | weight -= 1; |
1087 | } |
1088 | break; |
1089 | case '\\': |
ffed7fef |
1090 | un_char = 254; |
a687059c |
1091 | if (d[1]) { |
1092 | if (index("wds",d[1])) |
1093 | weight += 100; |
1094 | else if (seen['\''] || seen['"']) |
1095 | weight += 1; |
1096 | else if (index("rnftb",d[1])) |
1097 | weight += 40; |
1098 | else if (isdigit(d[1])) { |
1099 | weight += 40; |
1100 | while (d[1] && isdigit(d[1])) |
1101 | d++; |
1102 | } |
1103 | } |
1104 | else |
1105 | weight += 100; |
1106 | break; |
1107 | case '-': |
395c3793 |
1108 | if (last_un_char < (unsigned char) d[1] |
1109 | || d[1] == '\\') { |
ffed7fef |
1110 | if (index("aA01! ",last_un_char)) |
a687059c |
1111 | weight += 30; |
1112 | if (index("zZ79~",d[1])) |
1113 | weight += 30; |
1114 | } |
1115 | else |
1116 | weight -= 1; |
1117 | default: |
1118 | if (isalpha(*d) && d[1] && isalpha(d[1])) { |
1119 | bufptr = d; |
1120 | if (yylex() != WORD) |
1121 | weight -= 150; |
1122 | d = bufptr; |
1123 | } |
ffed7fef |
1124 | if (un_char == last_un_char + 1) |
a687059c |
1125 | weight += 5; |
ffed7fef |
1126 | weight -= seen[un_char]; |
a687059c |
1127 | break; |
1128 | } |
ffed7fef |
1129 | seen[un_char]++; |
a687059c |
1130 | } |
1131 | #ifdef DEBUGGING |
1132 | if (debug & 512) |
1133 | fprintf(stderr,"[%s] weight %d\n", |
1134 | checkpoint+1,weight); |
1135 | #endif |
1136 | *s++ = ']'; |
1137 | if (weight >= 0) /* probably a character class */ |
1138 | s = checkpoint; |
1139 | } |
1140 | } |
1141 | } |
1142 | if (*t == '@') |
1143 | str_ncat(toparse, "join($\",", 8); |
1144 | if (t[1] == '{' && s[-1] == '}') { |
1145 | str_ncat(toparse, t, 1); |
1146 | str_ncat(toparse, t+2, s - t - 3); |
1147 | } |
1148 | else |
1149 | str_ncat(toparse, t, s - t); |
1150 | if (*t == '@') |
1151 | str_ncat(toparse, ")", 1); |
1152 | t = s; |
1153 | } |
1154 | else |
1155 | s++; |
1156 | } |
1157 | str_ncat(str,t,s-t); |
1158 | if (toparse->str_ptr && *toparse->str_ptr == ',') { |
1159 | *toparse->str_ptr = '('; |
1160 | str_ncat(toparse,",$$);",5); |
1161 | str->str_u.str_args = parselist(toparse); |
1162 | str->str_u.str_args->arg_len--; /* ignore $$ reference */ |
1163 | } |
1164 | else |
1165 | str->str_u.str_args = Nullarg; |
1166 | str_free(toparse); |
1167 | str->str_pok |= SP_INTRP; |
1168 | str->str_nok = 0; |
1169 | str_replace(src,str); |
1170 | } |
1171 | |
1172 | STR * |
1173 | interp(str,src,sp) |
1174 | register STR *str; |
1175 | STR *src; |
1176 | int sp; |
1177 | { |
1178 | register char *s; |
1179 | register char *t; |
1180 | register char *send; |
1181 | register STR **elem; |
1182 | |
395c3793 |
1183 | if (str == &str_undef) |
1184 | return Nullstr; |
a687059c |
1185 | if (!(src->str_pok & SP_INTRP)) { |
1186 | int oldsave = savestack->ary_fill; |
1187 | |
1188 | (void)savehptr(&curstash); |
395c3793 |
1189 | curstash = curcmd->c_stash; /* so stabent knows right package */ |
a687059c |
1190 | intrpcompile(src); |
1191 | restorelist(oldsave); |
1192 | } |
1193 | s = src->str_ptr; /* assumed valid since str_pok set */ |
1194 | t = s; |
1195 | send = s + src->str_cur; |
1196 | |
1197 | if (src->str_u.str_args) { |
1198 | (void)eval(src->str_u.str_args,G_ARRAY,sp); |
1199 | /* Assuming we have correct # of args */ |
1200 | elem = stack->ary_array + sp; |
1201 | } |
1202 | |
1203 | str_nset(str,"",0); |
1204 | while (s < send) { |
1205 | if (*s == '$' && s+1 < send) { |
1206 | str_ncat(str,t,s-t); |
1207 | switch(*++s) { |
1208 | case 'a': |
1209 | str_scat(str,*++elem); |
1210 | break; |
1211 | case 'b': |
1212 | str_ncat(str,++s,1); |
1213 | break; |
1214 | } |
1215 | t = ++s; |
8d063cd8 |
1216 | } |
1217 | else |
1218 | s++; |
1219 | } |
8d063cd8 |
1220 | str_ncat(str,t,s-t); |
1221 | return str; |
1222 | } |
1223 | |
1224 | void |
1225 | str_inc(str) |
1226 | register STR *str; |
1227 | { |
1228 | register char *d; |
1229 | |
395c3793 |
1230 | if (!str || str == &str_undef) |
8d063cd8 |
1231 | return; |
1232 | if (str->str_nok) { |
a687059c |
1233 | str->str_u.str_nval += 1.0; |
8d063cd8 |
1234 | str->str_pok = 0; |
1235 | return; |
1236 | } |
378cc40b |
1237 | if (!str->str_pok || !*str->str_ptr) { |
a687059c |
1238 | str->str_u.str_nval = 1.0; |
8d063cd8 |
1239 | str->str_nok = 1; |
13281fa4 |
1240 | str->str_pok = 0; |
8d063cd8 |
1241 | return; |
1242 | } |
378cc40b |
1243 | d = str->str_ptr; |
1244 | while (isalpha(*d)) d++; |
1245 | while (isdigit(*d)) d++; |
1246 | if (*d) { |
8d063cd8 |
1247 | str_numset(str,atof(str->str_ptr) + 1.0); /* punt */ |
1248 | return; |
1249 | } |
378cc40b |
1250 | d--; |
8d063cd8 |
1251 | while (d >= str->str_ptr) { |
378cc40b |
1252 | if (isdigit(*d)) { |
1253 | if (++*d <= '9') |
1254 | return; |
1255 | *(d--) = '0'; |
1256 | } |
1257 | else { |
1258 | ++*d; |
1259 | if (isalpha(*d)) |
1260 | return; |
1261 | *(d--) -= 'z' - 'a' + 1; |
1262 | } |
8d063cd8 |
1263 | } |
1264 | /* oh,oh, the number grew */ |
a687059c |
1265 | STR_GROW(str, str->str_cur + 2); |
8d063cd8 |
1266 | str->str_cur++; |
1267 | for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--) |
1268 | *d = d[-1]; |
378cc40b |
1269 | if (isdigit(d[1])) |
1270 | *d = '1'; |
1271 | else |
1272 | *d = d[1]; |
8d063cd8 |
1273 | } |
1274 | |
1275 | void |
1276 | str_dec(str) |
1277 | register STR *str; |
1278 | { |
395c3793 |
1279 | if (!str || str == &str_undef) |
8d063cd8 |
1280 | return; |
1281 | if (str->str_nok) { |
a687059c |
1282 | str->str_u.str_nval -= 1.0; |
8d063cd8 |
1283 | str->str_pok = 0; |
1284 | return; |
1285 | } |
1286 | if (!str->str_pok) { |
a687059c |
1287 | str->str_u.str_nval = -1.0; |
8d063cd8 |
1288 | str->str_nok = 1; |
1289 | return; |
1290 | } |
378cc40b |
1291 | str_numset(str,atof(str->str_ptr) - 1.0); |
8d063cd8 |
1292 | } |
1293 | |
a687059c |
1294 | /* Make a string that will exist for the duration of the expression |
1295 | * evaluation. Actually, it may have to last longer than that, but |
1296 | * hopefully cmd_exec won't free it until it has been assigned to a |
1297 | * permanent location. */ |
1298 | |
1299 | static long tmps_size = -1; |
8d063cd8 |
1300 | |
1301 | STR * |
1302 | str_static(oldstr) |
1303 | STR *oldstr; |
1304 | { |
a687059c |
1305 | register STR *str = Str_new(78,0); |
8d063cd8 |
1306 | |
1307 | str_sset(str,oldstr); |
1308 | if (++tmps_max > tmps_size) { |
1309 | tmps_size = tmps_max; |
1310 | if (!(tmps_size & 127)) { |
1311 | if (tmps_size) |
a687059c |
1312 | Renew(tmps_list, tmps_size + 128, STR*); |
8d063cd8 |
1313 | else |
a687059c |
1314 | New(702,tmps_list, 128, STR*); |
8d063cd8 |
1315 | } |
1316 | } |
1317 | tmps_list[tmps_max] = str; |
34de22dd |
1318 | if (str->str_pok) |
1319 | str->str_pok |= SP_TEMP; |
8d063cd8 |
1320 | return str; |
1321 | } |
1322 | |
a687059c |
1323 | /* same thing without the copying */ |
1324 | |
8d063cd8 |
1325 | STR * |
a687059c |
1326 | str_2static(str) |
1327 | register STR *str; |
1328 | { |
395c3793 |
1329 | if (str == &str_undef) |
1330 | return str; |
a687059c |
1331 | if (++tmps_max > tmps_size) { |
1332 | tmps_size = tmps_max; |
1333 | if (!(tmps_size & 127)) { |
1334 | if (tmps_size) |
1335 | Renew(tmps_list, tmps_size + 128, STR*); |
1336 | else |
1337 | New(704,tmps_list, 128, STR*); |
1338 | } |
1339 | } |
1340 | tmps_list[tmps_max] = str; |
34de22dd |
1341 | if (str->str_pok) |
1342 | str->str_pok |= SP_TEMP; |
a687059c |
1343 | return str; |
1344 | } |
1345 | |
1346 | STR * |
1347 | str_make(s,len) |
8d063cd8 |
1348 | char *s; |
e929a76b |
1349 | STRLEN len; |
8d063cd8 |
1350 | { |
a687059c |
1351 | register STR *str = Str_new(79,0); |
8d063cd8 |
1352 | |
a687059c |
1353 | if (!len) |
1354 | len = strlen(s); |
1355 | str_nset(str,s,len); |
8d063cd8 |
1356 | return str; |
1357 | } |
1358 | |
1359 | STR * |
1360 | str_nmake(n) |
1361 | double n; |
1362 | { |
a687059c |
1363 | register STR *str = Str_new(80,0); |
8d063cd8 |
1364 | |
1365 | str_numset(str,n); |
1366 | return str; |
1367 | } |
a687059c |
1368 | |
1369 | /* make an exact duplicate of old */ |
1370 | |
1371 | STR * |
1372 | str_smake(old) |
1373 | register STR *old; |
1374 | { |
1375 | register STR *new = Str_new(81,0); |
1376 | |
1377 | if (!old) |
1378 | return Nullstr; |
1379 | if (old->str_state == SS_FREE) { |
1380 | warn("semi-panic: attempt to dup freed string"); |
1381 | return Nullstr; |
1382 | } |
1383 | if (old->str_state == SS_INCR && !(old->str_pok & 2)) |
e929a76b |
1384 | Str_Grow(old,0); |
a687059c |
1385 | if (new->str_ptr) |
1386 | Safefree(new->str_ptr); |
1387 | Copy(old,new,1,STR); |
27e2fb84 |
1388 | if (old->str_ptr) { |
a687059c |
1389 | new->str_ptr = nsavestr(old->str_ptr,old->str_len); |
27e2fb84 |
1390 | new->str_pok &= ~SP_TEMP; |
1391 | } |
a687059c |
1392 | return new; |
1393 | } |
1394 | |
1395 | str_reset(s,stash) |
1396 | register char *s; |
1397 | HASH *stash; |
1398 | { |
1399 | register HENT *entry; |
1400 | register STAB *stab; |
1401 | register STR *str; |
1402 | register int i; |
1403 | register SPAT *spat; |
1404 | register int max; |
1405 | |
1406 | if (!*s) { /* reset ?? searches */ |
1407 | for (spat = stash->tbl_spatroot; |
1408 | spat != Nullspat; |
1409 | spat = spat->spat_next) { |
1410 | spat->spat_flags &= ~SPAT_USED; |
1411 | } |
1412 | return; |
1413 | } |
1414 | |
1415 | /* reset variables */ |
1416 | |
395c3793 |
1417 | if (!stash->tbl_array) |
1418 | return; |
a687059c |
1419 | while (*s) { |
1420 | i = *s; |
1421 | if (s[1] == '-') { |
1422 | s += 2; |
1423 | } |
1424 | max = *s++; |
1425 | for ( ; i <= max; i++) { |
1426 | for (entry = stash->tbl_array[i]; |
1427 | entry; |
1428 | entry = entry->hent_next) { |
1429 | stab = (STAB*)entry->hent_val; |
1430 | str = stab_val(stab); |
1431 | str->str_cur = 0; |
1432 | str->str_nok = 0; |
1433 | #ifdef TAINT |
1434 | str->str_tainted = tainted; |
1435 | #endif |
1436 | if (str->str_ptr != Nullch) |
1437 | str->str_ptr[0] = '\0'; |
1438 | if (stab_xarray(stab)) { |
1439 | aclear(stab_xarray(stab)); |
1440 | } |
1441 | if (stab_xhash(stab)) { |
395c3793 |
1442 | hclear(stab_xhash(stab), FALSE); |
a687059c |
1443 | if (stab == envstab) |
1444 | environ[0] = Nullch; |
1445 | } |
1446 | } |
1447 | } |
1448 | } |
1449 | } |
1450 | |
1451 | #ifdef TAINT |
1452 | taintproper(s) |
1453 | char *s; |
1454 | { |
1455 | #ifdef DEBUGGING |
1456 | if (debug & 2048) |
1457 | fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid); |
1458 | #endif |
e929a76b |
1459 | if (tainted && (!euid || euid != uid || egid != gid)) { |
a687059c |
1460 | if (!unsafe) |
1461 | fatal("%s", s); |
1462 | else if (dowarn) |
1463 | warn("%s", s); |
1464 | } |
1465 | } |
1466 | |
1467 | taintenv() |
1468 | { |
1469 | register STR *envstr; |
1470 | |
1471 | envstr = hfetch(stab_hash(envstab),"PATH",4,FALSE); |
395c3793 |
1472 | if (envstr == &str_undef || envstr->str_tainted) { |
a687059c |
1473 | tainted = 1; |
395c3793 |
1474 | if (envstr->str_tainted == 2) |
1475 | taintproper("Insecure directory in PATH"); |
1476 | else |
1477 | taintproper("Insecure PATH"); |
a687059c |
1478 | } |
1479 | envstr = hfetch(stab_hash(envstab),"IFS",3,FALSE); |
395c3793 |
1480 | if (envstr != &str_undef && envstr->str_tainted) { |
a687059c |
1481 | tainted = 1; |
1482 | taintproper("Insecure IFS"); |
1483 | } |
1484 | } |
1485 | #endif /* TAINT */ |