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