Blame dc/string.c

Packit 70b277
/* 
Packit 70b277
 * implement string functions for dc
Packit 70b277
 *
Packit 70b277
 * Copyright (C) 1994, 1997, 1998, 2006, 2008, 2013
Packit 70b277
 * Free Software Foundation, Inc.
Packit 70b277
 *
Packit 70b277
 * This program is free software; you can redistribute it and/or modify
Packit 70b277
 * it under the terms of the GNU General Public License as published by
Packit 70b277
 * the Free Software Foundation; either version 3, or (at your option)
Packit 70b277
 * any later version.
Packit 70b277
 *
Packit 70b277
 * This program is distributed in the hope that it will be useful,
Packit 70b277
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 70b277
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 70b277
 * GNU General Public License for more details.
Packit 70b277
 *
Packit 70b277
 * You should have received a copy of the GNU General Public License
Packit 70b277
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 70b277
 *
Packit 70b277
 */
Packit 70b277
Packit 70b277
/* This should be the only module that knows the internals of type dc_string */
Packit 70b277
Packit 70b277
#include "config.h"
Packit 70b277
Packit 70b277
#include <stdio.h>
Packit 70b277
#ifdef HAVE_STDDEF_H
Packit 70b277
# include <stddef.h>	/* ptrdiff_t */
Packit 70b277
#else
Packit 70b277
# define ptrdiff_t	size_t
Packit 70b277
#endif
Packit 70b277
#ifdef HAVE_STDLIB_H
Packit 70b277
# include <stdlib.h>
Packit 70b277
#endif
Packit 70b277
#ifdef HAVE_STRING_H
Packit 70b277
# include <string.h>	/* memcpy */
Packit 70b277
#else
Packit 70b277
# ifdef HAVE_MEMORY_H
Packit 70b277
#  include <memory.h>	/* memcpy, maybe */
Packit 70b277
# else
Packit 70b277
#  ifdef HAVE_STRINGS_H
Packit 70b277
#   include <strings.h>	/* memcpy, maybe */
Packit 70b277
#  endif
Packit 70b277
# endif
Packit 70b277
#endif
Packit 70b277
#include "dc.h"
Packit 70b277
#include "dc-proto.h"
Packit 70b277
Packit 70b277
/* here is the completion of the dc_string type: */
Packit 70b277
struct dc_string {
Packit 70b277
	char *s_ptr;  /* pointer to base of string */
Packit 70b277
	size_t s_len; /* length of counted string */
Packit 70b277
	int  s_refs;  /* reference count to cut down on memory use by duplicates */
Packit 70b277
};
Packit 70b277
Packit 70b277

Packit 70b277
/* return a duplicate of the string in the passed value */
Packit 70b277
/* The mismatched data types forces the caller to deal with
Packit 70b277
 * bad dc_type'd dc_data values, and makes it more convenient
Packit 70b277
 * for the caller to not have to do the grunge work of setting
Packit 70b277
 * up a dc_type result.
Packit 70b277
 */
Packit 70b277
dc_data
Packit 70b277
dc_dup_str DC_DECLARG((value))
Packit 70b277
	dc_str value DC_DECLEND
