Date: Tue, 31 Oct 1995 07:45:05 -0800 From: Paul Traina <pst@Shockwave.COM> To: FreeBSD-gnats-submit@freebsd.org Subject: bin/803: bsd m4 chokes on config script Message-ID: <199510311545.HAA17304@precipice.shockwave.com> Resent-Message-ID: <199510311550.HAA26305@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 803
>Category: bin
>Synopsis: bsd m4 chokes and dies while FSF m4 works...
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Tue Oct 31 07:50:01 PST 1995
>Last-Modified:
>Originator: Paul Traina
>Organization:
Shockwave Engineering
>Release: FreeBSD 2.1-STABLE i386
>Environment:
2.1-stable as of this week
>Description:
I was porting over the new gnats-3.97 beta from Cygnus. When I went to
build gnats, m4 chocked and died. Input files and sample output are below.
I pulled down FSF m4 and it worked just fine. As you can see from the output
of m4, it's insanely confused at this point.
I checked NetBSD's and Lite-2's m4 distributions to see if there were any
fixes that we failed to pick up, and we are at least current with those
distributions.
>How-To-Repeat:
/usr/bin/m4 config.m4 config.c.in
output from broken m4 (edited down)
--------------
char *gnats_root = NULL;
char[] char[] <static char _gnats_addr GNATS_ADDR STR_MAX[] = ;
char *gnats_addr GNATS_ADDR STR_MAX = _gnats_addr GNATS_ADDR STR_MAX;> = ; char[] char[] <static char _gnats_addr GNATS_ADDR STR_MAX[] = ;
char *gnats_addr GNATS_ADDR STR_MAX = _gnats_addr GNATS_ADDR STR_MAX;>;
)>
, , char[], dnl
static char _gnats_server GNATS_SERVER char[] STR_MAX[] = ;
char *gnats_server GNATS_SERVER char[] STR_MAX = _gnats_server GNATS_SERVER char[] STR_MAX;dnl
define(>, { ""^ _gnats_server GNATS_SERVER char[] STR_MAX }^
)
m4: missing right quote
output from FSF m4 (edited down to cover same range...)
---------------
char *gnats_root = NULL;
static char _gnats_addr[STR_MAX] = GNATS_ADDR;
char *gnats_addr = _gnats_addr;
static char _gnats_server[STR_MAX] = GNATS_SERVER;
config.m4:
--------------
dnl
dnl Macros for generating declarations in sh/C configuration
dnl
changequote(<,>)dnl
define(<CN_CNT>, 0)dnl # of decls processed
define(<CN_INIT>,)dnl initializer list contents
define(<CN_KNR>,)dnl K&R initializers
dnl
dnl Generate the ANSI initializer list
define(<CN_ANSI>,<changequote([,])translit(CN_INIT,^,[,])changequote(,)>)dnl
dnl
dnl Generate the decl and initializers for an integral option
define(<CN_DOINT>,<<dnl
int $1 = $2;dnl
define(<CN_INIT>, CN_INIT { "$2"^ (char *) &$1 }^
)dnl
define(<CN_KNR>, CN_KNR confs[CN_CNT].key = "$2"; dnl
confs[CN_CNT].val = (char *) &$1;
)>>)dnl
dnl
dnl Generate the decl and initializers for a string option
define(<CN_DOCHARA>,<<dnl
static char _$1[$3] = $2;
char *$1 = _$1;dnl
define(<CN_INIT>, CN_INIT { "$2"^ _$1 }^
)dnl
define(<CN_KNR>, CN_KNR confs[CN_CNT].key = "$2"; confs[CN_CNT].val = $1;
)>>)dnl
dnl
dnl Generate the decl and initializers for an option
define(<CN_OPT>,<dnl
changequote(<,>)dnl
ifelse($3, int, CN_DOINT($1, $2), $3, char[], CN_DOCHARA($1, $2, $4))dnl
define(<CN_CNT>, incr(CN_CNT))dnl
changequote(,)dnl
>Fix:
>Audit-Trail:
>Unformatted:
>)dnl
dnl
changequote(,)dnl
config.c.in
--------------------
/* Configuration processing routines for GNATS -*- C -*-
Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
This file is part of GNU GNATS.
GNU GNATS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU GNATS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU GNATS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* The basic idea here is to be able to use the same configuration file for
sh scripts and C programs; the sh script just uses `.', but the C program
has to be a bit more trickier. And a lot uglier. */
/* FIXME, maybe: Use hash table for more option-ridden programs. */
#include "config.h"
#include "gnats.h"
#include "pathmax.h"
char *gnats_root = NULL;
CN_OPT(gnats_addr, GNATS_ADDR, char[], STR_MAX)
CN_OPT(gnats_server, GNATS_SERVER, char[], STR_MAX)
CN_OPT(gnats_server_port, GNATS_SERVER_PORT, int)
CN_OPT(gnats_service, GNATS_SERVICE, char[], STR_MAX)
CN_OPT(gnats_user, GNATS_USER, char[], STR_MAX)
CN_OPT(gnats_admin, GNATS_ADMIN, char[], STR_MAX)
CN_OPT(def_subm, DEFAULT_SUBMITTER, char[], STR_MAX)
CN_OPT(def_release, DEFAULT_RELEASE, char[], STR_MAX)
CN_OPT(flag_notify, NOTIFY, int)
CN_OPT(flag_ack, ACKNOWLEDGE, int)
CN_OPT(keep_rec, KEEP_RECEIVED_HEADERS, int)
CN_OPT(debug_mode, DEBUG_MODE, int)
CN_OPT(bday_start, BDAY_START, int)
CN_OPT(bday_end, BDAY_END, int)
CN_OPT(bweek_start, BWEEK_START, int)
CN_OPT(bweek_end, BWEEK_END, int)
CN_OPT(mail_agent, MAIL_AGENT, char[], STR_MAX)
CN_OPT(bindir, BINDIR, char[], STR_MAX)
CN_OPT(queue_dir, QUEUE_DIR, char[], STR_MAX)
struct conf
{
char* key;
char* val;
};
#ifdef __STDC__
#define STDCINIT
#endif
#ifdef STDCINIT
static struct conf confs[] = {
CN_ANSI};
#else
static struct conf confs[CN_CNT];
#endif
static char *fname = NULL;
static char *string_extract_double_quoted ();
static char *safe_strtok ();
/* Read in and set the above configuration parameters */
void
configure()
{
FILE *fp;
char line[STR_MAX];
#ifndef STDCINIT
CN_KNR#endif
if (! gnats_root)
{
gnats_root = getenv ("GNATS_ROOT");
if (! gnats_root)
gnats_root = X_GNATS_ROOT;
}
if (fname)
xfree (fname);
#define CONFSTR "%s/gnats-adm/config"
fname = xmalloc (strlen (gnats_root) + sizeof (CONFSTR) - 1);
sprintf (fname, CONFSTR, gnats_root);
fp = fopen (fname, "r");
if (fp == NULL) /* no config file; no problem */
return;
while (fgets (line, STR_MAX, fp) != NULL)
{
int i;
if (*line == '#') continue; /* comment */
for (i=0; i < sizeof(confs)/sizeof(struct conf); i++) {
int n = strlen(confs[i].key);
if (! strncmp(confs[i].key, line, n) && line[n] == '=') {
char *p = line+n+1;
int d;
if (sscanf (p, "%d", &d) > 0) /* NOTIFY=1 */
*((int *) confs[i].val) = d;
else /* string parameter */
{
/* Mimic somewhat the sh interpretation of the line. */
if (*p == '\'')
strcpy (confs[i].val, safe_strtok(p+1, "'"));
else if (*p == '"')
strcpy (confs[i].val, string_extract_double_quoted(p+1));
else strcpy (confs[i].val, safe_strtok(p, " \t\n"));
}
break;
}
}
}
}
static char *
safe_strtok (s, d)
char *s, *d;
{
char *r = strtok (s, d);
if (!r && *s != '\n')
r = strtok (s, "\n");
if (!r)
r = "";
return r;
}
/* Lifted largely from bash/subst.c */
static char *
string_extract_double_quoted (string)
char *string;
{
register int c, j, i; /* character, temp pos, str pos */
char *temp; /* The new string we return. */
int pass_next; /* State variables for the machine. */
pass_next = 0;
temp = (char *)xmalloc (strlen (string) + 1);
for (j = 0, i = 0; (c = string[i]) != '\0'; i++)
{
/* Process a character that was quoted by a backslash. */
if (pass_next)
{
/* Posix.2 sez:
``The backslash shall retain its special meaning as an escape
character only when followed by one of the characters:
$ ` " \ <newline>''. */
if (c != '$' && c != '`' && c != '"' && c != '\\' && c != '\n')
temp[j++] = '\\';
temp[j++] = c;
pass_next = 0;
continue;
}
/* A backslash protects the next character. The code just above
handles preserving the backslash in front of any character but
a double quote. */
if (c == '\\')
{
pass_next++;
continue;
}
/* An unescaped double quote serves to terminate the string. */
if (c == '"')
break;
/* Add the character to the quoted string we're accumulating. */
temp[j++] = c;
}
temp[j] = '\0';
strcpy (string, temp);
xfree (temp);
return (string);
}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199510311545.HAA17304>
