git: 83d7ed8af3d9 - main - config: drop dependency on libsbuf

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Thu, 09 Feb 2023 05:27:42 UTC
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=83d7ed8af3d9eab0567749d9d6e99a7e24d17817

commit 83d7ed8af3d9eab0567749d9d6e99a7e24d17817
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2023-02-09 04:56:10 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2023-02-09 04:56:10 +0000

    config: drop dependency on libsbuf
    
    Use an std::stringstream instead.  get_word() and get_quoted_word() both
    return a buffer that's presumed to not need release, so solve this by
    returning a new special configword type that holds a string or eof/eol
    state.  This cleans up caller checking for EOF/EOL to make it more
    explicit what they're doing, at least in the EOL cases which previously
    checked for NULL.
    
    Sponsored by:   Klara, Inc.
    Sponsored by:   NetApp, Inc.
    Differential Revision:  https://reviews.freebsd.org/D38276
---
 usr.sbin/config/Makefile                      |   6 +-
 usr.sbin/config/config.h                      |  57 +++++++++++-
 usr.sbin/config/{main.c => main.cc}           | 119 ++++++++++++--------------
 usr.sbin/config/mkmakefile.cc                 |  38 ++++----
 usr.sbin/config/{mkoptions.c => mkoptions.cc} |  39 +++++----
 5 files changed, 152 insertions(+), 107 deletions(-)

diff --git a/usr.sbin/config/Makefile b/usr.sbin/config/Makefile
index 241a501f52af..dab9aa43f036 100644
--- a/usr.sbin/config/Makefile
+++ b/usr.sbin/config/Makefile
@@ -5,8 +5,8 @@ SRCDIR:=${.PARSEDIR:tA}
 
 PROG_CXX=	config
 MAN=	config.5 config.8
-SRCS=	config.y main.c lang.l mkmakefile.cc mkheaders.c \
-	mkoptions.c y.tab.h kernconf.c
+SRCS=	config.y main.cc lang.l mkmakefile.cc mkheaders.c \
+	mkoptions.cc y.tab.h kernconf.c
 
 FILE2C?=file2c
 
@@ -18,8 +18,6 @@ CFLAGS+= -I. -I${SRCDIR}
 
 NO_WMISSING_VARIABLE_DECLARATIONS=
 
-LIBADD=	sbuf
-
 CLEANFILES+=	kernconf.c
 
 mkmakefile.o: configvers.h
diff --git a/usr.sbin/config/config.h b/usr.sbin/config/config.h
index 7d97d66979e2..8555bf000d0f 100644
--- a/usr.sbin/config/config.h
+++ b/usr.sbin/config/config.h
@@ -35,13 +35,66 @@
 /*
  * Config.
  */
