/* TODO:

   ---- HIGHEST PRIORITY ----

   * #ifndef

   * #if/#elif - Bearbeitung

   * leere argument-/tokenlists erlauben

   * Anzahl der Argumente checken (auch zuviele ergeben einen Error)

   * bei REDEFINING und allowredefinition=0 tokenlist genau ueberpruefen

   * Aufteilen in mehrere Sourcen main.c pplists.c etc.
   * Einige Variablen umbenennen (x,y,i,j,l,n etc =8)

   -----------------------------------------------------------------

   * Verbesserungen:
   * - Nach malloc()/vor free() ueberpruefen ob NULL-Pointer
   * - Statt per dlen per Ptr2EOL abfragen..

   * Fragen an Volker:
   * - _ alleine ein Identifier ? Ja

   ---- LOWEST PRIORITY ----

   * - Token loeschen, wenn nur noch TokenList benutzt wird.

   * - ParseIdent.. optimieren

   * - Rest optimieren =8)

   * - PreParsing umschreiben.. __LINE__ muss mit der echten
   *    Zeilennummer uebereinstimmen (die LFs drinlassen)
 */

/*
 * PreProcessor
 * $VER: VBPP V0.00 (19 Sep 1995)
 * (w) 1995 by Thorsten Schaaps
 */

#include <time.h>

#include "vbc.h"
#include "vbpp.h"

/*vb:   */
static char FILE_[]=__FILE__;

/*vb:   */
char pp_version[] = "vbpp V0.00 (w) 1995 by Thorsten Schaaps";

                                /* #define MAXIFNESTING 1024 *//*vb: ifnesting==incnesting */

FILE *in[MAXINCNESTING];        /*  Sourcefiles     */
int zn[MAXINCNESTING];          /*  Zeilennummern   */
char *filenames[MAXINCNESTING];  /*  Filenamen   */
int incnesting;                 /*  aktuelle Verschachtelungstiefe  */
unsigned long linenr;           /*  Zeilennummer */

char *incpath[MAXINCPATHS] =
{"vinclude:"};                  /*  Includepfade    */

int incpathc = 1;               /*  Anzahl der Includepfade     */

char ppstring[MAXPPINPUT];

int cmtnesting = 0;             /*  aktuelle Kommentar-Versch.-Tiefe */

                                          /*int ifnesting; *//*vb: *//*  aktuelle IF-Tiefe */
/*vb: ifnesting==incnesting */
short ifstatus[MAXINCNESTING];  /* Array fuer Status-Verschachtelung */
int if_cnt;                     /* Zaehler fuer #if's waehrend do_output=0 */
int abs_if_cnt;                 /* zaehlt auch waehrend do_output */

int do_output = 1;              /* Flag zur Erzeugung eines Outputs */

struct strnode *strlist;

struct mnode *mlist;

int did_expand;

/* Temporaere Debugging-Routinen */
void PrintSN(struct strnode *tl)
{
    switch (tl->type) {
    case NORMAL:
        printf(" Normal........:");
        break;
    case PP_IDENT:
        printf(" Identifier....:");
        break;
    case ARGUMENT:
        printf(" Argument Nr.%2d:", tl->number);
        break;
    case NUMBER:
        printf(" Number........:");
        break;
    case PP_STR:
        printf(" String........:");
        break;
    case SPACE:
        printf(" Space.........:");
        break;
    case SPECIAL:
        printf(" Special..Nr.%2d:", tl->flags);
        break;
    default:
        printf(" unknown..Nr.%2d:", tl->type);
        break;
    }
    printf(" %s\n", tl->str);
}
void PrintTL(struct strnode *tl)
{

#ifdef bla

    if (tl) {
        printf("TokenList:\n");
        while (tl) {
            PrintSN(tl);
            tl = tl->next;
        }
    }
#endif

}


/* ******* Listen-Funktionen ******* */

/* AddMakroNode - Fuegt eine Node an den Anfang einer Liste ein */
void AddMakroNode(struct mnode **list, struct mnode *node)
{

    if (DEBUG & 32)
        puts("AddMakroNode");

    if (node) {
        node->prev = NULL;
        node->next = *list;
        *list = node;
        if (node->next)
            node->next->prev = node;
    }
}


/* AddStrNode - Fuegt eine Node in die Liste ein */
void AddStrNode(struct strnode **list, struct strnode *node, char *str)
{

    if (DEBUG & 32)
        puts("AddStrNode");


    if (node || str) {
        if (!node)
            node = (struct strnode *) malloc(sizeof(struct strnode));
        /* HIER: Rueckgabewert wegen Fehler ! */
        if (!node) {
            error(196);
        } else {
            node->prev = NULL;
            node->next = *list;
            if (str)
                node->str = str;
            *list = node;
            if (node->next)
                node->next->prev = node;
        }
    }
}


/* AddStrNodeBehind - Fuegt eine Node ans Ende der Liste ein */
void AddStrNodeBehind(struct strnode **list, struct strnode *node, char *str)
{
    struct strnode *listnode;

    if (DEBUG & 32)
        puts("AddStrNodeBehind");


    if (node || str) {
        if (!node)
            node = (struct strnode *) malloc(sizeof(struct strnode));
        if (!node) {
            error(196);
        } else {
            if (!*list) {
                node->prev = NULL;
                node->next = NULL;
                *list = node;
            } else {
                listnode = *list;
                while (listnode->next) {
                    listnode = listnode->next;
                }
                node->prev = listnode;
                node->next = NULL;
                listnode->next = node;
            }
            if (str)
                node->str = str;
        }
    }
}


/* RemMakroNode - Entfernt eine Node aus der Liste ohne sie zu loeschen */
void RemMakroNode(struct mnode **list, struct mnode *node)
{

    if (DEBUG & 32)
        puts("RemMakroNode");


    if (node->prev) {
        if (node->next)
            node->next->prev = node->prev;
        node->prev->next = node->next;
    } else {
        if (node->next)
            node->next->prev = NULL;
        *list = node->next;
    }
    node->next = node->prev = NULL;
}

/* InsertMakroNode - Setzt eine Node hinter einer anderen ein */
void InsertMakroNode(struct mnode **list, struct mnode *node, struct mnode *behind)
{

    if (DEBUG & 32)
        puts("InsertMakroNode");


    if (behind) {
        node->prev = behind;
        node->next = behind->next;
        behind->next = node;
        if (node->next)
            node->next->prev = node;
    } else
        AddMakroNode(list, node);
}

/* RemStrNode - Entfernt eine Node aus der Liste ohne sie zu loeschen */
void RemStrNode(struct strnode **list, struct strnode *node)
{

    if (DEBUG & 32)
        puts("RemStrNode");


    if (node->prev) {
        if (node->next)
            node->next->prev = node->prev;
        node->prev->next = node->next;
    } else {
        if (node->next)
            node->next->prev = NULL;
        *list = node->next;
    }
    node->next = node->prev = NULL;
}


/* FindMakroNode - sucht den passenden Eintrag in der Liste
 *                 len=0 - der gesamte String muss uebereinstimmen
 *                 len>0 - die ersten len Zeichen muessen stimmen
 */
struct mnode *FindMakroNode(struct mnode *list, char *str, int len)
{

    if (DEBUG & 32)
        puts("FindMakroNode");

    while (list) {
        if (len) {
            if ((strlen(list->name) == len) && (!strncmp(list->name, str, len)))
                return (list);
        } else {
            if (!strcmp(list->name, str))
                return (list);
        }
        list = list->next;
    }
    return (0);
}


/* DelMakroNode - gibt den gesamten Speicher einer Node frei, ist list#NULL
 *                wird die Node vorher aus der Liste entfernt
 */
void DelMakroNode(struct mnode **list, struct mnode *node)
{

    if (DEBUG & 32)
        puts("DelMakroNode");


    if (node) {
        if (list && *list)
            RemMakroNode(list, node);
        if (node->name)
            free(node->name);
        if (node->args)
            free(node->args);
        if (node->token)
            free(node->token);
        if (node->tokenlist)
            DelStrList(&node->tokenlist);
        free(node);
    }
}


/* DelStrNode - gibt den gesamten Speicher einer Node frei, ist list#NULL
 *              wird die Node vorher aus der Liste entfernt
 */
