/* lorder - order a library Author: Monty Walls */ /* lorder: find ordering relations for object library * * author: Monty Walls * written: 1/29/88 * Copyright: Copyright (c) 1988 by Monty Walls. * Not derived from licensed software. * * Permission to copy and/or distribute granted under the * following conditions: * * 1). This notice must remain intact. * 2). The author is not responsible for the consequences of use * this software, no matter how awful, even if they * arise from defects in it. * 3). Altered version must not be represented as being the * original software. * * change log: * corrected & rewrote scanner to avoid lex. - 2/22/88 - mrw * oops reversed output filename order. 3/14/88 - mrw * progname = argv[0] - should be first. 5/25/88 - mbeck */ #include <ctype.h> #include <signal.h> #include <ar.h> #include <stdio.h> #define MAXLINE 256 FILE *lexin; char *yyfile; char *tempfile; char *progname; char template[] = "lorder.XXXXXX"; struct filelist { char *name; struct filelist *next; }; struct node { char *name; char *file; struct filelist *list; struct node *left, *right; }; struct filelist *list; struct node *tree, *lastnode; extern char *malloc(), *mktemp(); extern FILE *popen(), *fopen(); extern char *addfile(); extern void user_abort(); main(argc, argv) int argc; char **argv; { int i; char cmdstr[MAXLINE]; progname = argv[0]; if (argc > 1) { signal(SIGINT, user_abort); for (i = 1; argv[i] && *argv[i]; ++i) { /* The following code is caused by not enough memory * on floppy systems. * * so instead of ar | libupack ->to us. we use ar * >tmpfle; libupack <tempfile ->to us */ if (is_liba(argv[i])) { tempfile = mktemp(template); sprintf(cmdstr, "ar pv %s >%s", argv[i], tempfile); system(cmdstr); sprintf(cmdstr, "libupack <%s", tempfile); } else { yyfile = addfile(argv[i]); sprintf(cmdstr, "libupack <%s", argv[i]); } if ((lexin = popen(cmdstr, "r")) != (FILE *) NULL) { while (yylex() != EOF); pclose(lexin); if (tempfile) unlink(tempfile); } else { fprintf(stderr, "Error: %s could not open %s\n", progname, argv[i]); exit(1); } } printtree(tree); /* Then print list of files for ar also */ for (; list; list = list->next) fprintf(stdout, "%s %s\n", list->name, list->name); } else { fprintf(stderr, "Usage: %s file ....\n", progname); exit(1); } } void user_abort() { unlink(tempfile); exit(1); } char *xalloc(n) int n; { char *p; if ((p = malloc(n)) == (char *) NULL) { fprintf(stderr, "Error %s - out of memory\n", progname); exit(1); } return(p); } int is_liba(s) /* error handling done later */ char *s; { unsigned short key; FILE *fp; int ret = 0; if ((fp = fopen(s, "r")) != (FILE *) NULL) { fread(&key, sizeof(key), 1, fp); if (key == ARMAG) ret = 1; fclose(fp); } return(ret); } char *strsave(s) char *s; { char *p; p = xalloc(strlen(s) + 1); strcpy(p, s); return(p); } char *addfile(s) char *s; { struct filelist *p; p = (struct filelist *) xalloc(sizeof(struct filelist)); p->name = strsave(s); if (list) p->next = list; else p->next = NULL; list = p; return(p->name); } printtree(t) struct node *t; { struct filelist *fp; if (t) { if (t->file) { for (fp = t->list; fp && fp->name; fp = fp->next) if (t->file != fp->name) fprintf(stdout, "%s %s\n", fp->name, t->file); } printtree(t->right); printtree(t->left); } } struct node *finddef(s) char *s; { struct node *n; int cmp; if (tree) { lastnode = n = tree; while (n && n->name) { lastnode = n; if (!(cmp = strcmp(s, n->name))) return(n); else if (cmp > 0) n = n->left; else n = n->right; } } return((struct node *) NULL); } struct node *makedef(s) char *s; { struct node *n; int cmp; n = (struct node *) xalloc(sizeof(struct node)); n->name = strsave(s); n->left = (struct node *) NULL; n->right = (struct node *) NULL; if (tree) { cmp = strcmp(s, lastnode->name); if (cmp > 0) lastnode->left = n; else lastnode->right = n; } else tree = n; return(n); } void dodef(s) char *s; { struct node *n; if (n = finddef(s)) { if (n->file != NULL) fprintf(stderr, "Error %s - %s defined twice in %s and %s\n", progname, s, n->file, yyfile); else n->file = yyfile; } else { n = makedef(s); n->file = yyfile; n->list = (struct filelist *) NULL; } } void usedef(s) char *s; { struct node *n; struct filelist *fp, *lastfp; if (n = finddef(s)) { /* Scan file list for match */ if (n->list) { for (fp = n->list; fp; fp = fp->next) { if (fp->name == yyfile) { return; } lastfp = fp; } /* Reached here with no match */ lastfp->next = (struct filelist *) xalloc(sizeof(struct filelist)); lastfp->next->name = yyfile; lastfp->next->next = (struct filelist *) NULL; } else { /* Empty list so far */ n->list = (struct filelist *) xalloc(sizeof(struct filelist)); n->list->name = yyfile; n->list->next = (struct filelist *) NULL; } } else { n = makedef(s); n->file = (char *) NULL; n->list = (struct filelist *) xalloc(sizeof(struct filelist)); n->list->name = yyfile; n->list->next = (struct filelist *) NULL; } } /* Yylex - scanner for lorder * */ #define MAXNAME 33 #define is_first_char(c) ((c) == '.' || (c) == '_') #define is_second_char(c) ((c) == '_' || isalpha((c))) #define is_other_char(c) ((c) == '_' || isalnum((c))) #define alt_space(c) ((c) == ',' || (c) == '#') int yylex() { int col = 0; int i = 0; int is_member = 0; int in_define = 0; int lastch = 0; int was_space = 1; char s[MAXNAME]; while ((lastch = fgetc(lexin)) != EOF) { col++; /* increment col */ if (isspace(lastch)) { EOS: /* eos comes here */ if (i) { /* we have a string */ s[i] = '\0'; /* set eos */ i = 0; /* If we are in a define use dodef to add * location of defining member and global to * symbol table. */ if (in_define) dodef(s); /* If we are on a 'p -' line for an ar lib * define this member as the file we are * using. */ else if (is_member > 0) { is_member = 0; yyfile = addfile(s); } /* If we have a '.define' mark this line as * in_define. */ else if (strcmp(s, ".define") == 0) in_define = 1; /* Just a reference in the code to a var, so * add this reference to our symbol table. */ else usedef(s); } /* We are at the eol: reset our counters and switches */ if (lastch == '\n') { col = 0; is_member = 0; in_define = 0; } /* Lets do another character */ was_space = 1; continue; } /* Not a space and i == 0 */ if (i == 0) { /* Are we seeing 'p' in col 1 */ if (lastch == 'p' && col == 1) { is_member = -1; } /* Are we seeing '-' that follows 'p' in col 1 */ else if (lastch == '-' && is_member < 0 && col == 3) { is_member = 1; } /* If we have seen 'p -' now we are reading the name * or the first character of a global symbol */ else if (is_member > 0 || (is_first_char(lastch) && was_space)) { s[i++] = lastch; if (is_member < 0) is_member = 0; } was_space = alt_space(lastch); } /* Do the second char of a name */ else if (i == 1) { if (is_member > 0 || is_second_char(lastch)) { s[i++] = lastch; } else is_member = 0; was_space = alt_space(lastch); } /* Do the rest of a symbol or member name */ else if (is_member > 0 || is_other_char(lastch)) { s[i++] = lastch; was_space = alt_space(lastch); } else { was_space = alt_space(lastch); goto EOS; } } /* Returns EOF on end of file */ return(lastch); }