V10/cmd/config/mkconf.c.sv

/*
 * mkconf.c	1.10	85/01/03
 *	Functions in this file build conf.c from the devices list
 */

#include <stdio.h>
#include <ctype.h>
#include "y.tab.h"
#include "config.h"

#define next_word(fp, wd)\
    { register char *word = get_word(fp);\
	if (word == WEOF) return EOF; \
	else wd = word; }

#define max(a,b)    ((a) > (b) ? (a) : (b))
#define bit(n)	    (1L << (n))

static struct dev_list *dcur;

struct routine {
    char    *rt_name;
    char    *rt_type;
    int	    rt_class;
    char    *rt_default;
    char    *rt_empty;
};

#define FUNC	1
#define POINTER	2
#define LITERAL 3

struct routine block_routines[] = {
    {"open", "int", FUNC, "nulldev", "nodev"},
    {"close", "int", FUNC, "nulldev", "nodev"},
    {"strategy", "int", FUNC, "nodev"},
    {"dump", "int", FUNC, "nodev"},
    {"B_TAPE", NULL, LITERAL, "0"},
    {NULL}
};
struct routine char_routines[] = {
    {"open", "int", FUNC, "nulldev", "nodev"},
    {"close", "int", FUNC, "nulldev", "nodev"},
    {"read", "int", FUNC, "nodev"},
    {"write", "int", FUNC, "nodev"},
    {"ioctl", "int", FUNC, "nodev"},
    {"reset", "int", FUNC, "nulldev"},
    {"", NULL, NULL, "NULL"},
    {NULL}
};
struct routine stream_routines[] = {
    {"", NULL, NULL, "nodev"},
    {"", NULL, NULL, "nodev"},
    {"", NULL, NULL, "nodev"},
    {"", NULL, NULL, "nodev"},
    {"", NULL, NULL, "nodev"},
    {"reset", "int", FUNC, "nulldev"},
    {"info", "struct streamtab", POINTER, "NULL"},
    {NULL}
};
struct routine fs_routines[] = {
    {"put", "int", FUNC, "0"},
    {"get", "struct inode *", FUNC, "0"},
    {"free", "int", FUNC, "0"},
    {"updat", "int", FUNC, "0"},
    {"read", "int", FUNC, "0"},
    {"write", "int", FUNC, "0"},
    {"trunc", "int", FUNC, "0"},
    {"stat", "int", FUNC, "0"},
    {"nami", "int", FUNC, "0"},
    {"mount", "int", FUNC, "0"},
    {"ioctl", "int", FUNC, "0"},
    {NULL}
};
struct routine ld_routines[] = {
    {"info", "struct streamtab", POINTER, "NULL"},
    {NULL}
};

/*
 * dev_lookup
 *	look up a device name
 */

struct dev_list *dev_lookup(type, num)
register int type, num;
{
    register struct dev_list *devp;

    for (devp = devtab ; devp != NULL; devp = devp->dev_next)
    {
	if (devp->dev_type == type && devp->dev_num == num)
	    return devp;
    }
    return NULL;
}

/*
 * new_dent
 *	Make a new device list entry
 */

struct dev_list *new_dent()
{
    register struct dev_list *devp;

    devp = (struct dev_list *) malloc(sizeof *devp);
    devp->dev_next = NULL;
    if (dcur == NULL)
	dcur = devtab = devp;
    else
	dcur->dev_next = devp;
    dcur = devp;
    return devp;
}


/*
 * devices:
 *	Read in the "devices" file.
 *	Store it in the devtab linked list
 */

read_devices()
{

    devtab = NULL;
    read_devices_file(GLOBAL("devices"), TRUE);
    read_devices_file(LOCAL("devices"), FALSE);
}

static struct litlst *litlast;

