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