#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <tos.h>

	/* io streams */
		/* global um sie im fehlerfall schliežen zu k”nnen */
FILE *dest;
FILE *source;

	/* parameter die durch kommandozeilen optionen ge„ndert werden k”nnen */
		/* definition der zu schreibenden daten */
int write_function=0;
int write_typedef=0;
int write_define=0;
		/* doppelte referenzen nur einmal schreiben */
int dont_write_double=1;

		/* headerdatei fr hypertext */
char header_file[128]="HEADER.STG";
		/* ausgabedatei */
char out_file[128]="SHELP.STG";

char database[128]="Online-Hilfe zu C-Sourcen";

		/* puffergr”že fr typedef/funktionskopf */
long buf_size=8*1024l;
		/* puffergr”že fr namen */
long names_size=64*1024l;

		/* zeiger auf puffer */
char *fu;
char *buffer,*b;

typedef enum {
	FUNCTION=0,
	TYPEDEF,
	DEFINE,
} NAME_TYP;

typedef struct _names {
	struct _names 	*next;		/* zeiger auf n„chste struktur */
	int 			count;		/* nummer bei mehrfacheintr„gen */
	int 			unique;		/* name eindeutig (oder erstmalig) */
	NAME_TYP		typ;		/* typ des eintrags */
	char 			name[];
} NAMES;

NAMES *names,*next;
int name_count[3];				/* zaehler fr eintrage der versch. typen */

/*
		fehlercodes
*/
typedef enum {
	ERR_INTERNAL,
	ERR_FILE,
	ERR_MEMORY,
	ERR_OPTIONS,
	ERR_BUFFER,
	ERR_NAMES,
	ERR_NOFILES,
} ERR_NUMS;

void do_error(ERR_NUMS error)
{
	switch ( error ) {
	  case ERR_INTERNAL:		/* should not happen */
		fprintf(stderr,"Something went wrong\n");
	  break;
	  case ERR_MEMORY:
	  	fprintf(stderr,"Speicher reicht nicht\n");
	  break;
	  case ERR_FILE:
	  	fprintf(stderr,"Dateifehler\n");
	  break;
	  case ERR_OPTIONS:
	  	fprintf(stderr,"unbekannte Option angegeben\n");
	  break;
	  case ERR_BUFFER:
	  	fprintf(stderr,"Puffer fr Strukturen/Funktionen voll, vergr”žern mit -b \n");
	  break;
	  case ERR_NAMES:
	  	fprintf(stderr,"Puffer fr Namen voll, vergr”žern mit -s \n");
	  break;
	  case ERR_NOFILES:
	  	fprintf(stderr,"Keine Quelldateien angegeben \n");
	  break;
	}
	if ( source )
		fclose(source);
	if ( dest )
		fclose(dest);
	if ( fu )
		free(fu);
	if ( buffer )
		free(buffer);
	if ( names )
		free(names);

	exit(1);
}

/*
	schreibe in puffer
*/
void init_buffer(void)
{
	b=buffer;
}
void wr_buffer(char c)
{
	if ( b<buffer+buf_size )
		*b++=c;
	else
		do_error(ERR_BUFFER);
}

NAMES *protocol_name(char *name,NAME_TYP typ)
	/*
		protokolliere namen und typ in des liste 'names'
	*/
{
NAMES *act;
long len;
int unique=1;
int count=0;

	for ( act=names; act->next!=0l; act=act->next ) {
		if ( !strcmp(name,act->name) ) {
			if ( dont_write_double )
				return 0l;

			if ( typ==act->typ ) {
				count=act->count+1;
				unique=act->unique;
			}
			else
				unique=0;
		}
	}

	len=sizeof(NAMES)+strlen(name)+1;
	if ( len&1 )
		len++;
	next->next=(NAMES*)((char*)next+len);
	if ( next->next>(NAMES*)((char*)names+names_size) )
		do_error(ERR_NAMES);

	name_count[typ]++;
	next->typ=typ;
	next->count=count;
	next->unique=unique;
	strcpy(next->name,name);
	act=next;
	next=next->next;
	next->next=0l;
	return act;
}