read_devices_file(filename, must_exist)
    char *filename;
{
    FILE *fp;
    register struct dev_list *tp;
    register struct litlst *litp;
    register char *wd, *cond;
    int standard, type, num;
    char *index();

    fp = fopen(filename, "r");
    if (fp == NULL) {
	if (must_exist) {
	    perror(filename);
	    exit(1);
	} else
	    return;
    }
    while((wd = get_word(fp)) != WEOF)
    {
	if (wd == NULL)
	    continue;
	if (eq(wd, ":")) {
	    char line[100];
	    fgets(line, 100, fp);
	    if (!isspace(line[0]))
		continue;
	    if (wd = index(line, '\n'))
		*wd = '\0';
	    litp = (struct litlst *)malloc(sizeof(*litp) + strlen(line));
	    if (litp == NULL) {
		fprintf(stderr, "Out of memory\n");
		exit(10);
	    }
	    strcpy(litp->line = (char *)(litp + 1), line + 1);
	    litp->lit_next = NULL;
	    if (littab == NULL)
		littab = litlast = litp;
	    else
		litlast = litlast->lit_next = litp;
	    continue;
	}
	standard = FALSE;
	cond = NULL;
	if (eq(wd, "standard")) {
	    next_word(fp, wd);
	    standard = TRUE;
	} else if (eq(wd, "if")) {
	    next_word(fp, wd);
	    cond = ns(wd);
	    next_word(fp, wd);
	}
	if (eq(wd, "stream-device"))
	    type = STREAM_DEVICE;
	else if (eq(wd, "block-device"))
	    type = BLOCK_DEVICE;
	else if (eq(wd, "device"))
	    type = CHAR_DEVICE;
	else if (eq(wd, "line-discipline"))
	    type = LINE_DISC;
	else if (eq(wd, "file-system"))
	    type = FILE_SYS;
	else {
	    fprintf(stderr, "Unrecognized device type %d.\n", type);
	    exit(10);
	}

	next_word(fp, wd);
	if (wd == NULL) {
	    fprintf(stderr, "No device number.\n");
	    exit(10);
	}
	num = atoi(wd);

	next_word(fp, wd);
	if (wd == NULL) {
	    fprintf(stderr, "Huh, no name for device.\n");
	    exit(10);
	}
	if ((tp = dev_lookup(type, num)) == NULL)
	    tp = new_dent();
	tp->dev_name = ns(wd);
	tp->dev_type = type;
	tp->dev_num = num;
	tp->dev_standard = standard;
	tp->dev_if = cond;
	if (num > max_num[type])
	    max_num[type] = num;

	next_word(fp, wd);
	if (wd == NULL) {
	    tp->dev_mask = 0L;
	    continue;
	}
	tp->dev_prefix = ns(wd);

	switch (type) {
	    case STREAM_DEVICE:
		device_params(fp, tp, stream_routines);
		break;
	    case BLOCK_DEVICE:
		device_params(fp, tp, block_routines);
		break;
	    case CHAR_DEVICE:
		device_params(fp, tp, char_routines);
		break;
	    case LINE_DISC:
		device_params(fp, tp, ld_routines);
		break;
	    case FILE_SYS:
		device_params(fp, tp, fs_routines);
		break;
	}
    }
    fclose(fp);
}


/*
 *  device_params:
 *	read in a list of device parameters
 *
 */

device_params(fp, dp, routines)
FILE *fp;
struct dev_list *dp;
struct routine *routines;
{
    register struct routine *rp;
    char *wd;

    dp->dev_mask = 0L;
    for (;;) {
	next_word(fp, wd);
	if (wd == NULL)
	    break;
	for (rp = routines; rp->rt_name != NULL; ++rp)
	    if (eq(wd, rp->rt_name))
		break;
	if (rp->rt_name == NULL) {
	    fprintf(stderr, "Unknown entry point name '%s' for device %s.\n",
			    wd, dp->dev_name);
	    exit(10);
	}
	dp->dev_mask |= bit(rp - routines);
    }
}


