/* "p2c", a Pascal to C translator.
   Copyright (C) 1989 David Gillespie.
   Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125.

This program 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 (any version).

This program 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 this program; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

#define PROTO_LEX1_C
#include "trans.h"

/* Define LEXDEBUG for a token trace */
#define LEXDEBUG

#define EOFMARK 1

Static char dollar_flag;
Static char lex_initialized;
Static int if_flag;
Static int if_skip;
Static int commenting_flag;
Static char *commenting_ptr;
Static int skipflag;
Static char modulenotation;
Static short inputkind;
Static Strlist *instrlist;
Static char inbuf[300];
Static char *oldinfname;
Static char *oldctxname;
Static Strlist *endnotelist;

#define INP_FILE     0
#define INP_INCFILE  1
#define INP_STRLIST  2

Static struct inprec {
    struct inprec *next;
    short kind;
    char *fname, *inbufptr;
    int lnum;
    FILE *filep;
    Strlist *strlistp, *tempopts;
    Token curtok, saveblockkind;
    Symbol *curtoksym;
    Meaning *curtokmeaning;
} *topinput;

char *fixpascalname(name)
char *name;
{
    char *cp, *cp2;

    if (pascalsignif > 0) {
        name = format_ds("%.*s", pascalsignif, name);
        if (!pascalcasesens)
            upc(name);
	else if (pascalcasesens == 3)
	    lwc(name);
    } else if (!pascalcasesens)
        name = strupper(name);
    else if (pascalcasesens == 3)
	name = strlower(name);
    if (ignorenonalpha) {
	for (cp = cp2 = name; *cp; cp++)
	    if (isalnum(*cp))
		*cp2++ = *cp;
    }
    return name;
}



Static void makekeyword(name)
char *name;
{
    Symbol *sym;

    if (*name) {
        sym = findsymbol(name);
        sym->flags |= AVOIDNAME;
    }
}


Static void makeglobword(name)
char *name;
{
    Symbol *sym;

    if (*name) {
        sym = findsymbol(name);
        sym->flags |= AVOIDGLOB;
    }
}



Static void makekeywords()
{
    makekeyword("auto");
    makekeyword("break");
    makekeyword("char");
    makekeyword("continue");
    makekeyword("default");
    makekeyword("defined");   /* is this one really necessary? */
    makekeyword("double");
    makekeyword("enum");
    makekeyword("extern");
    makekeyword("float");
    makekeyword("int");
    makekeyword("long");
    makekeyword("noalias");
    makekeyword("register");
    makekeyword("return");
    makekeyword("short");
    makekeyword("signed");
    makekeyword("sizeof");
    makekeyword("static");
    makekeyword("struct");
    makekeyword("switch");
    makekeyword("typedef");
    makekeyword("union");
    makekeyword("unsigned");
    makekeyword("void");
    makekeyword("volatile");
    makekeyword("asm");
    makekeyword("fortran");
    makekeyword("entry");
    makekeyword("pascal");
    if (cplus != 0) {
        makekeyword("class");
        makekeyword("delete");
        makekeyword("friend");
        makekeyword("inline");
        makekeyword("new");
        makekeyword("operator");
        makekeyword("overload");
        makekeyword("public");
        makekeyword("this");
        makekeyword("virtual");
    }
    makekeyword(name_UCHAR);
    makekeyword(name_SCHAR);    /* any others? */
    makekeyword(name_BOOLEAN);
    makekeyword(name_PROCEDURE);
    makekeyword(name_ESCAPE);
    makekeyword(name_ESCIO);
    makekeyword(name_CHKIO);
    makekeyword(name_SETIO);
    makeglobword("main");
    makeglobword("vextern");     /* used in generated .h files */
    makeglobword("argc");
    makeglobword("argv");
    makekeyword("TRY");
    makekeyword("RECOVER");
    makekeyword("RECOVER2");
    makekeyword("ENDTRY");
}



Static Symbol *Pkeyword(name, tok)
char *name;
Token tok;
{
    Symbol *sp = NULL;

    if (pascalcasesens != 2) {
	sp = findsymbol(strlower(name));
	sp->kwtok = tok;
    }
    if (pascalcasesens != 3) {
	sp = findsymbol(strupper(name));
	sp->kwtok = tok;
    }
    return sp;
}


