diff --git a/usr.sbin/config/config.5 b/usr.sbin/config/config.5 index f523b7d33ce0..cee191409618 100644 --- a/usr.sbin/config/config.5 +++ b/usr.sbin/config/config.5 @@ -231,6 +231,7 @@ specifications. Each option specification has the form .Pp .D1 Ar MakeVariableName Ns Op = Ns Ar Value +.D1 Ar MakeVariableName Ns += Ns Ar Value .Pp and results in the appropriate .Xr make 1 @@ -243,7 +244,8 @@ is assumed to be the empty string. .Pp Example: .Bd -literal -offset indent -compact -makeoptions MYMAKEOPTION="foobar" +makeoptions MYMAKEOPTION="foo" +makeoptions MYMAKEOPTION+="bar" makeoptions MYNULLMAKEOPTION .Ed .\" -------- MAXUSERS -------- diff --git a/usr.sbin/config/config.h b/usr.sbin/config/config.h index 759eef039958..d55c96b00a9e 100644 --- a/usr.sbin/config/config.h +++ b/usr.sbin/config/config.h @@ -121,6 +121,7 @@ struct opt { char *op_value; int op_ownfile; /* true = own file, false = makefile */ SLIST_ENTRY(opt) op_next; + SLIST_ENTRY(opt) op_append; }; SLIST_HEAD(opt_head, opt) opt, mkopt, rmopts; diff --git a/usr.sbin/config/config.y b/usr.sbin/config/config.y index 9aa89e5593ce..9425daf3c337 100644 --- a/usr.sbin/config/config.y +++ b/usr.sbin/config/config.y @@ -13,6 +13,7 @@ %token NODEVICE %token ENV %token EQUALS +%token PLUSEQUALS %token HINTS %token IDENT %token MAXUSERS @@ -99,7 +100,7 @@ int yywrap(void); static void newdev(char *name); static void newfile(char *name); static void rmdev_schedule(struct device_head *dh, char *name); -static void newopt(struct opt_head *list, char *name, char *value); +static void newopt(struct opt_head *list, char *name, char *value, int append); static void rmopt_schedule(struct opt_head *list, char *name); static char * @@ -211,7 +212,7 @@ System_spec: ; System_id: - Save_id { newopt(&mkopt, ns("KERNEL"), $1); }; + Save_id { newopt(&mkopt, ns("KERNEL"), $1, 0); }; System_parameter_list: System_parameter_list ID @@ -226,13 +227,13 @@ Opt_list: Option: Save_id { - newopt(&opt, $1, NULL); + newopt(&opt, $1, NULL, 0); if (strchr($1, '=') != NULL) errx(1, "%s:%d: The `=' in options should not be " "quoted", yyfile, yyline); } | Save_id EQUALS Opt_value { - newopt(&opt, $1, $3); + newopt(&opt, $1, $3, 0); } ; Opt_value: @@ -255,8 +256,9 @@ Mkopt_list: ; Mkoption: - Save_id { newopt(&mkopt, $1, ns("")); } | - Save_id EQUALS Opt_value { newopt(&mkopt, $1, $3); } ; + Save_id { newopt(&mkopt, $1, ns(""), 0); } | + Save_id EQUALS Opt_value { newopt(&mkopt, $1, $3, 0); } | + Save_id PLUSEQUALS Opt_value { newopt(&mkopt, $1, $3, 1); } ; Dev: ID { $$ = $1; } @@ -282,7 +284,7 @@ NoDev_list: Device: Dev { - newopt(&opt, devopt($1), ns("1")); + newopt(&opt, devopt($1), ns("1"), 0); /* and the device part */ newdev($1); } @@ -401,9 +403,9 @@ findopt(struct opt_head *list, char *name) * Add an option to the list of options. */ static void -newopt(struct opt_head *list, char *name, char *value) +newopt(struct opt_head *list, char *name, char *value, int append) { - struct opt *op; + struct opt *op, *op2; /* * Ignore inclusions listed explicitly for configuration files. @@ -413,7 +415,8 @@ newopt(struct opt_head *list, char *name, char *value) return; } - if (findopt(list, name)) { + op2 = findopt(list, name); + if (op2 != NULL && !append) { printf("WARNING: duplicate option `%s' encountered.\n", name); return; } @@ -422,7 +425,12 @@ newopt(struct opt_head *list, char *name, char *value) op->op_name = name; op->op_ownfile = 0; op->op_value = value; - SLIST_INSERT_HEAD(list, op, op_next); + if (op2 != NULL) { + while (SLIST_NEXT(op2, op_append) != NULL) + op2 = SLIST_NEXT(op2, op_append); + SLIST_NEXT(op2, op_append) = op; + } else + SLIST_INSERT_HEAD(list, op, op_next); } /* diff --git a/usr.sbin/config/configvers.h b/usr.sbin/config/configvers.h index 2bcce1168409..28451585ec29 100644 --- a/usr.sbin/config/configvers.h +++ b/usr.sbin/config/configvers.h @@ -49,5 +49,5 @@ * * $FreeBSD$ */ -#define CONFIGVERS 600006 +#define CONFIGVERS 600007 #define MAJOR_VERS(x) ((x) / 100000) diff --git a/usr.sbin/config/lang.l b/usr.sbin/config/lang.l index b89c6c4caeaa..075f21f4dfc1 100644 --- a/usr.sbin/config/lang.l +++ b/usr.sbin/config/lang.l @@ -156,6 +156,7 @@ PATH [./][-/.%^A-Za-z_0-9]+ ";" { return SEMICOLON; } "," { return COMMA; } "=" { BEGIN TOEOL; return EQUALS; } +"+=" { BEGIN TOEOL; return PLUSEQUALS; } <> { int tok; diff --git a/usr.sbin/config/mkmakefile.c b/usr.sbin/config/mkmakefile.c index b6f1f1818cd2..a89db8eba7ab 100644 --- a/usr.sbin/config/mkmakefile.c +++ b/usr.sbin/config/mkmakefile.c @@ -110,7 +110,7 @@ makefile(void) { FILE *ifp, *ofp; char line[BUFSIZ]; - struct opt *op; + struct opt *op, *t; int versreq; read_files(); @@ -127,8 +127,12 @@ makefile(void) if (ofp == 0) err(1, "%s", path("Makefile.new")); fprintf(ofp, "KERN_IDENT=%s\n", ident); - SLIST_FOREACH(op, &mkopt, op_next) - fprintf(ofp, "%s=%s\n", op->op_name, op->op_value); + SLIST_FOREACH_SAFE(op, &mkopt, op_next, t) { + fprintf(ofp, "%s=%s", op->op_name, op->op_value); + while ((op = SLIST_NEXT(op, op_append)) != NULL) + fprintf(ofp, " %s", op->op_value); + fprintf(ofp, "\n"); + } if (debugging) fprintf(ofp, "DEBUG=-g\n"); if (profiling)