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: */ 53struct 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 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 */ 66dc_data 67dc_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 */ 79void 80dc_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 */ 95void 96dc_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 */ 112dc_data 113dc_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 */ 137dc_data 138dc_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 */ 186const char * 187dc_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 */ 198size_t 199dc_strlen DC_DECLARG((value)) 200 dc_str value DC_DECLEND 201{ 202 return value->s_len; 203} 204 205 206/* initialize the strings subsystem */ 207void 208dc_string_init DC_DECLVOID() 209{ 210 /* nothing to do for this implementation */ 211} 212