Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!caip!topaz!husc6!harvard!panda!genrad!decvax!mcnc!ncsu!uvacs!edison!dca From: dca@edison.UUCP (David Albrecht) Newsgroups: net.sources Subject: shortc Message-ID: <833@edison.UUCP> Date: Tue, 5-Aug-86 16:38:33 EDT Article-I.D.: edison.833 Posted: Tue Aug 5 16:38:33 1986 Date-Received: Sat, 9-Aug-86 06:10:03 EDT Organization: General Electric Company, Charlottesville, VA Lines: 651 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 X#include 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 X#include 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