/* %Z%%M% %I% %E% */

/*
 * Copyright (c) 1990-2009 by Wayne C. Gramlich.
 * All rights reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * for any purpose is hereby granted without fee provided that the above
 * copyright notice and this permission are retained.  The author makes
 * no representations about the suitability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 */

/* A number of routines that really belong in /usr/include/string.h: */

#ifndef HEAP_EXPORTS_H
#include "heap_exports.h"
#endif

#ifndef STR_EXPORTS_H
#include "str_exports.h"
#endif

#ifndef UNIX_ASSERT_H
#include "unix_assert.h"
#endif

#ifndef UNIX_STDIO_H
#include "unix_stdio.h"
#endif

#ifndef UNIX_STDARG_H
#include "unix_stdarg.h"
#endif

/* LINTLIBRARY */

/*
 * strdupl(str, heap)
 *	This routine will return a coopy of "str" allocated from "heap".
 */
Str
strdupl(
	Str		str,
	Heap		heap)
{
	Str		new;

	new = (Str)heap_alloc(heap, strlen(str) + 1);
	(void)strcpy(new, str);
	return new;
}

/*
 * strequal(str1, str1)
 *	This routien will return 1 if "str1" equals "str2" and 0 otherwise.
 */
int
strequal(
	Str		str1,
	Str		str2)
{
	return (strcmp(str1, str2) == 0);
}

/*
 * strhash(str)
 *	This routine will return a hash value for "str".
 */
int
strhash(
	Str		str)
{
	int		chr;
	int		hash;

	hash = 0;
	while ((chr = *str++) != '\0') {
		hash += chr;
	}
	return hash;
}

/*
 * strprintf(heap, format, arg1, ...)
 *	This routine will write each of the arguments into a string using
 *	"format" and return the resulting string allocated from "heap".
 */
Str
strprintf(
	Heap		heap,
	Str		format,
	...)
{
	va_list		args;
	static char	*buffer = (char *)0;
	static unsigned	buffer_size = 0;
	int		size;
	Str		str;
	char		*ptr;

	/* Figure out the string length: */
	va_start(args, format);
	size = strlen(format) + 1;
	for (ptr = strchr(format, '%');
	     ptr != (char *)0; ptr = strchr(ptr, '%')) {
		ptr++;
		if (ptr[0] != '%') {
			ptr += strspn(ptr, "0123456789.l");
			if (ptr[0] == 's') {
				/* String: */
				size += strlen(va_arg(args, char *));
			} else {
				/* Number or character: */
				va_arg(args, int);
				size += 10;
			}
		}
	}
	va_end(args);

	/* Ensure that buffer is large enough: */
	if (size > buffer_size) {
		if (buffer_size == 0) {
			buffer = malloc(size);
		} else {
			buffer = realloc(buffer, size);
		}
		assert(buffer != (char *)0);
		buffer_size = size;
	}

	/* Allocate and fill the string: */
	va_start(args, format);
	str = (Str)heap_alloc(heap, size + 1);
	(void)vsprintf(str, format, args);
	va_end(args);

	return str;
}

/*
 * strread(in_file, heap)
 *	This routine will return a string read from "in_file" and allocated
 *	from "heap".
 */
/* VARARGS2 */
Str
strread(
	Stdio		in_file,
	Heap		heap)
{
	Str		str;
	int		size;
	int		amount_read;

	size = fgetc(in_file) & 0xff;
	if (size == 0xff) {
		size = getw(in_file);
	}
	str = (Str)heap_alloc(heap, size + 1);
	amount_read = fread(str, 1, size, in_file);
	if (amount_read != size) {
		(void)fprintf(stderr, "Read %d bytes instead of %d bytes\n",
		              amount_read, size);
		assert_fail();
	}
	str[size] = '\0';
	return str;
}

/*
 * strwrite(str, out_file)
 *	This routine will write "str" to "out_file".  0 is returned.
 */
/* VARARGS2 */
int
strwrite(
	Str		str,
	Stdio		out_file)
{
	int		size;

	size = strlen(str);
	if (size >= 0xff) {
		(void)putc('\377', out_file);
		(void)putw(size, out_file);
	} else {
		(void)putc(size, out_file);
	}
	assert(fwrite(str, 1, size, out_file) == size);
	return 0;
}