void DelStrNode(struct strnode **list, struct strnode *node)
{

    if (DEBUG & 32)
        puts("DelStrNode");


    if (node) {
        if (list && *list)
            RemStrNode(list, node);
        if (node->str)
            free(node->str);
        free(node);
    }
}

void MergeStrNodes(struct strnode *prev, struct strnode *next)
{
    /* next will now be deleted and prev->str will be */
    /* the joined strings from prev&next */
    char *newstr;
/*vb:   */
    char c, *s, *d;

    if (DEBUG & 32)
        puts("MergeStrNodes");


    newstr = (char *) malloc(prev->len + next->len + 1);
/*vb: string-Routinen ersetzt (hoffentlich schneller)
   strcpy(newstr,prev->str);
   strcat(newstr,next->str);
 */
    d = newstr;
    s = prev->str;
    do {
        c = *s++;
        *d++ = c;
    } while (c);
    d--;
    s = next->str;
    do {
        c = *s++;
        *d++ = c;
    } while (c);

    if (prev->str)
        free(prev->str);        /*vb: wenn prev->str==0 knallts doch schon oben? */
    prev->str = newstr;
    prev->len += next->len;
    DelStrNode(NULL, next);
}

/* DelMakroList - loescht eine gesamte Liste */
void DelMakroList(struct mnode **list)
{

    if (DEBUG & 32)
        puts("DelMakroList");


    while (*list)
        DelMakroNode(list, *list);
    /*  *list=NULL; *//*vb: *list==0 */
}


/* DelStrList - loescht eine gesamte Liste samt der Nodes/Strings */
void DelStrList(struct strnode **list)
{

    if (DEBUG & 32)
        puts("DelStrList");


    while (*list)
        DelStrNode(list, *list);
    /*  *list=NULL; *//*vb: *list==0 */
}

/* AllocSpace - erzeugt eine StrNode vom Typ Space */
struct strnode *AllocSpace()
{
    struct strnode *newnode;
    char *newstr;


    if (DEBUG & 32)
        puts("AllocSpace");


    newstr = (char *) malloc(2);
    if (newstr) {
        newstr[0] = ' ';
        newstr[1] = 0;
        newnode = (struct strnode *) malloc(sizeof(struct strnode));
        if (newnode) {
            newnode->str = newstr;
            newnode->type = SPACE;
            newnode->len = 1;
            newnode->next = newnode->prev = NULL;
            newnode->flags = newnode->number = 0;
            return (newnode);
        }
    }
    return (NULL);
}


/* CloneStrList - erstellt eine exakte Kopie der Liste oder eines Ausschnittes */
/*                wenn listend#NULL */
struct strnode *CloneStrList(struct strnode *list, struct strnode *listend)
{
    struct strnode *prevnode = NULL, *newnode, *newlist = NULL;
    char *newstr;

    if (DEBUG & 32)
        puts("CloneStrList");


    while (list) {
        newnode = (struct strnode *) malloc(sizeof(struct strnode));
        if (!newnode) {
            DelStrList(&newlist);
            return (NULL);
        }
        newstr = (char *) malloc(list->len + 1);
        if (!newstr) {
            free(newnode);
            DelStrList(&newlist);
            return (NULL);
        }
        strcpy(newstr, list->str);
        newnode->str = newstr;
        newnode->len = list->len;
        newnode->flags = list->flags;
        newnode->type = list->type;
        newnode->number = list->number;
        newnode->next = NULL;
        newnode->prev = prevnode;

        if (prevnode)
            prevnode->next = newnode;
        else
            newlist = newnode;
        prevnode = newnode;

        if (listend && list == listend)
            list = NULL;
        else
            list = list->next;
    }
    return (newlist);
}


/* DoMakroFunction - erstellt eine StrList entsprechend des Function-Makros */
struct strnode *DoMakroFunction(struct mnode *makro)
{
    struct strnode *result = NULL;
    char *newstr = NULL, *timestr = NULL;
    int len, type;
    time_t timevalue;

    if (DEBUG & 32)
        puts("DoMakroFunction");


    if (makro->flags & FUNCTION) {
        switch (makro->funcnum) {
        case FUNCLINE:
            newstr = (char *) malloc(11);
            if (!newstr)
                return (NULL);
            sprintf(newstr, "%lu", linenr);
            len = strlen(newstr);
            type = NUMBER;
            break;
        case FUNCFILE:
            len = strlen(filenames[incnesting]);
            newstr = (char *) malloc(len + 1 + 2);
            if (!newstr)
                return (NULL);
            *newstr = '\"';
            strcpy((newstr + 1), filenames[incnesting]);
            strcat(newstr, "\"");
            type = PP_STR;
            break;
        case FUNCDATE:
            type = PP_STR;
            newstr = (char *) malloc(14);
            if (!newstr)
                return (NULL);
            timevalue = time(0);
            timestr = ctime(&timevalue);
            newstr[0] = '\"';
            strncpy(newstr + 1, timestr + 4, 7);        /* copy 'Mmm dd ' */
            strcpy(newstr + 8, timestr + 20);   /* copy 'yyyy' */
            newstr[12] = '\"';
            newstr[13] = 0;
            len = 13;
            break;
        case FUNCTIME:
            type = PP_STR;
            newstr = (char *) malloc(11);
            if (!newstr)
                return (NULL);
            timevalue = time(0);
            timestr = ctime(&timevalue);
            newstr[0] = '\"';
            strncpy(newstr + 1, timestr + 11, 8);       /* copy 'hh:mm:ss' */
            newstr[9] = '\"';
            newstr[10] = 0;
            len = 10;
            break;
        default:
            return (NULL);
            break;
        }
        result = (struct strnode *) malloc(sizeof(struct strnode));
        if (!result) {
            if (newstr)
                free(newstr);
            return (NULL);
        }
        result->prev = result->next = NULL;
        result->str = newstr;
        result->len = len;
        result->number = result->flags = 0;
        result->type = type;
    }
    return (result);
}


/* *******  String-Funktionen ****** */

/* Str2List - parsed einen String in eine StrList */
struct strnode *Str2List(char *str)
{
    struct strnode *newlist = NULL, *newnode = NULL;
    char *temp, *string;
    int length, type, flags;

    if (DEBUG & 32)
        puts("Str2List");

    while (*str) {
        flags = 0;
/*vb: casts eingefuegt   */
        if (isspace((unsigned char) *str)) {    /* Spaces parsen */
            temp = str + 1;
            length = 1;
            while (*temp && isspace((unsigned char) *temp)) {
                temp++;
                length++;
            }
            type = SPACE;
        } else if (*str == '\"') {      /* String parsen */
            temp = str + 1;
            length = 2;
            while (*temp && *temp != '\"')
                if (*temp == '\\') {
                    temp += 2;
                    length += 2;
                } else {
                    temp++;
                    length++;
                }
            type = PP_STR;
        } else if (*str == '\'') {      /* String parsen */
            temp = str + 1;
            length = 2;
            while (*temp && *temp != '\'')
                if (*temp == '\\') {
                    temp += 2;
                    length += 2;
                } else {
                    temp++;
                    length++;
                }
            type = PP_STR;
        } else if (isdigit((unsigned char) *str) || (*str == '.' && isdigit((unsigned char) *(str + 1)))) {
            /* Zahlen parsen */
            temp = str;
            length = 0;
            while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
                temp++;
                length++;
            }
            if (*temp == '.') {
                temp++;
                length++;
                if (isdigit((unsigned char) *temp) || *temp == 'e' || *temp == 'E')
                    while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
                        temp++;
                        length++;
                    }
            }
            if (*(temp - 1) == 'e' || *(temp - 1) == 'E')
                if (isdigit((unsigned char) *temp) || *temp == '+' || *temp == '-') {
                    temp++;
                    length++;
                    while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
                        temp++;
                        length++;
                    }
                }
            type = NUMBER;
        } else if (isalpha((unsigned char) *str) || *str == '_') {      /* moegl. Identifier parsen */
            temp = str + 1;
            length = 1;
            while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
                temp++;
                length++;
            }
            type = PP_IDENT;
        } else if (*str) {      /* alles andere als einzelne Zeichen */
            length = 1;
            type = NORMAL;
        }
        string = (char *) malloc(length + 1);
        if (!string) {
            error(196);
            DelStrList(&newlist);
            return (NULL);
        }
        strncpy(string, str, length);
        string[length] = 0;
        str += length;

        newnode = (struct strnode *) malloc(sizeof(struct strnode));
        if (!newnode) {
            error(196);
            if (string)
                free(string);
            return (NULL);
        }
        newnode->str = string;
        newnode->len = length;
        newnode->flags = flags;
        newnode->type = type;

        AddStrNodeBehind(&newlist, newnode, NULL);
    }
    return (newlist);
}