-#include <sys/cdefs.h>	/* __BEGIN_DECLS/__END_DECLS */
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef __cplusplus
+#include <string>
+
+class configword {
+private:
+	std::string	cw_word;
+	bool		cw_eof;
+	bool		cw_eol;
+public:
+	configword() : cw_word(""), cw_eof(false), cw_eol(false) {}
+	configword(std::string &&word) : cw_word(word), cw_eof(false), cw_eol(false) {}
+
+	bool eof() const {
+		return (cw_eof);
+	}
+
+	bool eol() const {
+		return (cw_eol);
+	}
+
+	configword &eof(bool eof) {
+		cw_eof = eof;
+		return (*this);
+	}
+
+	configword &eol(bool eol) {
+		cw_eol = eol;
+		return (*this);
+	}
+
+	char operator[](int idx) {
+		return (cw_word[idx]);
+	}
+
+	operator const char*() const {
+		return (cw_word.c_str());
+	}
+
+	const std::string &operator*() const {
+		return (cw_word);
+	}
+
+	const std::string *operator->() const {
+		return (&cw_word);
+	}
+};
+
+/*
+ * Is it ugly to limit these to C++ files? Yes.
+ */
+configword get_word(FILE *);
+configword get_quoted_word(FILE *);
+#endif
+
 __BEGIN_DECLS
 
 struct cfgfile {
@@ -186,8 +239,6 @@ extern char	kernconfstr[];
 extern int	do_trace;
 extern int	incignore;
 
-char	*get_word(FILE *);
-char	*get_quoted_word(FILE *);
 char	*path(const char *);
 char	*raisestr(char *);
 void	remember(const char *);
diff --git a/usr.sbin/config/main.c b/usr.sbin/config/main.cc
similarity index 90%
rename from usr.sbin/config/main.c
rename to usr.sbin/config/main.cc
index 988c296d97ce..ef24d373c8b0 100644
--- a/usr.sbin/config/main.c
+++ b/usr.sbin/config/main.cc
@@ -45,19 +45,21 @@ static const char rcsid[] =
 
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/sbuf.h>
 #include <sys/file.h>
 #include <sys/mman.h>
 #include <sys/param.h>
 
 #include <assert.h>
 #include <ctype.h>
+#include <dirent.h>
 #include <err.h>
+#include <iostream>
+#include <sstream>
 #include <stdio.h>
 #include <string.h>
 #include <sysexits.h>
 #include <unistd.h>
-#include <dirent.h>
+
 #include "y.tab.h"
 #include "config.h"
 #include "configvers.h"
@@ -111,7 +113,7 @@ struct hdr_list {
 	struct hdr_list *h_next;
 } *htab;
 
-static struct sbuf *line_buf = NULL;
+static std::stringstream line_buf;
 
 /*
  * Config builds a set of files for building a UNIX
@@ -313,24 +315,21 @@ usage(void)
 static void
 init_line_buf(void)
 {
-	if (line_buf == NULL) {
-		line_buf = sbuf_new(NULL, NULL, 80, SBUF_AUTOEXTEND);
-		if (line_buf == NULL) {
-			errx(EXIT_FAILURE, "failed to allocate line buffer");
-		}
-	} else {
-		sbuf_clear(line_buf);
-	}
+
+	line_buf.str("");
 }
 
-static char *
+static std::string
 get_line_buf(void)
 {
-	if (sbuf_finish(line_buf) != 0) {
+
+	line_buf.flush();
+	if (!line_buf.good()) {
 		errx(EXIT_FAILURE, "failed to generate line buffer, "
-		    "partial line = %s", sbuf_data(line_buf));
+		    "partial line = %s", line_buf.str().c_str());
 	}
-	return sbuf_data(line_buf);
+
+	return line_buf.str();
 }
 
 /*
@@ -339,7 +338,7 @@ get_line_buf(void)
  *	NULL on end of line
  *	pointer to the word otherwise
  */
-char *
+configword
 get_word(FILE *fp)
 {
 	int ch;
@@ -351,7 +350,7 @@ begin:
 		if (ch != ' ' && ch != '\t')
 			break;
 	if (ch == EOF)
-		return ((char *)EOF);
+		return (configword().eof(true));
 	if (ch == '\\'){
 		escaped_nl = 1;
 		goto begin;
@@ -362,22 +361,22 @@ begin:
 			goto begin;
 		}
 		else
-			return (NULL);
+			return (configword().eol(true));
 	}
-	sbuf_putc(line_buf, ch);
+	line_buf << (char)ch;
 	/* Negation operator is a word by itself. */
 	if (ch == '!') {
-		return get_line_buf();
+		return (configword(get_line_buf()));
 	}
 	while ((ch = getc(fp)) != EOF) {
 		if (isspace(ch))
 			break;
-		sbuf_putc(line_buf, ch);
+		line_buf << (char)ch;
 	}
 	if (ch == EOF)
-		return ((char *)EOF);
+		return (configword().eof(true));
 	(void) ungetc(ch, fp);
-	return (get_line_buf());
+	return (configword(get_line_buf()));
 }
 
 /*
@@ -385,7 +384,7 @@ begin:
  *	like get_word but will accept something in double or single quotes
  *	(to allow embedded spaces).
  */
