Minix1.5/commands/ibm/lorder.c

Compare this file to the similar file:
Show the results in this format:

/* 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);
}