Static Symbol *Pkeywordposs(name, tok)
char *name;
Token tok;
{
    Symbol *sp = NULL;

    if (pascalcasesens != 2) {
	sp = findsymbol(strlower(name));
	sp->kwtok = tok;
	sp->flags |= KWPOSS;
    }
    if (pascalcasesens != 3) {
	sp = findsymbol(strupper(name));
	sp->kwtok = tok;
	sp->flags |= KWPOSS;
    }
    return sp;
}


Static void makePascalwords()
{
    Pkeyword("AND", TOK_AND);
    Pkeyword("ARRAY", TOK_ARRAY);
    Pkeywordposs("ANYVAR", TOK_ANYVAR);
    Pkeywordposs("ABSOLUTE", TOK_ABSOLUTE);
    Pkeyword("BEGIN", TOK_BEGIN);
    Pkeywordposs("BY", TOK_BY);
    Pkeyword("CASE", TOK_CASE);
    Pkeyword("CONST", TOK_CONST);
    Pkeyword("DIV", TOK_DIV);
    Pkeywordposs("DEFINITION", TOK_DEFINITION);
    Pkeyword("DO", TOK_DO);
    Pkeyword("DOWNTO", TOK_DOWNTO);
    Pkeyword("ELSE", TOK_ELSE);
    Pkeywordposs("ELSIF", TOK_ELSIF);
    Pkeyword("END", TOK_END);
    Pkeywordposs("EXPORT", TOK_EXPORT);
    Pkeyword("FILE", TOK_FILE);
    Pkeyword("FOR", TOK_FOR);
    Pkeywordposs("FROM", TOK_FROM);
    Pkeyword("FUNCTION", TOK_FUNCTION);
    Pkeyword("GOTO", TOK_GOTO);
    Pkeyword("IF", TOK_IF);
    Pkeywordposs("IMPLEMENT", TOK_IMPLEMENT);
    Pkeywordposs("IMPLEMENTATION", TOK_IMPLEMENT);
    Pkeywordposs("IMPORT", TOK_IMPORT);
    Pkeyword("IN", TOK_IN);
    Pkeywordposs("INLINE", TOK_INLINE);
    Pkeywordposs("INTERFACE", TOK_EXPORT);
    Pkeywordposs("INTERRUPT", TOK_INTERRUPT);
    Pkeyword("LABEL", TOK_LABEL);
    Pkeywordposs("LOOP", TOK_LOOP);
    Pkeyword("MOD", TOK_MOD);
    Pkeywordposs("MODULE", TOK_MODULE);
    Pkeyword("NIL", TOK_NIL);
    Pkeyword("NOT", TOK_NOT);
    Pkeyword("OF", TOK_OF);
    Pkeyword("OR", TOK_OR);
    Pkeywordposs("ORIGIN", TOK_ORIGIN);
    Pkeywordposs("OTHERWISE", TOK_OTHERWISE);
    Pkeywordposs("OVERLAY", TOK_SEGMENT);
    Pkeyword("PACKED", TOK_PACKED);
    Pkeywordposs("POINTER", TOK_POINTER);
    Pkeyword("PROCEDURE", TOK_PROCEDURE);
    Pkeyword("PROGRAM", TOK_PROGRAM);
    Pkeywordposs("QUALIFIED", TOK_QUALIFIED);
    Pkeyword("RECORD", TOK_RECORD);
    Pkeywordposs("RECOVER", TOK_RECOVER);
    Pkeywordposs("REM", TOK_REM);
    Pkeyword("REPEAT", TOK_REPEAT);
    Pkeywordposs("RETURN", TOK_RETURN);
    if (which_lang == LANG_UCSD)
	Pkeyword("SEGMENT", TOK_SEGMENT);
    else
	Pkeywordposs("SEGMENT", TOK_SEGMENT);
    Pkeyword("SET", TOK_SET);
    Pkeywordposs("SHL", TOK_SHL);
    Pkeywordposs("SHR", TOK_SHR);
    Pkeyword("THEN", TOK_THEN);
    Pkeyword("TO", TOK_TO);
    Pkeywordposs("TRY", TOK_TRY);
    Pkeyword("TYPE", TOK_TYPE);
    Pkeyword("UNTIL", TOK_UNTIL);
    Pkeywordposs("USES", TOK_IMPORT);
    Pkeywordposs("UNIT", TOK_MODULE);
    if (which_lang == LANG_VAX)
	Pkeyword("VALUE", TOK_VALUE);
    else
	Pkeywordposs("VALUE", TOK_VALUE);
    Pkeyword("VAR", TOK_VAR);
    Pkeywordposs("VARYING", TOK_VARYING);
    Pkeyword("WHILE", TOK_WHILE);
    Pkeyword("WITH", TOK_WITH);
    Pkeywordposs("XOR", TOK_XOR);
    Pkeyword("__MODULE", TOK_MODULE);
    Pkeyword("__IMPORT", TOK_IMPORT);
    Pkeyword("__EXPORT", TOK_EXPORT);
    Pkeyword("__IMPLEMENT", TOK_IMPLEMENT);
}



