From 48bf3d3d0e0fc7b65115f13d2b9b422783fb9e41 Mon Sep 17 00:00:00 2001 From: phk Date: Sun, 13 Nov 1994 20:47:44 +0000 Subject: [PATCH] Added routines to read the canonical UNIX configuration file. This will later be applied to a number of programs (inetd for instance) to clean out the bogus code doing the same thing, modulus all the bugs. If you need to read a '#'-is-a-comment-file, please use these routines. I realize that the shlib# should be bumped (for the non-US world: increased by something), but will defer this until something significant happens. --- lib/libc/gen/Makefile.inc | 11 ++- lib/libc/gen/config.c | 187 +++++++++++++++++++++++++++++++++++++ lib/libc/gen/config_open.3 | 73 +++++++++++++++ 3 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 lib/libc/gen/config.c create mode 100644 lib/libc/gen/config_open.3 diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index e307157bad42..c9cf4e7656a8 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -1,11 +1,11 @@ # From: @(#)Makefile.inc 8.3 (Berkeley) 4/16/94 -# $Id: Makefile.inc,v 1.12 1994/09/25 01:38:27 wollman Exp $ +# $Id: Makefile.inc,v 1.13 1994/10/25 14:04:32 bde Exp $ # machine-independent gen sources .PATH: ${.CURDIR}/${MACHINE}/gen ${.CURDIR}/gen -SRCS+= alarm.c assert.c clock.c closedir.c confstr.c crypt.c ctermid.c \ - daemon.c devname.c disklabel.c err.c errlst.c \ +SRCS+= alarm.c assert.c clock.c closedir.c config.c confstr.c crypt.c \ + ctermid.c daemon.c devname.c disklabel.c err.c errlst.c \ exec.c fnmatch.c frexp.c fstab.c fts.c getbootfile.c getbsize.c \ getcap.c getcwd.c getdomainname.c getgrent.c getgrouplist.c \ gethostname.c getloadavg.c getlogin.c getmntinfo.c getnetgrent.c \ @@ -36,7 +36,8 @@ errlst.o errlst.po: rm -f errlst.s .endif -MAN3+= gen/alarm.3 gen/clock.3 gen/confstr.3 gen/crypt.3 gen/ctermid.3 \ +MAN3+= gen/alarm.3 gen/clock.3 gen/confstr.3 gen/config_open.3 \ + gen/crypt.3 gen/ctermid.3 \ gen/daemon.3 gen/devname.3 gen/directory.3 gen/err.3 gen/exec.3 \ gen/fnmatch.3 gen/frexp.3 gen/fts.3 gen/getbsize.3 gen/getbootfile.3 \ gen/getcap.3 gen/getcwd.3 gen/getdiskbyname.3 gen/getfsent.3 \ @@ -53,6 +54,8 @@ MAN3+= gen/alarm.3 gen/clock.3 gen/confstr.3 gen/crypt.3 gen/ctermid.3 \ gen/times.3 gen/timezone.3 gen/ttyname.3 gen/tzset.3 gen/ualarm.3 \ gen/uname.3 gen/unvis.3 gen/usleep.3 gen/utime.3 gen/valloc.3 gen/vis.3 +MLINKS+=config_open.3 config_next.3 config_open.3 config_close.3 \ + config_open.3 config_skip.3 MLINKS+=crypt.3 encrypt.3 crypt.3 setkey.3 MLINKS+=directory.3 closedir.3 directory.3 dirfd.3 directory.3 opendir.3 \ directory.3 readdir.3 directory.3 rewinddir.3 directory.3 seekdir.3 \ diff --git a/lib/libc/gen/config.c b/lib/libc/gen/config.c new file mode 100644 index 000000000000..6ea292b78b13 --- /dev/null +++ b/lib/libc/gen/config.c @@ -0,0 +1,187 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * $Id$ + * + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id: config.c,v 1.1 1994/01/14 12:24:39 jkh Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * This file contains four procedures used to read config-files. + * + * char * config_open(const char *filename,int contlines) + * Will open the named file, read it into a private malloc'ed area, + * and close the file again. + * All lines where the first !isspace() char is '#' are deleted. + * If contlines are non-zero lines where the first char is isspace() + * will be joined to the preceeding line. + * In case of trouble the name of the offending system call will be + * returned. On success NULL is returned. + * + * void config_close() + * This will free the internal malloc'ed area. + * + * char * config_next() + * This will return a pointer to the next entry in the area. NULL is + * returned at "end of file". The return value is '\0' terminated, and + * can be modified, but the contents must be copied somewhere else for + * permanent use. + * + * char * config_skip(char **p) + * This will pick out the next word from the string. The return-value + * points to the word found, and *p is advanced past the word. NULL is + * returned at "end of string". + * + * Many programs have a n*100 bytes config-file and N*1000 bytes of source + * to read it. Doing pointer-aerobics on files that small is a waste of + * time, and bashing around with getchar/ungetc isn't much better. These + * routines implement a simple algorithm and syntax. + * + * config_skip consider a contiguous string of !isspace() chars a word. + * + * 13nov1994 Poul-Henning Kamp phk@login.dknet.dk + */ + +#include +#include +#include +#include +#include +#include +#include + +static char *file_buf; +static char *ptr; + +char * +config_open(const char *filename, int contlines) +{ + int fd; + struct stat st; + char *p, *q; + + if ((fd = open(filename, O_RDONLY)) < 0) + return "open"; + if (fstat(fd, &st) < 0) { + close(fd); + return "fstat"; + } + if (file_buf) + free(file_buf); + file_buf = malloc(st.st_size + 2); + if (!file_buf) { + close(fd); + return "malloc"; + } + if (st.st_size != read(fd, file_buf, st.st_size)) { + free(file_buf); + file_buf = (char *) 0; + close(fd); + return "read"; + } + close(fd); + file_buf[st.st_size] = '\n'; + file_buf[st.st_size + 1] = '\0'; + + /* + * /^[ \t]*#[^\n]*$/d + * + * Delete all lines where the first !isspace() char is '#' + */ + + ptr = file_buf; + for (p = ptr; *p;) { + for (q = p; *q != '\n' && isspace(*q); q++) + continue; + if (*q == '#') { + p = strchr(p, '\n'); + if (p) + p++; + } else { + q = strchr(p, '\n'); + q++; + memcpy(ptr, p, q - p); + ptr += q - p; + p = q; + } + } + *ptr = '\0'; + ptr = file_buf; + + if (!contlines) + return 0; + + /* Join all lines starting with a isspace() char to the preceeding + * line */ + + for (p = ptr; *p;) { + q = strchr(p, '\n'); + if (isspace(*(q + 1))) + *q = ' '; + p = q + 1; + } + + return 0; +} + +void +config_close(void) +{ + if (file_buf) + free(file_buf); + ptr = file_buf = 0; +} + +/* + * Get next entry. config_open did all the weird stuff, so just return + * the next line. + */ + +char * +config_next(void) +{ + char *p; + + /* We might be done already ! */ + if (!ptr || !*ptr) + return 0; + + while (isspace(*ptr)) + ptr++; + p = ptr; + ptr = strchr(p, '\n'); + if (ptr) { + *ptr = '\0'; + ptr++; + } + return p; +} + +/* + * Return next word + */ + +char * +config_skip(char **p) +{ + char *q, *r; + + if (!*p || !**p) + return 0; + for (q = *p; isspace(*q); q++); + if (!*q) + return 0; + for (r = q; *r && !isspace(*r); r++); + if (*r) + *r++ = '\0'; + *p = r; + return q; +} diff --git a/lib/libc/gen/config_open.3 b/lib/libc/gen/config_open.3 new file mode 100644 index 000000000000..f51bc6cd01f8 --- /dev/null +++ b/lib/libc/gen/config_open.3 @@ -0,0 +1,73 @@ +.\" ---------------------------------------------------------------------------- +.\" "THE BEER-WARE LICENSE" (Revision 42): +.\" wrote this file. As long as you retain this notice you +.\" can do whatever you want with this stuff. If we meet some day, and you think +.\" this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp +.\" ---------------------------------------------------------------------------- +.\" +.\" $Id$ +.\" +.Dd November 13, 1994 +.Dt config_open 3 +.Os FreeBSD +.Sh NAME +.Nm config_open , +.Nm config_close , +.Nm config_next , +.Nm config_skip +.Nd read config files +.Sh SYNOPSIS +.Ft char * +.Fn config_open "const char *filename" "int contlines" +.Ft void +.Fn config_close +.Ft char * +.Fn config_next +.Ft char * +.Fn config_skip "char **string" +.Sh DESCRIPTION +These functions are used to read config files with the following syntax: +.Bl -bullet -compact +.It +All lines where the first +.Sq !isspace() +is '#' are comments which are discarded. +.It +If continuation-lines are enabled, any line starting with a +.Sq isspace() +character is joined to the preceeding line and blank lines are discarded. +.It +An entry starts at the first +.Sq !isspace() +character and ends at the first +.Sq Li \en +.Li . +.El +.Pp +.Fn config_open +will open the specified +.Fa filename +and read it into a private malloced area, and close the file again. If +.Fa contlines +is non-zero, continuation lines will be allowed. +In case of trouble, the name of the system-call causing the trouble will +be returned. If successful, +.Fn config_open +returns NULL. +.Pp +.Fn config_close +will free the malloced area. +.Pp +.Fn config_next +returns the next entry in the area. NULL is returned to indicate End-of-file. +The returned string is null-terminated. +.Pp +.Fn config_skip +returns the next word from the string +.Fa *string +.Li . +.Fa *string +will be advanced to point to the next word. +NULL is returned to indicate the end of the string. +.Sh AUTHOR +Poul-Henning Kamp