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