530d1cecded30897c41c1d1e1f0787a50e0aa99c
[pspp-builds.git] / src / libpspp / str.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000, 2006 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 "message.h"
23 #include <ctype.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include "alloc.h"
27 #include "message.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
274 /* Converts each character in S to lowercase. */
275 void
276 str_lowercase (char *s) 
277 {
278   for (; *s != '\0'; s++)
279     *s = tolower ((unsigned char) *s);
280 }
281 \f
282 /* Initializes ST with initial contents S. */
283 void
284 ds_create (struct string *st, const char *s)
285 {
286   st->length = strlen (s);
287   st->capacity = 8 + st->length * 2;
288   st->string = xmalloc (st->capacity + 1);
289   strcpy (st->string, s);
290 }
291
292 /* Initializes ST, making room for at least CAPACITY characters. */
293 void
294 ds_init (struct string *st, size_t capacity)
295 {
296   st->length = 0;
297   if (capacity > 8)
298     st->capacity = capacity;
299   else
300     st->capacity = 8;
301   st->string = xmalloc (st->capacity + 1);
302 }
303
304 /* Replaces the contents of ST with STRING.  STRING may overlap with
305    ST. */
306 void
307 ds_replace (struct string *st, const char *string)
308 {
309   size_t new_length = strlen (string);
310   if (new_length > st->capacity) 
311     {
312       /* The new length is longer than the allocated length, so
313          there can be no overlap. */
314       st->length = 0;
315       ds_concat (st, string, new_length);
316     }
317   else
318     {
319       /* Overlap is possible, but the new string will fit in the
320          allocated space, so we can just copy data. */
321       st->length = new_length;
322       memmove (st->string, string, st->length);
323     }
324 }
325
326 /* Frees ST. */
327 void
328 ds_destroy (struct string *st)
329 {
330   free (st->string);
331   st->string = NULL;
332 }
333
334 /* Swaps the contents of strings A and B. */
335 void
336 ds_swap (struct string *a, struct string *b) 
337 {
338   struct string tmp = *a;
339   *a = *b;
340   *b = tmp;
341 }
342
343 /* Truncates ST to zero length. */
344 void
345 ds_clear (struct string *st)
346 {
347   st->length = 0;
348 }
349
350 /* Pad ST on the right with copies of PAD until ST is at least
351    LENGTH characters in size.  If ST is initially LENGTH
352    characters or longer, this is a no-op. */
353 void
354 ds_rpad (struct string *st, size_t length, char pad) 
355 {
356   assert (st != NULL);
357   if (st->length < length) 
358     {
359       if (st->capacity < length)
360         ds_extend (st, length);
361       memset (&st->string[st->length], pad, length - st->length);
362       st->length = length;
363     }
364 }
365
366 /* Removes trailing spaces from ST.
367    Returns number of spaces removed. */
368 int
369 ds_rtrim_spaces (struct string *st) 
370 {
371   int cnt = 0;
372   while (isspace (ds_last (st))) 
373     {
374       st->length--;
375       cnt++;
376     }
377   return cnt;
378 }
379
380 /* If the last character in ST is C, removes it and returns true.
381    Otherwise, returns false without modifying ST. */
382 bool
383 ds_chomp (struct string *st, char c_) 
384 {
385   unsigned char c = c_;
386   if (ds_last (st) == c)
387     {
388       st->length--;
389       return true;
390     }
391   else
392     return false;
393 }
394
395 /* Ensures that ST can hold at least MIN_CAPACITY characters plus a null
396    terminator. */
397 void
398 ds_extend (struct string *st, size_t min_capacity)
399 {
400   if (min_capacity > st->capacity)
401     {
402       st->capacity *= 2;
403       if (st->capacity < min_capacity)
404         st->capacity = min_capacity * 2;
405       
406       st->string = xrealloc (st->string, st->capacity + 1);
407     }
408 }
409
410 /* Shrink ST to the minimum capacity need to contain its content. */
411 void
412 ds_shrink (struct string *st)
413 {
414   if (st->capacity != st->length)
415     {
416       st->capacity = st->length;
417       st->string = xrealloc (st->string, st->capacity + 1);
418     }
419 }
420
421 /* Truncates ST to at most LENGTH characters long. */
422 void
423 ds_truncate (struct string *st, size_t length)
424 {
425   if (length >= st->length)
426     return;
427   st->length = length;
428 }
429
430 /* Returns true if ST is empty, false otherwise. */
431 bool
432 ds_is_empty (const struct string *st) 
433 {
434   return st->length == 0;
435 }
436
437 /* Returns the length of ST. */
438 size_t
439 ds_length (const struct string *st)
440 {
441   return st->length;
442 }
443
444 /* Returns the allocation size of ST. */
445 size_t
446 ds_capacity (const struct string *st)
447 {
448   return st->capacity;
449 }
450
451 /* Returns the first character in ST as a value in the range of
452    unsigned char.  Returns EOF if ST is the empty string. */
453 int
454 ds_first (const struct string *st) 
455 {
456   return st->length > 0 ? (unsigned char) st->string[0] : EOF;
457 }
458
459 /* Returns the last character in ST as a value in the range of
460    unsigned char.  Returns EOF if ST is the empty string. */
461 int
462 ds_last (const struct string *st) 
463 {
464   return st->length > 0 ? (unsigned char) st->string[st->length - 1] : EOF;
465 }
466
467 /* Returns the value of ST as a null-terminated string. */
468 char *
469 ds_c_str (const struct string *st)
470 {
471   ((char *) st->string)[st->length] = '\0';
472   return st->string;
473 }
474
475 /* Returns the string data inside ST. */
476 char *
477 ds_data (const struct string *st)
478 {
479   return st->string;
480 }
481
482 /* Returns a pointer to the null terminator ST.
483    This might not be an actual null character unless ds_c_str() has
484    been called since the last modification to ST. */
485 char *
486 ds_end (const struct string *st)
487 {
488   return st->string + st->length;
489 }
490
491 /* Concatenates S onto ST. */
492 void
493 ds_puts (struct string *st, const char *s)
494 {
495   size_t s_len;
496
497   if (!s) return;
498
499   s_len = strlen (s);
500   ds_extend (st, st->length + s_len);
501   strcpy (st->string + st->length, s);
502   st->length += s_len;
503 }
504
505 /* Concatenates LEN characters from BUF onto ST. */
506 void
507 ds_concat (struct string *st, const char *buf, size_t len)
508 {
509   ds_extend (st, st->length + len);
510   memcpy (st->string + st->length, buf, len);
511   st->length += len;
512 }
513
514 void ds_vprintf (struct string *st, const char *format, va_list args);
515
516
517 /* Formats FORMAT as a printf string and appends the result to ST. */
518 void
519 ds_printf (struct string *st, const char *format, ...)
520 {
521   va_list args;
522
523   va_start (args, format);
524   ds_vprintf(st,format,args);
525   va_end (args);
526
527 }
528
529 /* Formats FORMAT as a printf string and appends the result to ST. */
530 void
531 ds_vprintf (struct string *st, const char *format, va_list args)
532 {
533   /* Fscking glibc silently changed behavior between 2.0 and 2.1.
534      Fsck fsck fsck.  Before, it returned -1 on buffer overflow.  Now,
535      it returns the number of characters (not bytes) that would have
536      been written. */
537
538   int avail, needed;
539   va_list a1;
540
541   va_copy(a1, args);
542   avail = st->capacity - st->length + 1;
543   needed = vsnprintf (st->string + st->length, avail, format, args);
544
545
546   if (needed >= avail)
547     {
548       ds_extend (st, st->length + needed);
549       
550       vsprintf (st->string + st->length, format, a1);
551     }
552   else
553     while (needed == -1)
554       {
555         va_list a2;
556         va_copy(a2, a1);
557
558         ds_extend (st, (st->capacity + 1) * 2);
559         avail = st->capacity - st->length + 1;
560
561         needed = vsnprintf (st->string + st->length, avail, format, a2);
562         va_end(a2);
563
564       }
565   va_end(a1);
566
567   st->length += needed;
568 }
569
570 /* Appends character CH to ST. */
571 void
572 ds_putc (struct string *st, int ch)
573 {
574   if (st->length == st->capacity)
575     ds_extend (st, st->length + 1);
576   st->string[st->length++] = ch;
577 }
578
579 /* Appends to ST a newline-terminated line read from STREAM.
580    Newline is the last character of ST on return, unless an I/O error
581    or end of file is encountered after reading some characters.
582    Returns 1 if a line is successfully read, or 0 if no characters at
583    all were read before an I/O error or end of file was
584    encountered. */
585 int
586 ds_gets (struct string *st, FILE *stream)
587 {
588   int c;
589
590   c = getc (stream);
591   if (c == EOF)
592     return 0;
593
594   for (;;)
595     {
596       ds_putc (st, c);
597       if (c == '\n')
598         return 1;
599
600       c = getc (stream);
601       if (c == EOF)
602         return 1;
603     }
604 }
605
606 /* Reads a line from STREAM into ST, then preprocesses as follows:
607
608    - Splices lines terminated with `\'.
609
610    - Deletes comments introduced by `#' outside of single or double
611      quotes.
612
613    - Trailing whitespace will be deleted.  
614
615    Increments cust_ln as appropriate.
616
617    Returns nonzero only if a line was successfully read. */
618 int
619 ds_get_config_line (FILE *stream, struct string *st, struct file_locator *where)
620 {
621   /* Read the first line. */
622   ds_clear (st);
623   where->line_number++;
624   if (!ds_gets (st, stream))
625     return 0;
626
627   /* Read additional lines, if any. */
628   for (;;)
629     {
630       /* Remove trailing whitespace. */
631       {
632         char *s = ds_c_str (st);
633         size_t len = ds_length (st);
634       
635         while (len > 0 && isspace ((unsigned char) s[len - 1]))
636           len--;
637         ds_truncate (st, len);
638       }
639
640       /* Check for trailing \.  Remove if found, bail otherwise. */
641       if (ds_length (st) == 0 || ds_c_str (st)[ds_length (st) - 1] != '\\')
642         break;
643       ds_truncate (st, ds_length (st) - 1);
644
645       /* Append another line and go around again. */
646       {
647         int success = ds_gets (st, stream);
648         where->line_number++;
649         if (!success)
650           return 1;
651       }
652     }
653
654   /* Find a comment and remove. */
655   {
656     char *cp;
657     int quote = 0;
658       
659     for (cp = ds_c_str (st); *cp; cp++)
660       if (quote)
661         {
662           if (*cp == quote)
663             quote = 0;
664           else if (*cp == '\\')
665             cp++;
666         }
667       else if (*cp == '\'' || *cp == '"')
668         quote = *cp;
669       else if (*cp == '#')
670         {
671           ds_truncate (st, cp - ds_c_str (st));
672           break;
673         }
674   }
675
676   return 1;
677 }
678 \f
679 /* Lengthed strings. */
680
681 /* Creates a new lengthed string LS with contents as a copy of
682    S. */
683 void
684 ls_create (struct fixed_string *ls, const char *s)
685 {
686   ls->length = strlen (s);
687   ls->string = xmalloc (ls->length + 1);
688   memcpy (ls->string, s, ls->length + 1);
689 }
690
691 /* Creates a new lengthed string LS with contents as a copy of
692    BUFFER with length LEN. */
693 void
694 ls_create_buffer (struct fixed_string *ls,
695                   const char *buffer, size_t len)
696 {
697   ls->length = len;
698   ls->string = xmalloc (len + 1);
699   memcpy (ls->string, buffer, len);
700   ls->string[len] = '\0';
701 }
702
703 /* Sets the fields of LS to the specified values. */
704 void
705 ls_init (struct fixed_string *ls, const char *string, size_t length)
706 {
707   ls->string = (char *) string;
708   ls->length = length;
709 }
710
711 /* Copies the fields of SRC to DST. */
712 void
713 ls_shallow_copy (struct fixed_string *dst, const struct fixed_string *src)
714 {
715   *dst = *src;
716 }
717
718 /* Frees the memory backing LS. */
719 void
720 ls_destroy (struct fixed_string *ls)
721 {
722   free (ls->string);
723 }
724
725 /* Sets LS to a null pointer value. */
726 void
727 ls_null (struct fixed_string *ls)
728 {
729   ls->string = NULL;
730 }
731
732 /* Returns nonzero only if LS has a null pointer value. */
733 int
734 ls_null_p (const struct fixed_string *ls)
735 {
736   return ls->string == NULL;
737 }
738
739 /* Returns nonzero only if LS is a null pointer or has length 0. */
740 int
741 ls_empty_p (const struct fixed_string *ls)
742 {
743   return ls->string == NULL || ls->length == 0;
744 }
745
746 /* Returns the length of LS, which must not be null. */
747 size_t
748 ls_length (const struct fixed_string *ls)
749 {
750   return ls->length;
751 }
752
753 /* Returns a pointer to the character string in LS. */
754 char *
755 ls_c_str (const struct fixed_string *ls)
756 {
757   return (char *) ls->string;
758 }
759
760 /* Returns a pointer to the null terminator of the character string in
761    LS. */
762 char *
763 ls_end (const struct fixed_string *ls)
764 {
765   return (char *) (ls->string + ls->length);
766 }