
#include <exec/types.h>
#include <lists.h>


#include "node.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>

#define Prototype extern
#define STREAM void*
#define DSTR struct _DSTR *
#include "protos.h"

#include "Dyn.h"

#define strupper strupr
#define strlower strlwr


#define NEW(x) x = calloc(sizeof(*x), 1)
#define RemHead 	(void *)RemHead
#define FindName	_FindName
#ifdef _DCC
#define bzero(p,s) setmem(p,s,0)
#endif


static char _buffer[256];
static struct List NStack, _private_init;



struct PNode {
    struct Node Node;
    struct PNode*Parent;
    DSTR	 Text;
#ifndef OLD
    struct PNode*Type;
#endif
    struct List  Subs;
    struct List  Defs;
    struct List  Types;
    struct List  Attrs;
}; /* struct PNode */

#ifdef OLD
#define Type Node.ln_Type
#define NODE_GetType(n) DLL_NumToNode(&(n)->Parent->Types, (n)->Type)
#define T_TYPE long
#else
#define NODE_GetType(n) n->Type
#define T_TYPE APTR
#endif


int   presetflags = 0;
T_TYPE presettype = 0L;
int   level	  = 0;
APTR NODE_root = NULL;


static int NODE_compare (struct Node *n, struct Node *m, APTR dummy) {
    return stricmp(n->ln_Name, m->ln_Name);
} /* NODE_compare */

void AddSorted (struct List *l, struct PNode *p) {
    DLL_AddSorted (l, (struct Node *)p, NODE_compare, NULL);
} /* AddSorted */

static int NODE_check (struct Node *n, char *name) {
    return stricmp(n->ln_Name, name) ? 0: 1;
} /* NODE_check */

struct PNode * FindName (struct List *l, char *name) {
    return (struct PNode *)DLL_Search(l, NODE_check, name);
} /* FindName */



/*  das hier wird noch wesentlich komplexer ... */
/*  wir fragen noch die parents ab, ob dort */
/*  evtl ein type deiniert ist	*/
/*  wir sollten noch abfragen, ob es ein default */
/*  gibt, das types definiert, ... */

unsigned long NODE_IsType (const char *name) {
    struct PNode *n, *m;
    n = GetHead(&NStack);
//printf ("IsType '%s' (in %s/) ", name, ((ULONG)n > 10)? n->Node.ln_Name: "-", (((ULONG)n > 10) && n->Type)? n->Type->Node.ln_Name: "-");
    if (!n) {
//puts ("n-NO");
	return NULL;
    }
    strcpy  (_buffer, name);
    strupper(_buffer);
    if (m = FindName(&n->Types, _buffer)) {
//puts ("d-YES");
	return (unsigned long)m;
    }
#ifndef OLD
    if (n->Type && (m = NODE_GetType(n))) {
//printf ("n=%08lx/%s; nt=%08lx/%s ", n, n->Node.ln_Name, m, m->Node.ln_Name);
	if (m = FindName(&m->Types, _buffer)) {
//puts ("t-YES");
	    return (unsigned long)m;
	}
    } else {
	// Das SOLLTE heissen: if m = GetDefault_of_n && m = findname m_types_buffer
	if ((m = n->Parent) && (m->Type) && (m = NODE_GetType(m))) {
	    if ((m = FindName(&m->Subs, n->Node.ln_Name))) {
		if ((m = FindName(&m->Types, _buffer))) {
//puts ("i-YES");
		    return (ULONG)m;
		}
	    }
	}
    } /* if */
#endif
//puts ("l-NO");
    return 0;
} /* NODE_IsType */

static unsigned long NODE_IsNeeded (const char *name) {
    struct PNode *n;
    n = GetHead(&NStack);
    if (!n)
	return 0;

    if (n->Parent && ((unsigned long)name > 10)) {
	struct PNode *m = n->Parent;
	// all `Types' Uppercase
	if (1 == (long)m->Node.ln_Name)
	    return 1;
	else
	// all `Needed' Uppercase
	if (2 == (long)m->Node.ln_Name)
	    return 1;
	else {
	// all `needed' entries of subs Uppercase
	    strcpy (_buffer, name);
	    strupper(_buffer);
	    if ((m->Parent) && (FindName(&m->Parent->Attrs, _buffer))) {
		return 1;
	    } else
	    if ((m->Parent) && (m = NODE_GetType(m)) && (FindName(&m->Subs, _buffer)))
	    {
		return 1;
	    } /* if */
	} /* if */
    } /* if */
    return 0;
} /* NODE_IsNeeded */