Static void deterministic(name)
char *name;
{
    Symbol *sym;

    if (*name) {
        sym = findsymbol(name);
        sym->flags |= DETERMF;
    }
}


Static void nosideeff(name)
char *name;
{
    Symbol *sym;

    if (*name) {
        sym = findsymbol(name);
        sym->flags |= NOSIDEEFF;
    }
}



Static void recordsideeffects()
{
    deterministic("abs");
    deterministic("acos");
    deterministic("asin");
    deterministic("atan");
    deterministic("atan2");
    deterministic("atof");
    deterministic("atoi");
    deterministic("atol");
    deterministic("ceil");
    deterministic("cos");
    deterministic("cosh");
    deterministic("exp");
    deterministic("fabs");
    deterministic("feof");
    deterministic("feoln");
    deterministic("ferror");
    deterministic("floor");
    deterministic("fmod");
    deterministic("ftell");
    deterministic("isalnum");
    deterministic("isalpha");
    deterministic("isdigit");
    deterministic("islower");
    deterministic("isspace");
    deterministic("isupper");
    deterministic("labs");
    deterministic("ldexp");
    deterministic("log");
    deterministic("log10");
    deterministic("memcmp");
    deterministic("memchr");
    deterministic("pow");
    deterministic("sin");
    deterministic("sinh");
    deterministic("sqrt");
    deterministic("strchr");
    deterministic("strcmp");
    deterministic("strcspn");
    deterministic("strlen");
    deterministic("strncmp");
    deterministic("strpbrk");
    deterministic("strrchr");
    deterministic("strspn");
    deterministic("strstr");
    deterministic("tan");
    deterministic("tanh");
    deterministic("tolower");
    deterministic("toupper");
    deterministic(setequalname);
    deterministic(subsetname);
    deterministic(signextname);
}





void init_lex()
{
    int i;

    inputkind = INP_FILE;
    inf_lnum = 0;
    inf_ltotal = 0;
    *inbuf = 0;
    inbufptr = inbuf;
    keepingstrlist = NULL;
    tempoptionlist = NULL;
    switch_strpos = 0;
    dollar_flag = 0;
    if_flag = 0;
    if_skip = 0;
    commenting_flag = 0;
    skipflag = 0;
    inbufindent = 0;
    modulenotation = 1;
    notephase = 0;
    endnotelist = NULL;
    for (i = 0; i < SYMHASHSIZE; i++)
        symtab[i] = 0;
    C_lex = 0;
    lex_initialized = 0;
}


void setup_lex()
{
    lex_initialized = 1;
    if (!strcmp(language, "MODCAL"))
        sysprog_flag = 2;
    else
        sysprog_flag = 0;
    if (shortcircuit < 0)
        partial_eval_flag = (which_lang == LANG_TURBO ||
			     which_lang == LANG_VAX ||
			     which_lang == LANG_OREGON ||
			     modula2 ||
			     hpux_lang);
    else
        partial_eval_flag = shortcircuit;
    iocheck_flag = 1;
    range_flag = 1;
    ovflcheck_flag = 1;
    stackcheck_flag = 1;
    fixedflag = 0;
    withlevel = 0;
    makekeywords();
    makePascalwords();
    recordsideeffects();
    topinput = 0;
    ignore_directives = 0;
    skipping_module = 0;
    blockkind = TOK_END;
    gettok();
}




int checkeatnote(msg)
char *msg;
{
    Strlist *lp;
    char *cp;
    int len;

    for (lp = eatnotes; lp; lp = lp->next) {
	if (!strcmp(lp->s, "1")) {
	    echoword("[*]", 0);
	    return 1;
	}
	if (!strcmp(lp->s, "0"))
	    return 0;
	len = strlen(lp->s);
	cp = msg;
	while (*cp && (*cp != lp->s[0] || strncmp(cp, lp->s, len)))
	    cp++;
	if (*cp) {
	    cp = lp->s;
	    if (*cp != '[')
		cp = format_s("[%s", cp);
	    if (cp[strlen(cp)-1] != ']')
		cp = format_s("%s]", cp);
	    echoword(cp, 0);
	    return 1;
	}
    }
    return 0;
}