/* List2Str - schreibt eine Liste als String zurueck */
int List2Str(struct strnode *list, char *str, int maxchars)
{
    int len = 0;
    char c, *p;

    if (DEBUG & 32)
        puts("List2Str");


    *str = 0;
    if (list) {
        while (list) {
            if ((len + (list->len)) > (maxchars - 1)) {
                error(177);
                return (0);
            } else {
                /*vb:   */
                p = list->str;
                do {
                    c = *p++;
                    *str++ = c;
                } while (c);
                str--;
/*        strcat(str,list->str); */
                len += list->len;
            }
            list = list->next;
        }
        return (len + 1);
    } else {
        *str = 0;
        return (1);
    }
}

/* ListLen - ermittelt die Laenge einer Str-Liste (in Zeichen) */
int ListLen(struct strnode *list)
{
    int len = 0;
    while (list) {
        len += list->len;
        list = list->next;
    }
    return (len);
}

/* ListStrLen - ermittelt die Laenge einer Str-List als String   */
/*              d.h. mit " am Anfang und Ende, sowie einem \ vor */
/*              jedem \ und "                                    */
int ListStrLen(struct strnode *list)
{
    int len = 2;
    while (list) {
        if (list->type == SPACE)
            len++;
        else {
            len += list->len;
            if (list->type == PP_STR && list->str[0] == '\"')
                len += 2;
            else if (list->type == NORMAL && list->str[0] == '\\')
                len++;
        }
        list = list->next;
    }
    return (len);
}

/* CopyList2StrStr - kopiert eine Str-List als String um         */
/*              d.h. mit " am Anfang und Ende, sowie einem \ vor */
/*              jedem \ und "                                    */
CopyList2StrStr(struct strnode * list, char *str)
{
    int len;

    if (DEBUG & 32)
        puts("CopyList2StrStr");


    str[0] = 0;
    if (list) {
        strcpy(str, "\"");
        len = 1;
        while (list) {
            if (list->type == SPACE) {
                len++;
                strcat(str, " ");
            } else {
                len += list->len;
                if (list->type == PP_STR && list->str[0] == '\"') {
                    strcat(str, "\\");
                    strncat(str, list->str, list->len - 1);
                    strcat(str, "\\\"");
                } else if (list->type == NORMAL && list->str[0] == '\\') {
                    strcat(str, "\\");
                    strcat(str, list->str);
                } else
                    strcat(str, list->str);
            }
            list = list->next;
        }
        strcat(str, "\"");
        len++;
    }
    return (len);
}

/* NextToSpecial - checked, ob die StrNode neben einem # oder ## steht */
int NextToSpecial(struct strnode *node)
{
    struct strnode *search;

    if (DEBUG & 32)
        puts("NextToSpecial");


    if (node->prev) {
        search = node->prev;
        while (search && search->type == SPACE)
            search = search->prev;
        if (search && search->type == SPECIAL)
            return (search->flags);
    }
    if (node->next) {
        search = node->next;
        while (search && search->type == SPACE)
            search = search->next;
        /* Hinter der Node ist ein # (ToString) ohne Bedeutung */
        if (search && search->type == SPECIAL
            && search->flags == KILLSPACES)
            return (KILLSPACES);
    }
    return (NONE);
}

/* FindBracket - sucht das passende Gegenstueck zu der (, auf die Node zeigt */
/*               dabei werden verschachtelte Klammern beachtet               */
struct strnode *FindBracket(struct strnode *node)
{

    if (DEBUG & 32)
        puts("FindBracket");


    if (node && node->next && node->type == NORMAL && node->str[0] == '(') {
        do {
            node = node->next;
            if (node && node->type == NORMAL) {
                if (node->str[0] == ')')
                    return (node);
                if (node->str[0] == '(')
                    node = FindBracket(node);
            }
        } while (node);
        return (NULL);
    } else
        return (NULL);
}

/* CloneArg - gibt eine Liste zurueck, die das n. Argument des Makros enthaelt */
struct strnode *CloneArg(struct strnode *list, int n, int *error)
{
    int argnum = 0;
    struct strnode *start;

    if (error)
        *error = OK;

    if (list) {
        if (DEBUG & 32)
            printf("CloneArg\n");
        if (list->type == PP_IDENT)
            list = list->next;
        while (list && list->type == SPACE)
            list = list->next;

        if (list && list->type == NORMAL && list->str[0] == '(') {
            list = list->next;  /* Skip ( */

            if (DEBUG & 32)
                printf("- IDENT skipped, ( found\n");

            while (list && (argnum < n)) {
                if (list->type == NORMAL) {
                    if (list->str[0] == ')')
                        list = NULL;
                    if (list && list->str[0] == '(')
                        list = (FindBracket(list))->next;
                    if (list && list->str[0] == ',')
                        argnum++;
                }
                if (list)
                    list = list->next;
            }

            while (list && list->type == SPACE)
                list = list->next;

            if (list) {
                if (list->type == NORMAL && (list->str[0] == ')' || list->str[0] == ',')) {     /* HIER evtl. ein Space erzeugen */
                    return (NULL);
                }
                start = list;
            } else {
                if (error)
                    *error = ARG_EXPECTED;
                return (NULL);
            }

            if (DEBUG & 32)
                printf("- Okay, Arg-Start found: %s\n", start->str);

            while (list && (argnum == n)) {
                if (list->type == NORMAL) {
                    switch (list->str[0]) {
                    case ')':
                    case ',':
                        argnum++;
                        list = list->prev;
                        break;
                    case '(':
                        list = FindBracket(list);
                    default:
                        if (list)
                            list = list->next;
                        break;
                    }
                } else if (list)
                    list = list->next;
            }

            while (list && list->type == SPACE)
                list = list->prev;

            if (DEBUG & 32)
                printf("- Okay, Arg-End found: %s\n", list->str);
            return (CloneStrList(start, list));

        } else {
            if (error)
                *error = ARG_EXPECTED;
            return (NULL);
        }
    } else
        return (NULL);
}

/* ExpandArgMakro - ersetzt ein Makro mit Argumenten */
int ExpandArgMakro(struct mnode *makro, struct strnode **list,
                   struct strnode **pos)
{
    struct strnode *clone, *temp, *temp1, *arg, *new;
    struct strnode *prev, *next;
    struct mnode *prevmakro;
    char *newstr;
    int spec, len, x;

    clone = CloneStrList(makro->tokenlist, NULL);
    if (!clone)
        return (OUT_OF_MEM);

    if (DEBUG & 32)
        printf("ExpandArgMakro - Clone build.\n");