void get_typedef_name(char *str)
	/*
		ermittle namen einer typedef angabe:
			zwei m”glichkeiten: typedef ... name;
								typedef ... (*name)(...);	(zeiger auf funktion)
	*/
{
char *h;
int klammer=0;
int something=0;

	h=buffer+strlen(buffer);
	while ( h>buffer ) {
		if ( isalnum(*h) || *h=='_' )
			something=1;
		if ( *h==')' )
			klammer++;
		if ( *h=='(' )
			klammer--;
		if ( !klammer && something && isspace(*h) )
			break;
		h--;
	}

	while ( !isalpha(*h) && *h!='_' )
		h++;

	while ( isalnum(*h) || *h=='_' )
		*str++=*h++;
	*str=0;
}

void store_name(NAMES *name,char *file,int line,char typ)
	/*
		schreibe namen in zieldatei

			@node NAME
			FILE file LINE nn

		wobei 'file' link auf Datei/Zeile ist
		gegebenenfalls doppelte Eintr„ge markieren
	*/
{
	fputs("@node ",dest);
	fputs(name->name,dest);

	if ( name->unique ) {
		if ( name->count )
			fprintf(dest,".%d\n\nFILE @{%s link %s/Main %d} LINE @{B}%d@{b}\n\n",name->count,file,file,line,line);
		else
			fprintf(dest,"\n\nFILE @{%s link %s/Main %d} LINE @{B}%d@{b}\n\n",file,file,line,line);
	}
	else {
		if ( name->count )
			fprintf(dest,".%c%d\n\nFILE @{%s link %s/Main %d} LINE @{B}%d@{b}\n\n",typ,name->count,file,file,line,line);
		else
			fprintf(dest,".%c\n\nFILE @{%s link %s/Main %d} LINE @{B}%d@{b}\n\n",typ,file,file,line,line);
	}
}

void store_typedef(char *file,int line)
	/*
		schreibe typedef angaben aus buffer nach DEST
	*/
{
char str[256];
NAMES *name;


	if ( !write_typedef )
		return;

	get_typedef_name(str);

	name=protocol_name(str,TYPEDEF);
	if ( !name )
		return;

	store_name(name,file,line,'T');

	fputs("typedef",dest);
	fputs(buffer,dest);
	fputs("\n\@endnode\n\n",dest);
}

void copy_typedef(int *line)
	/*
		lese typedef angaben ein
	*/
{
enum {
	C_READ,
	C_COMM_1,
	C_COMM_2,
	C_COMM_3,
} mode=C_READ;
int block_cnt=0,com_cnt=0;
int exit=0;
char c;

	init_buffer();
	do {
		c=fgetc(source);
		if ( c=='\n' )
			(*line)++;

		switch ( mode ) {
				/* lese text */
		  case C_READ:
			if ( c=='/' ) {			/* kommentar k”nnte anfangen */
				mode=C_COMM_1;
			}
			else if ( c=='{' )
				block_cnt++;
			else if ( c=='}' )
				block_cnt--;
			else if ( block_cnt==0 && c==';' )
				exit=1;
		  break;

				/* lese kommentar */
		  case C_COMM_1:
		  	if ( c=='*' ) {
		  		com_cnt++;
		  		mode=C_COMM_2;
			}
		  	else {
		  		if ( com_cnt )
		  			mode=C_COMM_2;
				else if ( c=='/' )
					mode=C_COMM_1;
		  		else
			  		mode=C_READ;
			}
		  break;
		  case C_COMM_2:
		  	if ( c=='*' )
		  		mode=C_COMM_3;
			else if ( c=='/' )
				mode=C_COMM_1;
		  break;
		  case C_COMM_3:
			if ( c=='/' ) {
				com_cnt--;
				if ( com_cnt==0 ) {
					mode=C_READ;
				}
				else
					mode=C_COMM_2;
			}
			else if ( c!='*' )
				mode=C_COMM_2;
		  break;
		}

		wr_buffer(c);
	} while ( !exit && !feof(source) );

	if ( feof(source) )
		do_error(ERR_INTERNAL);

	wr_buffer(0);
}

void get_define_name(char *str)
	/*
		ermittle namen in define-anweisung
	*/
{
char *h;

	h=buffer;
	while ( isalnum(*h) || *h=='_' )
		*str++=*h++;
	*str=0;
}

void store_define(char *file,int line)
	/*
		schreibe #define aus buffer nach DEST
	*/
{
char str[256];
NAMES *name;

	if ( !write_define )
		return;

	get_define_name(str);

	name=protocol_name(str,DEFINE);
	if ( !name )
		return;

	store_name(name,file,line,'D');

	fputs("#define ",dest);
	fputs(buffer,dest);
	fputs("\n\@endnode\n\n",dest);
}