void NODE_push (struct PNode *n) {
++level;
    Remove (&n->Node);
    AddHead(&NStack, &n->Node);
} /* NODE_push */


void NODE_PUSH (char *name, int full) {
    struct PNode *n;

//printf ("PUSH %s\n", name);
    /* eigentlich muessten wir hier duplikate eliminieren oder vereinigen */

    n = GetHead(&NStack);
    if (name && n)
	n = (struct PNode *)FindName(&n->Subs, name);
    else n =NULL;
    if (!n) {
	if (!full)
	    return;

	NEW(n);
	assert(n != NULL);
	bzero(n, sizeof(*n));

	NewList(&n->Subs);
	NewList(&n->Defs);
	NewList(&n->Types);
	NewList(&n->Attrs);

	n->Node.ln_Name = name;
	n->Node.ln_Pri	= presetflags;
	n->Parent	= GetHead(&NStack);
	n->Type 	= presettype;

	// to-upper decision
	if (NODE_IsNeeded(name))
	    strupper(name);

	AddHead(&_private_init, &n->Node);
    } else {

extern int lineno; struct PNode *p = n->Parent;
printf ("\t/* \"%s\", %d/l%d/p=%s/t=%d */\n", name, level + 1, lineno, p->Node.ln_Name? p->Node.ln_Name: "<DEF>", presettype);
printf ("\t/* **************** EXISTS ! */\n");
printf ("OldVal=%s\n", DynValue(&n->Text));

	assert (!presettype || (presettype == n->Type));
	if (full)
	    free (name);
    } /* if */

    NODE_push(n);

    presetflags = 0; presettype = 0L;
} /* NODE_PUSH */


void NODE_drop (struct PNode *n, BOOL full) {

/* printf ("dropping %s\n", n->Node.ln_Name); */
    {
	struct PNode *m;
	while (m = RemHead(&n->Subs)) {
	    NODE_drop(m, 1);
	} /* while */
	while (m = RemHead(&n->Defs)) {
	    NODE_drop(m, 1);
	} /* while */
	while (m = RemHead(&n->Types)) {
	    NODE_drop(m, 1);
	} /* while */
	while (m = RemHead(&n->Attrs)) {
	    NODE_drop(m, 1);
	} /* while */
    }
    DynClear(&n->Text);
    /* free(n->Reference); */
    if (full) {
	free(n->Node.ln_Name);
	free(n);
    } /* if */
} /* NODE_drop */


void NODE_POP (void) {
    struct PNode *n, *m;

level --;

    n = RemHead(&NStack);
//printf ("POP %s\n", n->Node.ln_Name);
    assert(n != NULL);
    if ((m = n->Parent)) {
	if (n->Node.ln_Name < (BYTE*)10) {
	    if (n->Node.ln_Name == NULL)
		AddTail (&m->Defs, &n->Node);
	    else {
		struct PNode *x, *y;
		if (n->Node.ln_Name == (char *)1L) {
		    for (x = GetHead (&n->Subs); x; x = y) {
			y = GetSucc(x);
			Remove	(&x->Node);
			AddTail (&m->Types, &x->Node);
			x->Parent = m;
		    } /* for */
		    //DLL_Join(&m->Types, &n->Subs);
		} if (n->Node.ln_Name == (char *)2L) {
		    for (x = GetHead (&n->Subs); x; x = y) {
			y = GetSucc(x);
			Remove	(&x->Node);
			AddTail (&m->Attrs, &x->Node);
			x->Parent = m;
		    } /* for */
		    //DLL_Join(&m->Attrs, &n->Subs);
		}
		NODE_drop(n, 1);
	    } /* if */
	} else
	    AddSorted(&m->Subs, n);
    } else
	assert (("POP on rootlevel!", 0));

} /* NODE_POP */


void NODE_CLEAR (void) {
    struct PNode *n;
    n = GetHead(&NStack);
    assert(n != NULL);
    NODE_drop(n, 0);
} /* NODE_CLEAR */

void NODE_TEXT (char *text) {
    struct PNode *n;
    n = GetHead(&NStack);
    assert(n != NULL);

    DynCat(&n->Text, text);
    free(text);
} /* NODE_TEXT */