    temp = clone;
    while (temp) {
        if (temp->type == ARGUMENT) {
            arg = CloneArg(*pos, temp->number, &x);
            if (!arg) {
                DelStrList(&clone);
                return (x);
            }
            if (DEBUG & 32) {
                printf("ARGUMENT:\n");
                PrintTL(arg);
                printf("Argument found - ");
            }
            if (spec = NextToSpecial(temp)) {
                /* nicht expandieren, nur einsetzen */
                if (spec == TOSTRING) {

                    if (DEBUG & 32)
                        printf("next to #\n");
                    /* als String einsetzen */
                    new = (struct strnode *) malloc(sizeof(struct strnode));
                    if (!new) {
                        DelStrList(&clone);
                        DelStrList(&arg);
                        return (OUT_OF_MEM);
                    }
                    len = ListStrLen(arg);
                    newstr = (char *) malloc(len + 1);
                    if (!newstr) {
                        DelStrList(&clone);
                        DelStrList(&arg);
                        if (new)
                            free(new);
                        return (OUT_OF_MEM);
                    }
                    CopyList2StrStr(arg, newstr);
                    DelStrList(&arg);
                    new->len = len + 2;
                    new->flags = new->number = 0;
                    new->type = PP_STR;
                    new->str = newstr;

                    prev = temp->prev;
                    next = temp->next;
                    DelStrNode(NULL, temp);     /* Argument */

                    while (prev && prev->type == SPACE) {
                        temp = prev->prev;
                        DelStrNode(&clone, prev);
                        prev = temp;
                    }

                    if (prev && prev->type == SPECIAL && prev->flags == TOSTRING) {
                        temp = prev->prev;
                        DelStrNode(&clone, prev);
                        prev = temp;
                    } else
                        ierror(0);

                    new->prev = prev;
                    if (prev)
                        prev->next = new;
                    else
                        clone = new;
                    new->next = next;
                    if (next)
                        next->prev = new;
                    temp = new;
                } else {
                    /* Einfach nur einsetzen */
                    if (DEBUG & 32)
                        printf("next to ##\n");
                    prev = temp->prev;
                    next = temp->next;
                    DelStrNode(NULL, temp);
                    arg->prev = prev;
                    if (prev)
                        prev->next = arg;
                    else
                        clone = arg;
                    while (arg->next)
                        arg = arg->next;
                    arg->next = next;
                    if (next)
                        next->prev = arg;
                    temp = arg;
                }
            } else {
                /* expandieren und einsetzen */
                if (DEBUG & 32)
                    printf("normal arg\n");
                if (x = ExpandList(&arg)) {
                    DelStrList(&clone);
                    DelStrList(&arg);
                    return (x);
                }
                if (DEBUG & 32) {
                    printf("expanded arg:\n");
                    PrintTL(arg);
                }
                prev = temp->prev;
                next = temp->next;
                DelStrNode(NULL, temp);
                arg->prev = prev;
                if (prev)
                    prev->next = arg;
                else
                    clone = arg;
                while (arg->next)
                    arg = arg->next;
                arg->next = next;
                if (next)
                    next->prev = arg;
                temp = arg;
            }                   /* of N2Special */
        }
        if (temp)
            temp = temp->next;
    }

    if (DEBUG & 32)
        printf("Arguments expanded.\n");

    temp = clone;
    while (temp) {
        if (temp->type == SPECIAL && temp->flags == KILLSPACES) {
            prev = temp->prev;
            next = temp->next;
            if ((prev->type == PP_IDENT || prev->type == NUMBER)) {
                switch (next->type) {
                case NUMBER:    /* merge -> ident */
                case PP_IDENT:
                    RemStrNode(&clone, next);
                    MergeStrNodes(prev, next);
                    next = temp->next;
                    /* next will now be deleted and prev->str will be */
                    /* the joined strings from prev&next */
                default:        /* no merge / del ## */
                    DelStrNode(&clone, temp);
                    temp = next;
                    break;
                }               /* of switch */
            } else {
                DelStrNode(&clone, temp);
                temp = next;
            }
        }
        if (temp)
            temp = temp->next;
    }

    /* 'makro' aus mlist ausklinken */
    prevmakro = makro->prev;
    RemMakroNode(&mlist, makro);

    /* alles expandieren */
    if (!(x = ExpandList(&clone))) {
        /* akt. StrNode durch clone-Liste ersetzen */

        if (DEBUG & 32) {
            printf("Complete Makro expanded\n");
            PrintTL(clone);
        }
        /* clone anstelle von pos in list einsetzen */
        prev = (*pos)->prev;
        next = (*pos)->next;

        DelStrNode(NULL, *pos);

#ifdef bla
        while (next && next->type == SPACE) {
            temp = next->next;
            DelStrNode(NULL, next);     /* SPACE zwischen Makro und Args loeschen */
            next = temp;
        }
#endif
        while (next && next->type == SPACE)
            next = next->next;
        /* SPACE hinter Makro ueberspringen */

        if (next && next->type == NORMAL && next->str[0] == '(') {
            temp = next;
            next = FindBracket(temp);
            if (next)
                next = next->next;
            do {
                temp1 = temp->next;
                DelStrNode(NULL, temp);         /* ARG-List hinter Makro loeschen */
                temp = temp1;
            } while (temp != next);
        } else {
            ierror(0);
        }


        /* vor clone ein SPACE einsetzen, wenn nicht PREV==SPACE */
/*vb:   hier !prev|| wegen Enforcerhit eingesetzt; waere prev&& besser? */
        if (!prev || prev->type != SPACE) {
            if (temp = AllocSpace()) {
                temp->next = clone;
                if (clone)
                    clone->prev = temp;
                clone = temp;
            }
        }
        clone->prev = prev;
        if (prev)
            prev->next = clone;
        else
            *list = clone;

        while (clone->next)
            clone = clone->next;
        /* nach clone ein SPACE einsetzen, wenn nicht NEXT==SPACE */
/*vb:   hier !next|| wegen Enforcerhit eingesetzt; waere next&& besser? */
        if (!next || next->type != SPACE) {
            if (temp = AllocSpace()) {
                temp->prev = clone;
                if (clone)
                    clone->next = temp;
                clone = temp;
            }
        }
        *pos = clone;
        clone->next = next;
        if (next)
            next->prev = clone;

        /* 'makro' wieder einsetzen */
        InsertMakroNode(&mlist, makro, prevmakro);
        return (OK);
    } else {
        InsertMakroNode(&mlist, makro, prevmakro);
        return (x);
    }

}

/* ExpandList - ersetzt alle Makros in der Liste */
int ExpandList(struct strnode **list)
{
    struct mnode *found, *before;
    struct strnode *clone, *beforestr, *afterstr, *listtemp, *temp2,
    *temp3;
    int result = OK;

    if (DEBUG & 32)
        puts("ExpandList");


    listtemp = *list;
    while (listtemp) {

        if (listtemp->type == PP_IDENT) {

            found = FindMakroNode(mlist, listtemp->str, 0);
            if (found) {
/*vb: merken, ob mind. ein Makro expandiert wurde   */
                did_expand = 1;
                if (found->flags & PARAMETER) {
                    /* Makro mit Argument(en) */
                    if (DEBUG & 32)
                        printf("Makro with args\n");

                    temp2 = listtemp->next;
                    while (temp2 && temp2->type == SPACE)
                        temp2 = temp2->next;

                    if (temp2 && temp2->type == NORMAL && temp2->str[0] == '(')
                        if (result = ExpandArgMakro(found, list, &listtemp))
                            return (result);

                } else {

                    /* Makro ohne Argument */

                    /* ExpandNormMakro - expandiert ein Makro ohne Argumente */
                    /* Parameter: s.o. */

                    if (found->flags & FUNCTION) {
                        clone = DoMakroFunction(found);
                    } else {
                        clone = CloneStrList(found->tokenlist, NULL);
                    }
                    if (!clone)
                        return (OUT_OF_MEM);
                    /* akt. MakroNode ausklinken um rekursive Exp. zu verhindern */
                    before = found->prev;
                    RemMakroNode(&mlist, found);
                    if (!(result = ExpandList(&clone))) {
                        /* akt. StrNode durch clone-Liste ersetzen */
                        beforestr = listtemp->prev;
                        afterstr = listtemp->next;
                        DelStrNode(NULL, listtemp);
                        listtemp = afterstr;
                        clone->prev = beforestr;
                        if (beforestr)
                            beforestr->next = clone;
                        else
                            *list = clone;
                        while (clone->next)
                            clone = clone->next;
                        clone->next = afterstr;
                        if (afterstr)
                            afterstr->prev = clone;
                        /* akt. Makronode wieder einsetzen */
                        InsertMakroNode(&mlist, found, before);
                    } else {
                        /* akt. Makronode wieder einsetzen */
                        InsertMakroNode(&mlist, found, before);
                        return (result);
                    }
                }
            }
        }
        if (listtemp)
            listtemp = listtemp->next;
    }

    return (OK);
}


/* ParseIdentifier - parsed den Input-Define-String und haengt das Makro */
/*                   in die Liste */

struct mnode *ParseIdentifier(char *str)
{
    int x, numargs = 0, flags = 0, len = 0;
    char *name = NULL, *args = NULL, *token = NULL, *temp, *temp2, *argtemp;
    struct mnode *newmakro, *found;
    struct strnode *tokenlist = NULL, *templist, *arglist = NULL, *templist2;
    struct strnode *next, *prev;

    if (DEBUG & 32)
        puts("ParseIdentifier");

/*vb: casts eingefuegt  */
    while (isspace((unsigned char) *str)) {
        str++;
    }
    if (!(isalpha((unsigned char) *str) || *str == '_')) {
        error(178);
        return (0);
    }
    temp = str;
    while (isalnum((unsigned char) *temp) || (*temp == '_')) {
        temp++;
        len++;
    }

