Skip site navigation (1)Skip section navigation (2)
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>