void beginerror()
{
    end_source();
    if (showprogress) {
        fprintf(stderr, "\r%60s\r", "");
        clearprogress();
    } else
	echobreak();
}


void counterror()
{
    if (maxerrors > 0) {
	if (--maxerrors == 0) {
	    fprintf(outf, "\n/* Translation aborted: Too many errors. */\n");
	    fprintf(outf,   "-------------------------------------------\n");
	    if (outf != stdout)
		printf("Translation aborted: Too many errors.\n");
	    if (verbose)
		fprintf(logf, "Translation aborted: Too many errors.\n");
	    closelogfile();
	    exit(EXIT_FAILURE);
	}
    }
}


void error(msg)     /* does not return */
char *msg;
{
    flushcomments(NULL, -1, -1);
    beginerror();
    fprintf(outf, "/* %s, line %d: %s */\n", infname, inf_lnum, msg);
    fprintf(outf, "/* Translation aborted. */\n");
    fprintf(outf, "--------------------------\n");
    if (outf != stdout) {
        printf("%s, line %d/%d: %s\n", infname, inf_lnum, outf_lnum, msg);
        printf("Translation aborted.\n");
    }
    if (verbose) {
	fprintf(logf, "%s, line %d/%d: %s\n",
		infname, inf_lnum, outf_lnum, msg);
	fprintf(logf, "Translation aborted.\n");
    }
    closelogfile();
    exit(EXIT_FAILURE);
}


void interror(proc, msg)      /* does not return */
char *proc, *msg;
{
    error(format_ss("Internal error in %s: %s", proc, msg));
}


void warning(msg)
char *msg;
{
    if (checkeatnote(msg)) {
	if (verbose)
	    fprintf(logf, "%s, %d/%d: Omitted warning: %s\n",
		    infname, inf_lnum, outf_lnum, msg);
	return;
    }
    beginerror();
    addnote(format_s("Warning: %s", msg), curserial);
    counterror();
}


void intwarning(proc, msg)
char *proc, *msg;
{
    if (checkeatnote(msg)) {
	if (verbose)
	    fprintf(logf, "%s, %d/%d: Omitted internal error in %s: %s\n",
		    infname, inf_lnum, outf_lnum, proc, msg);
	return;
    }
    beginerror();
    addnote(format_ss("Internal error in %s: %s", proc, msg), curserial);
    if (error_crash)
        exit(EXIT_FAILURE);
    counterror();
}




void note(msg)
char *msg;
{
    if (blockkind == TOK_IMPORT || checkeatnote(msg)) {
	if (verbose)
	    fprintf(logf, "%s, %d/%d: Omitted note: %s\n",
		    infname, inf_lnum, outf_lnum, msg);
	return;
    }
    beginerror();
    addnote(format_s("Note: %s", msg), curserial);
    counterror();
}



void endnote(msg)
char *msg;
{
    if (blockkind == TOK_IMPORT || checkeatnote(msg)) {
	if (verbose)
	    fprintf(logf, "%s, %d/%d: Omitted end-note: %s\n",
		    infname, inf_lnum, outf_lnum, msg);
	return;
    }
    if (verbose)
	fprintf(logf, "%s, %d/%d: Recorded end-note: %s\n",
		infname, inf_lnum, outf_lnum, msg);
    (void) strlist_add(&endnotelist, msg);
}


void showendnotes()
{
    while (initialcalls) {
	if (initialcalls->value)
	    endnote(format_s("Remember to call %s in main program [215]",
			     initialcalls->s));
	strlist_eat(&initialcalls);
    }
    if (endnotelist) {
	end_source();
	while (endnotelist) {
	    if (outf != stdout) {
		beginerror();
		printf("Note: %s\n", endnotelist->s);
	    }
	    fprintf(outf, "/* p2c: Note: %s */\n", endnotelist->s);
	    outf_lnum++;
	    strlist_eat(&endnotelist);
	}
    }
}