-char *
+configword
 get_quoted_word(FILE *fp)
 {
 	int ch;
@@ -397,7 +396,7 @@ begin:
 		if (ch != ' ' && ch != '\t')
 			break;
 	if (ch == EOF)
-		return ((char *)EOF);
+		return (configword().eof(true));
 	if (ch == '\\'){
 		escaped_nl = 1;
 		goto begin;
@@ -408,7 +407,7 @@ begin:
 			goto begin;
 		}
 		else
-			return (NULL);
+			return (configword().eol(true));
 	}
 	if (ch == '"' || ch == '\'') {
 		int quote = ch;
@@ -419,7 +418,7 @@ begin:
 				break;
 			if (ch == '\n' && !escaped_nl) {
 				printf("config: missing quote reading `%s'\n",
-					get_line_buf());
+					get_line_buf().c_str());
 				exit(2);
 			}
 			if (ch == '\\' && !escaped_nl) {
@@ -427,23 +426,23 @@ begin:
 				continue;
 			}
 			if (ch != quote && escaped_nl)
-				sbuf_putc(line_buf, '\\');
-			sbuf_putc(line_buf, ch);
+				line_buf << "\\";
+			line_buf << (char)ch;
 			escaped_nl = 0;
 		}
 	} else {
-		sbuf_putc(line_buf, ch);
+		line_buf << (char)ch;
 		while ((ch = getc(fp)) != EOF) {
 			if (isspace(ch))
 				break;
-			sbuf_putc(line_buf, ch);
+			line_buf << (char)ch;
 		}
 		if (ch != EOF)
 			(void) ungetc(ch, fp);
 	}
 	if (ch == EOF)
-		return ((char *)EOF);
-	return (get_line_buf());
+		return (configword().eof(true));
+	return (configword(get_line_buf()));
 }
 
 /*
@@ -466,7 +465,7 @@ path(const char *file)
  * will be able to obtain and build conifguration file with one command.
  */
 static void
-configfile_dynamic(struct sbuf *sb)
+configfile_dynamic(std::ostringstream &cfg)
 {
 	struct cputype *cput;
 	struct device *d;
@@ -476,38 +475,35 @@ configfile_dynamic(struct sbuf *sb)
 
 	asprintf(&lend, "\\n\\\n");
 	assert(lend != NULL);
-	sbuf_printf(sb, "options\t%s%s", OPT_AUTOGEN, lend);
-	sbuf_printf(sb, "ident\t%s%s", ident, lend);
-	sbuf_printf(sb, "machine\t%s%s", machinename, lend);
+	cfg << "options\t" << OPT_AUTOGEN << lend;
+	cfg << "ident\t" << ident << lend;
+	cfg << "machine\t" << machinename << lend;
 	SLIST_FOREACH(cput, &cputype, cpu_next)
-		sbuf_printf(sb, "cpu\t%s%s", cput->cpu_name, lend);
+		cfg << "cpu\t" << cput->cpu_name << lend;
 	SLIST_FOREACH(ol, &mkopt, op_next)
-		sbuf_printf(sb, "makeoptions\t%s=%s%s", ol->op_name,
-		    ol->op_value, lend);
+		cfg << "makeoptions\t" << ol->op_name << '=' <<
+		    ol->op_value << lend;
 	SLIST_FOREACH(ol, &opt, op_next) {
 		if (strncmp(ol->op_name, "DEV_", 4) == 0)
 			continue;
-		sbuf_printf(sb, "options\t%s", ol->op_name);
+		cfg << "options\t" << ol->op_name;
 		if (ol->op_value != NULL) {
-			sbuf_putc(sb, '=');
+			cfg << '=';
 			for (i = 0; i < strlen(ol->op_value); i++) {
 				if (ol->op_value[i] == '"')
-					sbuf_printf(sb, "\\%c",
-					    ol->op_value[i]);
+					cfg << '\\' << ol->op_value[i];
 				else
-					sbuf_printf(sb, "%c",
-					    ol->op_value[i]);
+					cfg << ol->op_value[i];
 			}
-			sbuf_printf(sb, "%s", lend);
-		} else {
-			sbuf_printf(sb, "%s", lend);
 		}
+
+		cfg << lend;
 	}
 	/*
 	 * Mark this file as containing everything we need.
 	 */
 	STAILQ_FOREACH(d, &dtab, d_next)
-		sbuf_printf(sb, "device\t%s%s", d->d_name, lend);
+		cfg << "device\t" << d->d_name << lend;
 	free(lend);
 }
 
