home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 3
/
goldfish_volume_3.bin
/
files
/
dev
/
misc
/
adoc
/
source
/
libfun.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-13
|
21KB
|
925 lines
/* -*- C -*-
* LIBFUN.C
*
* (c)Copyright 1995 by Tobias Ferber, All Rights Reserved
*
* This file is part of ADOC.
*
* ADOC is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 1 of the License,
* or (at your option) any later version.
*
* ADOC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $VER: $Id: libfun.c,v 1.13 1995/04/12 13:33:43 tf Exp $ */
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "libfun.h"
/* strexpand.c */
extern char *strexpand(char *, char **);
/* repair buggy realloc() implementation */
#define my_realloc(ptr,size) ( (ptr) ? realloc(ptr,size) : malloc(size) )
/* minimum #of chars added to funsec.data with each realloc() */
#define SECMINSIZE 1024
/* list of sections in a function description */
typedef struct funsec
{
struct funsec *succ, *pred;
char *name; /* section title keyword */
struct {
char *text; /* section text */
size_t len; /* strlen(text) */
size_t size; /* #of chars allocated for text */
} data;
} funsec_t;
/* library function nodes */
typedef struct libfun
{
struct libfun *succ, *pred;
char *name; /* name of the function: `library/function' */
struct funsec *sec; /* list of sections in the function description */
} libfun_t;
/* variables */
static libfun_t *funlist = (libfun_t *)0; /* list of all functions */
static libfun_t *funstack = (libfun_t *)0; /* function on the stack */
static libfun_t *thisfun = (libfun_t *)0; /* the current function (the one constructed last) */
static funsec_t *thissec = (funsec_t *)0; /* the current section in the current function */
char *pushfun(void) { char *result= funstack ? funstack->name : (char *)0; funstack = thisfun; return result; }
char *popfun(void) { char *result= funstack ? funstack->name : (char *)0; thisfun = funstack; return result; }
/**/
static libfun_t *libfun_head(libfun_t *lf) { return (lf && lf->pred) ? libfun_head(lf->pred) : lf; }
static libfun_t *libfun_tail(libfun_t *lf) { return (lf && lf->succ) ? libfun_tail(lf->succ) : lf; }
static funsec_t *funsec_head(funsec_t *fs) { return (fs && fs->pred) ? funsec_head(fs->pred) : fs; }
static funsec_t *funsec_tail(funsec_t *fs) { return (fs && fs->succ) ? funsec_tail(fs->succ) : fs; }
/****** libfun/newfun ********************************************************
*
* NAME
* newfun -- Begin a new function
*
* SYNOPSIS
* error= newfun(fun);
*
* int funindent(char *fun);
*
* FUNCTION
* This function adds the function `fun'. All sections added via
* newsec() will be made sections of this function.
*
* INPUTS
* fun - The name of the function to add.
* (should be of the form "library/function")
*
* RESULT
* error - either 0 on success or !=0 in case of an error
*
* SEE ALSO
* newsec(), funfree()
*
******************************************************************************
*
*/
static libfun_t *libfun_new(char *fun)
{
libfun_t *lf= (libfun_t *)0;
if(fun)
{
lf= (libfun_t *)malloc( sizeof(libfun_t) );
if(lf)
{
lf->name= strdup(fun);
if(lf->name)
{
lf->succ =
lf->pred = (libfun_t *)0;
lf->sec = (funsec_t *)0;
}
else
{
free(lf);
lf= (libfun_t *)0;
}
}
}
return lf;
}
/**/
int newfun(char *fun)
{
libfun_t *new= libfun_new(fun);
if(new)
{
libfun_t *lf= libfun_tail(funlist);
if(lf)
{
lf->succ= new;
new->pred= lf;
}
else funlist= new;
}
thisfun= new;
thissec= new->sec;
return new ? 0:1;
}
/****** libfun/funsort *******************************************************
*
* NAME
* funsort -- Sort all functions defined via newfun()
*
* SYNOPSIS
* funsort();
*
* void funsort(void);
*
* FUNCTION
* Here we sort all functions defined via newfun() alphabetically.
*
* INPUTS
* none
*
* RESULT
* none
*
* SEE ALSO
* newfun(), funfree()
*
******************************************************************************
*
*/
static int funbubble(libfun_t *a)
{
int result= 0;
/* perform a recursive bubble-sort on `a' and it's successors
return the #of bubbles */
if(a && a->succ)
{
libfun_t *b= a->succ;
if( strcmp(a->name, b->name) > 0 )
{
if( (b->pred= a->pred) )
b->pred->succ= b;
if( (a->succ= b->succ) )
a->succ->pred= a;
b->succ= a;
a->pred= b;
++result;
}
result += funbubble(b);
}
return result;
}
/**/
void funsort(void)
{
/* as long as there are bubbles... */
while( funbubble(libfun_head(funlist)) );
/* sorting might have made another libfun_t the head of funlist */
funlist= libfun_head(funlist);
for(thisfun= funlist; thisfun; thisfun= thisfun->succ)
{
/* make sure that thisfun->sec is the head of the sections */
thisfun->sec= funsec_head(thisfun->sec);
}
thisfun= (libfun_t *)0;
thissec= (funsec_t *)0;
}
/****** libfun/funexpand *****************************************************
*
* NAME
* funexpand -- Expand macros in all function bodies (unused)
*
* SYNOPSIS
* error= funexpand(macros);
*
* int funexpand(char **macros);
*
* FUNCTION
* This function performs a strexpand() on all body text sections of all
* functions.
*
* INPUTS
* macros - the expansion table for strexpand()
*
* RESULT
* error - either 0 on success or !=0 in case of an error
*
* SEE ALSO
* strexpand()
*
******************************************************************************
*
*/
int funexpand(char **macros)
{
int err= 0;
libfun_t *lf;
funsec_t *fs;
for(lf= libfun_head(funlist); lf && (err==0); lf= lf->succ)
{
for(fs= funsec_head(lf->sec); fs && (err==0); fs= fs->succ)
{
if( fs->data.text )
{
char *x= strexpand(fs->data.text, macros);
if(x)
{
free(fs->data.text);
fs->data.text= x;
}
else err= 1;
}
}
}
return err;
}
/****** libfun/funindent *****************************************************
*
* NAME
* funindent -- Perform an indentation correction on all functions
*
* SYNOPSIS
* error= funindent(indent, tabsize);
*
* int funindent(int indent, int tabsize);
*
* FUNCTION
* This function performs a global rework on all functions defined via
* newfun(). The first thing this function does is converting tabs in
* all body text lines into spaces. Then the indentation of body text
* lines in all functions is then resized to `indent' spaces.
* The indentation is minimized if `indent' is 0. The `tabsize' is
* needed to compute the minimum indentation of a body text, i.e. the
* maximum width of a columnar block beginning at column 1 which cuts
* leading white space without hurting any text.
*
* INPUTS
* indent - The number of spaces used for the new indentation
* of all body text lines
* tabsize - The number of columns between two tab stops
*
* RESULT
* error - either 0 on success or !=0 in case of an error
*
* SEE ALSO
*
******************************************************************************
*
*/
int funindent(int indent, int tabsize)
{
int err= 0;
libfun_t *lf;
funsec_t *fs;
for(lf= libfun_head(funlist); lf && (err==0); lf= lf->succ)
{
for(fs= funsec_head(lf->sec); fs && (err==0); fs= fs->succ)
{
char *s= fs->data.text;
/*printf("%s: %s\n",lf->name,fs->name);*/
if(s && *s)
{
int num_lines = 1; /* the number of lines in the body text */
int num_tabs = 0; /* number of tabs used in the body text */
int i, k; /* indentation counter */
int i_min= -1; /* minimum indentation of this body text */
/* compute the minimum indentation `i_min' in `s' */
while(*s)
{
/* get the indentation `i' of the current line */
for(i=0; *s==' ' || *s=='\t'; s++) {
if(*s=='\t') i+= tabsize, i-= (i%tabsize), num_tabs++;
else i++;
}
if( i>0 && (i<i_min || i_min<0) )
i_min= i;
for(;*s && *s!='\n';s++)
if(*s=='\t') ++num_tabs;
while(*s=='\n')
++s, ++num_lines;
}
if(i_min > 1)
{
/* allocate a new string buffer for the indented fs->data.text */
char *x= (char *)malloc( (size_t)(strlen(s= fs->data.text) + num_lines*indent + num_tabs*tabsize + 1) );
if(x)
{
char *t= x;
while(*s)
{
/* get the indentation of the current line */
for(i=0; *s==' ' || *s=='\t'; s++) {
if(*s=='\t') i+= tabsize, i-= (i%tabsize);
else i++;
}
if( *s && (*s!='\n') )
{
/* cut the columnar block & add the new indentation */
for(k= i - i_min + indent; k>0; k--)
*t++= ' ';
/* `i' still holds the indentation of the old body text line.
We need this value to expand tabs as if we would still
have the old indentation */
for(; *s && *s!='\n'; s++)
{
if(*s=='\t')
{
/* DICE (Amiga) compiles the following line wrong! */
/*do { *t++= ' '; } while( (++i) % tabsize );*/
do { *t++= ' '; i++; } while( (i % tabsize) );
}
else i++, *t++= *s;
}
}
while(*s=='\n')
*t++= *s++;
}
*t= '\0';
free(fs->data.text);
fs->data.text= x;
}
else err= __LINE__;
}
}
}
}
return err;
}
/****** libfun/newsec ********************************************************
*
* NAME
* newsec -- Add a new heading to the current function description
*
* SYNOPSIS
* error= newsec(title);
*
* int newsec(char *title);
*
* FUNCTION
* This function adds a new section heading `title' to the current
* function description which began with the last newfun() call.
* The following calls of addtext() will add the text to this new
* section.
*
* INPUTS
* title - The section heading keyword
*
* RESULT
* error - either 0 on success or !=0 in case of an error
*
* SEE ALSO
* newfun(), addtext()
*
******************************************************************************
*
*/
static funsec_t *funsec_new(char *title)
{
funsec_t *fs= (funsec_t *)malloc( sizeof(funsec_t) );
if(fs)
{
fs->name= (title) ? strdup(title) : (char *)0;
if(title && !fs->name)
{
free(fs);
fs= (funsec_t *)0;
}
else
{
fs->succ =
fs->pred = (funsec_t *)0;
fs->data.text = (char *)0;
fs->data.len =
fs->data.size = 0;
}
}
return fs;
}
/**/
int newsec(char *title)
{
int err= 0;
if(thisfun)
{
funsec_t *new= funsec_new(title);
if(new)
{
funsec_t *fs= funsec_tail(thisfun->sec);
if(fs)
{
fs->succ= new;
new->pred= fs;
}
else thisfun->sec= new;
}
else err= 2;
thissec= new;
}
else err= 1;
return err;
}
/****** libfun/addtext *******************************************************
*
* NAME
* addtext -- Add a new line of text to the current function description
*
* SYNOPSIS
* error= addtext(text);
*
* int funindent(char *text);
*
* FUNCTION
* This function dynamically adds a new line of text to the current
* section in the current function description. There does not need
* to be a trailing newline `\n' at the end of `text'.
*
* INPUTS
* text - The string to add to the description
*
* RESULT
* error - either 0 on success or !=0 in case of an error
*
* NOTES
* Body text can only be added to a section. There must be at least
* one newsec() following newfun() before this function can add body
* text lines.
*
* SEE ALSO
* newsec(), funfree()
*
******************************************************************************
*
*/
int addtext(char *text)
{
int err= 0;
if(thissec)
{
if(text)
{
/* get the minimum needed size of the text block */
size_t len= thissec->data.len + 1 + strlen(text) + 1; /* '\n' + '\0' */
/* see if we have enough room for '\n' and text */
if(len >= thissec->data.size)
{
/* resize the text buffer to the needed size + SECMINSIZE chars */
char *old= thissec->data.text;
char *new= (char *)my_realloc(old, (SECMINSIZE + len) * sizeof(char) );
if(new)
{
thissec->data.text = new;
thissec->data.size = SECMINSIZE + len;
if(!old)
*new= '\0';
}
else /* !new */
{
free(thissec->data.text);
thissec->data.text = (char *)0;
thissec->data.len =
thissec->data.size = 0;
err= 1;
}
}
/* append the new `text' portion to the section text */
if(thissec->data.text)
{
if(*thissec->data.text)
strcat(thissec->data.text,"\n");
if(*text)
strcat(thissec->data.text,text);
thissec->data.len= strlen(thissec->data.text);
}
}
/* else: no error */
}
else err= -1;
return err;
}
/****** libfun/getfun ********************************************************
*
* NAME
* getfun -- Get a function by name
*
* SYNOPSIS
* fun= getfun(name)
*
* char *getfun(char *name);
*
* FUNCTION
* This function searches the list of function descriptions for
* a function `name' and returns a pointer `fun' to the name of the
* function or a (char *)0 if there is no such function `name'.
*
* INPUTS
* name - The name of the function to look for
*
* RESULT
* fun - The real name of the function `name' or (char *)0
* if no function `name' was found.
*
* SEE ALSO
* newfun(), getsec()
*
******************************************************************************
*
*/
char *getfun(char *name)
{
libfun_t *lf= (libfun_t *)0;
if(name)
{
for(lf= libfun_head(funlist); (lf && strcmp(lf->name, name)); lf= lf->succ)
;
}
else lf= thisfun;
return lf ? lf->name : (char *)0;
}
/****** libfun/getsec ********************************************************
*
* NAME
* getsec -- Get a section text via section heading
*
* SYNOPSIS
* text= getsec(heading)
*
* char *getsec(char *heading);
*
* FUNCTION
* This function searches for the section `heading' in the function
* description of the current function. If this section exists then
* the corresponding section text is returned.
*
* INPUTS
* heading - The section title keyword to look for
*
* RESULT
* text - The section text of that section or (char *)0 if
* there is no such section in the description of the
* current function.
*
* SEE ALSO
* newsec(), getfun()
*
******************************************************************************
*
*/
char *getsec(char *name)
{
funsec_t *fs= (funsec_t *)0;
if(name)
{
if(thisfun)
{
for(fs= funsec_head(thisfun->sec); (fs && strcmp(fs->name, name)); fs= fs->succ)
;
}
}
else fs= thissec;
return fs ? fs->data.text : (char *)0;
}
/****** libfun/islib **********************************************************
*
* NAME
* islib -- Find a library in the list of functions
*
* SYNOPSIS
* gotit= islib(name)
*
* int islib(char *name);
*
* FUNCTION
* Scan the list of functions for a function which begins with `name'
* and has a `/' immediately following `name'.
*
* INPUTS
* name - The name of the library (without a trailing `/')
*
* RESULT
* gotit - 1 if there is at least one function `name/...'
* 0 otherwise.
*
******************************************************************************
*
*/
int islib(char *name)
{
libfun_t *lf= (libfun_t *)0;
if(name)
{
size_t l= strlen(name);
for(lf= libfun_head(funlist); (lf && strncmp(lf->name, name, l)); lf= lf->succ)
;
if(lf && lf->name && (lf->name)[l]!='/')
lf= (libfun_t *)0;
}
return lf ? 1:0;
}
/****** libfun/stepfun *******************************************************
*
* NAME
* stepfun -- Move the current function pointer
*
* SYNOPSIS
* fun= stepfun(trigger);
*
* char *stepfun(int trigger);
*
* FUNCTION
* This function moves the current function pointer according to the
* `trigger' value.
*
* INPUTS
* trigger - < 0 moves back `-trigger' functions
* = 0 moves to the first function
* > 0 moves forward `trigger' functions
*
* RESULT
* fun - The name of the function or (char *)0
*
* SEE ALSO
* stepsec()
*
******************************************************************************
*
*/
char *stepfun(int trigger)
{
char *result= (char *)0;
if(trigger > 0)
{
for(; thisfun && (trigger > 0); trigger--)
thisfun= thisfun->succ;
}
else if(trigger < 0)
{
for(; thisfun && (trigger < 0); trigger++)
thisfun= thisfun->pred;
}
else /* trigger == 0 */
thisfun= libfun_head(funlist);
if(thisfun)
{
thissec= funsec_head(thisfun->sec);
result= thisfun->name;
}
else thissec= (funsec_t *)0;
return result;
}
/****** libfun/stepsec *******************************************************
*
* NAME
* stepsec -- Move the current section pointer
*
* SYNOPSIS
* sec= stepsec(trigger);
*
* char *stepsec(int trigger);
*
* FUNCTION
* This function moves the current section pointer according to the
* `trigger' value.
*
* INPUTS
* trigger - < 0 moves back `-trigger' sections
* = 0 moves to the first section
* > 0 moves forward `trigger' sections
*
* RESULT
* sec - The name of the section or (char *)0
*
* SEE ALSO
* stepfun()
*
******************************************************************************
*
*/
char *stepsec(int trigger)
{
char *result= (char *)0;
if(trigger > 0)
{
for(; thissec && (trigger > 0); trigger--)
thissec= thissec->succ;
}
else if(trigger < 0)
{
for(; thissec && (trigger < 0); trigger++)
thissec= thissec->pred;
}
else /* trigger == 0 */
{
if(thisfun)
thissec= funsec_head(thisfun->sec);
else
thissec= (funsec_t *)0;
}
if(thissec)
result= thissec->name;
return result;
}
/****** libfun/funfree *******************************************************
*
* NAME
* funfree -- Dispose all function descriptions
*
* SYNOPSIS
* funfree();
*
* void funfree(void);
*
* FUNCTION
* This function disposes all function descriptions including all their
* sections.
*
* INPUTS
* none
*
* RESULT
* none
*
* SEE ALSO
* newfun(), newsec(), addtext()
*
******************************************************************************
*
*/
static funsec_t *funsec_dispose(funsec_t *fs)
{
if(fs)
{
fs->succ= funsec_dispose(fs->succ);
if(fs->name)
free(fs->name);
if(fs->data.text)
free(fs->data.text);
}
return (funsec_t *)0;
}
static libfun_t *libfun_dispose(libfun_t *lf)
{
if(lf)
{
lf->succ= libfun_dispose(lf->succ);
if(lf->name)
free(lf->name);
lf->sec= funsec_dispose( funsec_head(lf->sec) );
free(lf);
}
return (libfun_t *)0;
}
void funfree(void)
{
funlist= thisfun= libfun_dispose( libfun_head(funlist) );
thissec= (funsec_t *)0;
}