perl 1.0 patch 13: fix for faulty patch 12, plus random portability glitches
[p5sagit/p5-mst-13.2.git] / str.c
1 /* $Header: str.c,v 1.0.1.1 88/01/21 21:28:39 root Exp $
2  *
3  * $Log:        str.c,v $
4  * Revision 1.0.1.1  88/01/21  21:28:39  root
5  * Suppressed warning messages on signed vs unsigned chars in str_gets().
6  * 
7  * Revision 1.0  87/12/18  13:06:22  root
8  * Initial revision
9  * 
10  */
11
12 #include "handy.h"
13 #include "EXTERN.h"
14 #include "search.h"
15 #include "util.h"
16 #include "perl.h"
17
18 str_reset(s)
19 register char *s;
20 {
21     register STAB *stab;
22     register STR *str;
23     register int i;
24     register int max;
25     register SPAT *spat;
26
27     if (!*s) {          /* reset ?? searches */
28         for (spat = spat_root; spat != Nullspat; spat = spat->spat_next) {
29             spat->spat_flags &= ~SPAT_USED;
30         }
31         return;
32     }
33
34     /* reset variables */
35
36     while (*s) {
37         i = *s;
38         if (s[1] == '-') {
39             s += 2;
40         }
41         max = *s++;
42         for ( ; i <= max; i++) {
43             for (stab = stab_index[i]; stab; stab = stab->stab_next) {
44                 str = stab->stab_val;
45                 str->str_cur = 0;
46                 if (str->str_ptr != Nullch)
47                     str->str_ptr[0] = '\0';
48             }
49         }
50     }
51 }
52
53 str_numset(str,num)
54 register STR *str;
55 double num;
56 {
57     str->str_nval = num;
58     str->str_pok = 0;           /* invalidate pointer */
59     str->str_nok = 1;           /* validate number */
60 }
61
62 char *
63 str_2ptr(str)
64 register STR *str;
65 {
66     register char *s;
67
68     if (!str)
69         return "";
70     GROWSTR(&(str->str_ptr), &(str->str_len), 24);
71     s = str->str_ptr;
72     if (str->str_nok) {
73         sprintf(s,"%.20g",str->str_nval);
74         while (*s) s++;
75     }
76     *s = '\0';
77     str->str_cur = s - str->str_ptr;
78     str->str_pok = 1;
79 #ifdef DEBUGGING
80     if (debug & 32)
81         fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
82 #endif
83     return str->str_ptr;
84 }
85
86 double
87 str_2num(str)
88 register STR *str;
89 {
90     if (!str)
91         return 0.0;
92     if (str->str_len && str->str_pok)
93         str->str_nval = atof(str->str_ptr);
94     else
95         str->str_nval = 0.0;
96     str->str_nok = 1;
97 #ifdef DEBUGGING
98     if (debug & 32)
99         fprintf(stderr,"0x%lx num(%g)\n",str,str->str_nval);
100 #endif
101     return str->str_nval;
102 }
103
104 str_sset(dstr,sstr)
105 STR *dstr;
106 register STR *sstr;
107 {
108     if (!sstr)
109         str_nset(dstr,No,0);
110     else if (sstr->str_nok)
111         str_numset(dstr,sstr->str_nval);
112     else if (sstr->str_pok)
113         str_nset(dstr,sstr->str_ptr,sstr->str_cur);
114     else
115         str_nset(dstr,"",0);
116 }
117
118 str_nset(str,ptr,len)
119 register STR *str;
120 register char *ptr;
121 register int len;
122 {
123     GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
124     bcopy(ptr,str->str_ptr,len);
125     str->str_cur = len;
126     *(str->str_ptr+str->str_cur) = '\0';
127     str->str_nok = 0;           /* invalidate number */
128     str->str_pok = 1;           /* validate pointer */
129 }
130
131 str_set(str,ptr)
132 register STR *str;
133 register char *ptr;
134 {
135     register int len;
136
137     if (!ptr)
138         ptr = "";
139     len = strlen(ptr);
140     GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
141     bcopy(ptr,str->str_ptr,len+1);
142     str->str_cur = len;
143     str->str_nok = 0;           /* invalidate number */
144     str->str_pok = 1;           /* validate pointer */
145 }
146
147 str_chop(str,ptr)       /* like set but assuming ptr is in str */
148 register STR *str;
149 register char *ptr;
150 {
151     if (!(str->str_pok))
152         str_2ptr(str);
153     str->str_cur -= (ptr - str->str_ptr);
154     bcopy(ptr,str->str_ptr, str->str_cur + 1);
155     str->str_nok = 0;           /* invalidate number */
156     str->str_pok = 1;           /* validate pointer */
157 }
158
159 str_ncat(str,ptr,len)
160 register STR *str;
161 register char *ptr;
162 register int len;
163 {
164     if (!(str->str_pok))
165         str_2ptr(str);
166     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
167     bcopy(ptr,str->str_ptr+str->str_cur,len);
168     str->str_cur += len;
169     *(str->str_ptr+str->str_cur) = '\0';
170     str->str_nok = 0;           /* invalidate number */
171     str->str_pok = 1;           /* validate pointer */
172 }
173
174 str_scat(dstr,sstr)
175 STR *dstr;
176 register STR *sstr;
177 {
178     if (!(sstr->str_pok))
179         str_2ptr(sstr);
180     if (sstr)
181         str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
182 }
183
184 str_cat(str,ptr)
185 register STR *str;
186 register char *ptr;
187 {
188     register int len;
189
190     if (!ptr)
191         return;
192     if (!(str->str_pok))
193         str_2ptr(str);
194     len = strlen(ptr);
195     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
196     bcopy(ptr,str->str_ptr+str->str_cur,len+1);
197     str->str_cur += len;
198     str->str_nok = 0;           /* invalidate number */
199     str->str_pok = 1;           /* validate pointer */
200 }
201
202 char *
203 str_append_till(str,from,delim,keeplist)
204 register STR *str;
205 register char *from;
206 register int delim;
207 char *keeplist;
208 {
209     register char *to;
210     register int len;
211
212     if (!from)
213         return Nullch;
214     len = strlen(from);
215     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
216     str->str_nok = 0;           /* invalidate number */
217     str->str_pok = 1;           /* validate pointer */
218     to = str->str_ptr+str->str_cur;
219     for (; *from; from++,to++) {
220         if (*from == '\\' && from[1] && delim != '\\') {
221             if (!keeplist) {
222                 if (from[1] == delim || from[1] == '\\')
223                     from++;
224                 else
225                     *to++ = *from++;
226             }
227             else if (index(keeplist,from[1]))
228                 *to++ = *from++;
229             else
230                 from++;
231         }
232         else if (*from == delim)
233             break;
234         *to = *from;
235     }
236     *to = '\0';
237     str->str_cur = to - str->str_ptr;
238     return from;
239 }
240
241 STR *
242 str_new(len)
243 int len;
244 {
245     register STR *str;
246     
247     if (freestrroot) {
248         str = freestrroot;
249         freestrroot = str->str_link.str_next;
250         str->str_link.str_magic = Nullstab;
251     }
252     else {
253         str = (STR *) safemalloc(sizeof(STR));
254         bzero((char*)str,sizeof(STR));
255     }
256     if (len)
257         GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
258     return str;
259 }
260
261 void
262 str_grow(str,len)
263 register STR *str;
264 int len;
265 {
266     if (len && str)
267         GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
268 }
269
270 /* make str point to what nstr did */
271
272 void
273 str_replace(str,nstr)
274 register STR *str;
275 register STR *nstr;
276 {
277     safefree(str->str_ptr);
278     str->str_ptr = nstr->str_ptr;
279     str->str_len = nstr->str_len;
280     str->str_cur = nstr->str_cur;
281     str->str_pok = nstr->str_pok;
282     if (str->str_nok = nstr->str_nok)
283         str->str_nval = nstr->str_nval;
284     safefree((char*)nstr);
285 }
286
287 void
288 str_free(str)
289 register STR *str;
290 {
291     if (!str)
292         return;
293     if (str->str_len)
294         str->str_ptr[0] = '\0';
295     str->str_cur = 0;
296     str->str_nok = 0;
297     str->str_pok = 0;
298     str->str_link.str_next = freestrroot;
299     freestrroot = str;
300 }
301
302 str_len(str)
303 register STR *str;
304 {
305     if (!str)
306         return 0;
307     if (!(str->str_pok))
308         str_2ptr(str);
309     if (str->str_len)
310         return str->str_cur;
311     else
312         return 0;
313 }
314
315 char *
316 str_gets(str,fp)
317 register STR *str;
318 register FILE *fp;
319 {
320 #ifdef STDSTDIO         /* Here is some breathtakingly efficient cheating */
321
322     register char *bp;          /* we're going to steal some values */
323     register int cnt;           /*  from the stdio struct and put EVERYTHING */
324     register STDCHAR *ptr;      /*   in the innermost loop into registers */
325     register char newline = record_separator;/* (assuming >= 6 registers) */
326     int i;
327     int bpx;
328     int obpx;
329     register int get_paragraph;
330     register char *oldbp;
331
332     if (get_paragraph = !newline) {     /* yes, that's an assignment */
333         newline = '\n';
334         oldbp = Nullch;                 /* remember last \n position (none) */
335     }
336     cnt = fp->_cnt;                     /* get count into register */
337     str->str_nok = 0;                   /* invalidate number */
338     str->str_pok = 1;                   /* validate pointer */
339     if (str->str_len <= cnt)            /* make sure we have the room */
340         GROWSTR(&(str->str_ptr), &(str->str_len), cnt+1);
341     bp = str->str_ptr;                  /* move these two too to registers */
342     ptr = fp->_ptr;
343     for (;;) {
344       screamer:
345         while (--cnt >= 0) {                    /* this */      /* eat */
346             if ((*bp++ = *ptr++) == newline)    /* really */    /* dust */
347                 goto thats_all_folks;           /* screams */   /* sed :-) */ 
348         }
349         
350         fp->_cnt = cnt;                 /* deregisterize cnt and ptr */
351         fp->_ptr = ptr;
352         i = _filbuf(fp);                /* get more characters */
353         cnt = fp->_cnt;
354         ptr = fp->_ptr;                 /* reregisterize cnt and ptr */
355
356         bpx = bp - str->str_ptr;        /* prepare for possible relocation */
357         if (get_paragraph && oldbp)
358             obpx = oldbp - str->str_ptr;
359         GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + cnt + 1);
360         bp = str->str_ptr + bpx;        /* reconstitute our pointer */
361         if (get_paragraph && oldbp)
362             oldbp = str->str_ptr + obpx;
363
364         if (i == newline) {             /* all done for now? */
365             *bp++ = i;
366             goto thats_all_folks;
367         }
368         else if (i == EOF)              /* all done for ever? */
369             goto thats_really_all_folks;
370         *bp++ = i;                      /* now go back to screaming loop */
371     }
372
373 thats_all_folks:
374     if (get_paragraph && bp - 1 != oldbp) {
375         oldbp = bp;     /* remember where this newline was */
376         goto screamer;  /* and go back to the fray */
377     }
378 thats_really_all_folks:
379     fp->_cnt = cnt;                     /* put these back or we're in trouble */
380     fp->_ptr = ptr;
381     *bp = '\0';
382     str->str_cur = bp - str->str_ptr;   /* set length */
383
384 #else /* !STDSTDIO */   /* The big, slow, and stupid way */
385
386     static char buf[4192];
387
388     if (fgets(buf, sizeof buf, fp) != Nullch)
389         str_set(str, buf);
390     else
391         str_set(str, No);
392
393 #endif /* STDSTDIO */
394
395     return str->str_cur ? str->str_ptr : Nullch;
396 }
397
398
399 STR *
400 interp(str,s)
401 register STR *str;
402 register char *s;
403 {
404     register char *t = s;
405     char *envsave = envname;
406     envname = Nullch;
407
408     str_set(str,"");
409     while (*s) {
410         if (*s == '\\' && s[1] == '$') {
411             str_ncat(str, t, s++ - t);
412             t = s++;
413         }
414         else if (*s == '$' && s[1] && s[1] != '|') {
415             str_ncat(str,t,s-t);
416             s = scanreg(s,tokenbuf);
417             str_cat(str,reg_get(tokenbuf));
418             t = s;
419         }
420         else
421             s++;
422     }
423     envname = envsave;
424     str_ncat(str,t,s-t);
425     return str;
426 }
427
428 void
429 str_inc(str)
430 register STR *str;
431 {
432     register char *d;
433
434     if (!str)
435         return;
436     if (str->str_nok) {
437         str->str_nval += 1.0;
438         str->str_pok = 0;
439         return;
440     }
441     if (!str->str_pok) {
442         str->str_nval = 1.0;
443         str->str_nok = 1;
444         return;
445     }
446     for (d = str->str_ptr; *d && *d != '.'; d++) ;
447     d--;
448     if (!isdigit(*str->str_ptr) || !isdigit(*d) ) {
449         str_numset(str,atof(str->str_ptr) + 1.0);  /* punt */
450         return;
451     }
452     while (d >= str->str_ptr) {
453         if (++*d <= '9')
454             return;
455         *(d--) = '0';
456     }
457     /* oh,oh, the number grew */
458     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + 2);
459     str->str_cur++;
460     for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
461         *d = d[-1];
462     *d = '1';
463 }
464
465 void
466 str_dec(str)
467 register STR *str;
468 {
469     register char *d;
470
471     if (!str)
472         return;
473     if (str->str_nok) {
474         str->str_nval -= 1.0;
475         str->str_pok = 0;
476         return;
477     }
478     if (!str->str_pok) {
479         str->str_nval = -1.0;
480         str->str_nok = 1;
481         return;
482     }
483     for (d = str->str_ptr; *d && *d != '.'; d++) ;
484     d--;
485     if (!isdigit(*str->str_ptr) || !isdigit(*d) || (*d == '0' && d == str->str_ptr)) {
486         str_numset(str,atof(str->str_ptr) - 1.0);  /* punt */
487         return;
488     }
489     while (d >= str->str_ptr) {
490         if (--*d >= '0')
491             return;
492         *(d--) = '9';
493     }
494 }
495
496 /* make a string that will exist for the duration of the expression eval */
497
498 STR *
499 str_static(oldstr)
500 STR *oldstr;
501 {
502     register STR *str = str_new(0);
503     static long tmps_size = -1;
504
505     str_sset(str,oldstr);
506     if (++tmps_max > tmps_size) {
507         tmps_size = tmps_max;
508         if (!(tmps_size & 127)) {
509             if (tmps_size)
510                 tmps_list = (STR**)saferealloc((char*)tmps_list,
511                     (tmps_size + 128) * sizeof(STR*) );
512             else
513                 tmps_list = (STR**)safemalloc(128 * sizeof(char*));
514         }
515     }
516     tmps_list[tmps_max] = str;
517     return str;
518 }
519
520 STR *
521 str_make(s)
522 char *s;
523 {
524     register STR *str = str_new(0);
525
526     str_set(str,s);
527     return str;
528 }
529
530 STR *
531 str_nmake(n)
532 double n;
533 {
534     register STR *str = str_new(0);
535
536     str_numset(str,n);
537     return str;
538 }