/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident	"$Header: devbuild.c 1.4 89/08/17 $"

/*
 * devbuild - build more complex devices from simpler ones
 */

#include <sys/types.h>
#include <sys/devsw.h>

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <constab.h>

#define DEVTAB "/etc/devtab"
#define BUILDDIR "/etc/devbuild.d"
#define USAGE "usage: devbuild [-a]\n\tdevbuild devtype parent [use child ..] [args]"

#ifdef	lint
struct	streamtab {
	int dummy;
};
#endif	/* lint */

char line[BUFSIZ];
char builder[BUFSIZ];
char result[BUFSIZ];
struct constab *ctab;
struct constab *last_entry;
FILE *buildfp;

extern int   errno;
extern int   optind;
extern char *optarg;
extern int   lockf();
extern void  exit();

main(argc,argv)
int  argc;
char **argv;
{
	struct constab *cp;
	char	**kp;
	int	c;
	FILE	*devtab;
	int	errflag = 0;
	int	all = 0;
	
	/*
	 *      If no arguments are given, print out CONSTAB.
	 */

	if (argc == 1) {
		if (read_constab(&ctab, &last_entry) == 0) {
			for (cp = ctab; cp <= last_entry; cp++) {
				(void)printf("%s %s",
					cp->ct_parent, cp->ct_devtype);
				if (cp->ct_kids) {
					(void)printf(" use ");
					for (kp = cp->ct_kids; kp && *kp; kp++){
						(void)printf("%s ", *kp);
					}
				}
				(void)printf("\n");
			}
			exit(0);
		} else {
			exit(1);
		}
	}

	/*
	 *      check for proper arguments
	 */

	while ((c = getopt(argc, argv, "a")) != -1) {
		switch ((char)c) {
			case 'a':
				all++;
				break;
			case '?':
				errflag = 1;
				break;
		}
	}

	if (errflag) {
		(void)fprintf(stderr, "%s\n", USAGE);
		exit(2);
	}

	if (all) {
		if (argc != 2) {
			(void)fprintf(stderr, "%s\n", USAGE);
			exit(2);
		}

		devtab = fopen(DEVTAB, "r");
		if (devtab == NULL) {
			(void)fprintf(stderr, "devbuild: unable to open %s\n", DEVTAB);
			exit(1);
		}

		while (getline(devtab, line) != 0) {
			(void)build(line);
		}
		exit(0);
	}
	
	/*
	 * build up line from the rest of the arguments on the
	 * command line.
	 */

	argv++; argc--;
	line[0] = '\0';
	for (; argc > 0; argc--, argv++) {
		(void)strcat(line, argv[0]);
		(void)strcat(line, " ");
	}
	/*
	 * null out trailing blank
	 */
	line[strlen(line) - 1] = '\0';

	exit(build(line));
	/*NOTREACHED*/
}

/*
 * build
 *
 *	Pass input line to the appropriate build-er in BUILDDIR
 */
build(p)
	char *p;
{
	char *p1,*p2;
	FILE *cmd;

	(void)strcpy(builder, BUILDDIR);
	(void)strcat(builder, "/");
	p1 = builder + strlen(builder);
	if (sscanf(p, "%s", p1) != 1) {
		(void)fprintf(stderr, "devbuild: malformed line: <%s>\n", p);
		return(1);
	}
	if (access(builder, X_OK) < 0) {
		(void)fprintf(stderr,
			"devbuild: illegal virtual device type %s\n", p1);
		return(1);
	}
	p2=p;
	while (isspace(*p2)) p2++;
	(void)strcpy(p1, p2);

	if ((cmd = popen(builder, "r")) == NULL) {
		(void)fprintf(stderr,
			"devbuild: error trying to execute line <%s>\n", p);
		return(1);
	}

	if (fgets(result, BUFSIZ, cmd) == NULL) {
		(void)pclose(cmd);
		return(1);
	}

	(void)pclose(cmd);

	if (buildfp == NULL) {
		if ((buildfp = fopen(CONSTAB, "a")) == NULL) {
			(void)fprintf(stderr,
				"devbuild: warning - could not write on <%s>\n",
					CONSTAB);
			return(1);
		}
		if (lockf(fileno(buildfp), F_LOCK, 0L) < 0) {
			(void)fprintf(stderr,
				"devbuild: warning: cannot lock <%s>\n",
					CONSTAB);
		}
	}

	(void) fputs(result, buildfp);

	return(0);
}


/*
 *  given a file pointer and buffer, construct logical line in buffer
 *  (i.e., concatenate lines ending in '\').  return length of line
 *  treat as comments all chars after '#'
 *  ASSUMES that buffer is BUFSIZ long!
 */

static int
getline(f, linep)
	FILE *f;
	char *linep;
{	
	char *lptr, *lend;

	lptr = linep;
loop:
	while (fgets(lptr, (linep + BUFSIZ) - lptr, f) != NULL) {
		lend = lptr + strlen(lptr);
		if (lend == lptr || lend[-1] != '\n')	
			/* empty buf or line too long! */
			break;
		*--lend = '\0'; /* lop off ending '\n' */
		if ( lend == linep ) /* empty line - ignore */
			continue;
		lptr = lend;
		if (lend[-1] != '\\')
			break;
		/* continuation */
		lend[-1] = ' ';
	}
	if ((lend = strchr(linep, '#')) != NULL) {
		*lend = '\0'; /* lop off ending '\n' */
		lptr = lend;
		if (lend == linep)
			goto loop;
	}
	return(lptr - linep);
}