void NODE_access (int type) {
    presetflags = presetflags & ~(3) | type;
} /* NODE_access */

void NODE_type (const char *name) {
#ifdef OLD
    presettype = DLL_NodeToNum(NULL, (struct Node *)NODE_IsType(name));
#else
    presettype = (T_TYPE)NODE_IsType(name);
#endif
} /* NODE_type */

void NODE_spc (int type) {
    presetflags = presetflags & ~(3 << 2) | type;
} /* NODE_spc */





struct PNode * NODE_lock (struct PNode *n, const char *sub, int level)
{
    struct PNode *m;
//printf ("Q:4'%s'in'%s'\n", sub, n->Node.ln_Name);

    // explicite goback ...
    while (((*sub == '/') || (*sub == ':')) && n) {
	if (*sub == '/') {
	    n = n->Parent;
	    ++sub;
	} /* if */

	if (*sub == ':') {
	    n = NODE_root;
	    ++sub;
	} /* if */

	if (!*sub) {
	    return n;
	} /* if */
    } /* if */


    m = FindName (&n->Subs, (char *)sub);
    if (m)
	return m;

    m = n->Parent;
    if (m) {
	/* die defaults nur scannen, wenn wir nicht in den defaults sind ... */
	if (10 < (unsigned long)n->Node.ln_Name) {
	    struct PNode *d;

	    /* zuerst Defaults ... */
	    for (d = GetHead (&m->Defs); d; d = GetSucc(d)) {
		if (d->Type == n->Type && d != n) {
		    d = NODE_lock(d, sub, 0);
		    if (d) return d;
		    break;
		} /* if */
	    } /* for */

	    /* dann Type ... */
	    if ((d = NODE_GetType(n)) && d != n)
	    {
		d = NODE_lock(d, sub, 0);
		if (d) return d;
	    } /* if */
	} /* if */

	/* schliesslich auf Parentebene weitersuchen */
	if (level)
	    return NODE_lock(m, sub, level - 1);

    } /* if */

    return NULL;
} /* NODE_lock */

#define _NOLIMIT_  -1
#define _ONELEVEL_  0


char * _NODE_sub (struct PNode *n, const char *sub) {
    struct PNode *m;

    m = NODE_lock (n, (char *)sub, _NOLIMIT_);
    if (m)
	return (char *)(DynLen(&m->Text)? DynValue(&m->Text) :
			/* (char *)((m->Reference != NULL) ? m->Reference : */
						(char *)NULL);

    return NULL;
} /* NODE_sub */

void Log(char *, int, struct PNode*);
void ShowLog (void);


#define S_ITERATE_ "@ITERATE@"
#define L_ITERATE_ 9
#define S_IF_	   "@IF@"
#define L_IF_	   4
#define S_WITH_    "@WITH@"
#define L_WITH_    6
#define S_FOREACH_ "@FOREACH@"
#define L_FOREACH_ 9
#define S_TOUPPER_ "@TOUPPER@"
#define L_TOUPPER_ 9
#define S_TOLOWER_ "@TOLOWER@"
#define L_TOLOWER_ 9
#define _END_	   '@'
#define _NAME_	   "NAME"
#define _VALUE_    "VALUE"
#define _INDEX_    "IDX"
#define _TINDEX_   "TIDX"
#define _SETTABLE_ "SETTABLE"
#define _GETTABLE_ "GETTABLE"

int _NumQueries = 0;
int Index, TIndex;

char * NODE_sub (struct PNode *n, char *name);


BOOL NODE_hunt (DSTR *dest, char *tmplt, struct PNode *n)
{
    static int REK = 0;
    int nq_inter = _NumQueries, loops = 1;
    DSTR buffer = EmptyDyn;
    tmplt = strdup(tmplt);
    assert(tmplt != NULL);
    assert (++REK < 8);
    do {
	_NumQueries = 0;
	if (!flexprintf (&buffer, (void *)DynCat, tmplt, n, (void *)NODE_sub)) {
puts (DynValue(&buffer));
ShowLog();
	    assert(("FLEXPRINTF - INTERNAL ERROR", 0));
	} /* if */
	free (tmplt);
	tmplt = strdup(DynValue(&buffer));
	assert(tmplt != NULL);
	DynClear(&buffer);
    } while (_NumQueries && --loops);
    _NumQueries = nq_inter;
    DynCat(dest, tmplt);
    free(tmplt);

    --REK;
    return (BOOL)1;
} /* NODE_hunt */

