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