[comp.os.minix] Turbo C diff's for Minix 1.2; here they are ! Part 7 of 9

evas@euraiv1.UUCP (Eelco van Asperen) (10/02/87)

Here is part 7 of 9:						Eelco van Asperen.

# This is a shar archive.  Extract with sh, not csh.
# This archive ends with exit, so do not worry about trailing junk.
# --------------------------- cut here --------------------------
echo Extracting commands/find.c
sed 's/^X//' > commands/find.c << '+ END-OF-FILE 'commands/find.c
X/* find - look for files satisfying a predicat	Author: Erik Baalbergen */
X
X/*
X   *** Check the switches in the SWITCHES section below. ***
X
X   Differences from UNIX version 7 find(1):
X	* -name: no name allowed; only uid
X		e.g. find all core files: "find . -name core -a -print"
X
X   The "-atime" may not work well on Minix.
X   Please report bugs and suggestions to erikb@cs.vu.nl
X*/
X
X#include "stdio.h"
X
X/*######################## SWITCHES ##############################*/
X#include "stat.h"
X#define SHELL "/usr/bin/sh"
X
X#define PLEN	256	/* maximum path length; overflows are not detected */
X#define DIRSIZ	16	/* size of a directory entry */
X#define MAXARG	256	/* maximum length for an argv */
X#define NPATHS	256	/* maximum number of paths in path-list */
X#define BSIZE  1024	/* bytes per block */
X
X/*######################## DEFINITIONS ##############################*/
X#define SECS_PER_DAY	(24L * 60L * 60L)	/* check your planet */
X
Xstruct exec {
X	int e_cnt;
X	char *e_vec[MAXARG];
X};
X
X#define OP_NAME		1
X#define OP_PERM		2
X#define OP_TYPE		3
X#define OP_LINKS	4
X#define OP_USER		5
X#define OP_GROUP	6
X#define OP_SIZE		7
X#define OP_INUM		8
X#define OP_ATIME	9
X#define OP_MTIME	10
X#define OP_EXEC		11
X#define OP_OK		12
X#define OP_PRINT	13
X#define OP_NEWER	14
X#define OP_AND		15
X#define OP_OR		16
X
Xstruct oper {
X	char *op_str;
X	int op_val;
X} ops[] = {
X	{"name",	OP_NAME},
X	{"perm",	OP_PERM},
X	{"type",	OP_TYPE},
X	{"links",	OP_LINKS},
X	{"user",	OP_USER},
X	{"group",	OP_GROUP},
X	{"size",	OP_SIZE},
X	{"inum",	OP_INUM},
X	{"atime",	OP_ATIME},
X	{"mtime",	OP_MTIME},
X	{"exec",	OP_EXEC},
X	{"ok",		OP_OK},
X	{"print",	OP_PRINT},
X	{"newer",	OP_NEWER},
X	{"a",		OP_AND},
X	{"o",		OP_OR},
X	{0,		0}
X};
X
X#define EOI	-1
X#define NONE	0
X#define LPAR	20
X#define RPAR	21
X#define NOT	22
X
Xchar *prog, *strcpy(), *Malloc(), *find_bin();
X
Xstruct node {
X	int n_type;	/* any OP_ or NOT */
X	union {
X		char *n_str;
X		struct {
X			long n_val;
X			int n_sign;
X		} n_int;
X		struct exec *n_exec;
X		struct {
X			struct node *n_left, *n_right;
X		} n_opnd;
X	} n_info;
X};
Xstruct node *expr();
X
Xchar **ipp;
Xint tty;	/* fd for /dev/tty when using -ok */
Xlong current_time;
X
Xchar *
XMalloc(n)
X{
X	char *malloc(), *m;
X
X	if ((m = malloc(n)) == 0)
X		fatal("out of memory", "");
X	return m;
X}
X
Xchar *
XSalloc(s)
X	char *s;
X{
X	return strcpy(Malloc(strlen(s) + 1), s);
X}
X
Xmain(argc, argv)
X	char *argv[];
X{
X	char *pathlist[NPATHS];
X	int pathcnt = 0;
X	register i;
X	struct node *pred;
X
X	prog = *argv++;
X	while (--argc > 0 && lex(*argv) == NONE)
X		pathlist[pathcnt++] = *argv++;
X	if (pathcnt == 0 || argc == 0)
X		fatal("Usage: path-list predicate-list", "");
X	ipp = argv;
X	time(&current_time);
X	pred = expr(lex(*ipp));
X	if (lex(*++ipp) != EOI)
X		fatal("syntax error: garbage at end of predicate", "");
X	for (i = 0; i < pathcnt; i++)
X		find(pathlist[i], pred, "");
X	exit(0);
X}
X
Xfind(path, pred, last)
X	char *path, *last;
X	struct node *pred;
X{
X	char spath[PLEN], ent[DIRSIZ + 1];
X	struct stat st;
X	register char *send = spath;
X	FILE *fp, *fopen();
X
X	if (path[1] == '\0' && *path == '/') {
X		*send++ = '/';
X		*send = '\0';
X	}
X	else
X		while (*send++ = *path++) {}
X	if (stat(spath, &st) == -1)
X		nonfatal("can't get status of ", spath);
X	else {
X		(void) check(spath, &st, pred, last);
X		if ((st.st_mode & S_IFMT) == S_IFDIR) {
X			if ((fp = fopen(spath, "r")) == NULL) {
X				nonfatal("can't read directory ", spath);
X				return;
X			}
X			send[-1] = '/';
X			ent[DIRSIZ] = '\0';
X			while (fread(ent, DIRSIZ, 1, fp) == 1) {
X				if (!((*ent == '\0' && ent[1] == '\0')
X				|| (ent[2] == '.') &&
X					(ent[3] == '\0'
X					|| (ent[3] == '.' && ent[4] == '\0'))
X				)) {
X					strcpy(send, ent + 2);
X					find(spath, pred, ent + 2);
X				}
X			}
X			fclose(fp);
X		}
X	}
X}
X
Xcheck(path, st, n, last)
X	char *path, *last;
X	register struct stat *st;
X	register struct node *n;
X{
X	switch (n->n_type) {
X	case OP_AND:
X		return  check(path, st, n->n_info.n_opnd.n_left, last) &&
X			check(path, st, n->n_info.n_opnd.n_right, last);
X	case OP_OR:
X		return  check(path, st, n->n_info.n_opnd.n_left, last) ||
X			check(path, st, n->n_info.n_opnd.n_right, last);
X	case NOT:
X		return !check(path, st, n->n_info.n_opnd.n_left, last);
X	case OP_NAME:
X		return smatch(last, n->n_info.n_str);
X	case OP_PERM:
X		if (n->n_info.n_int.n_sign < 0)
X			return st->st_mode == (int) n->n_info.n_int.n_val;
X		return (st->st_mode & 0777) == (int) n->n_info.n_int.n_val;
X	case OP_NEWER:
X		return st->st_mtime > n->n_info.n_int.n_val;
X	case OP_TYPE:
X		return (st->st_mode & S_IFMT) == n->n_info.n_int.n_val;
X	case OP_LINKS:
X		return ichk((long)(st->st_nlink), n);
X	case OP_USER:
X		return st->st_uid == n->n_info.n_int.n_val;
X	case OP_GROUP:
X		return st->st_gid == n->n_info.n_int.n_val;
X	case OP_SIZE:
X		return ichk((st->st_size == 0) ? 0L :
X			((st->st_size - 1) / BSIZE + 1), n);
X	case OP_INUM:
X		return ichk((long)(st->st_ino), n);
X	case OP_ATIME:
X		return ichk(st->st_atime, n);
X	case OP_MTIME:
X		return ichk(st->st_mtime, n);
X	case OP_EXEC:
X	case OP_OK:
X		return execute(n->n_type, n->n_info.n_exec, path);
X	case OP_PRINT:
X		prints("%s\n", path);
X		return 1;
X	}
X	fatal("ILLEGAL NODE", "");
X}
X
Xichk(val, n)
X	long val;
X	struct node *n;
X{
X	switch (n->n_info.n_int.n_sign) {
X	case 0:
X		return val == n->n_info.n_int.n_val;
X	case 1:
X		return val > n->n_info.n_int.n_val;
X	case -1:
X		return val < n->n_info.n_int.n_val;
X	}
X	fatal("internal: bad n_sign", "");
X}
X
Xlex(str)
X	char *str;
X{
X	if (str == 0)
X		return EOI;
X	if (*str == '-') {
X		register struct oper *op;
X
X		str++;
X		for (op = ops; op->op_str; op++)
X			if (strcmp(str, op->op_str) == 0)
X				break;
X		return op->op_val;
X	}
X	if (str[1] == 0) {
X		switch(*str) {
X		case '(':
X			return LPAR;
X		case ')':
X			return RPAR;
X		case '!':
X			return NOT;
X		}
X	}
X	return NONE;
X}
X
Xstruct node *
Xnewnode(t)
X{
X	struct node *n = (struct node*) Malloc(sizeof(struct node));
X
X	n->n_type = t;
X	return n;
X}
X
X/*########################### PARSER ###################################*/
X/* grammar:
X	expr : primary | primary OR expr;
X	primary : secondary | secondary AND primary | secondary primary;
X	secondary : NOT secondary | LPAR expr RPAR | simple;
X	simple : -OP args...
X*/
Xstruct node *expr(), *primary(), *secondary(), *simple();
X
Xnumber(str, base, pl, ps)
X	char *str;
X	long *pl;
X	int *ps;
X{
X	int up = '0' + base - 1;
X	long val = 0;
X
X	*ps = ((*str == '-' || *str == '+') ? ((*str++ == '-') ? -1 : 1) : 0);
X	while (*str >= '0' && *str <= up)
X		val = base * val + *str++ - '0';
X	if (*str)
X		fatal("syntax error: illegal numeric value", "");
X	*pl = val;
X}
X
Xstruct node *
Xexpr(t)
X{
X	struct node *nd, *p, *nd2;
X
X	nd = primary(t);
X	if ((t = lex(*++ipp)) == OP_OR) {
X		nd2 = expr(lex(*++ipp));
X		p = newnode(OP_OR);
X		p->n_info.n_opnd.n_left = nd;
X		p->n_info.n_opnd.n_right = nd2;
X		return p;
X	}
X	ipp--;
X	return nd;
X}
X
Xstruct node *
Xprimary(t)
X{
X	struct node *nd, *p, *nd2;
X
X	nd = secondary(t);
X	if ((t = lex(*++ipp)) != OP_AND) {
X		ipp--;
X		if (t == EOI || t == RPAR || t == OP_OR)
X			return nd;
X	}
X	nd2 = primary(lex(*++ipp));
X	p = newnode(OP_AND);
X	p->n_info.n_opnd.n_left = nd;
X	p->n_info.n_opnd.n_right = nd2;
X	return p;
X}
X
Xstruct node *
Xsecondary(t)
X{
X	struct node *n, *p;
X
X	if (t == LPAR) {
X		n = expr(lex(*++ipp));
X		if (lex(*++ipp) != RPAR)
X			fatal("syntax error, ) expected", "");
X		return n;
X	}
X	if (t == NOT) {
X		n = secondary(lex(*++ipp));
X		p = newnode(NOT);
X		p->n_info.n_opnd.n_left = n;
X		return p;
X	}
X	return simple(t);
X}
X
Xcheckarg(arg)
X	char *arg;
X{
X	if (arg == 0)
X		fatal("syntax error, argument expected", "");
X}
X
Xstruct node *
Xsimple(t)
X{
X	struct node *p = newnode(t);
X	struct exec *e;
X	struct stat est;
X	long l;
X
X	switch (t) {
X	case OP_TYPE:
X		checkarg(*++ipp);
X		switch (**ipp) {
X		case 'b':
X			p->n_info.n_int.n_val = S_IFBLK;
X			break;
X		case 'c':
X			p->n_info.n_int.n_val = S_IFCHR;
X			break;
X		case 'd':
X			p->n_info.n_int.n_val = S_IFDIR;
X			break;
X		case 'f':
X			p->n_info.n_int.n_val = S_IFREG;
X			break;
X		default:
X			fatal("-type needs b, c, d or f", "");
X		}
X		break;
X	case OP_LINKS:
X	case OP_USER:
X	case OP_GROUP:
X	case OP_SIZE:
X	case OP_INUM:
X	case OP_PERM:
X		checkarg(*++ipp);
X		number(*ipp, (t == OP_PERM) ? 8 : 10, &(p->n_info.n_int.n_val),
X			&(p->n_info.n_int.n_sign));
X		break;
X	case OP_ATIME:
X	case OP_MTIME:
X		checkarg(*++ipp);
X		number(*ipp, 10, &l, &(p->n_info.n_int.n_sign));
X		p->n_info.n_int.n_val = current_time - l * SECS_PER_DAY;
X		/* more than n days old means less than the absolute time */
X		p->n_info.n_int.n_sign *= -1;
X		break;
X	case OP_EXEC:
X	case OP_OK:
X		checkarg(*++ipp);
X		e = (struct exec *)Malloc(sizeof(struct exec));
X		e->e_cnt = 2;
X		e->e_vec[0] = SHELL;
X		p->n_info.n_exec = e;
X		while (*ipp) {
X			if (**ipp == ';' && (*ipp)[1] == '\0') {
X				e->e_vec[e->e_cnt] = 0;
X				break;
X			}
X			e->e_vec[(e->e_cnt)++] = 
X				(**ipp == '{' && (*ipp)[1] == '}'
X				&& (*ipp)[2] == '\0') ? (char *)(-1) : *ipp;
X			ipp++;
X		}
X		if (*ipp == 0)
X			fatal("-exec/-ok: ; missing", "");
X		if ((e->e_vec[1] = find_bin(e->e_vec[2])) == 0)
X			fatal("can't find program ", e->e_vec[2]);
X		if (t == OP_OK)
X			if ((tty = open("/dev/tty", 2)) < 0)
X				fatal("can't open /dev/tty", "");
X		break;
X	case OP_NEWER:
X		checkarg(*++ipp);
X		if (stat(*ipp, &est) == -1)
X			fatal("-newer: can't get status of ", *ipp);
X		p->n_info.n_int.n_val = est.st_mtime;
X		break;
X	case OP_NAME:
X		checkarg(*++ipp);
X		p->n_info.n_str = *ipp;
X		break;
X	case OP_PRINT:
X		break;
X	default:
X		fatal("syntax error, operator expected", "");
X	}
X	return p;
X}
X
X/*######################## DIAGNOSTICS ##############################*/
X
Xnonfatal(s1, s2)
X	char *s1, *s2;
X{
X	std_err(prog);
X	std_err(": ");
X	std_err(s1);
X	std_err(s2);
X	std_err("\n");
X}
X
Xfatal(s1, s2)
X	char *s1, *s2;
X{
X	nonfatal(s1, s2);
X	exit(1);
X}
X
X/*################### SMATCH #########################*/
X/* Don't try to understand the following one... */
Xsmatch(s, t)	/* shell-like matching */
X	char *s, *t;
X{
X	register n;
X
X	if (*t == '\0')
X		return *s == '\0';
X	if (*t == '*') {
X		++t;
X		do
X			if (smatch(s,t))
X				return 1;
X		while (*s++ != '\0');
X		return 0;
X	}
X	if (*s == '\0') 
X		return 0;
X	if (*t == '\\')
X		return (*s == *++t) ? smatch(++s, ++t) : 0;
X	if (*t == '?')
X		return smatch(++s, ++t);
X	if (*t == '[') {
X		while (*++t != ']') {
X			if (*t == '\\')
X				++t;
X			if (*(t+1) != '-')
X				if (*t == *s) {
X					while (*++t != ']')
X						if (*t == '\\')
X							++t;
X					return smatch(++s, ++t);
X				}
X				else
X					continue;
X			if (*(t+2) == ']')
X				return (*s == *t || *s == '-');
X			n =  (*(t+2) == '\\') ? 3 : 2;
X			if (*s >= *t && *s <= *(t+n)) {
X				while (*++t != ']')
X					if (*t == '\\')
X						++t;
X				return smatch(++s, ++t);
X			}
X			t += n;
X		}
X		return 0;
X	}
X	return  (*s == *t) ? smatch(++s, ++t) : 0;
X}
X
X/*####################### EXECUTE ###########################*/
X/* do -exec or -ok */
X
Xchar *epath = 0;
X
Xchar *
Xgetpath()
X{
X	extern char **environ;
X	register char **e = environ;
X
X	if (epath)	/* retrieve PATH only once */
X		return epath;
X	while (*e) {
X		if (strncmp("PATH=", *e, 5) == 0) {
X			return epath = *e + 5;
X		}
X		e++;
X	}
X	fatal("can't get PATH from environment", "");
X}
X
Xchar *
Xfind_bin(s)
X	char *s;
X{
X	char *f, *l, buf[PLEN];
X	
X	if (*s == '/') /* absolute path name */
X		return (access(s, 1) == 0) ? s : 0;
X	l = f = getpath();
X	for (;;) {
X		if (*l == ':' || *l == 0) {
X			if (l == f) {
X				if (access(s, 1) == 0)
X					return Salloc(s);
X				f++;
X			}
X			else {
X				register char *p = buf, *q = s;
X
X				while (f != l)
X					*p++ = *f++;
X				f++;
X				*p++ = '/';
X				while (*p++ = *q++) {}
X				if (access(buf, 1) == 0)
X					return Salloc(buf);
X			}
X			if (*l == 0)
X				break;
X		}
X		l++;
X	}
X	return 0;
X}
X
Xexecute(op, e, path)
X	struct exec *e;
X	char *path;
X{
X	int s, pid;
X	char *argv[MAXARG];
X	register char **p, **q;
X
X	for (p = e->e_vec, q = argv; *p;) /* replace the {}s */
X		if ((*q++ = *p++) == (char *)-1)
X			q[-1] = path;
X	*q = '\0';
X	if (op == OP_OK) {
X		char answer[10];
X
X		for (p = &argv[2]; *p; p++) {
X			write(tty, *p, strlen(*p));
X			write(tty, " ", 1);
X		}
X		write(tty, "? ", 2);
X		if (read(tty, answer, 10) < 2 || *answer != 'y')
X			return 0;
X	}
X	if ((pid = fork()) == -1)
X		fatal("can't fork", "");
X	if (pid == 0) {
X		register i = 3;
X
X		while (close(i++) == 0) {}		/* wow!!! */
X		execv(argv[1], &argv[2]);	/* binary itself? */
X		execv(argv[0], &argv[1]);	/* shell command? */
X		fatal("exec failure: ", argv[1]);	/* none of them! */
X		exit(127);
X	}
X	return wait(&s) == pid && s == 0;
X}
+ END-OF-FILE commands/find.c
chmod u=rw,g=r,o=r commands/find.c
set `sum commands/find.c`
sum=$1
case $sum in
25453)	:;;
*)	echo 'Bad sum in 'commands/find.c >&2
esac
echo Extracting commands/fix.c
sed 's/^X//' > commands/fix.c << '+ END-OF-FILE 'commands/fix.c
X/* fix - combine file and diff listing	Author: Erik Baalbergen */
X
X/* Notes:
X   * files old and old.fix are equal after the following commands
X	   diff old new > difflist
X	   fix old difflist > old.fix
X   * the diff output is assumed to be produced by my diff program.
X   * the difflist has the following form:
X	   difflist ::= chunk*
X	   chunk ::= append | delete | change ;
X	   append ::= n1 'a' n2 [',' n3]? '\n' ['> ' line '\n'](n3 - n2 + 1)
X	   delete ::= n1 [',' n2]? 'd' n3 '\n' ['< ' line '\n'](n2 - n1 + 1)
X	   change ::= n1 [',' n2]? 'c' n3 [',' n4]? '\n'
X		      ['< ' line '\n'](n2 - n1 + 1)
X		      '---\n'
X		      ['> ' line '\n'](n4 - n3 + 1)
X	   where
X	   - n[1234] is an unsigned integer
X	   - "[pat](expr)" means "(expr) occurences of pat"
X	   - "[pat]?" means "either pat or nothing"
X   * the information in the diff listing is checked against the file to which
X     it is applied; an error is printed if there is a conflict
X*/
X
X#include <stdio.h>
X
Xextern char *fgets();
Xextern FILE *fopen();
X#define LINELEN	1024
X
Xchar *prog = 0;
X
Xchar *
Xgetline(fp, b)
X	FILE *fp;
X	char *b;
X{
X	if (fgets(b, LINELEN, fp) == NULL)
X		fatal("unexpected eof");
X	return b;
X}
X
X#define copy(str) printf("%s", str)
X
Xmain(argc, argv)
X	char **argv;
X{
X	char cmd, *fl, *fd, obuf[LINELEN], nbuf[LINELEN];
X	int o1, o2, n1, n2, here; 
X	FILE *fpf, *fpd;
X
X	prog = argv[0];
X	if (argc != 3)
X		fatal("use: %s original-file diff-list-file", prog);
X	if ((fpf = fopen(argv[1], "r")) == NULL)
X		fatal("can't read %s", argv[1]);
X	if ((fpd = fopen(argv[2], "r")) == NULL)
X		fatal("can't read %s", argv[2]);
X	here = 0;
X	while (getcommand(fpd, &o1, &o2, &cmd, &n1, &n2)) {
X		while (here < o1 - 1) {
X			here++;
X			copy(getline(fpf, obuf));
X		}
X		switch (cmd) {
X		case 'c':
X		case 'd':
X			if (cmd == 'd' && n1 != n2)
X				fatal("delete count conflict");
X			while (o1 <= o2) {
X				fl = getline(fpf, obuf);
X				here++;
X				fd = getline(fpd, nbuf);
X				if (strncmp(fd, "< ", 2))
X					fatal("illegal delete line");
X				if (strcmp(fl, fd + 2))
X					fatal("delete line conflict");
X				o1++;
X			}
X			if (cmd == 'd')
X				break;
X			if (strcmp(getline(fpd, nbuf), "---\n"))
X				fatal("illegal separator in chunk");
X			/*FALLTHROUGH*/
X		case 'a':
X			if (cmd == 'a') {
X				if (o1 != o2)
X					fatal("append count conflict");
X				copy(getline(fpf, obuf));
X				here++;
X			}
X			while (n1 <= n2) {
X				if (strncmp(getline(fpd, nbuf), "> ", 2))
X					fatal("illegal append line");
X				copy(nbuf + 2);
X				n1++;
X			}
X			break;
X		}
X	}
X	while (fgets(obuf, LINELEN, fpf) != NULL)
X		copy(obuf);
X	exit(0);
X}
X
Xisdigit(c)
X	char c;
X{
X	return c >= '0' && c <= '9';
X}
X
Xchar *
Xrange(s, p1, p2)
X	char *s;
X	int *p1, *p2;
X{
X	register int v1 = 0, v2;
X
X	while (isdigit(*s))
X		v1 = 10 * v1 + *s++ - '0';
X	v2 = v1;
X	if (*s == ',') {
X		s++;
X		v2 = 0;
X		while (isdigit(*s))
X			v2 = 10 * v2 + *s++ - '0';
X	}
X	if (v1 == 0 || v2 == 0 || v1 > v2)
X		fatal("illegal range");
X	*p1 = v1;
X	*p2 = v2;
X	return s;
X}
X
Xgetcommand(fp, o1, o2, pcmd, n1, n2)
X	FILE *fp;
X	int *o1, *o2, *n1, *n2;
X	char *pcmd;
X{
X	char buf[LINELEN];
X	register char *s;
X	char cmd;
X	
X	if ((s = fgets(buf, LINELEN, fp)) == NULL)
X		return 0;
X	s = range(s, o1, o2);
X	if ((cmd = *s++) != 'a' && cmd != 'c' && cmd != 'd')
X		fatal("illegal command");
X	s = range(s, n1, n2);
X	if (*s != '\n' && s[1] != '\0')
X		fatal("extra characters at end of command: %s", s);
X	*pcmd = cmd;
X	return 1;
X}
X
Xfatal(s, a)
X	char *s, *a;
X{
X	fprintf(stderr, "%s: fatal: ", prog);
X	fprintf(stderr, s, a);
X	fprintf(stderr, "\n");
X	exit(1);
X}
X
X
X
X
+ END-OF-FILE commands/fix.c
chmod u=rw,g=r,o=r commands/fix.c
set `sum commands/fix.c`
sum=$1
case $sum in
50220)	:;;
*)	echo 'Bad sum in 'commands/fix.c >&2
esac
echo Extracting commands/head.dif
sed 's/^X//' > commands/head.dif << '+ END-OF-FILE 'commands/head.dif
X1a2,3
X> /* change to use putc() instead of prints()    --  Dean Long 3/7/87    */
X> 
X8d9
X< char lbuf[256];
X43,44c44,47
X< 	else
X< 		do_file(n);
X---
X> 	else {
X> 		do_file(n);
X> 	 	fflush(stdout);
X> 	}
X48d50
X<   fflush(stdout);
X57,58c59,70
X<   /* Print the first 'n' lines of a file. */
X<   while (n--) do_line();
X---
X>   int c;
X> 
X>   /* Print the first 'n' lines of a file. */
X>   while(n)
X>     switch (c = getc(stdin)) {
X>       case EOF :
X>         return;
X>       case '\n':
X>         --n;
X>       default  :
X>         putc((char)c, stdout);
X>     }
X62,80c74,78
X< do_line()
X< {
X< /* Print one line. */
X< 
X<   char c, *cp;
X<   cp = lbuf;
X<   while ( (c = getc(stdin)) != '\n') *cp++ = c;
X<   *cp++ = '\n';
X<   *cp++ = 0;
X<   prints("%s",lbuf);
X< }
X< 
X< 
X< usage()
X< {
X<   std_err("Usage: head [-n] [file ...]\n");
X<   exit(1);
X< }
X< 
X---
X> usage()
X> {
X>   std_err("Usage: head [-n] [file ...]\n");
X>   exit(1);
X> }
+ END-OF-FILE commands/head.dif
chmod u=rw,g=r,o=r commands/head.dif
set `sum commands/head.dif`
sum=$1
case $sum in
60912)	:;;
*)	echo 'Bad sum in 'commands/head.dif >&2
esac
exit 0