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