char *tok_name(tok)
Token tok;
{
    if (tok == TOK_END && inputkind == INP_STRLIST)
	return "end of macro";
    if (tok == curtok && tok == TOK_IDENT)
        return format_s("'%s'", curtokcase);
    if (!modulenotation) {
        switch (tok) {
            case TOK_MODULE:    return "UNIT";
            case TOK_IMPORT:    return "USES";
            case TOK_EXPORT:    return "INTERFACE";
            case TOK_IMPLEMENT: return "IMPLEMENTATION";
	    default:		break;
        }
    }
    return toknames[(int) tok];
}



void expected(msg)
char *msg;
{
    error(format_ss("Expected %s, found %s", msg, tok_name(curtok)));
}


void expecttok(tok)
Token tok;
{
    if (curtok != tok)
        expected(tok_name(tok));
}


void needtok(tok)
Token tok;
{
    if (curtok != tok)
        expected(tok_name(tok));
    gettok();
}


int wexpected(msg)
char *msg;
{
    warning(format_ss("Expected %s, found %s [227]", msg, tok_name(curtok)));
    return 0;
}


int wexpecttok(tok)
Token tok;
{
    if (curtok != tok)
        return wexpected(tok_name(tok));
    else
	return 1;
}


int wneedtok(tok)
Token tok;
{
    if (wexpecttok(tok)) {
	gettok();
	return 1;
    } else
	return 0;
}


void alreadydef(sym)
Symbol *sym;
{
    warning(format_s("Symbol '%s' was already defined [220]", sym->name));
}


void undefsym(sym)
Symbol *sym;
{
    warning(format_s("Symbol '%s' is not defined [221]", sym->name));
}


void symclass(sym)
Symbol *sym;
{
    warning(format_s("Symbol '%s' is not of the appropriate class [222]", sym->name));
}


void badtypes()
{
    warning("Type mismatch [223]");
}


void valrange()
{
    warning("Value range error [224]");
}



void skipparens()
{
    Token begintok;

    if (curtok == TOK_LPAR) {
        gettok();
        while (curtok != TOK_RPAR)
            skipparens();
    } else if (curtok == TOK_LBR) {
        gettok();
        while (curtok != TOK_RBR)
            skipparens();
    } else if (curtok == TOK_BEGIN || curtok == TOK_RECORD ||
	       curtok == TOK_CASE) {
	begintok = curtok;
        gettok();
        while (curtok != TOK_END)
	    if (curtok == TOK_CASE && begintok == TOK_RECORD)
		gettok();
	    else
		skipparens();
    }
    gettok();
}


void skiptotoken2(tok1, tok2)
Token tok1, tok2;
{
    while (curtok != tok1 && curtok != tok2 &&
	   curtok != TOK_END && curtok != TOK_RPAR &&
	   curtok != TOK_RBR && curtok != TOK_EOF)
	skipparens();
}


void skippasttoken2(tok1, tok2)
Token tok1, tok2;
{
    skiptotoken2(tok1, tok2);
    if (curtok == tok1 || curtok == tok2)
	gettok();
}


void skippasttotoken(tok1, tok2)
Token tok1, tok2;
{
    skiptotoken2(tok1, tok2);
    if (curtok == tok1)
	gettok();
}


void skiptotoken(tok)
Token tok;
{
    skiptotoken2(tok, tok);
}


void skippasttoken(tok)
Token tok;
{
    skippasttoken2(tok, tok);
}



int skipopenparen()
{
    if (wneedtok(TOK_LPAR))
	return 1;
    skiptotoken(TOK_SEMI);
    return 0;
}


int skipcloseparen()
{
    if (curtok == TOK_COMMA)
	warning("Too many arguments for built-in routine [225]");
    else
	if (wneedtok(TOK_RPAR))
	    return 1;
    skippasttotoken(TOK_RPAR, TOK_SEMI);
    return 0;
}


int skipcomma()
{
    if (curtok == TOK_RPAR)
	warning("Too few arguments for built-in routine [226]");
    else
	if (wneedtok(TOK_COMMA))
	    return 1;
    skippasttotoken(TOK_RPAR, TOK_SEMI);
    return 0;
}





char *findaltname(name, num)
char *name;
int num;
{
    char *cp;

    if (num <= 0)
        return name;
    if (num == 1 && *alternatename1)
        return format_s(alternatename1, name);
    if (num == 2 && *alternatename2)
        return format_s(alternatename2, name);
    if (*alternatename)
        return format_sd(alternatename, name, num);
    cp = name;
    if (*alternatename1) {
        while (--num >= 0)
	    cp = format_s(alternatename1, cp);
    } else {
	while (--num >= 0)
	    cp = format_s("%s_", cp);
    }
    return cp;
}