void copy_define(int *line)
	/*
		lese #define und kopiere in puffer
		lese bis maximum von 
			ende der zeile  oder
			ende eines in der gleichen zeile beginnenden kommentars
	*/
{
enum {
	C_READ,
	C_COMM_1,
	C_COMM_2,
	C_COMM_3,
} mode=C_READ;
int com_cnt=0;
int exit=0;
char c;

	init_buffer();
	do {
		c=fgetc(source);
	} while ( isspace(c) );
	ungetc(c,source);

	do {
		c=fgetc(source);
		if ( c=='\n' )
			(*line)++;

		switch ( mode ) {
				/* lese text */
		  case C_READ:
			if ( c=='/' ) 			/* kommentar k”nnte anfangen */
				mode=C_COMM_1;
			else if ( c=='\n' )
				exit=1;
		  break;

				/* lese kommentar */
		  case C_COMM_1:
		  	if ( c=='*' ) {
		  		com_cnt++;
		  		mode=C_COMM_2;
			}
		  	else {
		  		if ( com_cnt )
		  			mode=C_COMM_2;
				else if ( c!='/' )
			  		mode=C_READ;
			}
		  break;
		  case C_COMM_2:
		  	if ( c=='*' )
		  		mode=C_COMM_3;
			else if ( c=='/' )
				mode=C_COMM_1;
		  break;
		  case C_COMM_3:
			if ( c=='/' ) {
				com_cnt--;
				if ( com_cnt==0 ) {
					mode=C_READ;
				}
				else
					mode=C_COMM_2;
			}
			else if ( c!='*' )
				mode=C_COMM_2;
		  break;
		}

		wr_buffer(c);
	} while ( (!exit || com_cnt) && !feof(source) );
	
	wr_buffer(0);
}

void get_fu_name(char *str)
	/*
		ermittle funktionsnamen
			berliest rckw„rts die Parameterliste
			nimmt ersten folgenden namen
	*/
{
char *h;
enum {
	FU_READ,
	FU_COM1,
	FU_COM2,
	FU_COM3,
	FU_NAME,
	FU_NAME2,
} mode=FU_READ;
int com_cnt=0,klammer=0;
int exit=0;

	h=fu+strlen(fu);
	do {
		switch ( mode ) {
		  case FU_READ:
		  	if ( *h=='/' )
		  		mode=FU_COM1;
			else if ( *h==')' ) {
				klammer++;
			}
			else if ( *h=='(' ) {
				klammer--;
				if ( !klammer )
					mode=FU_NAME;
			}
		  break;
		  case FU_COM1:
		  	if ( *h=='*' ) {
		  		com_cnt++;
		  		mode=FU_COM2;
		  	}
		  	else {
		  		if ( com_cnt )
					mode=FU_COM2;
		  		else
			  		mode=FU_READ;
			}
		  break;
		  case FU_COM2:
		  	if ( *h=='/' )
		  		mode=FU_COM1;
		  	else if ( *h=='*' )
		  		mode=FU_COM3;
		  break;
		  case FU_COM3:
		  	if ( *h=='/' ) {
		  		com_cnt--;
		  		if ( !com_cnt )
		  			mode=FU_READ;
		  		else
		  			mode=FU_COM2;
		  	}
		  	else if ( *h!='*' )
			  	mode=FU_COM2;
		  break;
		  case FU_NAME:
		  	if ( !isspace(*h) )
		  		mode=FU_NAME2;
		  break;
		  case FU_NAME2:
		  	if ( !isalnum(*h) && *h!='_' )
		  		exit=1;
		  break;
		}
		if ( !exit )
			h--;
	} while ( !exit && h>=fu );

	h++;
	while ( isalnum(*h) || *h=='_' )
		*str++=*h++;
	*str=0;
}

void store_function(char *file,int line)
	/*
		schreibe funktion
	*/
{
char str[256];
NAMES *name;

	if ( !write_function )
		return;

	get_fu_name(str);

	name=protocol_name(str,FUNCTION);
	if ( !name )
		return;

	store_name(name,file,line,'F');

	fputs(fu,dest);
	fputs("\n\@endnode\n\n",dest);
}