Packit 70b277
{
Packit 70b277
	dc_data result;
Packit 70b277
Packit 70b277
	++value->s_refs;
Packit 70b277
	result.v.string = value;
Packit 70b277
	result.dc_type = DC_STRING;
Packit 70b277
	return result;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* free an instance of a dc_str value */
Packit 70b277
void
Packit 70b277
dc_free_str DC_DECLARG((value))
Packit 70b277
	dc_str *value DC_DECLEND
Packit 70b277
{
Packit 70b277
	struct dc_string *string = *value;
Packit 70b277
Packit 70b277
	if (--string->s_refs < 1){
Packit 70b277
		free(string->s_ptr);
Packit 70b277
		free(string);
Packit 70b277
	}
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Output a dc_str value.
Packit 70b277
 * Free the value after use if discard_flag is set.
Packit 70b277
 */
Packit 70b277
void
Packit 70b277
dc_out_str DC_DECLARG((value, discard_flag))
Packit 70b277
	dc_str value DC_DECLSEP
Packit 70b277
	dc_discard discard_flag DC_DECLEND
Packit 70b277
{
Packit 70b277
	fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout);
Packit 70b277
	if (discard_flag == DC_TOSS)
Packit 70b277
		dc_free_str(&value);
Packit 70b277
}
Packit 70b277
Packit 70b277
/* make a copy of a string (base s, length len)
Packit 70b277
 * into a dc_str value; return a dc_data result
Packit 70b277
 * with this value
Packit 70b277
 */
Packit 70b277
dc_data
Packit 70b277
dc_makestring DC_DECLARG((s, len))
Packit 70b277
	const char *s DC_DECLSEP
Packit 70b277
	size_t len DC_DECLEND
Packit 70b277
{
Packit 70b277
	dc_data result;
Packit 70b277
	struct dc_string *string;
Packit 70b277
Packit 70b277
	string = dc_malloc(sizeof *string);
Packit 70b277
	string->s_ptr = dc_malloc(len+1);
Packit 70b277
	memcpy(string->s_ptr, s, len);
Packit 70b277
	string->s_ptr[len] = '\0';	/* nul terminated for those who need it */
Packit 70b277
	string->s_len = len;
Packit 70b277
	string->s_refs = 1;
Packit 70b277
	result.v.string = string;
Packit 70b277
	result.dc_type = DC_STRING;
Packit 70b277
	return result;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* read a dc_str value from FILE *fp;
Packit 70b277
 * if ldelim == rdelim, then read until a ldelim char or EOF is reached;
Packit 70b277
 * if ldelim != rdelim, then read until a matching rdelim for the
Packit 70b277
 * (already eaten) first ldelim is read.
Packit 70b277
 * Return a dc_data result with the dc_str value as its contents.
Packit 70b277
 */
Packit 70b277
dc_data
Packit 70b277
dc_readstring DC_DECLARG((fp, ldelim, rdelim))
Packit 70b277
	FILE *fp DC_DECLSEP
Packit 70b277
	int ldelim DC_DECLSEP
Packit 70b277
	int rdelim DC_DECLEND
Packit 70b277
{
Packit 70b277
	static char *line_buf = NULL;	/* a buffer to build the string in */ 
Packit 70b277
	static size_t buflen = 0;		/* the current size of line_buf */
Packit 70b277
	int depth=1;
Packit 70b277
	int c;
Packit 70b277
	char *p;
Packit 70b277
	const char *end;
Packit 70b277
Packit 70b277
	if (line_buf == NULL){
Packit 70b277
		/* initial buflen should be large enough to handle most cases */
Packit 70b277
		buflen = (size_t) 2016;
Packit 70b277
		line_buf = dc_malloc(buflen);
Packit 70b277
	}
Packit 70b277
	p = line_buf;
Packit 70b277
	end = line_buf + buflen;
Packit 70b277
	for (;;){
Packit 70b277
		c = getc(fp);
Packit 70b277
		if (c == EOF)
Packit 70b277
			break;
Packit 70b277
		else if (c == rdelim && --depth < 1)
Packit 70b277
			break;
Packit 70b277
		else if (c == ldelim)
Packit 70b277
			++depth;
Packit 70b277
		if (p >= end){
Packit 70b277
			ptrdiff_t offset = p - line_buf;
Packit 70b277
			/* buflen increment should be big enough
Packit 70b277
			 * to avoid execessive reallocs:
Packit 70b277
			 */
Packit 70b277
			buflen += 2048;
Packit 70b277
			line_buf = realloc(line_buf, buflen);
Packit 70b277
			if (line_buf == NULL)
Packit 70b277
				dc_memfail();
Packit 70b277
			p = line_buf + offset;
Packit 70b277
			end = line_buf + buflen;
Packit 70b277
		}
Packit 70b277
		*p++ = c;
Packit 70b277
	}
Packit 70b277
	return dc_makestring(line_buf, (size_t)(p-line_buf));
Packit 70b277
}
Packit 70b277
Packit 70b277
/* return the base pointer of the dc_str value;
Packit 70b277
 * This function is needed because no one else knows what dc_str
Packit 70b277
 * looks like.
Packit 70b277
 */
Packit 70b277
const char *
Packit 70b277
dc_str2charp DC_DECLARG((value))
Packit 70b277
	dc_str value DC_DECLEND
Packit 70b277
{
Packit 70b277
	return value->s_ptr;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* return the length of the dc_str value;
Packit 70b277
 * This function is needed because no one else knows what dc_str
Packit 70b277
 * looks like, and strlen(dc_str2charp(value)) won't work
Packit 70b277
 * if there's an embedded '\0'.
Packit 70b277
 */
Packit 70b277
size_t
Packit 70b277
dc_strlen DC_DECLARG((value))
Packit 70b277
	dc_str value DC_DECLEND
Packit 70b277
{
Packit 70b277
	return value->s_len;
Packit 70b277
}
Packit 70b277
Packit 70b277

Packit 70b277
/* initialize the strings subsystem */
Packit 70b277
void
Packit 70b277
dc_string_init DC_DECLVOID()
Packit 70b277
{
Packit 70b277
	/* nothing to do for this implementation */
Packit 70b277
}
Packit 70b277
Packit 70b277

Packit 70b277
/*
Packit 70b277
 * Local Variables:
Packit 70b277
 * mode: C
Packit 70b277
 * tab-width: 4
Packit 70b277
 * End:
Packit 70b277
 * vi: set ts=4 :
Packit 70b277
 */