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