[net.sources] field

randy@utcsri.UUCP (Randall S. Becker) (05/27/85)

	This is a version of FIELD written in C for programmers. My system
doesn't have such a facility so I decided to spend the brief time to
write my own library. The package is written with long identifiers which
are unique to 6 characters. Install it in /usr/lib. Cc .. -lfield will
give programmers access to the library.
	If you find any bugs, let me know. If there are any significant changes,
I'll eventually repost the corrected version.
	A sample (very bad) program is provided in test.c. Try it! You may not
like it.
	The software IS public domain and is NOT taken from Software Tools. Any
similarities are coincidental and unintentional.
	Please forgive the verbosity of the makefile. I have a bunch of standard
makefile templates (which I can post is anyone is interested) and software
to tell me what's going on with various products. Ignore it or use it at
your discretion.

I always welcome comments and suggestions for enhancement.

	Randy

		Randall S. Becker
		Usenet:	..!utcsri!randy or ..!utcsri!nucleus!randy
		CSNET:	randy@toronto   or nucleus!randy@toronto
--------- cut here -------- (there's nothing by source to the end of file) --
:	This is a 'shar' archive.
:	Run this through 'sh' and not 'csh'.
:
echo 'x - makefile (2108 bytes)'
sed 's/^X//' > makefile << //END*OF*FILE
X
X#	makefile for field(3)
X
X#	product identification:
X#
XNAME	=	field
XAUTHOR	=	R. Becker
XORIGIN	=	net.sources (utcsri!nucleus)
XMANUAL	=	3
XSECTION	=	3
XPRODUCT	=	lib${NAME}.a
XPRODUCTLIST =	${PRODUCT}
X
X#	support information:
X#
XOWNER	=	local
XEXECGRP	=	sysadmin
XDOCGRP	=	doc
XUMASK	=	644
X
X#	Locations of the sources, products and working directories
X#
XSRCDIR	=	/usr/src/usr.lib/${NAME}
XDSTDIR	=	/usr/lib
XMANDIR	=	/usr/man/man${SECTION}
XINCDIR	=	/usr/include
X
X#	compilation instructions
X#
XCFLAGS	= -i -O
XSYSINC	=
XINCLUDES=	field.h
XSOURCES	=	field.c
XOBJECTS	=	field.o
XLIBS	=
X
X#	products required for compilation and installation:
X#		note: LINK should be set to 'cp' if the source directory
X#		is not on the same file system as the destination directory.
XLANG	=	cc
XLINK	=	ln
X
X#	dependencies:
X#		This section lists the dependencies and any necessary rules
X#		for the compilation of the development version of the product
X${PRODUCT}:	${OBJECTS}
X	ar rcv ${PRODUCT} `lorder ${OBJECTS} | tsort`
X	ranlib ${PRODUCT}
X
X${OBJECTS}:	${INCLUDES} ${SYSINC}
X
Xtester:	${PRODUCT}
X	cc test.c ${PRODUCT} -o tester
X
X#	installation instructions
X#	The installation is broken down into two parts (install and installdoc)
X
X#	install:
X#		sets the correct mode of the product
X#		removes any members of the product list from the destination
X#			directory
X#		sets up the links to the new product
Xinstall:
X	@echo "make: installing " ${PRODUCT}
X	chgrp ${EXECGRP} ${PRODUCT}
X	chmod ${UMASK} ${PRODUCT}
X	-@for i in ${PRODUCTLIST}; do \
X		echo "rm ${DSTDIR}/"$$i; \
X		rm ${DSTDIR}/$$i; \
X	done
X	@for i in ${PRODUCTLIST}; do \
X		echo "(cd ${DSTDIR}; ln ${SRCDIR}/${PRODUCT}" $$i")"; \
X		(cd ${DSTDIR}; ${LINK} ${SRCDIR}/${PRODUCT} $$i) \
X	done
X	(cd /usr/include; ${LINK} ${SRCDIR}/field.h field.h)
X
X#	installdoc:
X#		removes the old copy of the manual page
X#		established the link to the new manual page
Xinstalldoc:
X	chgrp ${DOCGRP} ${NAME}.${MANUAL}
X	-rm ${MANDIR}/${NAME}.${MANUAL}
X	(cd ${MANDIR}; ${LINK} ${SRCDIR}/${NAME}.${MANUAL} ${NAME}.${MANUAL})
X
X#	clean up any old object files to conserve space on the disk or tape.
X#
Xclean:
X	rm -f ${OBJECTS}
//END*OF*FILE
echo 'x - field.3 (1262 bytes)'
sed 's/^X//' > field.3 << //END*OF*FILE
X.tr ~ \ 
X.TH FIELD 3L "25 May 1985"
X.SH NAME
Xfield, fsetstr, frelstr, fmaxfields \- field extraction processor
X.SH SYNOPSIS
X.B
Xint fsetstr(source)
X.br
Xchar *source;
X.br
X.sp
Xchar *field(n)
X.br
X.sp
Xfrelstr()
X.br
X.sp
Xint fmaxfields()
X.SH DESCRIPTION
X.PP
X.I Field
Xprovides a general purpose routine for extracting fields from strings. Fields
Xare considered to be strings delimited by colons (':') within other strings.
XFor example, the string "hello:there:you:\\::" has four fields "hello", "there",
X"you", and "\\:". Note that colons may be escaped by suffixing them with a 
Xbackslash.
X.PP
XA call to fsetstr() must be made to inform
Xfield() of the address of the string being scanned. 
X.PP
XWhen the program is 
Xfinished with the string it should call frelstr() to free the memory used by
Xfield(). 
X.PP
XFmaxfields() can be called to determine the number of fields actually present 
Xin the current string.
X.SH AUTHOR
XRandall S. Becker
X.SH DIAGNOSTICS
XFsetstr() can fail if there is not enough free memory to accomodate a copy
Xof the source string and an array of field pointers. A -2 is returned in this
Xcase.  Otherwise a 0 is returned.
X.PP
XIf the field number specified in field() is out of range (outside 1..n)
Xa -1 is returned. 
X.SH BUGS
XNone detected as of yet.
//END*OF*FILE
echo 'x - field.h (274 bytes)'
sed 's/^X//' > field.h << //END*OF*FILE
X/*	include file for the field(3L) package */
X
Xextern	int	fsetstr();	/* define a new string for parsing */
Xextern	frelstr();		/* release the string being parsed */
Xextern	char	*field();	/* extract a field */
Xextern	int	fmaxfields();	/* determine how many fields there are */
//END*OF*FILE
echo 'x - field.c (2886 bytes)'
sed 's/^X//' > field.c << //END*OF*FILE
X/* Author: Randall S. Becker, 26 May 1985 */
X
X/* field(3)	- field extraction algorithm */
X
X/* field maintains its own copy of the source string, __string, with all 
X	delimiter characters replaced by NULLS (ascii 0). An unterminated 
X	list of pointers to the beginning of each field, __fields, is 
X	created when the list is defined. The length of the list is stored 
X	in __maxfields. Access to the __fields list and __maxfields variable
X	is obtained through the routines field() and fmaxfields() respectively.
X
X	There is no implicit or explicit warrantee associated with this 
X	piece of software. You are free to us it but do so at your own risk.
X	The author requests that the line of the file be kept in this and
X	any subsequent modifications to this code. Thank you. */
X
X/* 	Any resemblance to the FIELD(1) code in Software Tools, K&P, is
X	purely coincidental. This code is the original work of the author.
X	*/
X	
X#ifdef CHECKING
X#	include <stdio.h>
X#	include <assert.h>
X#endif CHECKING
X
X/* error codes */
X#define	F_OK		0
X#define	F_ENDOFLIST	-1
X#define	F_NOMEMORY	-2
X
X#ifndef NULL
X#	define	NULL	(0)
X#endif  NULL
X#define	BACKSLASH	'\\'
X#define	DELIMITER	':'
X#define	TRUE		(1)
X#define	FALSE		(0)
X
Xstatic	char	*__string;
Xstatic	char	**__fields;
Xstatic	int	__maxfields;
Xstatic	int	__present = FALSE;
X
Xfsetstr(source)
X	char	*source;	/* the string being parsed */
X{
X	char	**fieldptr;
X	char	*strptr;
X	int	length = strlen(source);
X	char	*malloc(), *realloc();
X
X	if (__present)
X		frelstr();
X#	ifdef CHECKING
X		assert(! __present);
X#	endif CHECKING
X
X	__string = malloc( length + 1 );
X	strptr = __string;
X	/* copy the source string to the working area */
X	while ( *strptr++ = *source++ )
X		;
X
X	/* alloc space for all possible fields */
X	__fields = (char **) malloc ( (length+1) * sizeof(char *) ); 
X	fieldptr = __fields;
X	if (! __fields && ! __string) 
X		return(F_NOMEMORY);
X
X	__present = TRUE;
X	strptr = __string;
X	while (*strptr) {
X		*fieldptr++ = strptr;
X		__maxfields++;
X		/* skip to the next field */
X		while (*strptr && *strptr != DELIMITER) {
X			/* check for escaped delimiter (or anything) */
X			if (*strptr == BACKSLASH && *(strptr+1) )
X				strptr++;
X			strptr++;
X		}
X		if (*strptr)
X			*strptr++ = NULL;
X#		ifdef DEBUG
X			printf("found field %d = [%s]\n",__maxfields,
X							*(fieldptr-1));
X#		endif DEBUG
X	}
X
X	/* reduce the size of __fields to the actual number of fields */
X	__fields = (char **) realloc(__fields, __maxfields * sizeof(char *));
X
X	return (F_OK);
X}
X
Xfrelstr()
X{
X	if (__present) {
X		free(__string);
X		__string = NULL;
X		free(__fields);
X		__fields = NULL;
X		__maxfields = 0;
X		__present = FALSE;
X	}
X#	ifdef CHECKING
X		assert(! __present)
X#	endif CHECKING
X}
X
Xchar	*field(n)
X	int	n;	/* the field number */
X{
X	if (n < 0 || n > __maxfields)
X		return(F_ENDOFLIST);
X	else
X		return(__fields[n-1]);
X}
X
Xint	fmaxfields()
X{
X	if (__present)
X		return(__maxfields);
X	else
X		return(0);
X}
//END*OF*FILE
echo 'x - test.c (264 bytes)'
sed 's/^X//' > test.c << //END*OF*FILE
X#include "field.h"
X#include "stdio.h"
X
Xmain()
X{
X	char	buf[256];
X	int	i;
X
X	while (!feof(stdin)) {
X		gets(&buf);
X		printf("string=[%s]\n", buf);
X		fsetstr(&buf);
X		for(i=1; i<= fmaxfields(); i++) {
X			printf("  field %d: [%s]\n", i,field(i));
X		};
X		frelstr();
X	}
X}
//END*OF*FILE
-- 
		Randall S. Becker
		Usenet:	..!utcsri!randy
		CSNET:	randy@toronto