#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <defs.h>
#include <main.h>
#include <error.h>
#include <msglog.h>
#include <xalloc.h>
#include <utf8ing.h>
#include <lex.h>
#include <symtab.h>
#include <parse.h>
SYMBOL *symlist = NULL;
static SYMTAB *symtab = NULL;
static int constants_counter = 0;
static int sections_counter = 0;
static int repos_counter = 0;
static SYMBOL *free_const( SYMBOL *sp )
{
SYMBOL *next = NULL;
if( !sp ) return next;
next = sp->next;
free( sp->name );
switch( sp->type )
{
case STRING:
if( sp->u.string ) free( sp->u.string );
break;
case PATH:
if( sp->u.string ) free( sp->u.path );
break;
case NUMERICAL:
default:
break;
}
free( sp );
return next;
}
static void free_symlist( SYMBOL *sp );
static SYMBOL *free_symbol( SYMBOL *sp )
{
SYMBOL *next = NULL;
if( !sp ) return next;
if( sp->list ) (void)free_symlist( sp->list );
next = sp->next;
free( sp->name );
switch( sp->type )
{
case SECTION:
case STRING:
if( sp->u.string ) free( sp->u.string );
break;
case REPO:
case PATH:
if( sp->u.string ) free( sp->u.path );
break;
case VARIABLE:
case NUMERICAL:
default:
break;
}
free( sp );
return next;
}
static void free_symlist( SYMBOL *sp )
{
SYMBOL *next = NULL;
if( !sp ) return;
next = free_symbol( sp );
while( next )
{
next = free_symbol( next );
}
}
/******************************************
Initialize the stak of symlist pointers:
*/
void init_symtab( void )
{
SYMTAB *sa = (SYMTAB *)xmalloc( sizeof( SYMTAB ) );
symtab = NULL;
symlist = NULL;
constants_counter = 0;
sections_counter = 0;
repos_counter = 0;
sa->symlist = (SYMBOL **)&symlist;
sa->next = symtab;
symtab = sa;
}
/*******************************************
Push the address of symlist to the stack:
*/
void push_symlist( SYMBOL **head )
{
if( head )
{
SYMTAB *sa = (SYMTAB *)xmalloc( sizeof( SYMTAB ) );
sa->symlist = head;
sa->next = symtab;
symtab = sa;
}
}
/********************************************
Pop the address of symlist from the stack:
*/
void pop_symlist( void )
{
if( symtab && symtab->next )
{
SYMTAB *sa = symtab;
symtab = symtab->next;
free( sa );
}
}
/************************************
Free the stak of symlist pointers:
*/
void fini_symtab( void )
{
if( !symtab ) return;
while( symtab )
{
SYMTAB *sa = symtab;
symtab = symtab->next;
free( sa );
}
constants_counter = 0;
sections_counter = 0;
repos_counter = 0;
symtab = NULL;
free_symlist( symlist ); /* free main symlist */
symlist = NULL;
}
/******************************
Reverse symlist recursively:
*/
void reverse_symlist( SYMBOL **head )
{
SYMBOL *prev = NULL, *curr = *head, *next;
while( curr )
{
if( curr->list ) reverse_symlist( (SYMBOL **)&(curr->list) );
next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
*head = prev;
}
/******************************************************
Remove temporary constants from symlist recursively:
*/
void remove_consts( SYMBOL **head )
{
SYMBOL *tmp = NULL;
while( *head )
{
tmp = *head;
if( !strncmp( tmp->name, "__const.", 8 ) )
{
*head = tmp->next;
(void)free_const( tmp );
}
else
{
head = &tmp->next;
if( tmp->list ) remove_consts( (SYMBOL **)&(tmp->list) );
}
}
}
SYMBOL *assign_value( SYMBOL *dest, SYMBOL *src )
{
SYMBOL *ret = NULL;
if( !dest || !src ) return ret;
if( dest->type == VARIABLE ) /* always not initialized */
{
dest->type = src->type;
dest->u.value = 0;
switch( src->type )
{
case NUMERICAL:
dest->u.value = src->u.value;
break;
case STRING:
dest->u.string = strdup( (const char *)src->u.string );
break;
case PATH:
dest->u.path = strdup( (const char *)src->u.path );
break;
default:
/* error */
break;
}
}
else if( dest->type == STRING || dest->type == SECTION )
{
switch( src->type )
{
case STRING:
if( src->u.string )
{
if( dest->u.string ) free( dest->u.string );
dest->u.string = strdup( (const char *)src->u.string );
}
else
{
if( dest->u.string ) free( dest->u.string );
dest->u.string = NULL;
}
break;
default:
/* error */
break;
}
}
else if( dest->type == PATH || dest->type == REPO )
{
switch( src->type )
{
case PATH:
if( src->u.path )
{
if( dest->u.path ) free( dest->u.path );
dest->u.path = strdup( (const char *)src->u.path );
}
else
{
if( dest->u.path ) free( dest->u.path );
dest->u.path = NULL;
}
break;
default:
/* error */
break;
}
}
else if( dest->type == src->type )
{
switch( src->type )
{
case NUMERICAL:
dest->u.value = src->u.value;
break;
case STRING:
if( dest->u.string ) free( dest->u.string );
dest->u.string = strdup( (const char *)src->u.string );
break;
case PATH:
if( dest->u.path ) free( dest->u.path );
dest->u.path = strdup( (const char *)src->u.path );
break;
default:
/* error */
break;
}
}
else
{
/* error */
}
return dest;
}
SYMBOL *install( const char *s, int type, ... )
{
SYMBOL *sp = NULL;
char name[80] = "__undef";
if( !symtab ) return sp;
va_list argp;
if( ! type ) return( sp );
sp = (SYMBOL *)xmalloc( sizeof( SYMBOL ) );
switch( type )
{
case NUMERICAL:
case STRING:
case PATH:
sprintf( (char *)&name[0], "__const.%d", constants_counter++ );
sp->name = strdup( (const char *)&name[0] );
break;
case REPO:
sprintf( (char *)&name[0], "__repo.%d", repos_counter++ );
sp->name = strdup( (const char *)&name[0] );
break;
case SECTION:
sprintf( (char *)&name[0], "__section.%d", sections_counter++ );
sp->name = strdup( (const char *)&name[0] );
break;
default:
if( !s )
sp->name = strdup( (const char *)&name[0] );
else
sp->name = strdup( s );
break;
}
sp->type = type;
va_start( argp, type );
switch( type )
{
case SECTION:
case STRING:
{
char *string = (char *)va_arg( argp, char * );
if( string ) sp->u.string = strdup( (const char *)string );
break;
}
case REPO:
case PATH:
{
char *path = (char *)va_arg( argp, char * );
if( path ) sp->u.path = strdup( (const char *)path );
break;
}
case VARIABLE:
case NUMERICAL:
default:
sp->u.value = (int)va_arg( argp, int );
break;
}
sp->next = *(symtab->symlist); /* alloc in begin of list */
*(symtab->symlist) = sp;
return( sp );
}
/***********************************
Find variable in current symlist:
*/
SYMBOL *lookup( const char *s )
{
SYMBOL *sp;
for( sp = *(symtab->symlist); sp != (SYMBOL *)0; sp = sp->next )
{
if( strcmp( sp->name, s ) == 0 ) return( sp );
}
return( 0 ); /* запись не найдена */
}
/*********************************
Find section in global symlist:
*/
SYMBOL *lookup_section( const char *s )
{
SYMBOL *sp;
for( sp = symlist; sp != (SYMBOL *)0; sp = sp->next )
{
if( sp->type == SECTION && sp->u.string && strcmp( sp->u.string, s ) == 0 ) return( sp );
}
return( 0 ); /* запись не найдена */
}
/********************************
Find repo globally in symlist:
*/
#if 0
SYMBOL *lookup_repo_global( const char *s )
{
SYMBOL *sp;
for( sp = symlist; sp != (SYMBOL *)0; sp = sp->next )
{
/***************************
lookup in global section:
*/
if( sp->type == REPO && sp->u.path && strcmp( sp->u.path, s ) == 0 ) return( sp );
/*************************
lookup in each section:
*/
if( sp->type == SECTION && sp->list )
{
SYMBOL *rp;
for( rp = sp->list; rp != (SYMBOL *)0; rp = rp->next )
{
if( rp->type == REPO && rp->u.path && strcmp( rp->u.path, s ) == 0 ) return( rp );
}
}
}
return( 0 ); /* запись не найдена */
}
#endif
/*******************************
Find repo in current symlist:
*/
SYMBOL *lookup_repo( const char *s )
{
SYMBOL *sp;
for( sp = *(symtab->symlist); sp != (SYMBOL *)0; sp = sp->next )
{
if( sp->type == REPO && sp->u.path && strcmp( sp->u.path, s ) == 0 ) return( sp );
}
return( 0 ); /* запись не найдена */
}