void do_parse(char *file,int *line)
	/*
		lese quelle
			'etwas' mižraten :-(
	*/
{
char c;
enum {
	M_READ,			/* zust„nde des automaten zur typedef-erkennung */
	M_READ_SPACE,
	M_READ_T,
	M_READ_Y,
	M_READ_P,
	M_READ_E,
	M_READ_D,
	M_READ_E2,
	M_READ_F,
	M_COMM_1,
	M_COMM_2,
	M_COMM_3,
	M_STRING,
	M_STRING2,
	M_CHARACTER,
	M_CHARACTER2,
} mode;
int com_cnt=0;		/* verschachtelte kommentare */

enum {				/* zust„nde des automaten zur define-erkennung */
	D_READ,			/*  wertet typedef-automaten-zust„nde mit aus */
	D_READ_HASH,	/*  z.B. fr kommentare/strings */
	D_READ_D,
	D_READ_E,
	D_READ_F,
	D_READ_I,
	D_READ_N,
	D_READ_E2,
} dmode=D_READ;

enum {
	F_READ,
	F_PRAEPROC,
	F_NAME,
	F_FUNCTION_LIST,
	F_FUNCTION,
	F_FUTEXT,
} fmode=F_READ;
int name=0,block=0;
char *_fu=fu;
int copy=0;
int klammer=0;
int xline,xxline;

	mode=M_READ_SPACE;

	do {
		c=fgetc(source);
		if ( c=='\n' )
			(*line)++;

			/*
				automat fr erkennung von funktionen
						(muss vor automat fr typedef stehen, 
						 da dessen zustand wichtig)
			*/
		if ( !com_cnt && mode!=M_STRING && mode!=M_STRING2 && mode!=M_CHARACTER && mode!=M_CHARACTER2 ) {
			switch ( fmode ) {
			  case F_READ:
				if ( c=='{' ) {	/* } */
					block=1;
					fmode=F_FUTEXT;
				}
				if ( mode==M_READ_SPACE ) {
					if ( c=='#' )
						fmode=F_PRAEPROC;
					else if ( isalpha(c) || c=='_' ) {
						if ( !copy ) {
							_fu=fu;
							xxline=*line;
							copy=1;
						}
						name++;
						fmode=F_NAME;
					}
				}
			  break;
			  case F_PRAEPROC:
			  	if ( c=='\n' )
		  			fmode=F_READ;
			  break;
			  case F_NAME:
				if ( !(isalnum(c) || c=='_' || c=='*' || isspace(c))  ) {
					fmode=F_READ;
					if ( c=='(' ) {
						fmode=F_FUNCTION_LIST;
						klammer=1;
					}
					else {
						name=0;
						copy=0;
					}
				}
				else if ( isspace(c) )
					name++;
			  break;
			  case F_FUNCTION_LIST:
				if ( c=='(' )
					klammer++;
				else if ( c==')' ) {
					klammer--;
					if ( !klammer )
						fmode=F_FUNCTION;
				}
			  break;
			  case F_FUNCTION:
				if ( c=='{' ) {	/* } */
					if ( _fu>fu+buf_size )
						do_error(ERR_BUFFER);
					*_fu++=0;
					store_function(file,xxline);
					copy=0;
					name=0;
					block=1;
					fmode=F_FUTEXT;
				}
				else if ( !isspace(c) && c!='/' && c!='*' ) {
									/* war wohl ein prototyp oder sonstwas */
					fmode=F_READ;
					copy=0;
					name=0;
				}
				break;
			  case F_FUTEXT:
				if ( c=='{' )
					block++;
				else if ( c=='}' ) {
					block--;
					if ( !block )
						fmode=F_READ;
				}
			}

			/*
				automat fr erkennung von defines
						(muss vor automat fr typedef stehen, 
						 da dessen zustand wichtig)
			*/
	
			switch ( dmode ) {
			  case D_READ:
				if ( mode==M_READ_SPACE && c=='#' ) {
					dmode=D_READ_HASH;
				}
			  break;
			  case D_READ_HASH:
				if ( c=='d' )
					dmode=D_READ_D;
				else if ( !isspace(c) || c=='\n' )
					dmode=D_READ;
			  break;
			  case D_READ_D:
				if ( c=='e' )
					dmode=D_READ_E;
				else if ( !isspace(c) || c=='\n' )
					dmode=D_READ;
			  break;
			  case D_READ_E:
				if ( c=='f' )
					dmode=D_READ_F;
				else if ( !isspace(c) || c=='\n' )
					dmode=D_READ;
			  break;
			  case D_READ_F:
				if ( c=='i' )
					dmode=D_READ_I;
				else if ( !isspace(c) || c=='\n' )
					dmode=D_READ;
			  break;
			  case D_READ_I:
				if ( c=='n' )
					dmode=D_READ_N;
				else if ( !isspace(c) || c=='\n' )
					dmode=D_READ;
			  break;
			  case D_READ_N:
				if ( c=='e' )
					dmode=D_READ_E2;
				else if ( !isspace(c) || c=='\n' )
					dmode=D_READ;
			  break;
			}
		}
		if ( copy ) {
			if ( _fu>fu+buf_size )
				do_error(ERR_BUFFER);
			*_fu++=c;
		}

		switch ( mode ) {

				/* lese text */
		  case M_READ:
/* { */		if ( isspace(c) || c==';' || c=='}' )		
				mode=M_READ_SPACE;		/* space... -> typedef k”nnte folgen */
			else if ( c=='/' )		/* kommentar k”nnte anfangen */
				mode=M_COMM_1;
			else if ( c=='"' )		/* string f„ngt an */
				mode=M_STRING;
			else if ( c=='\'' )		/* char-const */
				mode=M_CHARACTER;
		  break;

				/* lese kommentar */
		  case M_COMM_1:
		  	if ( c=='*' ) {
		  		com_cnt++;
		  		mode=M_COMM_2;
			}
		  	else {
		  		if ( com_cnt )
		  			mode=M_COMM_2;
				else if ( c=='"' )
					mode=M_STRING;
				else if ( c=='/' )
					mode=M_COMM_1;
				else if ( isspace(c) )
					mode=M_READ_SPACE;
		  		else
			  		mode=M_READ;
			}
		  break;
		  case M_COMM_2:
		  	if ( c=='*' )
		  		mode=M_COMM_3;
			else if ( c=='/' )
				mode=M_COMM_1;
		  break;
		  case M_COMM_3:
			if ( c=='/' ) {
				com_cnt--;
				if ( com_cnt==0 )
					mode=M_READ_SPACE;
				else
					mode=M_COMM_2;
			}
			else if ( c!='*' )
				mode=M_COMM_2;
		  break;

				/* lese string */
		  case M_STRING:
		  	if ( c=='\\' )
		  		mode=M_STRING2;
			else if ( c=='"' )
				mode=M_READ;
		  break;
		  case M_STRING2:
			mode=M_STRING;
		  break;

				/* lese char-const */
		  case M_CHARACTER:
		  	if ( c=='\\' )
		  		mode=M_CHARACTER2;
		  	else if ( c=='\'' )
		  		mode=M_READ;
		  break;
		  case M_CHARACTER2:
		  	mode=M_CHARACTER;
		  break;

				/* lese sukzessive <SPACE>typedef */
		  case M_READ_SPACE:
  			if ( c=='t' )
				mode=M_READ_T;
			else if ( c=='/' )
				mode=M_COMM_1;
			else if ( c=='"' )
				mode=M_STRING;
			else if ( !isspace(c) )
				mode=M_READ;
		  break;
		  case M_READ_T:
			if ( c=='y' )
				mode=M_READ_Y;
			else if ( c=='"' )
				mode=M_STRING;
			else if ( c=='/' )
				mode=M_COMM_1;
			else if ( isspace(c) )
				mode=M_READ_SPACE;
			else
				mode=M_READ;
		  break;
		  case M_READ_Y:
			if ( c=='p' )
				mode=M_READ_P;
			else if ( c=='"' )
				mode=M_STRING;
			else if ( c=='/' )
				mode=M_COMM_1;
			else if ( isspace(c) )
				mode=M_READ_SPACE;
			else
				mode=M_READ;
		  break;
		  case M_READ_P:
			if ( c=='e' )
				mode=M_READ_E;
			else if ( c=='"' )
				mode=M_STRING;
			else if ( c=='/' )
				mode=M_COMM_1;
			else if ( isspace(c) )
				mode=M_READ_SPACE;
			else
				mode=M_READ;
		  break;
		  case M_READ_E:
			if ( c=='d' )
				mode=M_READ_D;
			else if ( c=='"' )
				mode=M_STRING;
			else if ( c=='/' )
				mode=M_COMM_1;
			else if ( isspace(c) )
				mode=M_READ_SPACE;
			else
				mode=M_READ;
		  break;
		  case M_READ_D:
			if ( c=='e' )
				mode=M_READ_E2;
			else if ( c=='"' )
				mode=M_STRING;
			else if ( c=='/' )
				mode=M_COMM_1;
			else if ( isspace(c) )
				mode=M_READ_SPACE;
			else
				mode=M_READ;
		  break;
		  case M_READ_E2:
			if ( c=='f' )
				mode=M_READ_F;
			else if ( c=='"' )
				mode=M_STRING;
			else if ( c=='/' )
				mode=M_COMM_1;
			else if ( isspace(c) )
				mode=M_READ_SPACE;
			else
				mode=M_READ;
		  break;
		}

		if ( mode==M_READ_F ) {
			xline=*line;
			copy_typedef(line);
			store_typedef(file,xline);
			mode=M_READ_SPACE;
			fmode=F_READ;
			dmode=D_READ;
			copy=0;
			name=0;
		}
		else if ( dmode==D_READ_E2 ) {
			xline=*line;
			copy_define(line);
			store_define(file,xline);
			dmode=D_READ;
			mode=M_READ_SPACE;
			copy=0;
			name=0;
		}
	} while ( !feof(source) );

	return;
}

