[net.sources] shortc

dca@edison.UUCP (David Albrecht) (08/05/86)

I have a UNIX PC which has the unfortunate affliction of possessing
a C compiler which needs unique short names.  It also doesn't support
long defines in the cpp.  Faced with altering the original source
I wasn't too impressed with the shortc utilities prepending of
characters to the name.  Therefore, I altered shortc to instead
produce recapitalization of the offending words to unmatch them.
I wasn't particularly enamored of writing a sed script to do the
conversion either so I also added an option (-c) which substitutes the
words and their remappings into a C program template (called template.c)
and emits it on stdout.  The C program right now is pretty rudimentary
but if you feel so inclined will be easy to extend.
If you get motivated and extend the template to not messing with
string contents etc.. please send me a copy.

Enjoy,

David Albrecht
----------- cut here ---------
#!/bin/sh
echo 'Start of /usr/spool/uucppublic/shortc, part 01 of 01:'
echo 'x - shortc.c'
sed 's/^X//' > shortc.c << '/'
Xchar ID[] = "@(#) shortc";
Xchar Usage[] = "usage: shortc [-symlen] [-p] file ... > Short.h\n";
X/*
X   Produce a set of preprocessor defines which guarantee that all identifiers
X   in the files are unique in the first symlen (default 7) characters.
X   Include the output into each file (or into a common header file).
X   Since the symbols being redefined are ambiguous within symlen chars
X   (that was the problem in the first place), the files must be compiled
X   using a flexnames version of cpp.
X   Lacking that, turn the output into a sed script and massage the source
X   files.  In this case, you may need to specify -p to parse preprocessor
X   lines, but watch for things like include-file names.
X   If using cpp, preprocessor symbols should be weeded out by hand; otherwise
X   they will cause (innocuous) redefinition messages.
X */
X
X#include <ctype.h>
X#include <stdio.h>
X
X#define SYMLEN  7           /* symbols must be unique within ... chars */
X#define MAXLEN  128         /* need a limit for tokenizing */
X#define HASHSIZ 2048        /* power of 2; not an upper limit */
X#define TRUE 1
X#define FALSE 0
X#define MAXSTRING 160
X
Xtypedef struct Symbol symbol;
Xstruct Symbol {
X	symbol  *link;          /* hash chain */
X	union {
X	    long chcase_mask;  /* re-capitalize for mapped name if flag > SEEN */
X	    symbol *xtrunc;    /* symbol which truncates to this one
X				  if flag == TRUNC */
X	} x;
X	char    flag;
X	char    inname[1];
X};
X#define chcase  x.chcase_mask
X#define trunc   x.xtrunc
X#define NOTSEEN 0           /* symbol never seen */
X#define TRUNC   1           /* trunc points to symbol which truncates to
X			       this one */
X#define SEEN    2           /* there is no conflict with this symbol */
X#define MULT    3	    /* re-capitalize to resolve conflict */
X
Xsymbol  *symtab[HASHSIZ];
X
Xstruct subsnames {
X    char *from_name;
X    char *to_name;
X    struct subsnames *next;
X    } *subsname_list = NULL;
X
Xint c_prog = FALSE;
X
Xint     symlen  = SYMLEN;
Xchar    parsepp;            /* if set, parse preprocessor lines */
X
Xsymbol  *lookup();
Xchar    *token(), *truncname();
Xchar    *myalloc();
X
Xextern  char *strcpy(), *strncpy();
Xextern  char *malloc();
X
Xmain (argc, argv) register char **argv; register argc; /*: entry point */
X{
X	while( --argc > 0 )
X	    doarg(*++argv);
X
X	dump();
X	exit(0);
X}
X
Xdoarg (arg) char *arg; /*: process one file or flag arg */
X{
X	register char *s;
X	register symbol *y;
X
X	if( *arg == '-' )
X	{   arg++;
X	    if( isdigit(*arg) )
X		symlen = atoi(arg);
X	    else if( *arg == 'p' )
X		parsepp = 1;
X	    else if( *arg == 'c' )
X		c_prog = TRUE;
X	    else fputs(Usage, stderr);
X	    return;
X	}
X
X	if( freopen(arg, "r", stdin) == NULL )
X	{   perror(arg);
X	    return;
X	}
X
X	while( s = token() )
X	    if( (y = lookup(s))->flag < SEEN )
X		newname(y);
X}
X
Xnewname (y) register symbol *y; /*: pick a new non-colliding name */
X{
X	register symbol *a;
X
X	/* repeat until no collision */
X	for( ;; )
X	{   /* pick another name */
X	    nextname(y);
X	    /* check its truncation for conflicts */
X	    a = lookup(truncname(y));
X	    if( a->flag == NOTSEEN )
X		break;
X	    /* if this is an original symbol and it collides with another
X	     * (maybe modified) symbol, fix the other one instead of this one
X	     */
X	    if( a->flag == TRUNC && y->flag == SEEN )
X	    {   newname(a->trunc);
X		break;
X	    }
X	    /* if already a short name, ok */
X	    if( a == y )
X		return;
X	}
X	/* flag what this truncates to */
X	a->trunc = y;
X	a->flag = TRUNC;
X}
X
Xnextname (y) register symbol *y; /*: find next possible name for this symbol */
X{
X	register char *s, *p;
X	register n;
X
X	switch( y->flag )
X	{   case TRUNC:
X		/* if another symbol truncates to this one, fix it not to */
X		newname(y->trunc);
X	    case NOTSEEN:
X		/* this symbol's name is available, so use it */
X		y->flag = SEEN;
X		y->chcase = 0;
X		return;
X	}
X	y->flag = MULT;
X	y->chcase++;
X}
X
Xchar *truncname (y) register symbol *y; /*: return symbol name truncated to symlen chars */
X{
X	static char buf[MAXLEN+10];
X
X	register long chcase_mask = y->chcase;
X	register i;
X	register char *str = y->inname, *str1 = buf, c;
X
X        for(i = 0; i < symlen; i++) {
X	    if (chcase_mask & 01) {
X		c = *(str++);
X		if (isupper(c)) c = tolower(c);
X		else c = toupper(c);
X		*(str1++) = c;
X 	    }
X	    else {
X		*(str1++) = *(str++);
X	    }
X	    chcase_mask >>= 1;
X	}
X	return buf;
X}
X
Xsymbol *lookup(s) char *s; /*: find name in symbol table */
X{
X	register h;
X
X	{   register char *p;
X	    register c;
X
X	    for( h = 0, p = s; (c = *p++); )
X		h += h + c;
X	}
X
X	{   register symbol *y, **yy;
X
X	    for( y = *(yy = &symtab[h & HASHSIZ-1]);; y = y->link )
X	    {   if( !y )
X		{   y = (symbol *)myalloc(sizeof *y + strlen(s));
X		    strcpy(y->inname, s);
X		    y->flag = NOTSEEN;
X		    y->link = *yy;
X		    *yy = y;
X		    break;
X		}
X		if( strcmp(y->inname, s) == 0 )
X		    break;
X	    }
X	    return y;
X	}
X}
X
Xdump () /*: output all mappings */
X{
X	register symbol *y;
X	register n,i;
X	register char c, *str;
X	struct subsnames *new_name, *curr_name, *prev_name;
X	FILE *template_file;
X	char in_string[MAXSTRING];
X
X    if (!c_prog) {
X	for( n = HASHSIZ; --n >= 0; ) {
X	    for( y = symtab[n]; y; y = y->link ) {
X		if( y->flag == MULT ) {
X		    str = y->inname;
X		    i = y->chcase;
X		    printf("#define %s ", y->inname);
X		    while (c = *(str++)) {
X			if (i & 01) {
X			    if (isupper(c)) c = tolower(c);
X			    else c = toupper(c);
X			    putchar(c);
X			}
X			else {
X			    putchar(c);
X			}
X			i >>= 1;
X		    }
X		    putchar('\n');
X		}
X	    }
X	}
X    }
X    else {
X	for( n = HASHSIZ; --n >= 0; ) {
X	    for( y = symtab[n]; y; y = y->link ) {
X		if( y->flag == MULT ) {
X		    i = y->chcase;
X		    new_name = (struct subsnames *) malloc(sizeof(*new_name));
X		    new_name->from_name =(char *) malloc(strlen(y->inname) + 1);
X		    new_name->to_name = (char *) malloc(strlen(y->inname) + 1);
X		    strcpy(new_name->from_name, y->inname);
X		    strcpy(new_name->to_name, y->inname); 
X		    str = new_name->to_name;
X		    while (c = *(str++)) {
X			if (i & 01) {
X			    if (isupper(c)) c = tolower(c);
X			    else c = toupper(c);
X			    *(str - 1) = c;
X			}
X			i >>= 1;
X		    }
X		    prev_name = NULL;
X		    curr_name = subsname_list;
X		    str = new_name->from_name;
X		    while (curr_name && strcmp(curr_name->from_name,str) < 0) {
X			prev_name = curr_name;
X			curr_name = prev_name->next;
X		    }
X		    if (!prev_name) {
X			new_name->next = subsname_list;
X			subsname_list = new_name;
X		    }
X		    else {
X			new_name->next = prev_name->next;
X			prev_name->next = new_name;
X		    }
X		}
X	    }
X	}
X	template_file = fopen("/usr/src/local/shortc/template.c","r");
X	if (!template_file) {
X	    fprintf(stderr, "unable to open template file\n");
X	    exit(1);
X	}
X	i = TRUE;
X	n = -1;
X	while (fgets(in_string, MAXSTRING - 1, template_file)) {
X	    if (!i && !strncmp(in_string,"/*E*/",5)) i = TRUE;
X	    if (i) fputs(in_string, stdout);
X
X	    if (!strncmp(in_string,"/*1*/",5)) {
X		curr_name = subsname_list;
X		while (curr_name) {
X		    n++;
X		    if (curr_name->next) {
X			printf("	\"%s\",\n", curr_name->from_name);
X		    }
X		    else {
X			printf("	\"%s\"\n", curr_name->from_name);
X		    }
X		    curr_name = curr_name->next;
X		}
X		i = FALSE;
X	    }
X	    else if (!strncmp(in_string,"/*2*/",5)) {
X		curr_name = subsname_list;
X		while (curr_name) {
X		    if (curr_name->next) {
X			printf("	\"%s\",\n", curr_name->to_name);
X		    }
X		    else {
X			printf("	\"%s\"\n", curr_name->to_name);
X		    }
X		    curr_name = curr_name->next;
X		}
X		i = FALSE;
X	    }
X	    else if (!strncmp(in_string,"/*3*/",5)) {
X		printf("	%d\n", n);
X		i = FALSE;
X	    }
X	}
X	close(template_file);
X    }
X}
X
Xchar *token () /*: return next interesting identifier */
X{
X	register c, state = 0;
X	register char *p;
X	static char buf[MAXLEN+1];
X
X	for( p = buf; (c = getchar()) != EOF; )
X	{   if( state )
X	    switch( state )
X	    {   case '/':
X		    if( c != '*' )
X		    {   state = 0;
X			break;
X		    }
X		    state = c;
X		    continue;
X
X		case 'S':
X		    if( c == '/' )
X			state = 0;
X		    else
X			state = '*';
X		case '*':
X		    if( c == state )
X			state = 'S';
X		    continue;
X
X		default:
X		    if( c == '\\' )
X			(void) getchar();
X		    else if( c == state )
X			state = 0;
X		    continue;
X	    }
X	    if( isalnum(c) || c == '_' )
X	    {   if( p < &buf[sizeof buf - 1] )
X		    *p++ = c;
X		continue;
X	    }
X	    if( p > buf )
X	    {   if( p-buf >= symlen && !isdigit(*buf) )
X		{   *p = '\0';
X		    ungetc(c, stdin);
X		    return buf;
X		}
X		p = buf;
X	    }
X	    if( c == '"' || c == '\'' || c == '/' )
X		state = c;
X	    else if( c == '#' && !parsepp )
X		state = '\n';
X	}
X	return NULL;
X}
X
Xchar *myalloc(n) /*: malloc with error detection */
X{
X	register char *p;
X
X	if( !(p = malloc((unsigned)n)) )
X	{   fprintf(stderr, "Out of space\n");
X	    exit(1);
X	}
X	return p;
X}
X
X
X
/
echo 'x - template.c'
sed 's/^X//' > template.c << '/'
X#define MAXSTRING 160
X#include <stdio.h>
X#include <ctype.h>
X
Xchar *from_words[]={
X/*1*/
X	"CleartoEOLN",
X	"_cleartoeoln",
X	"_transmit_on",
X	"address1",
X	"addressII",
X	"alternate_prompt",
X	"alternative_addresses",
X	"current_length",
X	"current_record",
X	"current_time",
X	"default_editor",
X	"default_weedlist",
X	"define_softkeys",
X	"display_central_message",
X	"display_error",
X	"display_headers",
X	"display_title",
X	"expand_env",
X	"expand_filename",
X	"expand_group",
X	"expand_site",
X	"expand_system",
X	"expanded",
X	"expanded_to",
X	"filename",
X	"forwarded",
X	"get_return",
X	"header_page",
X	"header_rec",
X	"header_table",
X	"last_line",
X	"machine_group",
X	"mailbox_defined",
X	"message_count",
X	"message_number",
X	"newaliases",
X	"optimize_and_add",
X	"optimize_arpa",
X	"optimize_cmplx_arpa",
X	"optimize_return",
X	"optionally_enter",
X	"original_cc",
X	"original_msg_num",
X	"parse_arpa_date",
X	"parse_arpa_from",
X	"pattern_enter",
X	"pattern_match",
X	"read_alias_files",
X	"remove_domains",
X	"remove_header",
X	"reply_to",
X	"resolve_received",
X	"ret_addr",
X	"return_value",
X	"return_value_of",
X	"sendmail",
X	"show_menu",
X	"show_msg_status",
X	"softkeys_off",
X	"subject_matches",
X	"subjectbuffer",
X	"system_call",
X	"system_data",
X	"system_data_file",
X	"system_files",
X	"system_hash_file",
X	"system_hash_table",
X	"system_record",
X	"tail_of_string",
X	"talk_to_sys",
X	"temp_file",
X	"timebuff",
X	"timebuffer",
X	"top_of_screen_left",
X	"unexpanded_to"
X/*E*/
X};
Xchar *to_words[]={
X/*2*/
X	"cleartoEOLN",
X	"_Cleartoeoln",
X	"_Transmit_on",
X	"Address1",
X	"aDdressII",
X	"Alternate_prompt",
X	"aLternative_addresses",
X	"CUrrent_length",
X	"cUrrent_record",
X	"Current_time",
X	"Default_editor",
X	"dEfault_weedlist",
X	"Define_softkeys",
X	"DIsplay_central_message",
X	"Display_error",
X	"dIsplay_headers",
X	"diSplay_title",
X	"ExPand_env",
X	"exPand_filename",
X	"eXpand_group",
X	"EXpand_site",
X	"Expand_system",
X	"Expanded",
X	"eXpanded_to",
X	"Filename",
X	"Forwarded",
X	"Get_return",
X	"HEader_page",
X	"Header_rec",
X	"hEader_table",
X	"Last_line",
X	"Machine_group",
X	"Mailbox_defined",
X	"Message_count",
X	"mEssage_number",
X	"Newaliases",
X	"oPtimize_and_add",
X	"opTimize_arpa",
X	"OPtimize_cmplx_arpa",
X	"Optimize_return",
X	"Optionally_enter",
X	"oRiginal_cc",
X	"Original_msg_num",
X	"pArse_arpa_date",
X	"Parse_arpa_from",
X	"Pattern_enter",
X	"pAttern_match",
X	"Read_alias_files",
X	"Remove_domains",
X	"rEmove_header",
X	"Reply_to",
X	"Resolve_received",
X	"Ret_addr",
X	"rEturn_value",
X	"Return_value_of",
X	"Sendmail",
X	"Show_menu",
X	"Show_msg_status",
X	"Softkeys_off",
X	"sUbject_matches",
X	"Subjectbuffer",
X	"sYStem_call",
X	"SYstem_data",
X	"syStem_data_file",
X	"SyStem_files",
X	"System_hash_file",
X	"sYstem_hash_table",
X	"SYStem_record",
X	"Tail_of_string",
X	"Talk_to_sys",
X	"Temp_file",
X	"Timebuff",
X	"tImebuffer",
X	"Top_of_screen_left",
X	"Unexpanded_to"
X/*E*/
X};
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{   char word[MAXSTRING], *wnext_ch = word;
X    int c;
X
X    while ((c = getchar()) != EOF) {
X	if (isalpha(c) || (wnext_ch != word && isdigit(c)) || c == '_') {
X	    *(wnext_ch++) = c;
X	}
X	else {
X	    if (wnext_ch != word) {
X		*wnext_ch = '\0';
X		output_word(word);
X		wnext_ch = word;
X	    }
X	    putchar(c);
X	}
X    }
X    if (wnext_ch != word) {
X	*wnext_ch = '\0';
X	output_word(word);
X	wnext_ch = word;
X    }
X}
X 
Xoutput_word(word)
Xchar *word;
X
X{   register int low_word, high_word, cmp_result, word_num;
X
X    low_word = 0;
X    high_word =
X/*3*/
X/*E*/
X;
X    while (high_word >= low_word) {
X	word_num = (high_word + low_word) >> 1;
X	if (!(cmp_result = strcmp(word, from_words[word_num]))) {
X	    fputs(to_words[word_num], stdout);
X	    return;
X	}
X	else if (cmp_result < 0) {
X	    high_word = word_num - 1;
X	}
X	else {
X	    low_word = word_num + 1;
X	}
X    }
X    fputs(word, stdout);
X}
/
echo 'Part 01 of /usr/spool/uucppublic/shortc complete.'
exit