Symbol *findsymbol_opt(name)
char *name;
{
    int i;
    unsigned int hash;
    char *cp;
    Symbol *sp;

    hash = 0;
    for (cp = name; *cp; cp++)
        hash = hash*3 + *cp;
    sp = symtab[hash % SYMHASHSIZE];
    while (sp && (i = strcmp(sp->name, name)) != 0) {
        if (i < 0)
            sp = sp->left;
        else
            sp = sp->right;
    }
    return sp;
}

Symbol *findsymbol(name)
char *name;
{
    int i;
    unsigned int hash;
    char *cp;
    Symbol **prev;
    Symbol *sp;

    hash = 0;
    for (cp = name; *cp; cp++)
        hash = hash*3 + *cp;
    prev = symtab + (hash % SYMHASHSIZE);
    while ((sp = *prev) != 0 &&
           (i = strcmp(sp->name, name)) != 0) {
        if (i < 0)
            prev = &(sp->left);
        else
            prev = &(sp->right);
    }
    if (!sp) {
        sp = ALLOCV(sizeof(Symbol) + strlen(name), Symbol, symbols);
        sp->mbase = sp->fbase = NULL;
        sp->left = sp->right = NULL;
        strcpy(sp->name, name);
        sp->flags = 0;
	sp->kwtok = TOK_NONE;
        sp->symbolnames = NULL;
        *prev = sp;
    }
    return sp;
}

void clearprogress()
{
    oldinfname = NULL;
}


void progress()
{
    char *ctxname;
    int needrefr;
    static int prevlen;

    if (showprogress) {
        if (!curctx || curctx == nullctx || curctx->kind == MK_MODULE ||
            !strncmp(curctx->name, "__PROCPTR", 9) || blockkind == TOK_IMPORT)
            ctxname = "";
        else
            ctxname = curctx->name;
        needrefr = (inf_lnum & 15) == 0;
        if (oldinfname != infname || oldctxname != ctxname) {
	    if (oldinfname != infname)
		prevlen = 60;
            fprintf(stderr, "\r%*s", prevlen + 2, "");
            oldinfname = infname;
            oldctxname = ctxname;
            needrefr = 1;
        }
        if (needrefr) {
            fprintf(stderr, "\r%5d %s  %s", inf_lnum, infname, ctxname);
	    prevlen = 8 + strlen(infname) + strlen(ctxname);
        } else {
            fprintf(stderr, "\r%5d", inf_lnum);
	    prevlen = 5;
	}
    }
}



void getline()
{
    char *cp, *cp2;

    switch (inputkind) {

        case INP_FILE:
        case INP_INCFILE:
            inf_lnum++;
	    inf_ltotal++;
            if (fgets(inbuf, 300, inf)) {
                cp = inbuf + strlen(inbuf);
                if (*inbuf && cp[-1] == '\n')
                    cp[-1] = 0;
		if (inbuf[0] == '#' && inbuf[1] == ' ' && isdigit(inbuf[2])) {
		    cp = inbuf + 2;    /* in case input text came */
		    inf_lnum = 0;      /*  from the C preprocessor */
		    while (isdigit(*cp))
			inf_lnum = inf_lnum*10 + (*cp++) - '0';
		    inf_lnum--;
		    while (isspace(*cp)) cp++;
		    if (*cp == '"' && (cp2 = my_strchr(cp+1, '"')) != NULL) {
			cp++;
			infname = stralloc(cp);
			infname[cp2 - cp] = 0;
		    }
		    getline();
		    return;
		}
		if (copysource && *inbuf) {
		    start_source();
		    fprintf(outf, "%s\n", inbuf);
		}
                if (keepingstrlist) {
                    strlist_append(keepingstrlist, inbuf)->value = inf_lnum;
                }
                if (showprogress && inf_lnum % showprogress == 0)
                    progress();
            } else {
                if (showprogress)
                    fprintf(stderr, "\n");
                if (inputkind == INP_INCFILE) {
                    pop_input();
                    getline();
                } else
                    strcpy(inbuf, "\001");
            }
            break;

        case INP_STRLIST:
            if (instrlist) {
                strcpy(inbuf, instrlist->s);
                if (instrlist->value)
                    inf_lnum = instrlist->value;
                else
                    inf_lnum++;
                instrlist = instrlist->next;
            } else
                strcpy(inbuf, "\001");
            break;
    }
    inbufptr = inbuf;
    inbufindent = 0;
}

