Add new g_string functions for reading from file/socket descriptors, and
[platform/upstream/glib.git] / gstring.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Portions Copyright (C) 1999 Tony Gale
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
23  * file for a list of people on the GLib Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 /* 
29  * MT safe
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include "glib.h"
45
46 #define G_STRING_BLOCK_SIZE 512
47
48 typedef struct _GRealStringChunk GRealStringChunk;
49 typedef struct _GRealString      GRealString;
50
51 struct _GRealStringChunk
52 {
53   GHashTable *const_table;
54   GSList     *storage_list;
55   gint        storage_next;
56   gint        this_size;
57   gint        default_size;
58 };
59
60 struct _GRealString
61 {
62   gchar *str;
63   gint   len;
64   gint   alloc;
65 };
66
67 G_LOCK_DEFINE_STATIC (string_mem_chunk);
68 static GMemChunk *string_mem_chunk = NULL;
69
70 /* Hash Functions.
71  */
72
73 gint
74 g_str_equal (gconstpointer v, gconstpointer v2)
75 {
76   return strcmp ((const gchar*) v, (const gchar*)v2) == 0;
77 }
78
79 /* a char* hash function from ASU */
80 guint
81 g_str_hash (gconstpointer v)
82 {
83   const char *s = (char*)v;
84   const char *p;
85   guint h=0, g;
86
87   for(p = s; *p != '\0'; p += 1) {
88     h = ( h << 4 ) + *p;
89     if ( ( g = h & 0xf0000000 ) ) {
90       h = h ^ (g >> 24);
91       h = h ^ g;
92     }
93   }
94
95   return h /* % M */;
96 }
97
98
99 /* String Chunks.
100  */
101
102 GStringChunk*
103 g_string_chunk_new (gint default_size)
104 {
105   GRealStringChunk *new_chunk = g_new (GRealStringChunk, 1);
106   gint size = 1;
107
108   while (size < default_size)
109     size <<= 1;
110
111   new_chunk->const_table       = NULL;
112   new_chunk->storage_list      = NULL;
113   new_chunk->storage_next      = size;
114   new_chunk->default_size      = size;
115   new_chunk->this_size         = size;
116
117   return (GStringChunk*) new_chunk;
118 }
119
120 void
121 g_string_chunk_free (GStringChunk *fchunk)
122 {
123   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
124   GSList *tmp_list;
125
126   g_return_if_fail (chunk != NULL);
127
128   if (chunk->storage_list)
129     {
130       for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
131         g_free (tmp_list->data);
132
133       g_slist_free (chunk->storage_list);
134     }
135
136   if (chunk->const_table)
137     g_hash_table_destroy (chunk->const_table);
138
139   g_free (chunk);
140 }
141
142 gchar*
143 g_string_chunk_insert (GStringChunk *fchunk,
144                        const gchar  *string)
145 {
146   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
147   gint len = strlen (string);
148   char* pos;
149
150   g_return_val_if_fail (chunk != NULL, NULL);
151
152   if ((chunk->storage_next + len + 1) > chunk->this_size)
153     {
154       gint new_size = chunk->default_size;
155
156       while (new_size < len+1)
157         new_size <<= 1;
158
159       chunk->storage_list = g_slist_prepend (chunk->storage_list,
160                                              g_new (char, new_size));
161
162       chunk->this_size = new_size;
163       chunk->storage_next = 0;
164     }
165
166   pos = ((char*)chunk->storage_list->data) + chunk->storage_next;
167
168   strcpy (pos, string);
169
170   chunk->storage_next += len + 1;
171
172   return pos;
173 }
174
175 gchar*
176 g_string_chunk_insert_const (GStringChunk *fchunk,
177                              const gchar  *string)
178 {
179   GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
180   char* lookup;
181
182   g_return_val_if_fail (chunk != NULL, NULL);
183
184   if (!chunk->const_table)
185     chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
186
187   lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
188
189   if (!lookup)
190     {
191       lookup = g_string_chunk_insert (fchunk, string);
192       g_hash_table_insert (chunk->const_table, lookup, lookup);
193     }
194
195   return lookup;
196 }
197
198 /* Strings.
199  */
200 static gint
201 nearest_power (gint num)
202 {
203   gint n = 1;
204
205   while (n < num)
206     n <<= 1;
207
208   return n;
209 }
210
211 static gint
212 nearest_multiple (int num, const int block)
213 {
214   gint n = block;
215
216   while (n < num)
217     n += block;
218
219   return n;
220 }
221
222 static void
223 g_string_maybe_expand (GRealString* string, gint len)
224 {
225   if (string->len + len >= string->alloc)
226     {
227       string->alloc = nearest_power (string->len + len + 1);
228       string->str = g_realloc (string->str, string->alloc);
229     }
230 }
231
232 static void
233 g_string_set_size (GRealString* string, gint size)
234 {
235   if (string->alloc <= size) {
236     string->alloc = nearest_power(size + 1);
237     string->str = g_realloc (string->str, string->alloc);
238   }
239 }
240
241 GString*
242 g_string_sized_new (guint dfl_size)
243 {
244   GRealString *string;
245
246   G_LOCK (string_mem_chunk);
247   if (!string_mem_chunk)
248     string_mem_chunk = g_mem_chunk_new ("string mem chunk",
249                                         sizeof (GRealString),
250                                         1024, G_ALLOC_AND_FREE);
251
252   string = g_chunk_new (GRealString, string_mem_chunk);
253   G_UNLOCK (string_mem_chunk);
254
255   string->alloc = 0;
256   string->len   = 0;
257   string->str   = NULL;
258
259   g_string_maybe_expand (string, MAX (dfl_size, 2));
260   string->str[0] = 0;
261
262   return (GString*) string;
263 }
264
265 GString*
266 g_string_new (const gchar *init)
267 {
268   GString *string;
269
270   string = g_string_sized_new (2);
271
272   if (init)
273     g_string_append (string, init);
274
275   return string;
276 }
277
278 void
279 g_string_free (GString *string,
280                gint free_segment)
281 {
282   g_return_if_fail (string != NULL);
283
284   if (free_segment)
285     g_free (string->str);
286
287   G_LOCK (string_mem_chunk);
288   g_mem_chunk_free (string_mem_chunk, string);
289   G_UNLOCK (string_mem_chunk);
290 }
291
292 GString*
293 g_string_assign (GString *lval,
294                  const gchar *rval)
295 {
296   g_string_truncate (lval, 0);
297   g_string_append (lval, rval);
298
299   return lval;
300 }
301
302 GString*
303 g_string_truncate (GString* fstring,
304                    gint len)
305 {
306   GRealString *string = (GRealString*)fstring;
307
308   g_return_val_if_fail (string != NULL, NULL);
309
310   string->len = len;
311
312   string->str[len] = 0;
313
314   return fstring;
315 }
316
317 GString*
318 g_string_append (GString *fstring,
319                  const gchar *val)
320 {
321   GRealString *string = (GRealString*)fstring;
322   int len;
323
324   g_return_val_if_fail (string != NULL, NULL);
325   g_return_val_if_fail (val != NULL, fstring);
326   
327   len = strlen (val);
328   g_string_maybe_expand (string, len);
329
330   strcpy (string->str + string->len, val);
331
332   string->len += len;
333
334   return fstring;
335 }
336
337 GString*
338 g_string_append_c (GString *fstring,
339                    gchar c)
340 {
341   GRealString *string = (GRealString*)fstring;
342
343   g_return_val_if_fail (string != NULL, NULL);
344   g_string_maybe_expand (string, 1);
345
346   string->str[string->len++] = c;
347   string->str[string->len] = 0;
348
349   return fstring;
350 }
351
352 GString*
353 g_string_prepend (GString *fstring,
354                   const gchar *val)
355 {
356   GRealString *string = (GRealString*)fstring;
357   gint len;
358
359   g_return_val_if_fail (string != NULL, NULL);
360   g_return_val_if_fail (val != NULL, fstring);
361
362   len = strlen (val);
363   g_string_maybe_expand (string, len);
364
365   g_memmove (string->str + len, string->str, string->len);
366
367   strncpy (string->str, val, len);
368
369   string->len += len;
370
371   string->str[string->len] = 0;
372
373   return fstring;
374 }
375
376 GString*
377 g_string_prepend_c (GString *fstring,
378                     gchar    c)
379 {
380   GRealString *string = (GRealString*)fstring;
381
382   g_return_val_if_fail (string != NULL, NULL);
383   g_string_maybe_expand (string, 1);
384
385   g_memmove (string->str + 1, string->str, string->len);
386
387   string->str[0] = c;
388
389   string->len += 1;
390
391   string->str[string->len] = 0;
392
393   return fstring;
394 }
395
396 GString*
397 g_string_insert (GString     *fstring,
398                  gint         pos,
399                  const gchar *val)
400 {
401   GRealString *string = (GRealString*)fstring;
402   gint len;
403
404   g_return_val_if_fail (string != NULL, NULL);
405   g_return_val_if_fail (val != NULL, fstring);
406   g_return_val_if_fail (pos >= 0, fstring);
407   g_return_val_if_fail (pos <= string->len, fstring);
408
409   len = strlen (val);
410   g_string_maybe_expand (string, len);
411
412   g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
413
414   strncpy (string->str + pos, val, len);
415
416   string->len += len;
417
418   string->str[string->len] = 0;
419
420   return fstring;
421 }
422
423 GString *
424 g_string_insert_c (GString *fstring,
425                    gint     pos,
426                    gchar    c)
427 {
428   GRealString *string = (GRealString*)fstring;
429
430   g_return_val_if_fail (string != NULL, NULL);
431   g_return_val_if_fail (pos <= string->len, fstring);
432
433   g_string_maybe_expand (string, 1);
434
435   g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
436
437   string->str[pos] = c;
438
439   string->len += 1;
440
441   string->str[string->len] = 0;
442
443   return fstring;
444 }
445
446 GString*
447 g_string_erase (GString *fstring,
448                 gint pos,
449                 gint len)
450 {
451   GRealString *string = (GRealString*)fstring;
452
453   g_return_val_if_fail (string != NULL, NULL);
454   g_return_val_if_fail (len >= 0, fstring);
455   g_return_val_if_fail (pos >= 0, fstring);
456   g_return_val_if_fail (pos <= string->len, fstring);
457   g_return_val_if_fail (pos + len <= string->len, fstring);
458
459   if (pos + len < string->len)
460     g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
461
462   string->len -= len;
463   
464   string->str[string->len] = 0;
465
466   return fstring;
467 }
468
469 GString*
470 g_string_down (GString *fstring)
471 {
472   GRealString *string = (GRealString*)fstring;
473   gchar *s;
474
475   g_return_val_if_fail (string != NULL, NULL);
476
477   s = string->str;
478
479   while (*s)
480     {
481       *s = tolower (*s);
482       s++;
483     }
484
485   return fstring;
486 }
487
488 GString*
489 g_string_up (GString *fstring)
490 {
491   GRealString *string = (GRealString*)fstring;
492   gchar *s;
493
494   g_return_val_if_fail (string != NULL, NULL);
495
496   s = string->str;
497
498   while (*s)
499     {
500       *s = toupper (*s);
501       s++;
502     }
503
504   return fstring;
505 }
506
507 static void
508 g_string_sprintfa_int (GString     *string,
509                        const gchar *fmt,
510                        va_list      args)
511 {
512   gchar *buffer;
513
514   buffer = g_strdup_vprintf (fmt, args);
515   g_string_append (string, buffer);
516   g_free (buffer);
517 }
518
519 void
520 g_string_sprintf (GString *string,
521                   const gchar *fmt,
522                   ...)
523 {
524   va_list args;
525
526   g_string_truncate (string, 0);
527
528   va_start (args, fmt);
529   g_string_sprintfa_int (string, fmt, args);
530   va_end (args);
531 }
532
533 void
534 g_string_sprintfa (GString *string,
535                    const gchar *fmt,
536                    ...)
537 {
538   va_list args;
539
540   va_start (args, fmt);
541   g_string_sprintfa_int (string, fmt, args);
542   va_end (args);
543 }
544
545 GStringError
546 g_string_readline (GString *dest_str,
547                    gint     max_length,
548                    gint     fd)
549 {
550   gint count=0, retval;
551   gchar c;
552
553   g_return_val_if_fail (dest_str != NULL, G_STRING_ERROR_INVAL);
554   g_return_val_if_fail (max_length > 0, G_STRING_ERROR_INVAL);
555   g_string_truncate(dest_str, 0);
556
557   for (count = 0; count < max_length; count++) {
558     if ( (retval = read(fd, &c, 1)) == 1 ) {
559       if (c == '\r') {
560         continue;
561       }
562       if (c == '\n') {
563         return(G_STRING_ERROR_NONE);
564       }
565       g_string_maybe_expand ((GRealString *) dest_str, 1);
566       dest_str->str[dest_str->len++] = c;
567       dest_str->str[dest_str->len] = 0;
568     } else if (retval == 0) {
569         return(G_STRING_ERROR_NODATA);
570     } else {
571       return(G_STRING_ERROR_READ);
572     }
573   }
574   return(G_STRING_ERROR_LENGTH);
575 }
576
577 GStringError
578 g_string_readline_buffered (GString *dest_str,
579                             GString *buff_str,
580                             gint     max_length,
581                             gint     fd,
582                             gint     match_bare_cr)
583 {
584   guint count, i=0, buff_size;
585
586   g_return_val_if_fail (dest_str != NULL, G_STRING_ERROR_INVAL);
587   g_return_val_if_fail (buff_str != NULL, G_STRING_ERROR_INVAL);
588   g_return_val_if_fail (max_length > 0, G_STRING_ERROR_INVAL);
589
590   /* Make the buffer a multiple of G_STRING_BLOCK_SIZE and
591    * bigger then max_length */
592   buff_size = nearest_multiple(max_length, G_STRING_BLOCK_SIZE);
593   g_string_set_size( (GRealString *) buff_str, buff_size);
594
595   do {
596     /* Allow the buffer to empty before reading more data.
597      * Prevents blocking on read() when data in the buffer */
598
599     if (buff_str->len != 0) {
600       /* Search for a CRLF, CR or LF */
601       for (i = 0; i < max_length-1; i++) {
602
603         /* Look for a CR */
604         if (buff_str->str[i] == '\r') {
605
606           /* Check for CRLF */
607           if (buff_str->str[i+1] == '\n') {
608             buff_str->str[i] = '\0';
609             i++;
610           } else if (match_bare_cr) {
611             buff_str->str[i] = '\0';
612           } else {
613             continue;
614           }
615
616           /* Copy the line to the destination string and
617            * remove it from the buffer */
618           g_string_assign( dest_str, buff_str->str );
619           g_string_erase( buff_str, 0, i+1);
620           return (G_STRING_ERROR_NONE);
621         }
622
623         /* Look for LF */
624         if (buff_str->str[i] == '\n') {
625           buff_str->str[i] = '\0';
626
627           /* Copy the line to the destination string and
628            * remove it from the buffer */
629           g_string_assign( dest_str, buff_str->str );
630           g_string_erase( buff_str, 0, i+1);
631           return (G_STRING_ERROR_NONE);      
632         }
633
634         /* If we hit a '\0' then we've exhausted the buffer */
635         if (buff_str->str[i] == '\0') {
636           break;
637         }
638       }
639     }
640
641     /* Read in a block of data, appending it to the buffer */
642     if ( (count = read(fd, buff_str->str + buff_str->len,
643                        buff_size - buff_str->len - 1)) < 0) {
644       return (G_STRING_ERROR_READ);
645     } else if (count == 0) {
646       return (G_STRING_ERROR_NODATA);
647     } else {
648       /* Fix up the buffer */
649       buff_str->len += count;
650       buff_str->str[buff_str->len] = '\0';
651     }
652
653   } while (i != max_length-1);
654
655   /* If we get here then we have reached max_length */
656   g_string_assign (dest_str, buff_str->str);
657   g_string_truncate (dest_str, max_length-1);
658   g_string_erase (buff_str, 0, max_length-1);
659
660   return (G_STRING_ERROR_LENGTH);
661 }
662
663 GList*
664 g_string_tokenise (GString *string,
665                    gchar   *delims,
666                    gint     max_tokens,
667                    gint     allow_empty)
668 {
669   GList *tokens=NULL;
670   GString *token;
671   gchar *current, *start, c;
672   guint count=1;
673
674   g_return_val_if_fail (string != NULL, NULL);
675   g_return_val_if_fail (delims != NULL, NULL);
676
677   if (max_tokens < 1) {
678     max_tokens = G_MAXINT;
679   }
680
681   current = string->str;
682   while (*current) {
683     /* Remove any leading delimiters */
684     if (!allow_empty) {
685       while ( *current && (strchr(delims, *current) != NULL) ) {
686         current++;
687       }
688     }
689
690     /* If we've reached max_tokens, use the remaining input string
691      * as the last token */
692     if (count == max_tokens) {
693       token = g_string_new(current);
694       tokens = g_list_append(tokens, token);
695       return (tokens);
696     }
697
698     /* Find the extent of the current token */
699     if ( *current ) {
700       start = current;
701       while ( *current && (strchr(delims, *current) == NULL) ) {
702         current++;
703       }
704       c = *current;
705       *current = '\0';
706       token = g_string_new( start );
707       *current = c;
708       tokens = g_list_append(tokens, token);
709       count++;
710       if (*current) {
711         current++;
712       }
713     }
714   }
715
716   return (tokens);
717 }
718
719 void
720 g_string_tokenise_free (GList *tokens,
721                         gint   free_token)
722 {
723
724   if (free_token) {
725     while(tokens) {
726       g_string_free( (GString *) tokens->data, TRUE );
727       tokens = g_list_next(tokens);
728     }
729   }
730
731   g_list_free(tokens);
732 }