    /* auf schon vorhandene (evtl. FESTE) Definition suchen */
    found = FindMakroNode(mlist, str, len);
    if (found && (found->flags & NOREDEF)) {
        error(179);
        return (0);
    }
/*vb:   */
    if (1) {
        /* Okay, ist egal, wie das alte Makro aussah */

/*vb:   */
        if (found && !(c_flags[15] & USEDFLAG)) {
            error(197);
        }
        temp = name = (char *) malloc(len + 1);         /* Speicher fuer Name-String belegen */
        if (!name) {
            error(196);
            return (0);
        }
        for (x = 0; x < len; x++) {
            *temp++ = *str++;
        }                       /* Namen kopieren */
        *temp = 0;

        if (*str == '(') {
            flags |= PARAMETER;
            str++;              /* jump over '(' */
            temp = str;
            len = 0;
/*vb: casts eingefuegt  */
            while (*temp && (*temp != ')'))
                if (!(isspace((unsigned char) *temp))) {
                    len++;
                    temp++;
                } else {
                    temp++;
                }
            if (*temp == 0) {
                error(180);
                if (name)
                    free(name);
                return (0);
            }
            args = temp = (char *) malloc(len + 1);
            if (!args) {
                error(196);
                if (name)
                    free(name);
                return (0);
            }
            for (x = 0; x < len;)
                if (!(isspace((unsigned char) *str))) {
                    x++;
                    *temp++ = *str++;
                } else {
                    str++;
                }
            *temp = 0;
            str++;              /* jump over ')' */

            /* Argumentliste parsen und auf Fehler pruefen */
            temp = args;
            while (*temp && (isalpha((unsigned char) *temp) || *temp == '_')) {
                temp++;
                while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
                    temp++;
                }
                if (!(*temp) || *temp == ',') {
                    numargs++;
                    if ((*temp == ',') && (isalpha((unsigned char) *(temp + 1)) || *(temp + 1) == '_'))
                        temp++;
                }
            }
            if (*temp) {
                if (args)
                    free(args);
                if (name)
                    free(name);
                if (*temp == ',') {
                    error(181);
                } else {
                    error(182);
                }
                return (0);
            }
        }
        while (isspace((unsigned char) *str))
            str++;              /* Skip Spaces */
        /* HIER: pruefen, ob tokenlist erstellt werden konnte (leere tokenlist->ok) */
        tokenlist = Str2List(str);
        if (DEBUG & 32)
            printf(" - build TokenList\n");
        templist = tokenlist;
        while (templist) {
            if ((templist->type == NORMAL) && (!strcmp(templist->str, "#"))) {

                if ((templist->next) && (templist->next->type == NORMAL)
                    && (!strcmp(templist->next->str, "#"))) {
                    /* ## KILLSPACES */
                    if ((templist->prev) && (templist->next->next)) {
                        templist->type = SPECIAL;
                        templist->flags = KILLSPACES;
                        DelStrNode(&tokenlist, templist->next);
                    } else {
                        error(183);
                        if (name)
                            free(name);
                        if (args)
                            free(args);
                        if (tokenlist)
                            DelStrList(&tokenlist);
                        return (0);
                    }
                }
            }
            templist = templist->next;
        }

        /* Token parsen/kopieren */
        if ((flags & PARAMETER)) {      /* Argumente parsen */
            arglist = NULL;
            temp = temp2 = args;
            while (*temp) {
                len = 0;
                while (*temp && *temp != ',') {
                    temp++;
                    len++;
                }
                if (*temp == ',')
                    temp++;
                argtemp = (char *) malloc(len + 1);
                if (!argtemp) {
                    error(196);
                    if (name)
                        free(name);
                    if (args)
                        free(args);
                    if (arglist)
                        DelStrList(&arglist);
                    if (tokenlist)
                        DelStrList(&tokenlist);
                    return (0);
                }
                strncpy(argtemp, temp2, len);
                temp2 = temp;
                *(argtemp + len) = 0;
                AddStrNodeBehind(&arglist, NULL, argtemp);
            }
            templist = tokenlist;
            while (templist) {
                if (templist->type == PP_IDENT) {
                    x = 0;
                    templist2 = arglist;
                    while (templist2) {
                        if (!strcmp(templist->str, templist2->str)) {
                            templist->type = ARGUMENT;
                            templist->number = x;
                        }
                        x++;
                        templist2 = templist2->next;
                    }
                }
                templist = templist->next;
            }
            DelStrList(&arglist);
            if (DEBUG & 32)
                printf(" - Arguments found.\n");
            /* #-Specials korrigieren, nachdem die Argumente erkannt wurden */
            templist = tokenlist;
            while (templist) {
                if ((templist->type == NORMAL) && (!strcmp(templist->str, "#"))) {
                    if ((templist->next) && (templist->next->type == ARGUMENT)) {
                        templist->type = SPECIAL;
                        templist->flags = TOSTRING;
                    } else {
                        error(184);
                        if (name)
                            free(name);
                        if (args)
                            free(args);
                        if (arglist)
                            DelStrList(&arglist);
                        if (tokenlist)
                            DelStrList(&tokenlist);
                        return (0);
                    }
                }
                templist = templist->next;
            }
            if (DEBUG & 32)
                printf(" - Special-# corrected.\n");
        } else {                /* Token kopieren */
            temp = str;
            len = 0;
            while ((*temp) && (*temp != '\n')) {
                temp++;
                len++;
            }
            temp = token = (char *) malloc(len + 1);
            if (!token) {
                error(196);
                if (name)
                    free(name);
                if (args)
                    free(args);
                if (tokenlist)
                    DelStrList(&tokenlist);
                return (0);
            }
            for (x = 0; x < len; x++) {
                *temp++ = *str++;
            }
            *temp = 0;
        }


        templist = tokenlist;
        while (templist) {
            if (templist->type == SPECIAL && templist->flags == KILLSPACES) {
                next = templist->next;
                prev = templist->prev;

                /* Kill Spaces before/after ## */
                while (prev && prev->type == SPACE) {
                    templist2 = prev->prev;
                    DelStrNode(&tokenlist, prev);
                    prev = templist2;
                }
                while (next && next->type == SPACE) {
                    templist2 = next->next;
                    DelStrNode(&tokenlist, next);
                    next = templist2;
                }
                if ((!next) || (!prev))
                    ierror(0);

                if (next->type != ARGUMENT && prev->type != ARGUMENT) {
                    if ((prev->type == PP_IDENT || prev->type == NUMBER)) {
                        switch (next->type) {
                        case NUMBER:    /* merge -> ident */
                        case PP_IDENT:
                            RemStrNode(&tokenlist, next);
                            MergeStrNodes(prev, next);
                            next = templist->next;
                            /* next will now be deleted and prev->str will be */
                            /* the joined strings from prev&next */
                        default:        /* no merge / del ## */
                            DelStrNode(&tokenlist, templist);
                            templist = next;
                            break;
                        }       /* of switch */
                    } else {
                        DelStrNode(&tokenlist, templist);
                        templist = next;
                    }
                }
            }
            if (templist)
                templist = templist->next;
        }


/* erst HIER bei allowredefinition=0 abfragen ?? */

        if (newmakro = (struct mnode *) malloc(sizeof(struct mnode))) {
            newmakro->name = name;
            newmakro->args = args;
            newmakro->token = token;
            newmakro->tokenlist = tokenlist;
            newmakro->flags = flags;
            newmakro->funcnum = 0;
            AddMakroNode(&mlist, newmakro);
        } else {
            error(196);
            if (name)
                free(name);
            if (token)
                free(token);
            if (args)
                free(args);
            if (tokenlist)
                DelStrList(&tokenlist);
        }
        return (newmakro);

    } else {
/*vb:   das ist irgendwie Unsinn hier, glaube ich   */
        ierror(0);
        /* HIER: ueberpruefen, ob Macrodefinitionen uebereinstimmen, sonst Error */
        if (*temp == '(') {
            if (found->flags & PARAMETER) {
                temp++;         /* skip ( */



            } else {
                error(185);
                return (NULL);
            }
        }
        /* HIER nur noch tokenlisten vergleichen */

    }
    if (DEBUG & 32)
        printf("ParseIdent falls of\n");
}