/* Wir brauchen etwas wie $(@LOCK@shortcut) */

struct List locks;

struct PNode *get_lock(char *name) {
    struct PNode *n;
    n = FindName ((struct List *)&locks, name);

//if (n) printf ("shortcut to %s found\n", name);

    return n;
} /* if */

char * NODE_Special (struct PNode *n, char *name)
{
    static DSTR retbuffer = EmptyDyn;
    char *pp;
    DSTR buffer = EmptyDyn;

	// if (DynLength(&retbuffer))
	//     DynClear(&retbuffer);
	// buffer = EmptyDyn;

    if (strnicmp(name, S_ITERATE_, L_ITERATE_) == 0) {
	struct PNode *m;
	int i = 0, ii = Index;
	name += L_ITERATE_;
/* puts("ITERATE..."); */

	for (m = GetHead(&n->Subs); m; m = GetSucc(m)) {
	    Index = i++;
	    if (!NODE_hunt (&buffer, name, m)) {
puts (DynValue(&buffer));
ShowLog();
		assert (("FLEXPRINTF - ERROR", 0));
	    } /* if */
	} /* for */
	Index = ii;

	goto clean_end;
    } /* if */
    if (strnicmp(name, S_IF_, L_IF_) == 0) {
	name += L_IF_;
/* puts("IF..."); */
	for (pp = name; *pp && (*pp != _END_); ++pp);
	if (*pp) {
	    int inv_mode = 0, cond;
	    *pp = 0;
	    if (*name == '!') {
		++name;
		inv_mode = 1;
	    }
/* printf(name); */
	    /* ---- IF-value_not_null */
	    name = NODE_sub(n, name);
	    *pp = _END_;

	    cond = name != NULL;
	    cond = cond && (atol(name) != 0);

/* printf (" cond %d\n", cond != inv_mode); */
	    if (cond != inv_mode) {
		if (!NODE_hunt (&buffer, pp + 1, n)) {
puts (DynValue(&buffer));
ShowLog();
		    assert (("FLEXPRINTF - ERROR", 0));
		} /* if */
		goto clean_end;
	    } else {
		return "";
	    } /* if */

	} /* if */
ShowLog();
	assert(("IF - BAD CONDITION", 0));
    } /* if */
    if (strnicmp(name, S_WITH_, L_WITH_) == 0) {
	struct PNode *m;
	name += L_WITH_;
/* puts("WITH..."); */
	for (pp = name; *pp && (*pp != _END_); ++pp);
	if (*pp) {
	    *pp = 0;


	    m = NODE_lock (n, name, _NOLIMIT_);
	    /* m = NODE_lock (n, name, _ONELEVEL_); */
	    *pp = _END_;
	    if (m) {
		if (!NODE_hunt  (&buffer, pp + 1, m)) {
puts (DynValue(&buffer));
ShowLog();
		    assert (("FLEXPRINTF - ERROR", 0));
		} /* if */
		goto clean_end;
	    } /* if */

ShowLog();
	    assert (("WITH - NAME NOT FOUND", 0));

	} /* if */
ShowLog();
	assert (("WITH - BAD NAME", 0));
    } /* if */
    if (strnicmp(name, S_FOREACH_, L_FOREACH_) == 0) {
	struct PNode *m;
	name += L_FOREACH_;
//puts("FOREACH...");
	for (pp = name; *pp && (*pp != _END_); ++pp);
	if (*pp) {
	    int ii = Index, it = TIndex;
	    *pp = 0;
	    TIndex = Index = 0;
//printf("%s in %s/%08lx...\n", name, n->Node.ln_Name, n);
	    for (m = GetHead(&n->Subs); m; m = GetSucc(m)) {
		++ Index;
//printf(" ? %s ?\n", m->Node.ln_Name);
		if (m->Type && !stricmp(m->Type->Node.ln_Name, name)) {
		    ++TIndex;
//puts ("     Yea!");
		    if (!NODE_hunt  (&buffer, pp + 1, m)) {
puts (DynValue(&buffer));
ShowLog();
			assert (("FLEXPRINTF - ERROR", 0));
		    } /* if */
		} /* if */
	    } /* for */

	    TIndex = it;
	    Index  = ii;
	    *pp    = _END_;
	    goto clean_end;
	} /* if */
ShowLog();
	assert (("FOREACH - BAD NAME", 0));
    } /* if */
    if (strnicmp(name, S_TOUPPER_, L_TOUPPER_) == 0) {
	name += L_TOUPPER_;
	if (!NODE_hunt (&buffer, name, n)) {
puts (DynValue(&buffer));
ShowLog();
	    assert (("FLEXPRINTF - ERROR", 0));
	} /* if */
	strupper(DynValue(&buffer));
	goto clean_end;
    } /* if */
    if (strnicmp(name, S_TOLOWER_, L_TOLOWER_) == 0) {
	name += L_TOLOWER_;
	if (!NODE_hunt (&buffer, name, n)) {
puts (DynValue(&buffer));
ShowLog();
	    assert (("FLEXPRINTF - ERROR", 0));
	} /* if */
	strlower(DynValue(&buffer));
	goto clean_end;
    } /* if */
    if (!strnicmp (name, "@debug@", 7)) {
	void NODE_TREE (struct PNode *p, APTR pa);
puts ("DEBUG");
	NODE_TREE(n, NULL);
	exit(0);
    } /* if */
    if (!strnicmp (name, "@lock@", 6)) {
	struct PNode *p;
	name += 6;
	//NODE_PUSH(name);
	//NODE_POP();

	for (pp = name; *pp && (*pp != _END_); ++pp);
	if (*pp) {
	    *pp = 0;
//printf ("locking %s as %s\n", n->Node.ln_Name, name);
	    if (NEW(p)) {
		p->Node.ln_Name = name;
		DynCpy(&p->Text, n->Node.ln_Name);
		AddHead((struct List *)&locks, &p->Node);

//{struct PNode *n;
//for (n = GetHead (&locks);n;n = GetSucc(n)) {
//    printf ("locked %s\n", n->Node.ln_Name);
//    get_lock (n->Node.ln_Name);
//} /* for */
//}

		if (!NODE_hunt  (&buffer, pp + 1, n)) {
puts (DynValue(&buffer));
ShowLog();
		    assert (("FLEXPRINTF - ERROR", 0));
		} /* if */

		Remove (&p->Node);
		DynClear(&p->Text);
		free(p);
	    } else {
ShowLog();
		assert("Alloc" == NULL);
	    } /* if */
	    *pp = _END_;
	    goto clean_end;
	} /* if */
    } /* if */


    return NULL;

clean_end:
	DynDCpy(&retbuffer, &buffer);
	DynClear(&buffer);
	return DynValue (&retbuffer);
} /* NODE_Special */