conf()
{
    FILE *fp;
    register struct dev_list	*dp;

    read_devices();

    fp = fopen(LOCAL("conf.c"), "w");
    if (fp == NULL) {
	perror(LOCAL("conf.c"));
	exit(1);
    }
    fprintf(fp, "\t/* conf.c built automatically by config */\n\n");
    fprintf(fp, "#include \"../h/param.h\"\n");
    fprintf(fp, "#include \"../h/systm.h\"\n");
    fprintf(fp, "#include \"../h/conf.h\"\n");
    fprintf(fp, "#include \"../h/inode.h\"\n");
    fprintf(fp, "#include \"../h/stream.h\"\n");
    fprintf(fp, "#include \"../h/buf.h\"\n");
    fprintf(fp, "int nulldev(), nodev();\n\n");

    for (dp = devtab; dp; dp = dp->dev_next) {
	if (dp->dev_mask == 0L)
	    continue;
	switch (dp->dev_type) {
	    case CHAR_DEVICE:
		do_declare(fp, dp, char_routines);
		break;
	    case BLOCK_DEVICE:
		do_declare(fp, dp, block_routines);
		break;
	    case STREAM_DEVICE:
		do_declare(fp, dp, stream_routines);
		break;
	    case LINE_DISC:
		do_declare(fp, dp, ld_routines);
		break;
	    case FILE_SYS:
		decl_list(fp, dp, fs_routines);
		break;
	}
	putc('\n', fp);
    }

    fprintf(fp, "struct bdevsw bdevsw[] = {\n");
    do_table(fp, block_routines, BLOCK_DEVICE, NULL, NULL);
    fprintf(fp, "    0\n};\n\n");

    fprintf(fp, "struct cdevsw cdevsw[] = {\n");
    do_table(fp, char_routines, CHAR_DEVICE, stream_routines, STREAM_DEVICE);
    fprintf(fp, "    0\n};\n");
    fprintf(fp, "int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]) - 1;\n\n");

    fprintf(fp, "struct fstypsw fstypsw[] = {\n");
    do_table(fp, fs_routines, FILE_SYS, NULL, NULL);
    fprintf(fp, "};\n");
    fprintf(fp, "int nfstyp = sizeof(fstypsw) / sizeof(fstypsw[0]);\n\n");

    fprintf(fp, "struct streamtab *streamtab[] = {\n");
    do_table(fp, ld_routines, LINE_DISC, NULL, NULL);
    fprintf(fp, "};\n");
    fprintf(fp, "int nstream = sizeof(streamtab) / sizeof(streamtab[0]);\n\n");

    while (littab != NULL) {
	fprintf(fp, "%s\n", littab->line);
	littab = littab->lit_next;
    }

    fclose(fp);
}


char *toentry(dp, routine)
    struct dev_list *dp;
    char *routine;
{
    static char entry[40];

    sprintf(entry, "%s%s", dp->dev_prefix, routine);
    return entry;
}

do_declare(fp, dp, routines)
    FILE *fp;
    struct dev_list *dp;
    struct routine *routines;
{
    char *tomacro();

    if (dp->dev_if)
	fprintf(fp, "#if %s\n", dp->dev_if);
    else if (!dp->dev_standard) {
	include(fp, dp->dev_name);
	fprintf(fp, "#if %s > 0\n", tomacro(dp->dev_name));
    }

    decl_list(fp, dp, routines);

    if (!dp->dev_standard) {
	fprintf(fp, "#else\n");
	define_list(fp, dp, routines);
	fprintf(fp, "#endif\n");
    }
}

decl_list(fp, dp, routines)
    FILE    *fp;
    struct dev_list *dp;
    struct routine *routines;
{
    register struct routine *rp, *rp2;
    register long   mask;
    register int    ndone;
    char    *entry;

    for (rp = routines, mask = dp->dev_mask; rp->rt_name != NULL; ++rp) {
	for (rp2 = rp, ndone = 0; rp2->rt_name != NULL; ++rp2) {
	    if (rp2->rt_type == NULL || (mask & bit(rp2 - routines)) == 0)
		continue;
	    entry = toentry(dp, rp2->rt_name);
	    if (eq(rp2->rt_type, rp->rt_type) && !declared(entry, FALSE)) {
		mask &= ~bit(rp2 - routines);
		if (++ndone == 1)
		    fprintf(fp, "    extern %s ", rp->rt_type);
		else
		    putc(',', fp);
		fprintf(fp, "%s%s", entry, rp2->rt_class == FUNC ? "()" : "");
	    }
	}
	if (ndone > 0)
	    fprintf(fp, ";\n");
    }
}