/* PreParse - 3-Zeichen-Folgen ersetzen, \+CR Zeilen anhaengen, usw.. */

int PreParse()
{
    char *src, *dest, *dest2;
    int slen, dlen = 0;
    int cat = 0;                /*vb: um zu merken, ob Zeilen mit \ verbunden werden */
    dest2 = string;

    if (DEBUG & 32)
        puts("PreParse");


    if (!fgets(ppstring, MAXPPINPUT, in[incnesting])) {
        if (cmtnesting)
            error(186);
/*vb:   */
/*      if(ifstatus[incnesting]) error(186); */
/*      ifnesting--; */
        if (DEBUG & 32)
            printf("-- end of file  ifnesting-1:%d\n\n", incnesting);
        if (incnesting) {
            fclose(in[incnesting]);
            incnesting--;
            return (pp_nextline());
        } else
            return (0);
    } else if (DEBUG & 32)
        printf("gets1:%s\n", ppstring);         /*vb: */

    if ((strlen(ppstring) == (MAXPPINPUT - 1)) && (ppstring[MAXPPINPUT - 2] != '\n')) {
        error(177);
        return (0);
    }
    zn[incnesting]++;
    linenr = zn[incnesting];

    do {
        /* Zeilen einlesen, bis kein Kommentar mehr */

        /* Zeilen einlesen bis kein \ mehr am Ende */
        do {
            /* Source-String an Dest-String anhaengen und ??x-Folgen ersetzen */
/*vb: das killt sonst das angehaengte wieder   */
            if (cat == 0) {
                dest = src = ppstring;
                slen = 0;
            }
            do {
                if (*src != '\n') {

                    if ((*src == '?') && (*(src + 1) == '?') && !(c_flags[16] & USEDFLAG)) {
                        switch (*(src + 2)) {
                        case '=':
                            *dest++ = '#';
                            src += 2;
                            break;
                        case '/':
                            *dest++ = '\\';
                            src += 2;
                            break;
                        case '\'':
                            *dest++ = '^';
                            src += 2;
                            break;
                        case '(':
                            *dest++ = '[';
                            src += 2;
                            break;
                        case ')':
                            *dest++ = ']';
                            src += 2;
                            break;
                        case '!':
                            *dest++ = '|';
                            src += 2;
                            break;
                        case '<':
                            *dest++ = '{';
                            src += 2;
                            break;
                        case '>':
                            *dest++ = '}';
                            src += 2;
                            break;
                        case '-':
                            *dest++ = '~';
                            src += 2;
                            break;
                        default:
                            *dest++ = *src;
                            break;
                        }       /* of switch */
                    } else {
                        *dest++ = *src;
                    }

                    if (slen < MAXPPINPUT) {
                        slen++;
                    } else {
                        error(177);
                        return (0);
                    }
                }
            } while (*src++);

            src = dest;
            /* dest->lastchar+2/NULL+1 (dest-1)-> 0 (dest-2)->lastchar */
            if (*(dest - 2) == '\\') {
                /*vb: sollte das slen statt dlen sein?  */
                if (fgets(src, MAXPPINPUT - dlen, in[incnesting])) {
                    if (DEBUG & 32)
                        printf("gets2:%s\n", src);      /*vb:  */
/* Hier auf LF+0 abfragen */
                    dest -= 2;
                    zn[incnesting]++;
                    cat = 1;    /*vb: merken, dass Zeilen verbunden wurden */
                }
            }
        } while (*dest == '\\');

        src = ppstring;
        while (*src) {
            /* ' Strings ueberlesen */
            if ((*src == '\'') && (!cmtnesting)) {
                if (dlen < MAXINPUT) {
                    *dest2++ = *src++;
                    dlen++;
                } else {
                    error(177);
                    return (0);
                }
                while (*src && *src != '\'') {
                    if (*src == '\\') {
                        *dest2++ = *src++;
                        dlen++;
                    };
                    if (dlen < MAXINPUT) {
                        *dest2++ = *src++;
                        dlen++;
                    } else {
                        error(177);
                        return (0);
                    }
                }
                if (dlen < MAXINPUT) {
                    *dest2++ = *src++;
                    dlen++;
                } else {
                    error(177);
                    return (0);
                }
            }
            /* " Strings ueberlesen */
            if ((*src == '\"') && (!cmtnesting)) {
                *dest2++ = *src++;
                dlen++;
                while (*src && *src != '\"') {
                    if (*src == '\\') {
                        *dest2++ = *src++;
                        dlen++;
                    };
                    if (dlen < MAXINPUT) {
                        *dest2++ = *src++;
                        dlen++;
                    } else {
                        error(177);
                        return (0);
                    }
                }
                if (dlen < MAXINPUT) {
                    *dest2++ = *src++;
                    dlen++;
                } else {
                    error(177);
                    return (0);
                }
            }
            /* Kommentare weglassen */
            if ((*src == '/') && (*(src + 1) == '*')) {
                src += 2;
                if (dlen < MAXINPUT) {
                    *dest2++ = ' ';
                    dlen++;
                } else {
                    error(177);
                    return (0);
                }
                if ((cmtnesting && (c_flags[13] & USEDFLAG)) || (!cmtnesting))
                    cmtnesting++;
                else
                    error(198);
            } else {
                if ((*src == '*') && (*(src + 1) == '/') && cmtnesting) {
                    src += 2;
                    cmtnesting--;
                }
            }

            /* C++-Comment weglassen */
            if ((!cmtnesting) && (*src == '/') && (*(src + 1) == '/') && (c_flags[14] & USEDFLAG))
                *src = 0;

            if (!cmtnesting) {
                if (*src) {
                    *dest2++ = *src++;
                }
                if (dlen < MAXINPUT) {
                    dlen++;
                } else {
                    error(177);
                    return (0);
                }
            } else {
                if (*src)
                    src++;
            }
        }

        if (cmtnesting) {
            if (!fgets(ppstring, MAXPPINPUT, in[incnesting])) {
                if (cmtnesting)
                    error(186);
                if (incnesting) {
                    fclose(in[incnesting]);
                    incnesting--;
                    return (pp_nextline());
                } else
                    return (0);
            } else if (DEBUG & 32)
                printf("gets2:%s\n", ppstring);         /*vb:   */

            if ((strlen(ppstring) == (MAXPPINPUT - 1)) && (ppstring[MAXPPINPUT - 2] != '\n')) {
                error(177);
                return (0);
            }
            zn[incnesting]++;
        }
    } while (cmtnesting);

/*vb: das ueberschreibt den Speicher */
#if 0
    *dest2-- = 0;
    while (isspace(*dest2))
        *dest2-- = 0;           /* Spaces killen */
#endif

/*vb: hoffe, das ist besser */
    *dest2 = 0;
    while (dest2 > string && isspace((unsigned char) *--dest2))
        *dest2 = 0;


    return (1);
}

/* **************** PreProcessor ***************** */

