17d8a9cc2Snia/*
27d8a9cc2Snia *       Copyright 1988 by Evans & Sutherland Computer Corporation,
37d8a9cc2Snia *                          Salt Lake City, Utah
47d8a9cc2Snia *  Portions Copyright 1989 by the Massachusetts Institute of Technology
57d8a9cc2Snia *                        Cambridge, Massachusetts
6645f5050Syouri *
77d8a9cc2Snia * Copyright 1992 Claude Lecommandeur.
8645f5050Syouri */
9645f5050Syouri
10645f5050Syouri/***********************************************************************
11645f5050Syouri *
12645f5050Syouri * $XConsortium: parse.c,v 1.52 91/07/12 09:59:37 dave Exp $
13645f5050Syouri *
14645f5050Syouri * parse the .twmrc file
15645f5050Syouri *
16645f5050Syouri * 17-Nov-87 Thomas E. LaStrange       File created
17645f5050Syouri * 10-Oct-90 David M. Sternlicht       Storing saved colors on root
18645f5050Syouri *
19645f5050Syouri * Do the necessary modification to be integrated in ctwm.
20645f5050Syouri * Can no longer be used for the standard twm.
21645f5050Syouri *
22645f5050Syouri * 22-April-92 Claude Lecommandeur.
23645f5050Syouri *
24645f5050Syouri ***********************************************************************/
25645f5050Syouri
267d8a9cc2Snia#include "ctwm.h"
277d8a9cc2Snia
28645f5050Syouri#include <stdio.h>
297d8a9cc2Snia#include <stdlib.h>
307d8a9cc2Snia#include <string.h>
317d8a9cc2Snia#include <strings.h>
327d8a9cc2Snia#ifdef USEM4
337d8a9cc2Snia# include <sys/types.h>
347d8a9cc2Snia# include <sys/wait.h>
35645f5050Syouri#endif
367d8a9cc2Snia
377d8a9cc2Snia#include "ctwm_atoms.h"
38645f5050Syouri#include "screen.h"
39645f5050Syouri#include "parse.h"
407d8a9cc2Snia#include "parse_int.h"
417d8a9cc2Snia#include "deftwmrc.h"
42645f5050Syouri#ifdef SOUNDS
43645f5050Syouri#  include "sound.h"
44645f5050Syouri#endif
45645f5050Syouri
467d8a9cc2Snia#ifndef SYSTEM_INIT_FILE
477d8a9cc2Snia#error "No SYSTEM_INIT_FILE set"
48645f5050Syouri#endif
49645f5050Syouri
507d8a9cc2Sniastatic bool ParseStringList(const char **sl);
51645f5050Syouri
527d8a9cc2Snia/*
537d8a9cc2Snia * With current bison, this is defined in the gram.tab.h, so this causes
547d8a9cc2Snia * a warning for redundant declaration.  With older bisons and byacc,
557d8a9cc2Snia * it's not, so taking it out causes a warning for implicit declaration.
567d8a9cc2Snia * A little looking around doesn't show any handy #define's we could use
577d8a9cc2Snia * to be sure of the difference.  This should quiet it down on gcc/clang
587d8a9cc2Snia * anyway...
597d8a9cc2Snia */
607d8a9cc2Snia#ifdef __GNUC__
617d8a9cc2Snia# pragma GCC diagnostic push
627d8a9cc2Snia# pragma GCC diagnostic ignored "-Wredundant-decls"
637d8a9cc2Sniaextern int yyparse(void);
647d8a9cc2Snia# pragma GCC diagnostic pop
65645f5050Syouri#else
66645f5050Syouriextern int yyparse(void);
677d8a9cc2Snia#endif
68645f5050Syouri
697d8a9cc2Snia// Because of how this winds up shared with callback funcs in the
707d8a9cc2Snia// parsing, it's difficult to unwind from being global, so just accept
717d8a9cc2Snia// it.
72645f5050Syouristatic FILE *twmrc;
737d8a9cc2Snia
74645f5050Syouristatic int ptr = 0;
75645f5050Syouristatic int len = 0;
767d8a9cc2Snia#define BUF_LEN 300
777d8a9cc2Sniastatic char buff[BUF_LEN + 1];
787d8a9cc2Sniastatic const char **stringListSource, *currentString;
797d8a9cc2Snia
807d8a9cc2Snia#ifdef NON_FLEX_LEX
817d8a9cc2Snia/*
827d8a9cc2Snia * While these are (were) referenced in a number of places through the
837d8a9cc2Snia * file, overflowlen is initialized to 0, only possibly changed in
847d8a9cc2Snia * twmUnput(), and unless it's non-zero, neither is otherwise touched.
857d8a9cc2Snia * So this is purely a twmUnput()-related var, and with flex, never used
867d8a9cc2Snia * for anything.
877d8a9cc2Snia */
887d8a9cc2Sniastatic char overflowbuff[20];           /* really only need one */
89645f5050Syouristatic int overflowlen;
90645f5050Syouri#endif
91645f5050Syouri
927d8a9cc2Sniaint ConstrainedMoveTime = 400;          /* milliseconds, event times */
937d8a9cc2Sniabool ParseError;                        /* error parsing the .twmrc file */
947d8a9cc2Sniaint RaiseDelay = 0;                     /* msec, for AutoRaise */
957d8a9cc2Sniaint (*twmInputFunc)(void);              /* used in lexer */
96645f5050Syouri
977d8a9cc2Sniastatic int twmrc_lineno;
98645f5050Syouri
997d8a9cc2Snia
1007d8a9cc2Snia/* Actual file loader */
1017d8a9cc2Sniastatic int ParseTwmrc(const char *filename);
1027d8a9cc2Snia
1037d8a9cc2Snia/* lex plumbing funcs */
1047d8a9cc2Sniastatic bool doparse(int (*ifunc)(void), const char *srctypename,
1057d8a9cc2Snia                    const char *srcname);
106645f5050Syouri
107645f5050Syouristatic int twmStringListInput(void);
108645f5050Syouri#ifndef USEM4
109645f5050Syouristatic int twmFileInput(void);
110645f5050Syouri#else
1117d8a9cc2Sniastatic int m4twmFileInput(void);
112645f5050Syouri#endif
113645f5050Syouri
1147d8a9cc2Snia#if defined(YYDEBUG) && YYDEBUG
1157d8a9cc2Sniaint yydebug = 1;
1167d8a9cc2Snia#endif
117645f5050Syouri
118645f5050Syouri
1197d8a9cc2Snia/**
1207d8a9cc2Snia * Principal entry point from top-level code to parse the config file.
1217d8a9cc2Snia * This tries the various permutations of config files we could load.
1227d8a9cc2Snia * For most possible names, we try loading `$NAME.$SCREENNUM` before
1237d8a9cc2Snia * trying `$NAME`.  If a `-f filename` is given on the command line, it's
1247d8a9cc2Snia * passed in here, and the normal `~/.[c]twmrc*` attempts are skipped if
1257d8a9cc2Snia * it's not found.
126645f5050Syouri *
1277d8a9cc2Snia * \param filename A filename given in the -f command-line argument (or
1287d8a9cc2Snia * NULL)
1297d8a9cc2Snia * \return true/false for whether a valid config was parsed out from
1307d8a9cc2Snia * somewhere.
131645f5050Syouri */
1327d8a9cc2Sniabool
1337d8a9cc2SniaLoadTwmrc(const char *filename)
134645f5050Syouri{
1357d8a9cc2Snia	int ret = -1;
1367d8a9cc2Snia	char *tryname = NULL;
1377d8a9cc2Snia
1387d8a9cc2Snia	/*
1397d8a9cc2Snia	 * Check for the twmrc file in the following order:
1407d8a9cc2Snia	 *   0.  -f filename.#
1417d8a9cc2Snia	 *   1.  -f filename
1427d8a9cc2Snia	 *       (skip to 6 if -f was given)
1437d8a9cc2Snia	 *   2.  .ctwmrc.#
1447d8a9cc2Snia	 *   3.  .ctwmrc
1457d8a9cc2Snia	 *   4.  .twmrc.#
1467d8a9cc2Snia	 *   5.  .twmrc
1477d8a9cc2Snia	 *   6.  system.ctwmrc
1487d8a9cc2Snia	 */
1497d8a9cc2Snia#define TRY(fn) if((ret = ParseTwmrc(fn)) != -1) { goto DONE_TRYING; }  (void)0
1507d8a9cc2Snia
1517d8a9cc2Snia	if(filename) {
1527d8a9cc2Snia		/* -f filename.# */
1537d8a9cc2Snia		asprintf(&tryname, "%s.%d", filename, Scr->screen);
1547d8a9cc2Snia		if(tryname == NULL) {
1557d8a9cc2Snia			// Oh, we're _screwed_...
1567d8a9cc2Snia			return false;
1577d8a9cc2Snia		}
1587d8a9cc2Snia		TRY(tryname);
159645f5050Syouri
1607d8a9cc2Snia		/* -f filename */
1617d8a9cc2Snia		TRY(filename);
162645f5050Syouri
1637d8a9cc2Snia		/* If we didn't get either from -f, don't try the ~ bits */
1647d8a9cc2Snia		goto TRY_FALLBACK;
1657d8a9cc2Snia	}
166645f5050Syouri
1677d8a9cc2Snia	if(Home) {
1687d8a9cc2Snia		/* ~/.ctwmrc.screennum */
1697d8a9cc2Snia		free(tryname);
1707d8a9cc2Snia		asprintf(&tryname, "%s/.ctwmrc.%d", Home, Scr->screen);
1717d8a9cc2Snia		if(tryname == NULL) {
1727d8a9cc2Snia			return false;
173645f5050Syouri		}
1747d8a9cc2Snia		TRY(tryname);
175645f5050Syouri
1767d8a9cc2Snia		// All later attempts are guaranteed shorter strings than that,
1777d8a9cc2Snia		// so we can just keep sprintf'ing over it.
178645f5050Syouri
1797d8a9cc2Snia		/* ~/.ctwmrc */
1807d8a9cc2Snia		sprintf(tryname, "%s/.ctwmrc", Home);
1817d8a9cc2Snia		TRY(tryname);
182645f5050Syouri
1837d8a9cc2Snia		/* ~/.twmrc.screennum */
1847d8a9cc2Snia		sprintf(tryname, "%s/.twmrc.%d", Home, Scr->screen);
1857d8a9cc2Snia		TRY(tryname);
186645f5050Syouri
1877d8a9cc2Snia		/* ~/.twmrc */
1887d8a9cc2Snia		sprintf(tryname, "%s/.twmrc", Home);
1897d8a9cc2Snia		TRY(tryname);
1907d8a9cc2Snia	}
191645f5050Syouri
1927d8a9cc2SniaTRY_FALLBACK:
1937d8a9cc2Snia	/* system.twmrc */
1947d8a9cc2Snia	if((ret = ParseTwmrc(SYSTEM_INIT_FILE)) != -1) {
1957d8a9cc2Snia		if(ret && filename) {
1967d8a9cc2Snia			// If we were -f'ing, fell back to the system default, and
1977d8a9cc2Snia			// that succeeeded, we warn.  It's "normal"(ish) to not have
1987d8a9cc2Snia			// a personal twmrc and fall back...
1997d8a9cc2Snia			fprintf(stderr,
2007d8a9cc2Snia			        "%s:  unable to open twmrc file %s, using %s instead\n",
2017d8a9cc2Snia			        ProgramName, filename, SYSTEM_INIT_FILE);
2027d8a9cc2Snia		}
2037d8a9cc2Snia		goto DONE_TRYING;
204645f5050Syouri	}
2057d8a9cc2Snia
2067d8a9cc2Snia
2077d8a9cc2SniaDONE_TRYING:
2087d8a9cc2Snia#undef TRY
2097d8a9cc2Snia	free(tryname);
2107d8a9cc2Snia
2117d8a9cc2Snia	/*
2127d8a9cc2Snia	 * If we wound up with -1 all the way, we totally failed to find a
2137d8a9cc2Snia	 * file to work with.  Fall back to builtin config.
2147d8a9cc2Snia	 */
2157d8a9cc2Snia	if(ret == -1) {
2167d8a9cc2Snia		// Only warn if -f.
2177d8a9cc2Snia		if(filename) {
2187d8a9cc2Snia			fprintf(stderr,
2197d8a9cc2Snia			        "%s:  unable to open twmrc file %s, using built-in defaults instead\n",
2207d8a9cc2Snia			        ProgramName, filename);
2217d8a9cc2Snia		}
2227d8a9cc2Snia		return ParseStringList(defTwmrc);
223645f5050Syouri	}
224645f5050Syouri
2257d8a9cc2Snia
2267d8a9cc2Snia	/* Better have a useful value in ret... */
2277d8a9cc2Snia	return ret;
228645f5050Syouri}
229645f5050Syouri
230645f5050Syouri
2317d8a9cc2Snia/**
2327d8a9cc2Snia * Try parsing a file as a ctwmrc.
233645f5050Syouri *
2347d8a9cc2Snia * \param filename The filename to try opening and parsing.
2357d8a9cc2Snia * \return -1,0,1.  0/1 should be treated as false/true for whether
2367d8a9cc2Snia * parsing the file succeeded.  -1 means the file couldn't be opened.
237645f5050Syouri */
2387d8a9cc2Sniastatic int
2397d8a9cc2SniaParseTwmrc(const char *filename)
2407d8a9cc2Snia{
2417d8a9cc2Snia	bool status;
242645f5050Syouri
2437d8a9cc2Snia#if 0
2447d8a9cc2Snia	fprintf(stderr, "%s(): Trying %s\n", __func__, filename);
2457d8a9cc2Snia#endif
246645f5050Syouri
2477d8a9cc2Snia	/* See if we can open the file */
2487d8a9cc2Snia	if(!filename) {
2497d8a9cc2Snia		return -1;
2507d8a9cc2Snia	}
2517d8a9cc2Snia	twmrc = fopen(filename, "r");
2527d8a9cc2Snia	if(!twmrc) {
2537d8a9cc2Snia		return -1;
2547d8a9cc2Snia	}
255645f5050Syouri
256645f5050Syouri
2577d8a9cc2Snia	/* Got it.  Kick off the parsing, however we do it. */
2587d8a9cc2Snia#ifdef USEM4
2597d8a9cc2Snia	FILE *raw = NULL;
2607d8a9cc2Snia	if(CLarg.GoThroughM4) {
2617d8a9cc2Snia		/*
2627d8a9cc2Snia		 * Hold onto raw filehandle so we can fclose() it below, and
2637d8a9cc2Snia		 * swap twmrc over to the output from m4
2647d8a9cc2Snia		 */
2657d8a9cc2Snia		raw = twmrc;
2667d8a9cc2Snia		twmrc = start_m4(raw);
267645f5050Syouri	}
2687d8a9cc2Snia	status = doparse(m4twmFileInput, "file", filename);
2697d8a9cc2Snia	fclose(twmrc);
2707d8a9cc2Snia	if(raw) {
2717d8a9cc2Snia		fclose(raw);
272645f5050Syouri	}
2737d8a9cc2Snia#else
2747d8a9cc2Snia	status = doparse(twmFileInput, "file", filename);
2757d8a9cc2Snia	fclose(twmrc);
2767d8a9cc2Snia#endif
277645f5050Syouri
2787d8a9cc2Snia	/* And we're done */
2797d8a9cc2Snia	return status;
280645f5050Syouri
2817d8a9cc2Snia	/* NOTREACHED */
282645f5050Syouri}
283645f5050Syouri
2847d8a9cc2Sniastatic bool
2857d8a9cc2SniaParseStringList(const char **sl)
286645f5050Syouri{
2877d8a9cc2Snia	stringListSource = sl;
2887d8a9cc2Snia	currentString = *sl;
2897d8a9cc2Snia	return doparse(twmStringListInput, "string list", NULL);
290645f5050Syouri}
291645f5050Syouri
292645f5050Syouri
2937d8a9cc2Snia/*
2947d8a9cc2Snia * Util used throughout the code (possibly often wrongly?)
295645f5050Syouri */
2967d8a9cc2Sniavoid twmrc_error_prefix(void)
297645f5050Syouri{
2987d8a9cc2Snia	fprintf(stderr, "%s:  line %d:  ", ProgramName, twmrc_lineno);
299645f5050Syouri}
300645f5050Syouri
301645f5050Syouri
302645f5050Syouri
303645f5050Syouri/*
3047d8a9cc2Snia * Everything below here is related to plumbing and firing off lex/yacc
305645f5050Syouri */
306645f5050Syouri
307645f5050Syouri
308645f5050Syouri/*
3097d8a9cc2Snia * Backend func that takes an input-providing func and hooks it up to the
3107d8a9cc2Snia * lex/yacc parser to do the work
311645f5050Syouri */
3127d8a9cc2Sniastatic bool
3137d8a9cc2Sniadoparse(int (*ifunc)(void), const char *srctypename,
3147d8a9cc2Snia        const char *srcname)
315645f5050Syouri{
3167d8a9cc2Snia	ptr = 0;
3177d8a9cc2Snia	len = 0;
3187d8a9cc2Snia	twmrc_lineno = 0;
3197d8a9cc2Snia	ParseError = false;
3207d8a9cc2Snia	twmInputFunc = ifunc;
3217d8a9cc2Snia#ifdef NON_FLEX_LEX
3227d8a9cc2Snia	overflowlen = 0;
3237d8a9cc2Snia#endif
324645f5050Syouri
3257d8a9cc2Snia	yyparse();
326645f5050Syouri
3277d8a9cc2Snia	if(ParseError) {
3287d8a9cc2Snia		fprintf(stderr, "%s:  errors found in twm %s",
3297d8a9cc2Snia		        ProgramName, srctypename);
3307d8a9cc2Snia		if(srcname) {
3317d8a9cc2Snia			fprintf(stderr, " \"%s\"", srcname);
3327d8a9cc2Snia		}
3337d8a9cc2Snia		fprintf(stderr, "\n");
3347d8a9cc2Snia	}
3357d8a9cc2Snia	return !(ParseError);
3367d8a9cc2Snia}
337645f5050Syouri
338645f5050Syouri
3397d8a9cc2Snia/*
3407d8a9cc2Snia * Various input routines for the lexer for the various sources of
3417d8a9cc2Snia * config.
3427d8a9cc2Snia */
343645f5050Syouri
3447d8a9cc2Snia#ifndef USEM4
3457d8a9cc2Snia#include <ctype.h>
346645f5050Syouri
3477d8a9cc2Snia/* This has Tom's include() funtionality.  This is utterly useless if you
3487d8a9cc2Snia * can use m4 for the same thing.               Chris P. Ross */
349645f5050Syouri
3507d8a9cc2Snia#define MAX_INCLUDES 10
351645f5050Syouri
3527d8a9cc2Sniastatic struct incl {
3537d8a9cc2Snia	FILE *fp;
3547d8a9cc2Snia	char *name;
3557d8a9cc2Snia	int lineno;
3567d8a9cc2Snia} rc_includes[MAX_INCLUDES];
3577d8a9cc2Sniastatic int include_file = 0;
358645f5050Syouri
359645f5050Syouri
3607d8a9cc2Sniastatic int twmFileInput(void)
361645f5050Syouri{
3627d8a9cc2Snia#ifdef NON_FLEX_LEX
3637d8a9cc2Snia	if(overflowlen) {
3647d8a9cc2Snia		return (int) overflowbuff[--overflowlen];
365645f5050Syouri	}
366645f5050Syouri#endif
3677d8a9cc2Snia
3687d8a9cc2Snia	while(ptr == len) {
3697d8a9cc2Snia		while(include_file) {
3707d8a9cc2Snia			if(fgets(buff, BUF_LEN, rc_includes[include_file].fp) == NULL) {
3717d8a9cc2Snia				free(rc_includes[include_file].name);
3727d8a9cc2Snia				fclose(rc_includes[include_file].fp);
3737d8a9cc2Snia				twmrc_lineno = rc_includes[include_file--].lineno;
3747d8a9cc2Snia			}
3757d8a9cc2Snia			else {
3767d8a9cc2Snia				break;
3777d8a9cc2Snia			}
3787d8a9cc2Snia		}
3797d8a9cc2Snia
3807d8a9cc2Snia		if(!include_file)
3817d8a9cc2Snia			if(fgets(buff, BUF_LEN, twmrc) == NULL) {
3827d8a9cc2Snia				return 0;
3837d8a9cc2Snia			}
3847d8a9cc2Snia		twmrc_lineno++;
3857d8a9cc2Snia
3867d8a9cc2Snia		if(strncmp(buff, "include", 7) == 0) {
3877d8a9cc2Snia			/* Whoops, an include file! */
3887d8a9cc2Snia			char *p = buff + 7, *q;
3897d8a9cc2Snia			FILE *fp;
3907d8a9cc2Snia
3917d8a9cc2Snia			while(isspace(*p)) {
3927d8a9cc2Snia				p++;
3937d8a9cc2Snia			}
3947d8a9cc2Snia			for(q = p; *q && !isspace(*q); q++) {
3957d8a9cc2Snia				continue;
3967d8a9cc2Snia			}
3977d8a9cc2Snia			*q = 0;
3987d8a9cc2Snia
3997d8a9cc2Snia			if((fp = fopen(p, "r")) == NULL) {
4007d8a9cc2Snia				fprintf(stderr, "%s: Unable to open included init file %s\n",
4017d8a9cc2Snia				        ProgramName, p);
4027d8a9cc2Snia				continue;
4037d8a9cc2Snia			}
4047d8a9cc2Snia			if(++include_file >= MAX_INCLUDES) {
4057d8a9cc2Snia				fprintf(stderr, "%s: init file includes nested too deep\n",
4067d8a9cc2Snia				        ProgramName);
4077d8a9cc2Snia				continue;
4087d8a9cc2Snia			}
4097d8a9cc2Snia			rc_includes[include_file].fp = fp;
4107d8a9cc2Snia			rc_includes[include_file].lineno = twmrc_lineno;
4117d8a9cc2Snia			twmrc_lineno = 0;
4127d8a9cc2Snia			rc_includes[include_file].name = strdup(p);
4137d8a9cc2Snia			continue;
4147d8a9cc2Snia		}
4157d8a9cc2Snia		ptr = 0;
4167d8a9cc2Snia		len = strlen(buff);
417645f5050Syouri	}
4187d8a9cc2Snia	return ((int)buff[ptr++]);
419645f5050Syouri}
4207d8a9cc2Snia#else /* USEM4 */
4217d8a9cc2Snia/* If you're going to use m4, use this version instead.  Much simpler.
4227d8a9cc2Snia * m4 ism's credit to Josh Osborne (stripes) */
423645f5050Syouri
4247d8a9cc2Sniastatic int m4twmFileInput(void)
425645f5050Syouri{
4267d8a9cc2Snia	int line;
4277d8a9cc2Snia	static FILE *cp = NULL;
4287d8a9cc2Snia
4297d8a9cc2Snia	if(cp == NULL && CLarg.keepM4_filename) {
4307d8a9cc2Snia		cp = fopen(CLarg.keepM4_filename, "w");
4317d8a9cc2Snia		if(cp == NULL) {
4327d8a9cc2Snia			fprintf(stderr,
4337d8a9cc2Snia			        "%s:  unable to create m4 output %s, ignoring\n",
4347d8a9cc2Snia			        ProgramName, CLarg.keepM4_filename);
4357d8a9cc2Snia			CLarg.keepM4_filename = NULL;
4367d8a9cc2Snia		}
437645f5050Syouri	}
438645f5050Syouri
4397d8a9cc2Snia#ifdef NON_FLEX_LEX
4407d8a9cc2Snia	if(overflowlen) {
4417d8a9cc2Snia		return((int) overflowbuff[--overflowlen]);
442645f5050Syouri	}
443645f5050Syouri#endif
444645f5050Syouri
4457d8a9cc2Snia	while(ptr == len) {
4467d8a9cc2Snianextline:
4477d8a9cc2Snia		if(fgets(buff, BUF_LEN, twmrc) == NULL) {
4487d8a9cc2Snia			if(cp) {
4497d8a9cc2Snia				fclose(cp);
4507d8a9cc2Snia			}
4517d8a9cc2Snia			return(0);
4527d8a9cc2Snia		}
4537d8a9cc2Snia		if(cp) {
4547d8a9cc2Snia			fputs(buff, cp);
4557d8a9cc2Snia		}
456645f5050Syouri
4577d8a9cc2Snia		if(sscanf(buff, "#line %d", &line)) {
4587d8a9cc2Snia			twmrc_lineno = line - 1;
4597d8a9cc2Snia			goto nextline;
4607d8a9cc2Snia		}
4617d8a9cc2Snia		else {
4627d8a9cc2Snia			twmrc_lineno++;
4637d8a9cc2Snia		}
464645f5050Syouri
4657d8a9cc2Snia		ptr = 0;
4667d8a9cc2Snia		len = strlen(buff);
467645f5050Syouri	}
4687d8a9cc2Snia	return ((int)buff[ptr++]);
469645f5050Syouri}
4707d8a9cc2Snia#endif /* USEM4 */
471645f5050Syouri
472645f5050Syouri
4737d8a9cc2Sniastatic int twmStringListInput(void)
474645f5050Syouri{
4757d8a9cc2Snia#ifdef NON_FLEX_LEX
4767d8a9cc2Snia	if(overflowlen) {
4777d8a9cc2Snia		return (int) overflowbuff[--overflowlen];
4787d8a9cc2Snia	}
4797d8a9cc2Snia#endif
480645f5050Syouri
4817d8a9cc2Snia	/*
4827d8a9cc2Snia	 * return the character currently pointed to
4837d8a9cc2Snia	 */
4847d8a9cc2Snia	if(currentString) {
4857d8a9cc2Snia		unsigned int c = (unsigned int) * currentString++;
486645f5050Syouri
4877d8a9cc2Snia		if(c) {
4887d8a9cc2Snia			return c;        /* if non-nul char */
4897d8a9cc2Snia		}
4907d8a9cc2Snia		currentString = *++stringListSource;  /* advance to next bol */
4917d8a9cc2Snia		return '\n';                    /* but say that we hit last eol */
4927d8a9cc2Snia	}
4937d8a9cc2Snia	return 0;                           /* eof */
494645f5050Syouri}
495645f5050Syouri
496645f5050Syouri
497645f5050Syouri
498645f5050Syouri/*
4997d8a9cc2Snia * unput/output funcs for AT&T lex.  No longer supported, and expected to
5007d8a9cc2Snia * be GC'd in a release or two.
501645f5050Syouri */
5027d8a9cc2Snia#ifdef NON_FLEX_LEX
503645f5050Syouri
5047d8a9cc2Sniavoid twmUnput(int c)
505645f5050Syouri{
5067d8a9cc2Snia	if(overflowlen < sizeof overflowbuff) {
5077d8a9cc2Snia		overflowbuff[overflowlen++] = (char) c;
508645f5050Syouri	}
5097d8a9cc2Snia	else {
5107d8a9cc2Snia		twmrc_error_prefix();
5117d8a9cc2Snia		fprintf(stderr, "unable to unput character (%c)\n",
5127d8a9cc2Snia		        c);
513fb81d040Schristos	}
514645f5050Syouri}
515645f5050Syouri
5167d8a9cc2Sniavoid TwmOutput(int c)
517645f5050Syouri{
5187d8a9cc2Snia	putchar(c);
519645f5050Syouri}
520645f5050Syouri
5217d8a9cc2Snia#endif /* NON_FLEX_LEX */
522