@@ -515,7 +511,7 @@ configfile_dynamic(struct sbuf *sb)
  * Generate file from the configuration files.
  */
 static void
-configfile_filebased(struct sbuf *sb)
+configfile_filebased(std::ostringstream &cfg)
 {
 	FILE *cff;
 	struct cfgfile *cf;
@@ -534,11 +530,11 @@ configfile_filebased(struct sbuf *sb)
 		}
 		while ((i = getc(cff)) != EOF) {
 			if (i == '\n')
-				sbuf_printf(sb, "\\n\\\n");
+				cfg << "\\n\\\n";
 			else if (i == '"' || i == '\'')
-				sbuf_printf(sb, "\\%c", i);
+				cfg << '\\' << i;
 			else
-				sbuf_putc(sb, i);
+				cfg << i;
 		}
 		fclose(cff);
 	}
@@ -548,7 +544,7 @@ static void
 configfile(void)
 {
 	FILE *fo;
-	struct sbuf *sb;
+	std::ostringstream cfg;
 	char *p;
 
 	/* Add main configuration file to the list of files to be included */
@@ -557,16 +553,14 @@ configfile(void)
 	fo = fopen(p, "w");
 	if (!fo)
 		err(2, "%s", p);
-	sb = sbuf_new(NULL, NULL, 2048, SBUF_AUTOEXTEND);
-	assert(sb != NULL);
-	sbuf_clear(sb);
 	if (filebased) {
 		/* Is needed, can be used for backward compatibility. */
-		configfile_filebased(sb);
+		configfile_filebased(cfg);
 	} else {
-		configfile_dynamic(sb);
+		configfile_dynamic(cfg);
 	}
-	sbuf_finish(sb);
+
+	cfg.flush();
 	/* 
 	 * We print first part of the template, replace our tag with
 	 * configuration files content and later continue writing our
@@ -577,10 +571,9 @@ configfile(void)
 		errx(EXIT_FAILURE, "Something went terribly wrong!");
 	*p = '\0';
 	fprintf(fo, "%s", kernconfstr);
-	fprintf(fo, "%s", sbuf_data(sb));
+	fprintf(fo, "%s", cfg.str().c_str());
 	p += strlen(KERNCONFTAG);
 	fprintf(fo, "%s", p);
-	sbuf_delete(sb);
 	fclose(fo);
 	moveifchanged(path("config.c.new"), path("config.c"));
 	cfgfile_removeall();
diff --git a/usr.sbin/config/mkmakefile.cc b/usr.sbin/config/mkmakefile.cc
index 2aabb9e0f347..472f85fa4bc2 100644
--- a/usr.sbin/config/mkmakefile.cc
+++ b/usr.sbin/config/mkmakefile.cc
@@ -380,7 +380,8 @@ read_file(char *fname)
 	struct file_list *tp;
 	struct device *dp;
 	struct opt *op;
-	char *wd, *rfile, *compilewith, *depends, *clean, *warning;
+	configword wd;
+	char *rfile, *compilewith, *depends, *clean, *warning;
 	const char *objprefix;
 	int compile, match, nreqs, std, filetype, negate,
 	    imp_rule, no_ctfconvert, no_obj, before_depend, nowerror;
@@ -400,33 +401,34 @@ next:
 	 *	[ nowerror ] [ local ]
 	 */
 	wd = get_word(fp);
-	if (wd == (char *)EOF) {
+	if (wd.eof()) {
 		(void) fclose(fp);
 		return;
 	} 
-	if (wd == NULL)
+	if (wd.eol())
 		goto next;
 	if (wd[0] == '#')
 	{
-		while (((wd = get_word(fp)) != (char *)EOF) && wd)
+		while (!(wd = get_word(fp)).eof() && !wd.eol())
 			;
 		goto next;
 	}
 	if (eq(wd, "include")) {
 		wd = get_quoted_word(fp);
-		if (wd == (char *)EOF || wd == NULL)
+		if (wd.eof() || wd.eol())
 			errout("%s: missing include filename.\n", fname);
-		(void) snprintf(ifname, sizeof(ifname), "../../%s", wd);
+		(void) snprintf(ifname, sizeof(ifname), "../../%s",
+		    wd->c_str());
 		read_file(ifname);
-		while (((wd = get_word(fp)) != (char *)EOF) && wd)
+		while (!(wd = get_word(fp)).eof() && !wd.eol())
 			;
 		goto next;
 	}
 	rfile = ns(wd);
 	wd = get_word(fp);
-	if (wd == (char *)EOF)
+	if (wd.eof())
 		return;
-	if (wd == NULL)
+	if (wd.eol())
 		errout("%s: No type for %s.\n", fname, rfile);
 	tp = fl_lookup(rfile);
 	compile = 0;
@@ -449,9 +451,9 @@ next:
 		std = 1;
 	else if (!eq(wd, "optional"))
 		errout("%s: \"%s\" %s must be optional or standard\n",
-		    fname, wd, rfile);
-	for (wd = get_word(fp); wd; wd = get_word(fp)) {
-		if (wd == (char *)EOF)
+		    fname, wd->c_str(), rfile);
+	for (wd = get_word(fp); !wd.eol(); wd = get_word(fp)) {
+		if (wd.eof())
 			return;
 		if (eq(wd, "!")) {
 			negate = 1;
@@ -489,7 +491,7 @@ next:
 		}
 		if (eq(wd, "dependency")) {
 			wd = get_quoted_word(fp);
-			if (wd == (char *)EOF || wd == NULL)
+			if (wd.eof() || wd.eol())
 				errout("%s: %s missing dependency string.\n",
 				       fname, rfile);
 			depends = ns(wd);
@@ -497,7 +499,7 @@ next:
 		}
 		if (eq(wd, "clean")) {
 			wd = get_quoted_word(fp);
-			if (wd == (char *)EOF || wd == NULL)
+			if (wd.eof() || wd.eol())
 				errout("%s: %s missing clean file list.\n",
 				       fname, rfile);
 			clean = ns(wd);
@@ -505,7 +507,7 @@ next:
 		}
 		if (eq(wd, "compile-with")) {
 			wd = get_quoted_word(fp);
-			if (wd == (char *)EOF || wd == NULL)
+			if (wd.eof() || wd.eol())
 				errout("%s: %s missing compile command string.\n",
 				       fname, rfile);
 			compilewith = ns(wd);
@@ -513,7 +515,7 @@ next:
 		}
 		if (eq(wd, "warning")) {
 			wd = get_quoted_word(fp);
-			if (wd == (char *)EOF || wd == NULL)
+			if (wd.eof() || wd.eol())
 				errout("%s: %s missing warning text string.\n",
 				       fname, rfile);
 			warning = ns(wd);
@@ -521,7 +523,7 @@ next:
 		}
 		if (eq(wd, "obj-prefix")) {
 			wd = get_quoted_word(fp);
-			if (wd == (char *)EOF || wd == NULL)
+			if (wd.eof() || wd.eol())
 				errout("%s: %s missing object prefix string.\n",
 				       fname, rfile);
 			objprefix = ns(wd);
@@ -542,7 +544,7 @@ next:
 		nreqs++;
 		if (std)
 			errout("standard entry %s has optional inclusion specifier %s!\n",
-			       rfile, wd);
+			       rfile, wd->c_str());
 		STAILQ_FOREACH(dp, &dtab, d_next)
 			if (eq(dp->d_name, wd)) {
 				if (negate)
diff --git a/usr.sbin/config/mkoptions.c b/usr.sbin/config/mkoptions.cc
similarity index 94%
rename from usr.sbin/config/mkoptions.c
rename to usr.sbin/config/mkoptions.cc
index b93e56e3a491..f45c1026417c 100644
--- a/usr.sbin/config/mkoptions.c
+++ b/usr.sbin/config/mkoptions.cc
@@ -141,7 +141,7 @@ options(void)
 static void
 do_option(char *name)
 {
-	char *file, *inw;
+	char *file;
 	const char *basefile;
 	struct opt_list *ol;
 	struct opt *op;
@@ -198,18 +198,17 @@ do_option(char *name)
 	seen = 0;
 	tidy = 0;
 	for (;;) {
-		char *cp;
+		configword cp, inw;
 		char *invalue;
 
 		/* get the #define */
-		if ((inw = get_word(inf)) == NULL || inw == (char *)EOF)
+		if ((inw = get_word(inf)).eol() || inw.eof())
 			break;
 		/* get the option name */
-		if ((inw = get_word(inf)) == NULL || inw == (char *)EOF)
+		if ((inw = get_word(inf)).eol() || inw.eof())
 			break;
-		inw = ns(inw);
 		/* get the option value */
-		if ((cp = get_word(inf)) == NULL || cp == (char *)EOF)
+		if ((cp = get_word(inf)).eol() || cp.eof())
 			break;
 		/* option value */
 		invalue = ns(cp); /* malloced */
@@ -224,25 +223,25 @@ do_option(char *name)
 		if (!eq(inw, name) && !ol) {
 			fprintf(stderr,
 			    "WARNING: unknown option `%s' removed from %s\n",
-			    inw, file);
+			    inw->c_str(), file);
 			tidy++;
 		} else if (ol != NULL && !eq(basefile, ol->o_file)) {
 			fprintf(stderr,
 			    "WARNING: option `%s' moved from %s to %s\n",
-			    inw, basefile, ol->o_file);
+			    inw->c_str(), basefile, ol->o_file);
 			tidy++;
 		} else {
 			op = (struct opt *) calloc(1, sizeof *op);
 			if (op == NULL)
 				err(EXIT_FAILURE, "calloc");
-			op->op_name = inw;
+			op->op_name = ns(inw);
 			op->op_value = invalue;
 			SLIST_INSERT_HEAD(&op_head, op, op_next);
 		}
 
 		/* EOL? */
 		cp = get_word(inf);
-		if (cp == (char *)EOF)
+		if (cp.eof())
 			break;
 	}
 	(void)fclose(inf);
@@ -364,25 +363,26 @@ static int
 read_option_file(const char *fname, int flags)
 {
 	FILE *fp;
-	char *wd, *optname, *val;
+	configword wd;
+	char *optname, *val;
 	char genopt[MAXPATHLEN];
 
 	fp = fopen(fname, "r");
 	if (fp == NULL)
 		return (0);
-	while ((wd = get_word(fp)) != (char *)EOF) {
-		if (wd == NULL)
+	while (!(wd = get_word(fp)).eof()) {
+		if (wd.eol())
 			continue;
 		if (wd[0] == '#') {
-			while (((wd = get_word(fp)) != (char *)EOF) && wd)
+			while (!(wd = get_word(fp)).eof() && !wd.eol())
 				continue;
 			continue;
 		}
 		optname = ns(wd);
-		val = get_word(fp);
-		if (val == (char *)EOF)
+		wd = get_word(fp);
+		if (wd.eof())
 			return (1);
-		if (val == NULL) {
+		if (wd.eol()) {
 			if (flags) {
 				fprintf(stderr, "%s: compat file requires two"
 				    " words per line at %s\n", fname, optname);
@@ -391,10 +391,11 @@ read_option_file(const char *fname, int flags)
 			char *s = ns(optname);
 			(void)snprintf(genopt, sizeof(genopt), "opt_%s.h",
 			    lower(s));
-			val = genopt;
+			val = ns(genopt);
 			free(s);
+		} else {
+			val = ns(wd);
 		}
-		val = ns(val);
 		if (flags == 0)
 			insert_option(fname, optname, val);
 		else