int pp_init(void)
{
    char *macroname;
    struct mnode *macronode;

    if (!(c_flags[6] & USEDFLAG))
        printf("%s\n", pp_version);

    incnesting = /*ifnesting= */ -1;    /*vb:  */
    cmtnesting = if_cnt = abs_if_cnt = 0;
    mlist = NULL;
    strlist = NULL;

    macroname = (char *) malloc(9);
    if (!macroname)
        return (0);
    strcpy(macroname, "__LINE__");
    macronode = (struct mnode *) malloc(sizeof(struct mnode));
    if (!macronode) {
        if (macroname)
            free(macroname);
        return (0);
    }
    macronode->name = macroname;
    macronode->args = macronode->token = NULL;
    macronode->tokenlist = NULL;
    macronode->flags = FUNCTION | NODELETE | NOREDEF;
    macronode->funcnum = FUNCLINE;
    AddMakroNode(&mlist, macronode);

    macroname = (char *) malloc(9);
    if (!macroname)
        return (0);
    strcpy(macroname, "__FILE__");
    macronode = (struct mnode *) malloc(sizeof(struct mnode));
    if (!macronode) {
        if (macroname)
            free(macroname);
        DelMakroList(&mlist);
        return (0);
    }
    macronode->name = macroname;
    macronode->args = macronode->token = NULL;
    macronode->tokenlist = NULL;
    macronode->flags = FUNCTION | NODELETE | NOREDEF;
    macronode->funcnum = FUNCFILE;
    AddMakroNode(&mlist, macronode);

    macroname = (char *) malloc(9);
    if (!macroname)
        return (0);
    strcpy(macroname, "__DATE__");
    macronode = (struct mnode *) malloc(sizeof(struct mnode));
    if (!macronode) {
        if (macroname)
            free(macroname);
        DelMakroList(&mlist);
        return (0);
    }
    macronode->name = macroname;
    macronode->args = macronode->token = NULL;
    macronode->tokenlist = NULL;
    macronode->flags = FUNCTION | NODELETE | NOREDEF;
    macronode->funcnum = FUNCDATE;
    AddMakroNode(&mlist, macronode);

    macroname = (char *) malloc(9);
    if (!macroname)
        return (0);
    strcpy(macroname, "__TIME__");
    macronode = (struct mnode *) malloc(sizeof(struct mnode));
    if (!macronode) {
        if (macroname)
            free(macroname);
        DelMakroList(&mlist);
        return (0);
    }
    macronode->name = macroname;
    macronode->args = macronode->token = NULL;
    macronode->tokenlist = NULL;
    macronode->flags = FUNCTION | NODELETE | NOREDEF;
    macronode->funcnum = FUNCTIME;
    AddMakroNode(&mlist, macronode);

    macroname = (char *) malloc(9);
    if (!macroname)
        return (0);
    strcpy(macroname, "__STDC__");
    macronode = (struct mnode *) malloc(sizeof(struct mnode));
    if (!macronode) {
        if (macroname)
            free(macroname);
        DelMakroList(&mlist);
        return (0);
    }
    macronode->name = macroname;
    macronode->args = NULL;
    macroname = (char *) malloc(2);
    if (!macroname) {
        if (macronode->name)
            free(macronode->name);
        if (macronode)
            free(macronode);
        DelMakroList(&mlist);
        return (0);
    }
    strcpy(macroname, "1");
    macronode->token = macroname;
    macronode->tokenlist = Str2List(macroname);
    if (!macronode->tokenlist) {
        if (macronode->name)
            free(macronode->name);
        if (macronode->token)
            free(macronode->token);
        if (macronode)
            free(macronode);
        DelMakroList(&mlist);
        return (0);
    }
    macronode->flags = NODELETE;
    macronode->funcnum = 0;
    AddMakroNode(&mlist, macronode);

    return (1);
}


void pp_free(void)
{
    int i;

    if (DEBUG & 32)
        puts("pp_free");

/*vb: Schleifenindex korrekt gesetzt    */
    for (i = incnesting; i >= 0; i--)
        if (in[i])
            fclose(in[i]);
    DelMakroList(&mlist);
    DelStrList(&strlist);
}

int pp_include(char *f)
{
    if (DEBUG & 32)
        printf("trying to include %s\n", f);    /*vb:  */

    if (incnesting >= MAXINCNESTING - 1) {
        error(187);
        return (0);
    }
/*vb:   */
/*    if(ifnesting>=MAXIFNESTING-1)   {error("Too many nested #ifs or #includes",0);return(0);} */
    incnesting++;
    /*    ifnesting++; *//*vb:   */
    ifstatus[incnesting] = 0;   /*vb:   */

    if (DEBUG & 32)
        printf("-- include: ifnesting:%d ifstatus:0 \n\n", incnesting);

    in[incnesting] = fopen(f, "r");
    if (!in[incnesting]) {
        incnesting--;
        return (0);
    }
    filenames[incnesting] = f;
    zn[incnesting] = linenr = 0;
    return (1);
}



/* ********************** Main-Function ******************* */
int pp_nextline(void)
{
    char *src, *dest, *temp;
    int complete_len, len, i, result;
    struct mnode *makro;
    struct strnode *linelist, *inclinelist;

    if (DEBUG & 32)
        puts("pp_nextline");

    dest = string;
    dest[0] = 0;

    /* String vorbereiten, 3ZF ersetzen, \-Zeilen anhaengen, Kommentare loeschen */
    if (!PreParse())
        return (0);

    /* Ueberpruefung auf PreProcessor-Commands */
    src = string;
/*vb: casts eingefuegt  */
    while (isspace((unsigned char) *src)) {
        src++;
    }                           /* SkipSpaces */

    if (*src == '#') {          /* #-Direktive gefunden */
        src++;                  /* # ueberlesen */

        while (isspace((unsigned char) *src)) {
            src++;
        }                       /* SkipSpaces */

/*vb:   Direktiven, die nichts mit #if etc. zu tun haben, nach hinten   */


/* IFDEF */
        if (!strncmp(src, "ifdef", 5)) {
            src += 5;
            abs_if_cnt++;       /*vb: */
            if (isspace((unsigned char) *src)) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }
                /* identifier suchen */
                if (do_output) {
/*vb:   */
/*            if(ifnesting>=MAXIFNESTING-1) {error("Too many nested #if's",0); return(0);} */
/*            ifnesting++; */
                    temp = src;
                    len = 0;
                    while ((isalnum((unsigned char) *temp)) || (*temp == '_')) {
                        temp++;
                        len++;
                    }
                    makro = FindMakroNode(mlist, src, len);
                    if (DEBUG & 32)
                        printf("-- #ifdef found, ");
                    if (makro) {
/*vb:   */
                        ifstatus[incnesting] = 1;       /* Bedingung == TRUE */
                        if (DEBUG & 32)
                            printf(" condition '%s' found     (TRUE)\n", makro->name);
                    } else {
/*vb:   */
                        ifstatus[incnesting] = 2;       /* Bedingung == FALSE */
                        do_output = 0;
                        if (DEBUG & 32)
                            printf(" condition not found (FALSE)\n\n");
                    }
                } else {
                    if_cnt++;
                    if (DEBUG & 32)
                        printf("-- #ifdef found and if_cnt increased\n\n");
                }
                string[0] = 0;  /*vb: yo   */
                return (1);
            }
        }                       /* EO IFDEF */
        /* IFNDEF */
        if (!strncmp(src, "ifndef", 6)) {
            src += 6;
            abs_if_cnt++;       /*vb: */
            if (isspace((unsigned char) *src)) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }

                /* identifier suchen */
                if (do_output) {
/*vb:   */
/*            if(ifnesting>=MAXIFNESTING-1) {error("Too many nested #if's",0); return(0);} */
/*            ifnesting++; */
                    temp = src;
                    len = 0;
                    while ((isalnum((unsigned char) *temp)) || (*temp == '_')) {
                        temp++;
                        len++;
                    }
                    if (DEBUG & 32)
                        printf("-- FindMakroNode: len=%d temp=%p\n", len, (void*)temp);
                    makro = FindMakroNode(mlist, src, len);
                    if (DEBUG & 32)
                        printf("-- #ifndef found, ");
                    if (!makro) {
/*vb:   */
                        ifstatus[incnesting] = 1;       /* Bedingung == TRUE (Makro not existing) */
                        if (DEBUG & 32)
                            printf(" condition not found  (TRUE)\n\n");
                    } else {
/*vb:   */
                        ifstatus[incnesting] = 2;       /* Bedingung == FALSE */
                        do_output = 0;
                        if (DEBUG & 32)
                            printf(" condition '%s'     found (FALSE)\n\n", makro->name);
                    }
                    /* HIER: string[0]=0; */
                } else {
                    if_cnt++;
                    if (DEBUG & 32)
                        printf("-- #ifndef found and if_cnt increased\n\n");
                }
                string[0] = 0;  /*vb:   */
                return (1);
            }
        }                       /* EO IFNDEF */
        /* IF */
        if (!strncmp(src, "if", 2)) {
            src += 2;
            abs_if_cnt++;       /*vb:   */
            if (isspace((unsigned char) *src)) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }
                /* Bedingung auswerten */



                printf("****** WARNING ******* #if is not yet implemented\n");


                string[0] = 0;  /*vb:   */
                return (1);
            }
        }                       /* EO IF */
        /* ELIF */
        if (!strncmp(src, "elif", 4)) {
            src += 4;
            if (isspace((unsigned char) *src)) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }
                /* Bedingung auswerten */





                printf("****** WARNING ******* #elif is not yet implemented\n");




                string[0] = 0;  /*vb:   */
                return (1);
            }
        }                       /* EO ELIF */
        /* ELSE */
        if (!strncmp(src, "else", 4)) {
            src += 4;
            if (isspace((unsigned char) *src) || *src == 0) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }

                if (!if_cnt) {
                    switch (ifstatus[incnesting]) {     /*vb:   */
                    case 0:
                        error(188);
                        return (0);
                        break;
                    case 1:
                        do_output = 0;
                        /* HIER: auf #endif suchen SearchENDIF(); */
                        /* HIER: ifnesting--; do_output=1; */
                        break;
                    case 2:
                        ifstatus[incnesting] = 3;       /*vb:   */
                        do_output = 1;
                        break;
                    case 3:
                        error(189);
                        return (0);
                        break;
                    }
                }
                string[0] = 0;  /*vb:    */
                return (1);
            }
        }                       /* EO ELSE */
        /* ENDIF */
        if (!strncmp(src, "endif", 5)) {
            src += 5;
            abs_if_cnt--;       /*vb:   */
            if (isspace((unsigned char) *src) || *src == 0) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }
                /* HIER: Auf Zeilenende testen */

                if (DEBUG & 32)
                    printf("-- #endif found, ");

                if (if_cnt) {
                    if_cnt--;
                    if (DEBUG & 32)
                        printf("if_cnt decreased (to %d)\n", if_cnt);
                } else {
                    if (DEBUG & 32)
                        printf("ifnesting: %d  ifstatus: %d\n", incnesting, ifstatus[incnesting]);
                    if (abs_if_cnt < 0 /*(incnesting==-1)||ifstatus[incnesting]==0 */ ) {       /*vb:   */
                        error(190);
                        return (0);
                    }
                    /*            ifnesting--; *//*vb:   */
                    /* HIER: evtl. do_output entsprechend ifstatus[] setzen */
                    /*vb: natuerlich    */
                    do_output = 1;
                    ifstatus[incnesting] = abs_if_cnt > 0;      /*vb: 1 oder 0   */
                }
                string[0] = 0;  /*vb: ja */
                return (1);
            }
        }                       /* EO ENDIF */
        /*vb: andere Direktiven gegebenenfalls ueberspringen    */
        if (!do_output) {
            if (DEBUG & 32)
                printf("do_output==0 => skipping: %s\n", src);
            string[0] = 0;
            return (1);
        }
