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