define_list(fp, dp, routines)
    FILE *fp;
    struct dev_list *dp;
    struct routine *routines;
{
    register struct routine *rp;
    char    *entry;

    for (rp = routines; rp->rt_name != NULL; ++rp) {
	if (rp->rt_type != NULL && (dp->dev_mask & bit(rp - routines))) {
	    entry = toentry(dp, rp->rt_name);
	    if (!declared(entry, FALSE)) {
		fprintf(fp, "#   define %s\t", entry);
		if (rp->rt_class == POINTER)
		    fprintf(fp, "*(%s *)", rp->rt_type);
		fprintf(fp, "%s\n", rp->rt_empty? rp->rt_empty
						: rp->rt_default);
	    }
	}
    }
}

static struct idlst *decs;

declared(str, declare)
    char    *str;
{
    register struct idlst *dec;

    for (dec = decs; dec; dec = dec->id_next)
	if (eq(dec->id, str))
	    return TRUE;

    if (declare) {
	if ((dec = (struct idlst *)malloc(sizeof(*dec))) == NULL) {
	    fprintf(stderr, "Out of memory\n");
	    exit(10);
	}
	dec->id = str;
	dec->id_next = decs;
	decs = dec;
    }

    return FALSE;
}

do_table(fp, rt1, devtype1, rt2, devtype2)
    FILE *fp;
    struct routine *rt1, *rt2;
{
    register struct dev_list	*dp;
    register int    n, maxn;

    maxn = rt2 ? max(max_num[devtype1],max_num[devtype2]) : max_num[devtype1];
    for (n = 0; n <= maxn; ++n) {
	for (dp = devtab; dp; dp = dp->dev_next) {
	    if (dp->dev_num != n)
		continue;
	    if (dp->dev_type == devtype1) {
		fprintf(fp, "/*%s*/\t", dp->dev_name);
		filled_list(fp, dp, dp->dev_mask, rt1);
		fprintf(fp, "\t/* %d */\n", n);
		break;
	    } else if (dp->dev_type == devtype2) {
		fprintf(fp, "/*%s*/\t", dp->dev_name);
		filled_list(fp, dp, dp->dev_mask, rt2);
		fprintf(fp, "\t/* %d */\n", n);
		break;
	    }
	}
	if (dp == NULL) {
	    fprintf(fp, "/*xx*/\t");
	    filled_list(fp, NULL, 0L, rt1);
	    fprintf(fp, "\t/* %d */\n", n);
	}
    }
}

filled_list(fp, dp, mask, routines)
    FILE *fp;
    struct dev_list *dp;
    long mask;
    struct routine *routines;
{
    register struct routine *rp;

    for (rp = routines; rp->rt_name != NULL; ++rp) {
	if (mask & bit(rp - routines)) {
	    if (rp->rt_class == POINTER)
		putc('&', fp);
	    if (rp->rt_class == LITERAL)
		fprintf(fp, "%s, ", rp->rt_name);
	    else
		fprintf(fp, "%s, ", toentry(dp, rp->rt_name));
	} else if (dp == NULL && rp->rt_empty)
	    fprintf(fp, "%s, ", rp->rt_empty);
	else
	    fprintf(fp, "%s, ", rp->rt_default);
    }
}

static struct idlst *incs;

include(fp, name)
    FILE    *fp;
    char    *name;
{
    register struct idlst *inc;

    for (inc = incs; inc; inc = inc->id_next)
	if (eq(inc->id, name))
	    return;

    fprintf(fp, "#include \"%s.h\"\n", name);
    if ((inc = (struct idlst *)malloc(sizeof(*inc))) == NULL) {
	fprintf(stderr, "Out of memory\n");
	exit(10);
    }
    inc->id = name;
    inc->id_next = incs;
    incs = inc;
}