[comp.bugs.4bsd] Behavior of "define class from file" varies with SCANF +FIX

bruce@ogicse.ogc.edu (Bruce Jerrick) (12/15/89)

Description:
	The behavior of "Fxfile" definitions (in sendmail.cf) with no
	scanf format changes when readcf.c is compiled with SCANF
	(enable scanf formats).

	non-SCANF, no format:       enter all words from each line
	SCANF, no format            same as %s, enter first word only

	This is the case in sendmail 5.59, 5.61, and IDA 1.2.8 .  In
	fact, with the distributed IDA config files, all words in
	/usr/lib/uucp/L.sys are considered UUCP site names (Any, ACU, etc.!).

	A better, compatible solution is included below, which eliminates
	the need for defining SCANF for compilation.

Repeat-By:
	A typical scenario might be:

	Define UUCP sites in sendmail.cf:

	    FU/usr/lib/uucp/L.sys

	With SCANF not defined (when compiling readcf.c), any word in
	L.sys will be considered a valid UUCP site.  E.g., try mailing to
	"ACU!user".
	
	Then recompile with SCANF defined (affects readcf.c only), and
	only the real site names in L.sys will be valid.

	You may argue that "FU/usr/lib/uucp/L.sys %s" is the proper form,
	but to enable that, SCANF must be defined, and then the behavior
	of Fxfile lines without formats will change.  And, with SCANF
	defined, it's messy (at best) to intentionally read in all words
	of a file line.

Fix:
	The fix eliminates the SCANF compiler macro, and makes the default
	format be no format, not "%s" (the latter was only effective when
	compiled with SCANF, hence the behavior change).

	(Line numbers may vary; if you don't know that already, get some
	help).

***************
*** 38,45 ****
  **		Cxword		Put word into class x.
  **		Fxfile [fmt]	Read file for lines to put into
  **				class x.  Use scanf string 'fmt'
! **				or "%s" if not present.  Fmt should
! **				only produce one string-valued result.
  **		Hname: value	Define header with field-name 'name'
  **				and value as specified; this will be
  **				macro expanded immediately before
--- 38,46 ----
  **		Cxword		Put word into class x.
  **		Fxfile [fmt]	Read file for lines to put into
  **				class x.  Use scanf string 'fmt'
! **				if present; read all words in a line
! **				if not.  'fmt' must only produce one
! **				string-valued result.
  **		Hname: value	Define header with field-name 'name'
  **				and value as specified; this will be
  **				macro expanded immediately before
***************
*** 183,191 ****
  				/* read from file */
  				for (p = &buf[2]; *p != '\0' && !isspace(*p); p++)
  					continue;
! 				if (*p == '\0')
! 					p = "%s";
! 				else
  				{
  					*p = '\0';
  					while (isspace(*++p))
--- 184,190 ----
  				/* read from file */
  				for (p = &buf[2]; *p != '\0' && !isspace(*p); p++)
  					continue;
! 				if (*p != '\0')
  				{
  					*p = '\0';
  					while (isspace(*++p))
***************
*** 299,305 ****
  **	Parameters:
  **		class -- class to define.
  **		filename -- name of file to read.
! **		fmt -- scanf string to use for match.
  **
  **	Returns:
  **		none
--- 298,305 ----
  **	Parameters:
  **		class -- class to define.
  **		filename -- name of file to read.
! **		fmt -- scanf format string to use for match
! **			(may be null or empty).
  **
  **	Returns:
  **		none
***************
*** 306,313 ****
  **
  **	Side Effects:
  **
! **		puts all lines in filename that match a scanf into
! **			the named class.
  */
  
  fileclass(class, filename, fmt)
--- 306,314 ----
  **
  **	Side Effects:
  **
! **		breaks up lines in filename (those matching a scanf format
! **			'fmt', if present; otherwise all lines) into words
! **			and puts them into the named class.
  */
  
  fileclass(class, filename, fmt)
***************
*** 332,346 ****
  	{
  		register STAB *s;
  		register char *p;
- # ifdef SCANF
  		char wordbuf[MAXNAME+1];
  
! 		if (sscanf(buf, fmt, wordbuf) != 1)
! 			continue;
! 		p = wordbuf;
! # else SCANF
! 		p = buf;
! # endif SCANF
  
  		/*
  		**  Break up the match into words.
--- 333,348 ----
  	{
  		register STAB *s;
  		register char *p;
  		char wordbuf[MAXNAME+1];
  
! 		if (fmt != NULL && *fmt != '\0')
! 		{
! 			if (sscanf(buf, fmt, wordbuf) != 1)
! 				continue;
! 			p = wordbuf;
! 		}
! 		else
! 			p = buf;
  
  		/*
  		**  Break up the match into words.