char * __NODE_sub (struct PNode *n, char *name)
{
    char *res;


    if (!n) {
	void NODE_TREE (struct PNode *p, APTR pa);
	n = GetHead(&NStack);
	assert (n != NULL);
//NODE_TREE(n, NULL);
    }

//printf ("Q:4'%s'in'%s'\n", name, n->Node.ln_Name);


    res = NULL;
    res = NULL;
    {
	if (name[0] == '?')
	    return (NODE_lock (n, name + 1, _NOLIMIT_))? "1": "0";
	    /* return (NODE_lock (n, name + 1, _ONELEVEL_))? "1": "0"; */
	if ((name[0] == '!') && (name[1] == '?'))
	    return (NODE_lock (n, name + 2, _NOLIMIT_))? "0": "1";
	    /* return (NODE_lock (n, name + 2, _ONELEVEL_))? "0": "1"; */

	if (stricmp(_NAME_, name) == 0) {
	    return n->Node.ln_Name;
	} /* if */
	if (stricmp("__type", name) == 0) {
	    return n->Type ? n->Type->Node.ln_Name: "";
	} /* if */
	if (stricmp(_SETTABLE_, name) == 0) {
	    return (n->Node.ln_Pri & CA_CONST) ? "0": "1";
	} /* if */
	if (stricmp(_GETTABLE_, name) == 0) {
	    return (n->Node.ln_Pri & CA_HIDDEN) ? "0": "1";
	} /* if */
	if (stricmp(_VALUE_, name) == 0) {
	    return DynValue(&n->Text);
	} /* if */
	if (stricmp(_INDEX_, name) == 0) {
    static char rb2[16];
	    sprintf (rb2, "%d", Index);
	    return rb2;
	} /* if */
	if (stricmp(_TINDEX_, name) == 0) {
    static char rb3[16];
	    sprintf (rb3, "%d", TIndex);
	    return rb3;
	} /* if */

	if (*name == _END_) {
	    return NODE_Special(n, name);
	} /* if */
    }

    {
	struct PNode *x;
	if ((x = get_lock(name))) {
//printf ("wanting %s from %s\n", DynValue(&x->Text), x->Node.ln_Name);
//fflush(stdout);
	    return NODE_sub(x, _VALUE_);
	}
    }

    res = _NODE_sub(n, name);
    ++_NumQueries;

    if (!res) {
	printf ("FAIL: %s/%s!\n", n->Node.ln_Name, name);
    }

    /* return res; */

    { /* /* ---- HIER muss das TRACE-DOWN HIN!!!!! */
	DSTR buffer = EmptyDyn;
static DSTR retbuffer = EmptyDyn;
	if (!flexprintf (&buffer, (void *)DynCat, res, n, (void *)NODE_sub)) {
puts (DynValue(&buffer));
ShowLog();
	    assert(("FLEXPRINTF - INTERNAL ERROR", 0));
	} /* if */

	DynDCpy(&retbuffer, &buffer);
	DynClear(&buffer);
	return DynValue(&retbuffer);
    }


} /* NODE_sub */

