d42a59157cb70ad7633f8466c2e0f99a8e90e3c8
[p5sagit/p5-mst-13.2.git] / x2p / str.c
1 /* $RCSfile: str.c,v $$Revision: 4.1 $$Date: 92/08/07 18:29:26 $
2  *
3  *    Copyright (c) 1991, Larry Wall
4  *
5  *    You may distribute under the terms of either the GNU General Public
6  *    License or the Artistic License, as specified in the README file.
7  *
8  * $Log:        str.c,v $
9  */
10
11 #include "handy.h"
12 #include "EXTERN.h"
13 #include "util.h"
14 #include "a2p.h"
15
16 str_numset(str,num)
17 register STR *str;
18 double num;
19 {
20     str->str_nval = num;
21     str->str_pok = 0;           /* invalidate pointer */
22     str->str_nok = 1;           /* validate number */
23 }
24
25 char *
26 str_2ptr(str)
27 register STR *str;
28 {
29     register char *s;
30
31     if (!str)
32         return "";
33     GROWSTR(&(str->str_ptr), &(str->str_len), 24);
34     s = str->str_ptr;
35     if (str->str_nok) {
36         sprintf(s,"%.20g",str->str_nval);
37         while (*s) s++;
38     }
39     *s = '\0';
40     str->str_cur = s - str->str_ptr;
41     str->str_pok = 1;
42 #ifdef DEBUGGING
43     if (debug & 32)
44         fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
45 #endif
46     return str->str_ptr;
47 }
48
49 double
50 str_2num(str)
51 register STR *str;
52 {
53     if (!str)
54         return 0.0;
55     if (str->str_len && str->str_pok)
56         str->str_nval = atof(str->str_ptr);
57     else
58         str->str_nval = 0.0;
59     str->str_nok = 1;
60 #ifdef DEBUGGING
61     if (debug & 32)
62         fprintf(stderr,"0x%lx num(%g)\n",str,str->str_nval);
63 #endif
64     return str->str_nval;
65 }
66
67 str_sset(dstr,sstr)
68 STR *dstr;
69 register STR *sstr;
70 {
71     if (!sstr)
72         str_nset(dstr,No,0);
73     else if (sstr->str_nok)
74         str_numset(dstr,sstr->str_nval);
75     else if (sstr->str_pok)
76         str_nset(dstr,sstr->str_ptr,sstr->str_cur);
77     else
78         str_nset(dstr,"",0);
79 }
80
81 str_nset(str,ptr,len)
82 register STR *str;
83 register char *ptr;
84 register int len;
85 {
86     GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
87     bcopy(ptr,str->str_ptr,len);
88     str->str_cur = len;
89     *(str->str_ptr+str->str_cur) = '\0';
90     str->str_nok = 0;           /* invalidate number */
91     str->str_pok = 1;           /* validate pointer */
92 }
93
94 str_set(str,ptr)
95 register STR *str;
96 register char *ptr;
97 {
98     register int len;
99
100     if (!ptr)
101         ptr = "";
102     len = strlen(ptr);
103     GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
104     bcopy(ptr,str->str_ptr,len+1);
105     str->str_cur = len;
106     str->str_nok = 0;           /* invalidate number */
107     str->str_pok = 1;           /* validate pointer */
108 }
109
110 str_chop(str,ptr)       /* like set but assuming ptr is in str */
111 register STR *str;
112 register char *ptr;
113 {
114     if (!(str->str_pok))
115         str_2ptr(str);
116     str->str_cur -= (ptr - str->str_ptr);
117     bcopy(ptr,str->str_ptr, str->str_cur + 1);
118     str->str_nok = 0;           /* invalidate number */
119     str->str_pok = 1;           /* validate pointer */
120 }
121
122 str_ncat(str,ptr,len)
123 register STR *str;
124 register char *ptr;
125 register int len;
126 {
127     if (!(str->str_pok))
128         str_2ptr(str);
129     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
130     bcopy(ptr,str->str_ptr+str->str_cur,len);
131     str->str_cur += len;
132     *(str->str_ptr+str->str_cur) = '\0';
133     str->str_nok = 0;           /* invalidate number */
134     str->str_pok = 1;           /* validate pointer */
135 }
136
137 str_scat(dstr,sstr)
138 STR *dstr;
139 register STR *sstr;
140 {
141     if (!(sstr->str_pok))
142         str_2ptr(sstr);
143     if (sstr)
144         str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
145 }
146
147 str_cat(str,ptr)
148 register STR *str;
149 register char *ptr;
150 {
151     register int len;
152
153     if (!ptr)
154         return;
155     if (!(str->str_pok))
156         str_2ptr(str);
157     len = strlen(ptr);
158     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
159     bcopy(ptr,str->str_ptr+str->str_cur,len+1);
160     str->str_cur += len;
161     str->str_nok = 0;           /* invalidate number */
162     str->str_pok = 1;           /* validate pointer */
163 }
164
165 char *
166 str_append_till(str,from,delim,keeplist)
167 register STR *str;
168 register char *from;
169 register int delim;
170 char *keeplist;
171 {
172     register char *to;
173     register int len;
174
175     if (!from)
176         return Nullch;
177     len = strlen(from);
178     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
179     str->str_nok = 0;           /* invalidate number */
180     str->str_pok = 1;           /* validate pointer */
181     to = str->str_ptr+str->str_cur;
182     for (; *from; from++,to++) {
183         if (*from == '\\' && from[1] && delim != '\\') {
184             if (!keeplist) {
185                 if (from[1] == delim || from[1] == '\\')
186                     from++;
187                 else
188                     *to++ = *from++;
189             }
190             else if (strchr(keeplist,from[1]))
191                 *to++ = *from++;
192             else
193                 from++;
194         }
195         else if (*from == delim)
196             break;
197         *to = *from;
198     }
199     *to = '\0';
200     str->str_cur = to - str->str_ptr;
201     return from;
202 }
203
204 STR *
205 str_new(len)
206 int len;
207 {
208     register STR *str;
209     
210     if (freestrroot) {
211         str = freestrroot;
212         freestrroot = str->str_link.str_next;
213     }
214     else {
215         str = (STR *) safemalloc(sizeof(STR));
216         bzero((char*)str,sizeof(STR));
217     }
218     if (len)
219         GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
220     return str;
221 }
222
223 void
224 str_grow(str,len)
225 register STR *str;
226 int len;
227 {
228     if (len && str)
229         GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
230 }
231
232 /* make str point to what nstr did */
233
234 void
235 str_replace(str,nstr)
236 register STR *str;
237 register STR *nstr;
238 {
239     safefree(str->str_ptr);
240     str->str_ptr = nstr->str_ptr;
241     str->str_len = nstr->str_len;
242     str->str_cur = nstr->str_cur;
243     str->str_pok = nstr->str_pok;
244     if (str->str_nok = nstr->str_nok)
245         str->str_nval = nstr->str_nval;
246     safefree((char*)nstr);
247 }
248
249 void
250 str_free(str)
251 register STR *str;
252 {
253     if (!str)
254         return;
255     if (str->str_len)
256         str->str_ptr[0] = '\0';
257     str->str_cur = 0;
258     str->str_nok = 0;
259     str->str_pok = 0;
260     str->str_link.str_next = freestrroot;
261     freestrroot = str;
262 }
263
264 str_len(str)
265 register STR *str;
266 {
267     if (!str)
268         return 0;
269     if (!(str->str_pok))
270         str_2ptr(str);
271     if (str->str_len)
272         return str->str_cur;
273     else
274         return 0;
275 }
276
277 char *
278 str_gets(str,fp)
279 register STR *str;
280 register FILE *fp;
281 {
282 #ifdef USE_STD_STDIO            /* Here is some breathtakingly efficient cheating */
283
284     register char *bp;          /* we're going to steal some values */
285     register int cnt;           /*  from the stdio struct and put EVERYTHING */
286     register STDCHAR *ptr;      /*   in the innermost loop into registers */
287     register char newline = '\n';       /* (assuming at least 6 registers) */
288     int i;
289     int bpx;
290
291     cnt = fp->_cnt;                     /* get count into register */
292     str->str_nok = 0;                   /* invalidate number */
293     str->str_pok = 1;                   /* validate pointer */
294     if (str->str_len <= cnt)            /* make sure we have the room */
295         GROWSTR(&(str->str_ptr), &(str->str_len), cnt+1);
296     bp = str->str_ptr;                  /* move these two too to registers */
297     ptr = fp->_ptr;
298     for (;;) {
299         while (--cnt >= 0) {
300             if ((*bp++ = *ptr++) == newline)
301                 if (bp <= str->str_ptr || bp[-2] != '\\')
302                     goto thats_all_folks;
303                 else {
304                     line++;
305                     bp -= 2;
306                 }
307         }
308         
309         fp->_cnt = cnt;                 /* deregisterize cnt and ptr */
310         fp->_ptr = ptr;
311         i = _filbuf(fp);                /* get more characters */
312         cnt = fp->_cnt;
313         ptr = fp->_ptr;                 /* reregisterize cnt and ptr */
314
315         bpx = bp - str->str_ptr;        /* prepare for possible relocation */
316         GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + cnt + 1);
317         bp = str->str_ptr + bpx;        /* reconstitute our pointer */
318
319         if (i == newline) {             /* all done for now? */
320             *bp++ = i;
321             goto thats_all_folks;
322         }
323         else if (i == EOF)              /* all done for ever? */
324             goto thats_all_folks;
325         *bp++ = i;                      /* now go back to screaming loop */
326     }
327
328 thats_all_folks:
329     fp->_cnt = cnt;                     /* put these back or we're in trouble */
330     fp->_ptr = ptr;
331     *bp = '\0';
332     str->str_cur = bp - str->str_ptr;   /* set length */
333
334 #else /* !USE_STD_STDIO */      /* The big, slow, and stupid way */
335
336     static char buf[4192];
337
338     if (fgets(buf, sizeof buf, fp) != Nullch)
339         str_set(str, buf);
340     else
341         str_set(str, No);
342
343 #endif /* USE_STD_STDIO */
344
345     return str->str_cur ? str->str_ptr : Nullch;
346 }
347
348 void
349 str_inc(str)
350 register STR *str;
351 {
352     register char *d;
353
354     if (!str)
355         return;
356     if (str->str_nok) {
357         str->str_nval += 1.0;
358         str->str_pok = 0;
359         return;
360     }
361     if (!str->str_pok) {
362         str->str_nval = 1.0;
363         str->str_nok = 1;
364         return;
365     }
366     for (d = str->str_ptr; *d && *d != '.'; d++) ;
367     d--;
368     if (!isdigit(*str->str_ptr) || !isdigit(*d) ) {
369         str_numset(str,atof(str->str_ptr) + 1.0);  /* punt */
370         return;
371     }
372     while (d >= str->str_ptr) {
373         if (++*d <= '9')
374             return;
375         *(d--) = '0';
376     }
377     /* oh,oh, the number grew */
378     GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + 2);
379     str->str_cur++;
380     for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
381         *d = d[-1];
382     *d = '1';
383 }
384
385 void
386 str_dec(str)
387 register STR *str;
388 {
389     register char *d;
390
391     if (!str)
392         return;
393     if (str->str_nok) {
394         str->str_nval -= 1.0;
395         str->str_pok = 0;
396         return;
397     }
398     if (!str->str_pok) {
399         str->str_nval = -1.0;
400         str->str_nok = 1;
401         return;
402     }
403     for (d = str->str_ptr; *d && *d != '.'; d++) ;
404     d--;
405     if (!isdigit(*str->str_ptr) || !isdigit(*d) || (*d == '0' && d == str->str_ptr)) {
406         str_numset(str,atof(str->str_ptr) - 1.0);  /* punt */
407         return;
408     }
409     while (d >= str->str_ptr) {
410         if (--*d >= '0')
411             return;
412         *(d--) = '9';
413     }
414 }
415
416 /* make a string that will exist for the duration of the expression eval */
417
418 STR *
419 str_mortal(oldstr)
420 STR *oldstr;
421 {
422     register STR *str = str_new(0);
423     static long tmps_size = -1;
424
425     str_sset(str,oldstr);
426     if (++tmps_max > tmps_size) {
427         tmps_size = tmps_max;
428         if (!(tmps_size & 127)) {
429             if (tmps_size)
430                 tmps_list = (STR**)saferealloc((char*)tmps_list,
431                     (tmps_size + 128) * sizeof(STR*) );
432             else
433                 tmps_list = (STR**)safemalloc(128 * sizeof(char*));
434         }
435     }
436     tmps_list[tmps_max] = str;
437     return str;
438 }
439
440 STR *
441 str_make(s)
442 char *s;
443 {
444     register STR *str = str_new(0);
445
446     str_set(str,s);
447     return str;
448 }
449
450 STR *
451 str_nmake(n)
452 double n;
453 {
454     register STR *str = str_new(0);
455
456     str_numset(str,n);
457     return str;
458 }