081ffea5a74d36290c05450b3d5e52e04cd8fa90
[pspp-builds.git] / src / str.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "str.h"
22 #include "error.h"
23 #include <ctype.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include "alloc.h"
27 #include "error.h"
28 \f
29 /* sprintf() wrapper functions for convenience. */
30
31 #if !__GNUC__
32 char *
33 spprintf (char *buf, const char *format,...)
34 {
35 #if HAVE_GOOD_SPRINTF
36   int count;
37 #endif
38   va_list args;
39
40   va_start (args, format);
41 #if HAVE_GOOD_SPRINTF
42   count =
43 #endif
44     vsprintf (buf, format, args);
45   va_end (args);
46
47 #if HAVE_GOOD_SPRINTF
48   return &buf[count];
49 #else
50   return strchr (buf, 0);
51 #endif
52 }
53 #endif /* !__GNUC__ */
54
55 #if !__GNUC__ && !HAVE_GOOD_SPRINTF
56 int
57 nsprintf (char *buf, const char *format,...)
58 {
59   va_list args;
60
61   va_start (args, format);
62   vsprintf (buf, format, args);
63   va_end (args);
64
65   return strlen (buf);
66 }
67
68 int
69 nvsprintf (char *buf, const char *format, va_list args)
70 {
71   vsprintf (buf, format, args);
72   return strlen (buf);
73 }
74 #endif /* Not GNU C and not good sprintf(). */
75 \f
76 /* Reverses the order of NBYTES bytes at address P, thus converting
77    between little- and big-endian byte orders.  */
78 void
79 buf_reverse (char *p, size_t nbytes)
80 {
81   char *h = p, *t = &h[nbytes - 1];
82   char temp;
83
84   nbytes /= 2;
85   while (nbytes--)
86     {
87       temp = *h;
88       *h++ = *t;
89       *t-- = temp;
90     }
91 }
92
93 /* Finds the last NEEDLE of length NEEDLE_LEN in a HAYSTACK of length
94    HAYSTACK_LEN.  Returns a pointer to the needle found. */
95 char *
96 buf_find_reverse (const char *haystack, size_t haystack_len,
97                  const char *needle, size_t needle_len)
98 {
99   int i;
100   for (i = haystack_len - needle_len; i >= 0; i--)
101     if (!memcmp (needle, &haystack[i], needle_len))
102       return (char *) &haystack[i];
103   return 0;
104 }
105
106 /* Compares the SIZE bytes in A to those in B, disregarding case,
107    and returns a strcmp()-type result. */
108 int
109 buf_compare_case (const char *a_, const char *b_, size_t size)
110 {
111   const unsigned char *a = (unsigned char *) a_;
112   const unsigned char *b = (unsigned char *) b_;
113
114   while (size-- > 0) 
115     {
116       unsigned char ac = toupper (*a++);
117       unsigned char bc = toupper (*b++);
118
119       if (ac != bc) 
120         return ac > bc ? 1 : -1;
121     }
122
123   return 0;
124 }
125
126 /* Compares A of length A_LEN to B of length B_LEN.  The shorter
127    string is considered to be padded with spaces to the length of
128    the longer. */
129 int
130 buf_compare_rpad (const char *a, size_t a_len, const char *b, size_t b_len)
131 {
132   size_t min_len;
133   int result;
134
135   min_len = a_len < b_len ? a_len : b_len;
136   result = memcmp (a, b, min_len);
137   if (result != 0)
138     return result;
139   else 
140     {
141       size_t idx;
142       
143       if (a_len < b_len) 
144         {
145           for (idx = min_len; idx < b_len; idx++)
146             if (' ' != b[idx])
147               return ' ' > b[idx] ? 1 : -1;
148         }
149       else 
150         {
151           for (idx = min_len; idx < a_len; idx++)
152             if (a[idx] != ' ')
153               return a[idx] > ' ' ? 1 : -1;
154         }
155       return 0;
156     }
157 }
158
159 /* Compares strin A to string B.  The shorter string is
160    considered to be padded with spaces to the length of the
161    longer. */
162 int
163 str_compare_rpad (const char *a, const char *b)
164 {
165   return buf_compare_rpad (a, strlen (a), b, strlen (b));
166 }
167
168 /* Copies string SRC to buffer DST, of size DST_SIZE bytes.
169    DST is truncated to DST_SIZE bytes or padded on the right with
170    spaces as needed. */
171 void
172 buf_copy_str_rpad (char *dst, size_t dst_size, const char *src)
173 {
174   size_t src_len = strlen (src);
175   if (src_len >= dst_size)
176     memcpy (dst, src, dst_size);
177   else
178     {
179       memcpy (dst, src, src_len);
180       memset (&dst[src_len], ' ', dst_size - src_len);
181     }
182 }
183
184 /* Copies string SRC to buffer DST, of size DST_SIZE bytes.
185    DST is truncated to DST_SIZE bytes or padded on the left with
186    spaces as needed. */
187 void
188 buf_copy_str_lpad (char *dst, size_t dst_size, const char *src)
189 {
190   size_t src_len = strlen (src);
191   if (src_len >= dst_size)
192     memcpy (dst, src, dst_size);
193   else
194     {
195       size_t pad_cnt = dst_size - src_len;
196       memset (&dst[0], ' ', pad_cnt);
197       memcpy (dst + pad_cnt, src, src_len);
198     }
199 }
200
201 /* Copies buffer SRC, of SRC_SIZE bytes, to DST, of DST_SIZE bytes.
202    DST is truncated to DST_SIZE bytes or padded on the right with
203    spaces as needed. */
204 void
205 buf_copy_rpad (char *dst, size_t dst_size,
206                const char *src, size_t src_size)
207 {
208   if (src_size >= dst_size)
209     memmove (dst, src, dst_size);
210   else
211     {
212       memmove (dst, src, src_size);
213       memset (&dst[src_size], ' ', dst_size - src_size);
214     }
215 }
216
217 /* Copies string SRC to string DST, which is in a buffer DST_SIZE
218    bytes long.
219    Truncates DST to DST_SIZE - 1 characters or right-pads with
220    spaces to DST_SIZE - 1 characters if necessary. */
221 void
222 str_copy_rpad (char *dst, size_t dst_size, const char *src)
223 {
224   size_t src_len = strlen (src);
225   if (src_len < dst_size - 1)
226     {
227       memcpy (dst, src, src_len);
228       memset (&dst[src_len], ' ', dst_size - 1 - src_len);
229     }
230   else
231     memcpy (dst, src, dst_size - 1);
232   dst[dst_size - 1] = 0;
233 }
234
235 /* Copies SRC to DST, which is in a buffer DST_SIZE bytes long.
236    Truncates DST to DST_SIZE - 1 characters, if necessary. */
237 void
238 str_copy_trunc (char *dst, size_t dst_size, const char *src) 
239 {
240   size_t src_len = strlen (src);
241   assert (dst_size > 0);
242   if (src_len + 1 < dst_size)
243     memcpy (dst, src, src_len + 1);
244   else 
245     {
246       memcpy (dst, src, dst_size - 1);
247       dst[dst_size - 1] = '\0';
248     }
249 }
250
251 /* Copies buffer SRC, of SRC_LEN bytes,
252    to DST, which is in a buffer DST_SIZE bytes long.
253    Truncates DST to DST_SIZE - 1 characters, if necessary. */
254 void
255 str_copy_buf_trunc (char *dst, size_t dst_size,
256                     const char *src, size_t src_size) 
257 {
258   size_t dst_len;
259   assert (dst_size > 0);
260
261   dst_len = src_size < dst_size ? src_size : dst_size - 1;
262   memcpy (dst, src, dst_len);
263   dst[dst_len] = '\0';
264 }
265
266 /* Converts each character in S to uppercase. */
267 void
268 str_uppercase (char *s) 
269 {
270   for (; *s != '\0'; s++)
271     *s = toupper ((unsigned char) *s);
272 }
273 \f
274 /* Initializes ST with initial contents S. */
275 void
276 ds_create (struct string *st, const char *s)
277 {
278   st->length = strlen (s);
279   st->capacity = 8 + st->length * 2;
280   st->string = xmalloc (st->capacity + 1);
281   strcpy (st->string, s);
282 }
283
284 /* Initializes ST, making room for at least CAPACITY characters. */
285 void
286 ds_init (struct string *st, size_t capacity)
287 {
288   st->length = 0;
289   if (capacity > 8)
290     st->capacity = capacity;
291   else
292     st->capacity = 8;
293   st->string = xmalloc (st->capacity + 1);
294 }
295
296 /* Replaces the contents of ST with STRING.  STRING may overlap with
297    ST. */
298 void
299 ds_replace (struct string *st, const char *string)
300 {
301   size_t new_length = strlen (string);
302   if (new_length > st->capacity) 
303     {
304       /* The new length is longer than the allocated length, so
305          there can be no overlap. */
306       st->length = 0;
307       ds_concat (st, string, new_length);
308     }
309   else
310     {
311       /* Overlap is possible, but the new string will fit in the
312          allocated space, so we can just copy data. */
313       st->length = new_length;
314       memmove (st->string, string, st->length);
315     }
316 }
317
318 /* Frees ST. */
319 void
320 ds_destroy (struct string *st)
321 {
322   free (st->string);
323   st->string = NULL;
324 }
325
326 /* Truncates ST to zero length. */
327 void
328 ds_clear (struct string *st)
329 {
330   st->length = 0;
331 }
332
333 /* Pad ST on the right with copies of PAD until ST is at least
334    LENGTH characters in size.  If ST is initially LENGTH
335    characters or longer, this is a no-op. */
336 void
337 ds_rpad (struct string *st, size_t length, char pad) 
338 {
339   assert (st != NULL);
340   if (st->length < length) 
341     {
342       if (st->capacity < length)
343         ds_extend (st, length);
344       memset (&st->string[st->length], pad, length - st->length);
345       st->length = length;
346     }
347 }
348
349 /* Ensures that ST can hold at least MIN_CAPACITY characters plus a null
350    terminator. */
351 void
352 ds_extend (struct string *st, size_t min_capacity)
353 {
354   if (min_capacity > st->capacity)
355     {
356       st->capacity *= 2;
357       if (st->capacity < min_capacity)
358         st->capacity = min_capacity * 2;
359       
360       st->string = xrealloc (st->string, st->capacity + 1);
361     }
362 }
363
364 /* Shrink ST to the minimum capacity need to contain its content. */
365 void
366 ds_shrink (struct string *st)
367 {
368   if (st->capacity != st->length)
369     {
370       st->capacity = st->length;
371       st->string = xrealloc (st->string, st->capacity + 1);
372     }
373 }
374
375 /* Truncates ST to at most LENGTH characters long. */
376 void
377 ds_truncate (struct string *st, size_t length)
378 {
379   if (length >= st->length)
380     return;
381   st->length = length;
382 }
383
384 /* Returns the length of ST. */
385 size_t
386 ds_length (const struct string *st)
387 {
388   return st->length;
389 }
390
391 /* Returns the allocation size of ST. */
392 size_t
393 ds_capacity (const struct string *st)
394 {
395   return st->capacity;
396 }
397
398 /* Returns the value of ST as a null-terminated string. */
399 char *
400 ds_c_str (const struct string *st)
401 {
402   ((char *) st->string)[st->length] = '\0';
403   return st->string;
404 }
405
406 /* Returns the string data inside ST. */
407 char *
408 ds_data (const struct string *st)
409 {
410   return st->string;
411 }
412
413 /* Returns a pointer to the null terminator ST.
414    This might not be an actual null character unless ds_c_str() has
415    been called since the last modification to ST. */
416 char *
417 ds_end (const struct string *st)
418 {
419   return st->string + st->length;
420 }
421
422 /* Concatenates S onto ST. */
423 void
424 ds_puts (struct string *st, const char *s)
425 {
426   size_t s_len;
427
428   if (!s) return;
429
430   s_len = strlen (s);
431   ds_extend (st, st->length + s_len);
432   strcpy (st->string + st->length, s);
433   st->length += s_len;
434 }
435
436 /* Concatenates LEN characters from BUF onto ST. */
437 void
438 ds_concat (struct string *st, const char *buf, size_t len)
439 {
440   ds_extend (st, st->length + len);
441   memcpy (st->string + st->length, buf, len);
442   st->length += len;
443 }
444
445 void ds_vprintf (struct string *st, const char *format, va_list args);
446
447
448 /* Formats FORMAT as a printf string and appends the result to ST. */
449 void
450 ds_printf (struct string *st, const char *format, ...)
451 {
452   va_list args;
453
454   va_start (args, format);
455   ds_vprintf(st,format,args);
456   va_end (args);
457
458 }
459
460 /* Formats FORMAT as a printf string and appends the result to ST. */
461 void
462 ds_vprintf (struct string *st, const char *format, va_list args)
463 {
464   /* Fscking glibc silently changed behavior between 2.0 and 2.1.
465      Fsck fsck fsck.  Before, it returned -1 on buffer overflow.  Now,
466      it returns the number of characters (not bytes) that would have
467      been written. */
468
469   int avail, needed;
470   va_list a1;
471
472   va_copy(a1, args);
473   avail = st->capacity - st->length + 1;
474   needed = vsnprintf (st->string + st->length, avail, format, args);
475
476
477   if (needed >= avail)
478     {
479       ds_extend (st, st->length + needed);
480       
481       vsprintf (st->string + st->length, format, a1);
482     }
483   else
484     while (needed == -1)
485       {
486         va_list a2;
487         va_copy(a2, a1);
488
489         ds_extend (st, (st->capacity + 1) * 2);
490         avail = st->capacity - st->length + 1;
491
492         needed = vsnprintf (st->string + st->length, avail, format, a2);
493         va_end(a2);
494
495       }
496   va_end(a1);
497
498   st->length += needed;
499 }
500
501 /* Appends character CH to ST. */
502 void
503 ds_putc (struct string *st, int ch)
504 {
505   if (st->length == st->capacity)
506     ds_extend (st, st->length + 1);
507   st->string[st->length++] = ch;
508 }
509
510 /* Appends to ST a newline-terminated line read from STREAM.
511    Newline is the last character of ST on return, unless an I/O error
512    or end of file is encountered after reading some characters.
513    Returns 1 if a line is successfully read, or 0 if no characters at
514    all were read before an I/O error or end of file was
515    encountered. */
516 int
517 ds_gets (struct string *st, FILE *stream)
518 {
519   int c;
520
521   c = getc (stream);
522   if (c == EOF)
523     return 0;
524
525   for (;;)
526     {
527       ds_putc (st, c);
528       if (c == '\n')
529         return 1;
530
531       c = getc (stream);
532       if (c == EOF)
533         return 1;
534     }
535 }
536
537 /* Reads a line from STREAM into ST, then preprocesses as follows:
538
539    - Splices lines terminated with `\'.
540
541    - Deletes comments introduced by `#' outside of single or double
542      quotes.
543
544    - Trailing whitespace will be deleted.  
545
546    Increments cust_ln as appropriate.
547
548    Returns nonzero only if a line was successfully read. */
549 int
550 ds_get_config_line (FILE *stream, struct string *st, struct file_locator *where)
551 {
552   /* Read the first line. */
553   ds_clear (st);
554   where->line_number++;
555   if (!ds_gets (st, stream))
556     return 0;
557
558   /* Read additional lines, if any. */
559   for (;;)
560     {
561       /* Remove trailing whitespace. */
562       {
563         char *s = ds_c_str (st);
564         size_t len = ds_length (st);
565       
566         while (len > 0 && isspace ((unsigned char) s[len - 1]))
567           len--;
568         ds_truncate (st, len);
569       }
570
571       /* Check for trailing \.  Remove if found, bail otherwise. */
572       if (ds_length (st) == 0 || ds_c_str (st)[ds_length (st) - 1] != '\\')
573         break;
574       ds_truncate (st, ds_length (st) - 1);
575
576       /* Append another line and go around again. */
577       {
578         int success = ds_gets (st, stream);
579         where->line_number++;
580         if (!success)
581           return 1;
582       }
583     }
584
585   /* Find a comment and remove. */
586   {
587     char *cp;
588     int quote = 0;
589       
590     for (cp = ds_c_str (st); *cp; cp++)
591       if (quote)
592         {
593           if (*cp == quote)
594             quote = 0;
595           else if (*cp == '\\')
596             cp++;
597         }
598       else if (*cp == '\'' || *cp == '"')
599         quote = *cp;
600       else if (*cp == '#')
601         {
602           ds_truncate (st, cp - ds_c_str (st));
603           break;
604         }
605   }
606
607   return 1;
608 }
609 \f
610 /* Lengthed strings. */
611
612 /* Creates a new lengthed string LS with contents as a copy of
613    S. */
614 void
615 ls_create (struct fixed_string *ls, const char *s)
616 {
617   ls->length = strlen (s);
618   ls->string = xmalloc (ls->length + 1);
619   memcpy (ls->string, s, ls->length + 1);
620 }
621
622 /* Creates a new lengthed string LS with contents as a copy of
623    BUFFER with length LEN. */
624 void
625 ls_create_buffer (struct fixed_string *ls,
626                   const char *buffer, size_t len)
627 {
628   ls->length = len;
629   ls->string = xmalloc (len + 1);
630   memcpy (ls->string, buffer, len);
631   ls->string[len] = '\0';
632 }
633
634 /* Sets the fields of LS to the specified values. */
635 void
636 ls_init (struct fixed_string *ls, const char *string, size_t length)
637 {
638   ls->string = (char *) string;
639   ls->length = length;
640 }
641
642 /* Copies the fields of SRC to DST. */
643 void
644 ls_shallow_copy (struct fixed_string *dst, const struct fixed_string *src)
645 {
646   *dst = *src;
647 }
648
649 /* Frees the memory backing LS. */
650 void
651 ls_destroy (struct fixed_string *ls)
652 {
653   free (ls->string);
654 }
655
656 /* Sets LS to a null pointer value. */
657 void
658 ls_null (struct fixed_string *ls)
659 {
660   ls->string = NULL;
661 }
662
663 /* Returns nonzero only if LS has a null pointer value. */
664 int
665 ls_null_p (const struct fixed_string *ls)
666 {
667   return ls->string == NULL;
668 }
669
670 /* Returns nonzero only if LS is a null pointer or has length 0. */
671 int
672 ls_empty_p (const struct fixed_string *ls)
673 {
674   return ls->string == NULL || ls->length == 0;
675 }
676
677 /* Returns the length of LS, which must not be null. */
678 size_t
679 ls_length (const struct fixed_string *ls)
680 {
681   return ls->length;
682 }
683
684 /* Returns a pointer to the character string in LS. */
685 char *
686 ls_c_str (const struct fixed_string *ls)
687 {
688   return (char *) ls->string;
689 }
690
691 /* Returns a pointer to the null terminator of the character string in
692    LS. */
693 char *
694 ls_end (const struct fixed_string *ls)
695 {
696   return (char *) (ls->string + ls->length);
697 }