/* DEFINE */
        if ( /*(do_output)&& */ (!strncmp(src, "define", 6))) {         /*vb:   */
            if (DEBUG & 32)
                printf("#define found\n");
            src += 6;
            if (isspace((unsigned char) *src)) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }
                if (ParseIdentifier(src)) {
                    string[0] = 0;
                    return (1);
                } else {
                    if (DEBUG & 32)
                        printf("ParseIdent returned 0\n");
                    return (0);
                }
            }
        }                       /* EO DEFINE */
        /* UNDEF */
        if ( /*(do_output)&& */ (!strncmp(src, "undef", 5))) {  /*vb:   */
            src += 5;
            if (isspace((unsigned char) *src)) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }
                temp = src;
                len = 0;
                while ((isalnum((unsigned char) *temp)) || (*temp == '_')) {
                    temp++;
                    len++;
                }
                makro = FindMakroNode(mlist, src, len);
                if (makro->flags & NODELETE) {
                    error(199);
                } else {
                    DelMakroNode(&mlist, makro);
                }
                while (isspace((unsigned char) *temp)) {
                    temp++;
                }
                if (*temp != 0 && *temp != '\n') {
                    error(200);
                }
                string[0] = 0;
                return (1);
            }
        }                       /* EO UNDEF */
        /* INCLUDE */
        if ( /*(do_output)&& */ (!strncmp(src, "include", 7))) {        /*vb:   */
            src += 7;
            if (isspace((unsigned char) *src)) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }
                if (*src != '<' && *src != '\"') {
                    /* Versuchen den Rest zu expandieren */
                    inclinelist = Str2List(src);
                    if (!ExpandList(&inclinelist)) {
                        if (List2Str(inclinelist, src, MAXINPUT - (src - string))) {
                            /* HIER exit ? */
                        }
                    } else {
                        error(191);     /* HIER exit ? */
                    }
                }
/*vb: geaendert, so dass #include "..." auch noch im Standardpfad sucht */
                if (DEBUG & 32)
                    printf("includename=%s\n", src);
                if (*src == '<' || *src == '\"') {
                    char *m = src, c;
                    if (*src == '<')
                        c = '>';
                    else
                        c = '\"';
                    if (*src == '\"') {
                        /* im aktuellen Verzeichnis suchen und includen */
                        src++;
                        temp = src;
                        len = 0;
                        while (*temp != '\"') {
                            temp++;
                            len++;
                        }
                        temp++;
                        while (isspace((unsigned char) *temp))
                            temp++;
                        if (*temp) {
                            error(200);
                        }
                        temp = (char *) malloc(len + 1);
                        if (temp) {
                            strncpy(temp, src, len);
                            *(temp + len) = 0;
                            if (pp_include(temp)) {
                                AddStrNode(&strlist, NULL, temp);
                                string[0] = 0;
                                return (1);
                            } else {
                                if (temp)
                                    free(temp);
/*vb:
   error("pp: cannot open file to include",0);
   return(0); */
                            }
                        } else {
                            error(196);
                        }       /* HIER: Exit? */
                    }
                    /* in den Standard-Verzeichnissen suchen und includen */
                    src = m;
                    src++;
                    temp = src;
                    len = 0;
                    while (*temp != c && *temp != 0) {
                        temp++;
                        len++;
                    }           /*vb: sicherer */
                    temp++;
                    while (isspace((unsigned char) *temp))
                        temp++;
                    if (*temp) {
                        error(200);
                    }
                    temp = NULL;
                    for (i = 0; i < incpathc; i++) {
                        complete_len = strlen(incpath[i]) + len;
                        temp = (char *) malloc(complete_len + 1);
                        if (temp) {
                            strcpy(temp, incpath[i]);
                            strncat(temp, src, len);
                            *(temp + complete_len) = 0;
                            if (pp_include(temp)) {
                                AddStrNode(&strlist, NULL, temp);
                                if (DEBUG & 32)
                                    printf("include <%s> found\n", temp);
                                string[0] = 0;
                                return (1);
                            } else {
                                if (temp)
                                    free(temp);
                            }
                        } else {
                            error(196);
                        }       /* HIER: Exit ? */
                    }           /* of FOR i */
                    error(191);
                    return (0);
                } else {
                    error(192);
                    return (0);
                }
            } else {
                error(193);
                return (0);
            }
        }                       /* EO INCLUDE */
        /* LINE */
        if (!strncmp(src, "line", 4)) {
            src += 4;
            if (isspace((unsigned char) *src)) {
                return (1);     /* Ignorieren und an Compiler weiterreichen */
            }
        }                       /* EO LINE */
        /* ERROR */
        if (!strncmp(src, "error", 5)) {
            src += 5;
            if (isspace((unsigned char) *src)) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }

                return (1);
            }
        }                       /* EO ERROR */
        /* PRAGMA */
        if (!strncmp(src, "pragma", 6)) {
            src += 6;
            if (isspace((unsigned char) *src)) {
                while (isspace((unsigned char) *src)) {
                    src++;
                }

                return (1);
            }
        }                       /* EO PRAGMA */
        /* Unknown */
        /*    if(do_output){ */
        /*vb:   */
        error(193);
        return (0);
        /*    } *//*vb:   */
    } else if (do_output) {
        /* Normale Anweisung. Komplette Zeile expandieren */

/*vb:   */

        linelist = Str2List(string);

        if (DEBUG & 32)
            PrintTL(linelist);

/*vb: */
        did_expand = 0;

        if (result = ExpandList(&linelist)) {
            switch (result) {
            case OUT_OF_MEM:
                error(196);
                break;
            case NUM_OF_ARGS:
                error(194);
                break;
            case ARG_EXPECTED:
                error(195);
                break;
            default:
                ierror(0);
                break;
            }
            DelStrList(&linelist);
            return (0);
        }
        if (DEBUG & 32)
            PrintTL(linelist);

/*vb: List2Str nur aufrufen, falls etwas expandiert wurde   */
        if (did_expand && !List2Str(linelist, string, MAXINPUT)) {
            DelStrList(&linelist);
            return (0);
        }
        DelStrList(&linelist);

/*vb:   */
    } else
        string[0] = 0;
    return (1);
}