void make_xname(char *out,char *in)
	/*
		erzeuge absoluten dateinamen 'out' aus dem m”glicherweise relativen 'in'
	*/
{
	if ( in[1]==':' )
		strcpy(out,in);
	else {
		out[0]=Dgetdrv()+'A';
		out[1]=':';
		if ( *in=='\\' )
			strcpy(out+2,in);
		else {
			Dgetpath(out+2,0);
			strcat(out,"\\");
			strcat(out,in);
		}
	}
}

void do_file(char *name)
	/*
		bearbeite datei
	*/
{
int line;
char xname[256];

	source=fopen(name,"r");
	if ( !source )
		return;
	line=1;

	make_xname(xname,name);

	do_parse(xname,&line);

	fclose(source);
	source=0l;
}

int qsort_cmp(NAMES **n1,NAMES **n2)
{
	return strcmp((*n1)->name,(*n2)->name);
}

void write_indizes(void)
	/* 
		schreibe index-seiten
	*/
{
int i,j,k,l;
NAMES **index,*n;
char types[]="FTD";

	for ( i=0; i<3; i++ ) {

		switch ( i ) {
		  case TYPEDEF:
			fputs("@node Typ-Definitionen\n\n",dest);
			fputs("@{B}Typ Definitionen@{b}\n\n",dest);
		  break;
		  case DEFINE:
			fputs("@node Pr„prozessor-Definitionen\n\n",dest);
			fputs("@{B}Pr„prozessor Definitionen@{b}\n\n",dest);
		  break;
		  case FUNCTION:
			fputs("@node Funktionen\n\n",dest);
			fputs("@{B}Funktionen@{b}\n\n",dest);
		  break;
		}

		if ( name_count[i] ) {
			index=calloc(name_count[i],sizeof(*index));
			j=0;
			for ( n=names; n->next!=0; n=n->next ) {
				if ( n->typ==i ) {
					index[j++]=n;
				}
			}
			qsort(index,name_count[i],sizeof(*index),qsort_cmp);
			free(index);
	
			for ( j=0; j<name_count[i]; j++ ) {

				l=24;
				if ( index[j]->unique ) {
					if ( index[j]->count ) {
						l=22;
						fprintf(dest,"@{%s.%d link %s.%d}",index[j]->name,index[j]->count,index[j]->name,index[j]->count);
					}
					else
						fprintf(dest,"@{%s link %s}",index[j]->name,index[j]->name);
				}
				else {
					if ( index[j]->count ) {
						l=21;
						fprintf(dest,"@{%s.%c%d link %s.%c%d}",index[j]->name,types[index[j]->typ],index[j]->count,index[j]->name,types[index[j]->typ],index[j]->count);
					}
					else {
						l=22;
						fprintf(dest,"@{%s.%c link %s.%c}",index[j]->name,types[index[j]->typ],index[j]->name,types[index[j]->typ]);
					}
				}
				if ( !((j+1)%3) )
					fputs("\n",dest);
				else {
					if ( strlen(index[j]->name)<l-2 )
						for ( k=l-(int)strlen(index[j]->name); k>0; k-- )
							fputs(" ",dest);
					else
						fputs("  ",dest);
				}
			}
		}
		else {
			fputs("Keine Eintragungen",dest);
		}
		fputs("\n\n@endnode\n\n",dest);
	}
}

