Merge from vendor branch LESS:
[dragonfly.git] / contrib / bc / dc / string.c
1 /* 
2  * implement string functions for dc
3  *
4  * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you can either send email to this
18  * program's author (see below) or write to:
19  *
20  *    The Free Software Foundation, Inc.
21  *    59 Temple Place, Suite 330
22  *    Boston, MA 02111 USA
23  */
24
25 /* This should be the only module that knows the internals of type dc_string */
26
27 #include "config.h"
28
29 #include <stdio.h>
30 #ifdef HAVE_STDDEF_H
31 # include <stddef.h>    /* ptrdiff_t */
32 #else
33 # define ptrdiff_t      size_t
34 #endif
35 #ifdef HAVE_STDLIB_H
36 # include <stdlib.h>
37 #endif
38 #ifdef HAVE_STRING_H
39 # include <string.h>    /* memcpy */
40 #else
41 # ifdef HAVE_MEMORY_H
42 #  include <memory.h>   /* memcpy, maybe */
43 # else
44 #  ifdef HAVE_STRINGS_H
45 #   include <strings.h> /* memcpy, maybe */
46 #  endif
47 # endif
48 #endif
49 #include "dc.h"
50 #include "dc-proto.h"
51
52 /* here is the completion of the dc_string type: */
53 struct dc_string {
54         char *s_ptr;  /* pointer to base of string */
55         size_t s_len; /* length of counted string */
56         int  s_refs;  /* reference count to cut down on memory use by duplicates */
57 };
58
59 \f
60 /* return a duplicate of the string in the passed value */
61 /* The mismatched data types forces the caller to deal with
62  * bad dc_type'd dc_data values, and makes it more convenient
63  * for the caller to not have to do the grunge work of setting
64  * up a dc_type result.
65  */
66 dc_data
67 dc_dup_str DC_DECLARG((value))
68         dc_str value DC_DECLEND
69 {
70         dc_data result;
71
72         ++value->s_refs;
73         result.v.string = value;
74         result.dc_type = DC_STRING;
75         return result;
76 }
77
78 /* free an instance of a dc_str value */
79 void
80 dc_free_str DC_DECLARG((value))
81         dc_str *value DC_DECLEND
82 {
83         struct dc_string *string = *value;
84
85         if (--string->s_refs < 1){
86                 free(string->s_ptr);
87                 free(string);
88         }
89 }
90
91 /* Output a dc_str value.
92  * Add a trailing newline if "newline" is set.
93  * Free the value after use if discard_flag is set.
94  */
95 void
96 dc_out_str DC_DECLARG((value, newline, discard_flag))
97         dc_str value DC_DECLSEP
98         dc_newline newline DC_DECLSEP
99         dc_discard discard_flag DC_DECLEND
100 {
101         fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout);
102         if (newline == DC_WITHNL)
103                 putchar('\n');
104         if (discard_flag == DC_TOSS)
105                 dc_free_str(&value);
106 }
107
108 /* make a copy of a string (base s, length len)
109  * into a dc_str value; return a dc_data result
110  * with this value
111  */
112 dc_data
113 dc_makestring DC_DECLARG((s, len))
114         const char *s DC_DECLSEP
115         size_t len DC_DECLEND
116 {
117         dc_data result;
118         struct dc_string *string;
119
120         string = dc_malloc(sizeof *string);
121         string->s_ptr = dc_malloc(len+1);
122         memcpy(string->s_ptr, s, len);
123         string->s_ptr[len] = '\0';      /* nul terminated for those who need it */
124         string->s_len = len;
125         string->s_refs = 1;
126         result.v.string = string;
127         result.dc_type = DC_STRING;
128         return result;
129 }
130
131 /* read a dc_str value from FILE *fp;
132  * if ldelim == rdelim, then read until a ldelim char or EOF is reached;
133  * if ldelim != rdelim, then read until a matching rdelim for the
134  * (already eaten) first ldelim is read.
135  * Return a dc_data result with the dc_str value as its contents.
136  */
137 dc_data
138 dc_readstring DC_DECLARG((fp, ldelim, rdelim))
139         FILE *fp DC_DECLSEP
140         int ldelim DC_DECLSEP
141         int rdelim DC_DECLEND
142 {
143         static char *line_buf = NULL;   /* a buffer to build the string in */ 
144         static size_t buflen = 0;               /* the current size of line_buf */
145         int depth=1;
146         int c;
147         char *p;
148         const char *end;
149
150         if (!line_buf){
151                 /* initial buflen should be large enough to handle most cases */
152                 buflen = 2016;
153                 line_buf = dc_malloc(buflen);
154         }
155         p = line_buf;
156         end = line_buf + buflen;
157         for (;;){
158                 c = getc(fp);
159                 if (c == EOF)
160                         break;
161                 else if (c == rdelim && --depth < 1)
162                         break;
163                 else if (c == ldelim)
164                         ++depth;
165                 if (p >= end){
166                         ptrdiff_t offset = p - line_buf;
167                         /* buflen increment should be big enough
168                          * to avoid execessive reallocs:
169                          */
170                         buflen += 2048;
171                         line_buf = realloc(line_buf, buflen);
172                         if (!line_buf)
173                                 dc_memfail();
174                         p = line_buf + offset;
175                         end = line_buf + buflen;
176                 }
177                 *p++ = c;
178         }
179         return dc_makestring(line_buf, (size_t)(p-line_buf));
180 }
181
182 /* return the base pointer of the dc_str value;
183  * This function is needed because no one else knows what dc_str
184  * looks like.
185  */
186 const char *
187 dc_str2charp DC_DECLARG((value))
188         dc_str value DC_DECLEND
189 {
190         return value->s_ptr;
191 }
192
193 /* return the length of the dc_str value;
194  * This function is needed because no one else knows what dc_str
195  * looks like, and strlen(dc_str2charp(value)) won't work
196  * if there's an embedded '\0'.
197  */
198 size_t
199 dc_strlen DC_DECLARG((value))
200         dc_str value DC_DECLEND
201 {
202         return value->s_len;
203 }
204
205 \f
206 /* initialize the strings subsystem */
207 void
208 dc_string_init DC_DECLVOID()
209 {
210         /* nothing to do for this implementation */
211 }