dca@edison.UUCP (David Albrecht) (08/05/86)

The following is a somewhat altered shortc.  As I have a cc which
uses short names and a cpp which doesn't support flexnames I am
faced with altering the original source of some programs to get
them to pass through my CC.  The original shortc was very useful
in this regard but I was unhappy with its algorithm of prepending
characters to the names to make them unique.

I therefore altered shortc to instead use something in my opinion
more swave and deboner i.e. recapitalization
to eliminate collisions.  I also altered it to have an option (-c)
which will emit a C program which will filter the names to their
unique counterparts.  The C program is very rudimentary but is
in the form of a template which can be easily extended (if
you make a more sophisticated version of the template please
send me a copy).

Finally, I realised that it used a last truncation
wins algorithm which makes it impossible guarantee that a symbol
will not be truncated by ordering the files or by including a
special file at the front which is a list of symbols you want
unaltered.  I 'fixed' it (commented out some code) so that
first truncation wins.  If you saw the original posting I 
am resubmitting this because I only realised that last truncation
wins after I sent it out.

Enjoy,

David Albrecht

----------- cut here -------------
#!/bin/sh
echo 'Start of /usr/spool/uucppublic/shortc, part 01 of 01:'
echo 'x - shortc.c'
sed 's/^X//' > shortc.c << '/'
Xchar ID[] = "@(#) shortc";
Xchar Usage[] = "usage: shortc [-symlen] [-cp] file ... > Short.h\n";
X/*
X   Produce a set of preprocessor defines which guarantee that all identifiers
X   in the files are unique in the first symlen (default 7) characters.
X   Include the output into each file (or into a common header file).
X   Since the symbols being redefined are ambiguous within symlen chars
X   (that was the problem in the first place), the files must be compiled
X   using a flexnames version of cpp.
X   Lacking that, turn the output into a sed script and massage the source
X   files.  In this case, you may need to specify -p to parse preprocessor
X   lines, but watch for things like include-file names.
X   Alternatively, you can specify -c as an option and instead of a list
X   of defines the C source for a program to filter the names will be
X   emitted.
X   If using cpp, preprocessor symbols should be weeded out by hand; otherwise
X   they will cause (innocuous) redefinition messages.
X   To lock in names that you want unchanged (if possible) list the files
X   containing them first on the processing list.  If symbols and the
X   interfering names are in the same file then dummy up a file which
X   is nought but a list of names and include it first.
X */
X
X#include <ctype.h>
X#include <stdio.h>
X
X#define SYMLEN  7           /* symbols must be unique within ... chars */
X#define MAXLEN  128         /* need a limit for tokenizing */
X#define HASHSIZ 2048        /* power of 2; not an upper limit */
X#define TRUE 1
X#define FALSE 0
X#define MAXSTRING 160
X
Xtypedef struct Symbol symbol;
Xstruct Symbol {
X	symbol  *link;          /* hash chain */
X	union {
X	    long chcase_mask;  /* re-capitalize for mapped name if flag > SEEN */
X	    symbol *xtrunc;    /* symbol which truncates to this one
X				  if flag == TRUNC */
X	} x;
X	char    flag;
X	char    inname[1];
X};
X#define chcase  x.chcase_mask
X#define trunc   x.xtrunc
X#define NOTSEEN 0           /* symbol never seen */
X#define TRUNC   1           /* trunc points to symbol which truncates to
X			       this one */
X#define SEEN    2           /* there is no conflict with this symbol */
X#define MULT    3	    /* re-capitalize to resolve conflict */
X
Xsymbol  *symtab[HASHSIZ];
X
Xstruct subsnames {
X    char *from_name;
X    char *to_name;
X    struct subsnames *next;
X    } *subsname_list = NULL;
X
Xint c_prog = FALSE;
X
Xint     symlen  = SYMLEN;
Xchar    parsepp;            /* if set, parse preprocessor lines */
X
Xsymbol  *lookup();
Xchar    *token(), *truncname();
Xchar    *myalloc();
X
Xextern  char *strcpy(), *strncpy();
Xextern  char *malloc();
X
Xmain (argc, argv) register char **argv; register argc; /*: entry point */
X{
X	while( --argc > 0 )
X	    doarg(*++argv);
X
X	dump();
X	exit(0);
X}
X
Xdoarg (arg) char *arg; /*: process one file or flag arg */
X{
X	register char *s;
X	register symbol *y;
X
X	if( *arg == '-' )
X	{   arg++;
X	    if( isdigit(*arg) )
X		symlen = atoi(arg);
X	    else if( *arg == 'p' )
X		parsepp = 1;
X	    else if( *arg == 'c' )
X		c_prog = TRUE;
X	    else fputs(Usage, stderr);
X	    return;
X	}
X
X	if( freopen(arg, "r", stdin) == NULL )
X	{   perror(arg);
X	    return;
X	}
X
X	while( s = token() )
X	    if( (y = lookup(s))->flag < SEEN )
X		newname(y);
X}
X
Xnewname (y) register symbol *y; /*: pick a new non-colliding name */
X{
X	register symbol *a;
X
X	/* repeat until no collision */
X	for( ;; )
X	{   /* pick another name */
X	    nextname(y);
X	    /* check its truncation for conflicts */
X	    a = lookup(truncname(y));
X	    if( a->flag == NOTSEEN )
X		break;
X	    /* if this is an original symbol and it collides with another
X	     * (maybe modified) symbol, fix the other one instead of this one
X		DCA - eliminated this because it makes it so that last
X                truncation wins.  To lock in names unmodified it would be
X                preferable that the first one wins so that we can
X                include a file at the front which locks in the symbols
X                we want unchanged.
X
X	    if( a->flag == TRUNC && y->flag == SEEN )
X	    {   newname(a->trunc);
X		break;
X	    }
X	    */
X	    /* if already a short name, ok */
X	    if( a == y )
X		return;
X	}
X	/* flag what this truncates to */
X	a->trunc = y;
X	a->flag = TRUNC;
X}
X
Xnextname (y) register symbol *y; /*: find next possible name for this symbol */
X{
X	register char *s, *p;
X	register n;
X
X	switch( y->flag )
X	{   case TRUNC:
X		/* if another symbol truncates to this one, fix it not to */
X		newname(y->trunc);
X	    case NOTSEEN:
X		/* this symbol's name is available, so use it */
X		y->flag = SEEN;
X		y->chcase = 0;
X		return;
X	}
X	y->flag = MULT;
X	y->chcase++;
X}
X
Xchar *truncname (y) register symbol *y; /*: return symbol name truncated to symlen chars */
X{
X	static char buf[MAXLEN+10];
X
X	register long chcase_mask = y->chcase;
X	register i;
X	register char *str = y->inname, *str1 = buf, c;
X
X        for(i = 0; i < symlen; i++) {
X	    if (chcase_mask & 01) {
X		c = *(str++);
X		if (isupper(c)) c = tolower(c);
X		else c = toupper(c);
X		*(str1++) = c;
X 	    }
X	    else {
X		*(str1++) = *(str++);
X	    }
X	    chcase_mask >>= 1;
X	}
X	return buf;
X}
X
Xsymbol *lookup(s) char *s; /*: find name in symbol table */
X{
X	register h;
X
X	{   register char *p;
X	    register c;
X
X	    for( h = 0, p = s; (c = *p++); )
X		h += h + c;
X	}
X
X	{   register symbol *y, **yy;
X
X	    for( y = *(yy = &symtab[h & HASHSIZ-1]);; y = y->link )
X	    {   if( !y )
X		{   y = (symbol *)myalloc(sizeof *y + strlen(s));
X		    strcpy(y->inname, s);
X		    y->flag = NOTSEEN;
X		    y->link = *yy;
X		    *yy = y;
X		    break;
X		}
X		if( strcmp(y->inname, s) == 0 )
X		    break;
X	    }
X	    return y;
X	}
X}
X
Xdump () /*: output all mappings */
X{
X	register symbol *y;
X	register n,i;
X	register char c, *str;
X	struct subsnames *new_name, *curr_name, *prev_name;
X	FILE *template_file;
X	char in_string[MAXSTRING];
X
X    if (!c_prog) {
X	for( n = HASHSIZ; --n >= 0; ) {
X	    for( y = symtab[n]; y; y = y->link ) {
X		if( y->flag == MULT ) {
X		    str = y->inname;
X		    i = y->chcase;
X		    printf("#define %s ", y->inname);
X		    while (c = *(str++)) {
X			if (i & 01) {
X			    if (isupper(c)) c = tolower(c);
X			    else c = toupper(c);
X			    putchar(c);
X			}
X			else {
X			    putchar(c);
X			}
X			i >>= 1;
X		    }
X		    putchar('\n');
X		}
X	    }
X	}
X    }
X    else {
X	for( n = HASHSIZ; --n >= 0; ) {
X	    for( y = symtab[n]; y; y = y->link ) {
X		if( y->flag == MULT ) {
X		    i = y->chcase;
X		    new_name = (struct subsnames *) malloc(sizeof(*new_name));
X		    new_name->from_name =(char *) malloc(strlen(y->inname) + 1);
X		    new_name->to_name = (char *) malloc(strlen(y->inname) + 1);
X		    strcpy(new_name->from_name, y->inname);
X		    strcpy(new_name->to_name, y->inname); 
X		    str = new_name->to_name;
X		    while (c = *(str++)) {
X			if (i & 01) {
X			    if (isupper(c)) c = tolower(c);
X			    else c = toupper(c);
X			    *(str - 1) = c;
X			}
X			i >>= 1;
X		    }
X		    prev_name = NULL;
X		    curr_name = subsname_list;
X		    str = new_name->from_name;
X		    while (curr_name && strcmp(curr_name->from_name,str) < 0) {
X			prev_name = curr_name;
X			curr_name = prev_name->next;
X		    }
X		    if (!prev_name) {
X			new_name->next = subsname_list;
X			subsname_list = new_name;
X		    }
X		    else {
X			new_name->next = prev_name->next;
X			prev_name->next = new_name;
X		    }
X		}
X	    }
X	}
X	template_file = fopen("/usr/src/local/shortc/template.c","r");
X	if (!template_file) {
X	    fprintf(stderr, "unable to open template file\n");
X	    exit(1);
X	}
X	i = TRUE;
X	n = -1;
X	while (fgets(in_string, MAXSTRING - 1, template_file)) {
X	    if (!i && !strncmp(in_string,"/*E*/",5)) i = TRUE;
X	    if (i) fputs(in_string, stdout);
X
X	    if (!strncmp(in_string,"/*1*/",5)) {
X		curr_name = subsname_list;
X		while (curr_name) {
X		    n++;
X		    if (curr_name->next) {
X			printf("	\"%s\",\n", curr_name->from_name);
X		    }
X		    else {
X			printf("	\"%s\"\n", curr_name->from_name);
X		    }
X		    curr_name = curr_name->next;
X		}
X		i = FALSE;
X	    }
X	    else if (!strncmp(in_string,"/*2*/",5)) {
X		curr_name = subsname_list;
X		while (curr_name) {
X		    if (curr_name->next) {
X			printf("	\"%s\",\n", curr_name->to_name);
X		    }
X		    else {
X			printf("	\"%s\"\n", curr_name->to_name);
X		    }
X		    curr_name = curr_name->next;
X		}
X		i = FALSE;
X	    }
X	    else if (!strncmp(in_string,"/*3*/",5)) {
X		printf("	%d\n", n);
X		i = FALSE;
X	    }
X	}
X	close(template_file);
X    }
X}
X
Xchar *token () /*: return next interesting identifier */
X{
X	register c, state = 0;
X	register char *p;
X	static char buf[MAXLEN+1];
X
X	for( p = buf; (c = getchar()) != EOF; )
X	{   if( state )
X	    switch( state )
X	    {   case '/':
X		    if( c != '*' )
X		    {   state = 0;
X			break;
X		    }
X		    state = c;
X		    continue;
X
X		case 'S':
X		    if( c == '/' )
X			state = 0;
X		    else
X			state = '*';
X		case '*':
X		    if( c == state )
X			state = 'S';
X		    continue;
X
X		default:
X		    if( c == '\\' )
X			(void) getchar();
X		    else if( c == state )
X			state = 0;
X		    continue;
X	    }
X	    if( isalnum(c) || c == '_' )
X	    {   if( p < &buf[sizeof buf - 1] )
X		    *p++ = c;
X		continue;
X	    }
X	    if( p > buf )
X	    {   if( p-buf >= symlen && !isdigit(*buf) )
X		{   *p = '\0';
X		    ungetc(c, stdin);
X		    return buf;
X		}
X		p = buf;
X	    }
X	    if( c == '"' || c == '\'' || c == '/' )
X		state = c;
X	    else if( c == '#' && !parsepp )
X		state = '\n';
X	}
X	return NULL;
X}
X
Xchar *myalloc(n) /*: malloc with error detection */
X{
X	register char *p;
X
X	if( !(p = malloc((unsigned)n)) )
X	{   fprintf(stderr, "Out of space\n");
X	    exit(1);
X	}
X	return p;
X}
X
X
X
/
echo 'x - template.c'
sed 's/^X//' > template.c << '/'
X#define MAXSTRING 160
X#include <stdio.h>
X#include <ctype.h>
X
Xchar *from_words[]={
X/*1*/
X	"CleartoEOLN",
X	"_cleartoeoln",
X	"_transmit_on",
X	"address1",
X	"addressII",
X	"alternate_prompt",
X	"alternative_addresses",
X	"current_length",
X	"current_record",
X	"current_time",
X	"default_editor",
X	"default_weedlist",
X	"define_softkeys",
X	"display_central_message",
X	"display_error",
X	"display_headers",
X	"display_title",
X	"expand_env",
X	"expand_filename",
X	"expand_group",
X	"expand_site",
X	"expand_system",
X	"expanded",
X	"expanded_to",
X	"filename",
X	"forwarded",
X	"get_return",
X	"header_page",
X	"header_rec",
X	"header_table",
X	"last_line",
X	"machine_group",
X	"mailbox_defined",
X	"message_count",
X	"message_number",
X	"newaliases",
X	"optimize_and_add",
X	"optimize_arpa",
X	"optimize_cmplx_arpa",
X	"optimize_return",
X	"optionally_enter",
X	"original_cc",
X	"original_msg_num",
X	"parse_arpa_date",
X	"parse_arpa_from",
X	"pattern_enter",
X	"pattern_match",
X	"read_alias_files",
X	"remove_domains",
X	"remove_header",
X	"reply_to",
X	"resolve_received",
X	"ret_addr",
X	"return_value",
X	"return_value_of",
X	"sendmail",
X	"show_menu",
X	"show_msg_status",
X	"softkeys_off",
X	"subject_matches",
X	"subjectbuffer",
X	"system_call",
X	"system_data",
X	"system_data_file",
X	"system_files",
X	"system_hash_file",
X	"system_hash_table",
X	"system_record",
X	"tail_of_string",
X	"talk_to_sys",
X	"temp_file",
X	"timebuff",
X	"timebuffer",
X	"top_of_screen_left",
X	"unexpanded_to"
X/*E*/
X};
Xchar *to_words[]={
X/*2*/
X	"cleartoEOLN",
X	"_Cleartoeoln",
X	"_Transmit_on",
X	"Address1",
X	"aDdressII",
X	"Alternate_prompt",
X	"aLternative_addresses",
X	"CUrrent_length",
X	"cUrrent_record",
X	"Current_time",
X	"Default_editor",
X	"dEfault_weedlist",
X	"Define_softkeys",
X	"DIsplay_central_message",
X	"Display_error",
X	"dIsplay_headers",
X	"diSplay_title",
X	"ExPand_env",
X	"exPand_filename",
X	"eXpand_group",
X	"EXpand_site",
X	"Expand_system",
X	"Expanded",
X	"eXpanded_to",
X	"Filename",
X	"Forwarded",
X	"Get_return",
X	"HEader_page",
X	"Header_rec",
X	"hEader_table",
X	"Last_line",
X	"Machine_group",
X	"Mailbox_defined",
X	"Message_count",
X	"mEssage_number",
X	"Newaliases",
X	"oPtimize_and_add",
X	"opTimize_arpa",
X	"OPtimize_cmplx_arpa",
X	"Optimize_return",
X	"Optionally_enter",
X	"oRiginal_cc",
X	"Original_msg_num",
X	"pArse_arpa_date",
X	"Parse_arpa_from",
X	"Pattern_enter",
X	"pAttern_match",
X	"Read_alias_files",
X	"Remove_domains",
X	"rEmove_header",
X	"Reply_to",
X	"Resolve_received",
X	"Ret_addr",
X	"rEturn_value",
X	"Return_value_of",
X	"Sendmail",
X	"Show_menu",
X	"Show_msg_status",
X	"Softkeys_off",
X	"sUbject_matches",
X	"Subjectbuffer",
X	"sYStem_call",
X	"SYstem_data",
X	"syStem_data_file",
X	"SyStem_files",
X	"System_hash_file",
X	"sYstem_hash_table",
X	"SYStem_record",
X	"Tail_of_string",
X	"Talk_to_sys",
X	"Temp_file",
X	"Timebuff",
X	"tImebuffer",
X	"Top_of_screen_left",
X	"Unexpanded_to"
X/*E*/
X};
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{   char word[MAXSTRING], *wnext_ch = word;
X    int c;
X
X    while ((c = getchar()) != EOF) {
X	if (isalpha(c) || (wnext_ch != word && isdigit(c)) || c == '_') {
X	    *(wnext_ch++) = c;
X	}
X	else {
X	    if (wnext_ch != word) {
X		*wnext_ch = '\0';
X		output_word(word);
X		wnext_ch = word;
X	    }
X	    putchar(c);
X	}
X    }
X    if (wnext_ch != word) {
X	*wnext_ch = '\0';
X	output_word(word);
X	wnext_ch = word;
X    }
X}
X 
Xoutput_word(word)
Xchar *word;
X
X{   register int low_word, high_word, cmp_result, word_num;
X
X    low_word = 0;
X    high_word =
X/*3*/
X/*E*/
X;
X    while (high_word >= low_word) {
X	word_num = (high_word + low_word) >> 1;
X	if (!(cmp_result = strcmp(word, from_words[word_num]))) {
X	    fputs(to_words[word_num], stdout);
X	    return;
X	}
X	else if (cmp_result < 0) {
X	    high_word = word_num - 1;
X	}
X	else {
X	    low_word = word_num + 1;
X	}
X    }
X    fputs(word, stdout);
X}
/
echo 'Part 01 of /usr/spool/uucppublic/shortc complete.'
exit