void write_filenames(int first,int last,char *names[])
	/* 
		schreibe dateinamen
	*/
{
char str[256];
int i;

	fputs("@node Source-Files\n\n",dest);
	fputs("@{B}Source Files@{b}\n\n",dest);
	for ( i=first; i<last; i++ ) {
		make_xname(str,names[i]);
		fputs("  @{",dest);
		fputs(str,dest);
		fputs(" link ",dest);
		fputs(str,dest);
		fputs("/Main}\n",dest);
	}
	fputs("@endnode",dest);
}
 
int main(int argc,char *argv[])
{
int i,ii;
char c;

	printf("\nSHelp\n\n  Online-Hilfe zu C-Sourcen mit ST-Guide\n");
	printf("  V0.1 31.12.1994\n");
	printf("  written by Th. Morus Walter\n\n");
	if ( argc==1 ) {
		printf("Usage   : shelp [Optionen] File[s]\n");
		printf("Optionen: -d    : doppelte Referenzen jedesmal schreiben (.NR zur Kennung)\n");
		printf("          -sSIZE: Puffergr”že fr Namen angeben (in Kbyte), Default: 64\n");
		printf("          -bSIZE: Puffergr”že fr Strukturen/Funktionsk”pfe angeben (in Kbyte)\n");
		printf("                  Default: 8\n");
		printf("          -hFILE: Headerfile angeben, Default: HEADER.STG\n");
		printf("          -oFILE: Outputfile angeben, Default: SDOKU.STG\n");
		printf("          -iTEXT: Database angeben, Default: \"Online-Hilfe zu C-Sourcen\"\n");
		printf("          -f    : Funktionsdeklarationen ausgeben\n");
		printf("          -t    : Typ-Definitionen (typedef) ausgeben\n");
		printf("          -p    : Pr„prozessor Definitionen ausgeben\n");
		printf("            ist weder -f noch -t noch -p gesetzt, so wird -f -t -p verwendet\n\n");
		return 1;
	}

	i=1;
	while ( *argv[i]=='-' ) {
		switch ( tolower(argv[i][1]) ) {
		  case 'f':
			write_function=1;
		  break;
		  case 't':
			write_typedef=1;
		  break;
		  case 'p':
			write_define=1;
		  break;
		  case 's':
			sscanf(argv[i]+2,"%ld",&names_size);
			names_size*=1024;
		  break;
		  case 'b':
			sscanf(argv[i]+2,"%ld",&buf_size);
			buf_size*=1024;
		  break;
		  case 'd':
			dont_write_double=0;
		  break;
		  case 'h':
		    strcpy(header_file,argv[i]+2);
		  break;
		  case 'o':
		    strcpy(out_file,argv[i]+2);
		  break;
		  case 'i':
		    strcpy(database,argv[i]+2);
		  break;
		  default:
			do_error(ERR_OPTIONS);
		  break;
		}
		i++;
		if ( i==argc )
			break;
	}

	if ( i==argc )
		do_error(ERR_NOFILES);

	if ( write_function==0 && write_typedef==0 && write_define==0 )
		write_function=write_typedef=write_define=1;

	names=malloc(names_size);
	if ( !names )
		do_error(ERR_MEMORY);
	buffer=malloc(buf_size);
	if ( !buffer )
		do_error(ERR_MEMORY);
	fu=malloc(buf_size);
	if ( !fu )
		do_error(ERR_MEMORY);

	next=names;
	next->next=0l;

	dest=fopen(out_file,"w");
	if ( !dest )
		do_error(ERR_FILE);

	fputs("@database \"",dest);
	fputs(database,dest);
	fputs("\"\n",dest);

	source=fopen(header_file,"r");
	if ( source ) {
		c=fgetc(source);
		while ( !feof(source) ) {
			fputc(c,dest);
			c=fgetc(source);
		}
		fclose(source);
		source=0l;
	}
	ii=i;
	for ( ; i<argc; i++ ) {
		printf("bearbeite %s\n",argv[i]);
		do_file(argv[i]);
	}

	printf("schreibe Indexseiten\n");
	write_indizes();
	printf("schreibe Dateiliste\n");
	write_filenames(ii,argc,argv);

	fclose(dest);
	free(fu);
	free(buffer);
	free(names);

	return 0;
}