void DropLog (void);

char * NODE_sub (struct PNode *n, char *name) {
    static int level = 0;
    Log (name, level, n);
    ++level;
    name = __NODE_sub (n, name);
    --level;
    DropLog();
    return name;
}


void NODE_init (void)
{
    //atexit (ShowLog);
    NewList(&NStack);
    NewList(&_private_init);
    NewList((struct List *)&locks);
    NODE_PUSH("ROOT", 1);
    NODE_root = GetHead (&NStack);
} /* NODE_init */




void ResetNumQueries (void)
{
    _NumQueries = 0;
} /* ResetNumQueries */

int NumQueries (void)
{
    return _NumQueries;
} /* NumQueries */


void NODE_TREE (struct PNode *p, APTR pa) {
    static int counter = 0;
    int i;
    struct PNode *c;

    if (!counter && !p) {
	for (p = GetTail (&NStack); p; p = GetPred(p)) {
	    ++counter;
	    NODE_TREE(p, GetSucc(p));
	}
	counter = 0;
	return;
//	  p = GetHead(&NStack);
    }
//	  p = NODE_root;

    ++ counter;

    for (i = 0; i < counter; ++i) printf ("  ");
    printf ("[%d]a=%08lx t=%08lx n='%s' p=%08lx?=%08lx\n", counter, p, p->Type, p->Node.ln_Name, p->Parent,pa);
    if (GetHead(&p->Types)) {
	for (i = 0; i < counter; ++i) printf ("  ");
	printf (" [%d]types:\n", counter);
	for (c = GetHead(&p->Types); c; c = GetSucc (c))
	    NODE_TREE (c,p);
    }
    if (GetHead(&p->Subs)) {
	for (i = 0; i < counter; ++i) printf ("  ");
	printf (" [%d]subs:\n", counter);
	for (c = GetHead(&p->Subs); c; c = GetSucc (c))
	    NODE_TREE (c,p);
    }
    -- counter;
} /* NODE_TREE */


struct List Logs = {0L,0L,0L};
void Log (char *text, int level, struct PNode *nn) {
    struct Node *n;

    if (!Logs.lh_Head)
	NewList (&Logs);

    if (NEW(n)) {
	AddTail(&Logs, n);
	n->ln_Pri  = level;
	n->ln_Name = strdup (text);
    }
}

void DropLog (void)
{
    struct Node *n;
    if (!Logs.lh_Head)
	NewList (&Logs);

    n = RemTail (&Logs);
    if (n) {
	free (n->ln_Name);
	free (n);
    }
} /* DropLog */


void ShowLog (void) {
    struct Node *n;

    if (!Logs.lh_Head)
	NewList (&Logs);

    for (n = GetHead (&Logs); n; n = GetSucc(n))
	printf ("%d: %-20.20s\n", (int)n->ln_Pri, n->ln_Name);
}
