Path: utzoo!utgpu!water!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!mailrus!nrl-cmf!ukma!rutgers!pyrnj!pyrdc!uunet!mcvax!hp4nl!botter!star.cs.vu.nl!ast From: ast@cs.vu.nl (Andy Tanenbaum) Newsgroups: comp.os.minix Subject: Re: Re: 1.3 checksums and bugs Message-ID: <1536@ast.cs.vu.nl> Date: 17 Oct 88 16:08:57 GMT References: <658@faui44.informatik.uni-erlangen.de> <1070004@hpuarca.HP.COM> Reply-To: ast@cs.vu.nl (Andy Tanenbaum) Organization: VU Informatica, Amsterdam Lines: 1672 In article <1070004@hpuarca.HP.COM> linas@hpuarca.HP.COM (Linas Petras) writes: > >Could I please ask you Andy, that you post the lastest and greatest versions of >'ar' 'lorder' and 'tsort'. Ok. Here they are. Actually, I have a subsequent patch for tsort, but that will not be in 1.3, so it is not included here. These are the 1.3 files. Andy Tanenbaum (ast@cs.vu.nl) : This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. : --------------------------- cut here -------------------------- PATH=/bin:/usr/bin:/usr/ucb echo Extracting 'ar.c' sed 's/^X//' > 'ar.c' << '+ END-OF-FILE ''ar.c' X/* ar - archiver Author: Michiel Huisjes */ X/* V7 upgrade Author: Monty Walls */ X X/* X * Usage: ar 'key' [posname] archive [file] ... X * X * where 'key' is one of: qrqtpmx X * X * q: quickly append to the end of the archive file X * m: move named files X * r: replace (append when not in archive) X * d: delete X * t: print contents of archive X * p: print named files X * x: extract X * X * concatencated with one or more of: vuaibcl X * X * l: local temporary file for work instead of /tmp/ar.$$$$$ X * v: verbose X * a: after 'posname' X * b: before 'posname' X * i: before 'posname' X * c: create (suppresses creation message) X * u: replace only if dated later than member in archive X */ X X/* mods: X * 1.2 upgrade. X * local directory support (mrw). X * full V7 functionality + complete rewrite (mrw). X * changed verbose mode to give member name on print (mrw). X * fixed up error messages to give more info (mrw). X * X * notes: X * pdp11 long format & Intel long format are different. X * X * change log: X * forgot that ar_size is a long for printing - 2/14/88 - mrw X * got the mode bit maps mirrored - 2/19/88 - mrw X * print & extract member logic fixed - 2/19/88 - mrw X */ X X/* include files */ X#include X#include X#include X X/* ar.c header file V7 */ X X#define ARMAG 0177545l Xstruct ar_hdr { X char ar_name[14]; X long ar_date; /* not Intel format */ X char ar_uid; X char ar_gid; X int ar_mode; X long ar_size; /* not Intel format */ X}; X X X/* macro functions */ X#define FOREVER (32766) X#define odd(nr) (nr & 1) X#define even(nr) (odd(nr) ? nr + 1 : nr) X#define quit(pid,sig) (kill(pid,sig),sleep(FOREVER)) X#ifndef tell X# define tell(f) (lseek(f, 0l, 1)) X#endif X X/* option switches */ X/* major options */ X#define EXTRACT 0x01 X#define REPLACE 0x02 X#define PRINT 0x04 X#define TABLE 0x08 X#define DELETE 0x10 X#define APPEND 0x20 X#define MOVE 0x40 X X/* minor options */ X#define BEFORE 0x01 X#define AFTER 0x02 X#define LOCAL 0x01 X#define VERBOSE 0x01 X#define CREATE 0x01 X#define ONLY 0x01 X X/* mode bits maps */ X#define EXEC_OWNER 00100 X#define EXEC_GROUP 00010 X#define EXEC_ALL 00001 X#define READ_OWNER 00400 X#define READ_GROUP 00040 X#define READ_ALL 00004 X#define WRITE_OWNER 00200 X#define WRITE_GROUP 00020 X#define WRITE_ALL 00002 X#define SET_UID 04000 X#define SET_GID 02000 X X/* global defines */ X#define BUFFERSIZE 4096 X#define WRITE 2 /* both read & write */ X#define READ 0 X#define MAGICSIZE sizeof(short) /* size of magic number in file */ X X/* option switches */ Xchar verbose = 0; Xchar local = 0; Xchar create = 0; Xchar only = 0; Xchar major = 0; Xchar minor = 0; X X/* global variables */ Xchar *tmp1; Xchar *tmp2; Xchar *progname; Xchar *posname = NULL; Xchar *afile; Xchar buffer[BUFFERSIZE]; Xlong pos_offset = -1; Xint mypid; X X/* keep track of member moves using this struct */ Xstruct mov_list { X long pos; X struct mov_list *next; X} *moves = NULL; X X/* forward declarations and external references */ Xextern char *malloc(); Xextern char *mktemp(), *rindex(); Xextern int strncmp(); Xextern print_date(); Xextern user_abort(), usage(); Xextern long lseek(); Xextern char *basename(); X Xint Xmain(argc, argv) Xint argc; Xchar **argv; X{ X int ac, opts_seen = 0, rc; X char *av; X X progname = argv[0]; X if (argc < 3) X usage(); X X for (av = argv[1]; *av; ++av) { X switch (*av) { /* major option */ X case 'q': X major |= APPEND; X ++opts_seen; X break; X case 'r': X major |= REPLACE; X ++opts_seen; X break; X case 'x': X major |= EXTRACT; X ++opts_seen; X break; X case 'p': X major |= PRINT; X ++opts_seen; X break; X case 'm': X major |= MOVE; X ++opts_seen; X break; X case 'd': X major |= DELETE; X ++opts_seen; X break; X case 't': X major |= TABLE; X ++opts_seen; X break; X case 'l': X local |= LOCAL; X break; X case 'a': X minor |= AFTER; X break; X case 'i': X case 'b': X minor |= BEFORE; X break; X case 'v': X verbose |= VERBOSE; X break; X case 'c': X create |= CREATE; X break; X case 'u': X only |= ONLY; X break; X default: X usage(); X } X } X X if (opts_seen != 1) X usage(); X X /* now do edits on options */ X if (!(major & (REPLACE | MOVE))) { X if (minor & (AFTER | BEFORE)) X usage(); X } X else if (major & MOVE) { X if (!(minor & (AFTER | BEFORE))) X usage(); X } X else if (only & ONLY) X if (!(major & REPLACE)) X usage(); X X if (local) X tmp1 = mktemp("./ar.1.XXXXXX"); X else X tmp1 = mktemp("/tmp/ar.1.XXXXXX"); X X /* now if minor says AFTER or BEFORE - then get posname */ X if (minor & (AFTER | BEFORE) && argc >= 4) { X posname = argv[2]; X afile = argv[3]; X ac = 4; X } X else { X posname = (char *)NULL; X afile = argv[2]; X ac = 3; X } X X /* exit logic consists of doing a kill on my pid to insure that we */ X /* get the current clean up and exit logic */ X mypid = getpid(); X signal(SIGINT, user_abort); X X switch (major) { X case REPLACE: X case DELETE: X case MOVE: X ar_members(ac, argc, argv); X break; X case EXTRACT: X case TABLE: X case PRINT: X ar_common(ac, argc, argv); X break; X case APPEND: X append_members(ac, argc, argv); X break; X default: X usage(); X } X X for (rc = 0; ac < argc; ++ac) { X if (*argv[ac] != '\0') { X /* no processing done on this name */ X fprintf(stderr,"Error %s: %s not found in %s\n", progname, argv[ac], afile); X rc = 1; X } X } X fflush(stdout); X exit(rc); X} X Xusage() X{ X fprintf(stderr,"Usage: %s [qrxdpmt][abivulc] [posname] afile name ... \n",progname); X exit(1); X} X Xuser_abort() X{ X unlink(tmp1); X exit(1); X} X Xinsert_abort() X{ X unlink(tmp1); X unlink(tmp2); X exit(1); X} X Xmwrite(fd, address, bytes) Xint fd; Xregister char *address; Xregister int bytes; X{ X if (write(fd, address, bytes) != bytes) { X fprintf(stderr," Error: %s - Write error\n",progname); X quit(mypid, SIGINT); X } X} X Xlong Xswap(l) Xlong l; X{ X union { X struct { X int word1, word2; X } words; X long n; X } u_in, u_out; X X u_in.n = l; X u_out.words.word1 = u_in.words.word2; X u_out.words.word2 = u_in.words.word1; X return (u_out.n); X X} X Xaddmove(pos) Xlong pos; X{ X struct mov_list *newmove; X X newmove = (struct mov_list *)malloc(sizeof(struct mov_list)); X newmove->pos = pos; X newmove->next = moves; X moves = newmove; X} X Xstruct ar_hdr * Xget_member(fd) Xint fd; X{ X int ret; X static struct ar_hdr member; X X if ((ret = read(fd, &member, sizeof(struct ar_hdr))) <= 0) X return ((struct ar_hdr *)NULL); X if (ret != sizeof(struct ar_hdr)) { X fprintf(stderr,"Error: ar corrupted archive %s\n",afile); X quit(mypid,SIGINT); X } X X /* the archive long format is pdp11 not intel X * therefore we must reformat them for our internal use X */ X X member.ar_date = swap(member.ar_date); X member.ar_size = swap(member.ar_size); X return (&member); X} X Xint Xopen_archive(filename, opt, to_create) Xchar *filename; Xint opt; X{ X static unsigned short magic; X int fd; X X /* to_create can have values of 0,1,2 */ X /* 0 - don't create a file. */ X /* 1 - create file but use create switch message mode */ X /* 2 - create file but don't talk about it */ X X if (to_create) { X if ((fd = creat(filename, 0644)) < 0) { X fprintf(stderr, "Error: %s can not create %s\n",progname, filename); X quit(mypid,SIGINT); X } X if (!create && to_create == 1) fprintf(stderr, "%s:%s created\n", progname, filename); X magic = ARMAG; X mwrite(fd, &magic, MAGICSIZE); X return (fd); X } X else { X if ((fd = open(filename, opt)) < 0) { X if (opt == WRITE) X return (open_archive(filename, opt, 1)); X else { X fprintf(stderr, "Error: %s can not open %s\n",progname, filename); X quit(mypid,SIGINT); X } X } X /* now check the magic number for ar V7 file */ X lseek(fd, 0l, 0); X read(fd, &magic, MAGICSIZE); X if (magic != ARMAG) { X fprintf(stderr, "Error: not %s V7 format - %s\n",progname, filename); X quit(mypid,SIGINT); X } X if (major & APPEND) X lseek(fd, 0l, 2); /* seek eof position */ X X return (fd); X } X} X X Xint Xrebuild(fd, tempfd) Xregister int fd, tempfd; X{ X register int n; X X /* after we have built the archive to a temporary file and */ X /* everything has worked out- we copy the archive back to */ X /* original file */ X X signal(SIGINT, SIG_IGN); X close(fd); X close(tempfd); X fd = open_archive(afile, WRITE, 2); X tempfd = open_archive(tmp1, WRITE, 0); X while ((n = read(tempfd, buffer, BUFFERSIZE)) > 0) X mwrite(fd, buffer, n); X close(tempfd); X unlink(tmp1); X return (fd); X} X Xprint_mode(mode) Xshort mode; X{ X char g_ex, o_ex, all_ex; X char g_rd, o_rd, all_rd; X char g_wr, o_wr, all_wr; X X g_ex = EXEC_GROUP & mode ? 'x' : '-'; X o_ex = EXEC_OWNER & mode ? 'x' : '-'; X all_ex = EXEC_ALL & mode ? 'x' : '-'; X X g_ex = SET_GID & mode ? 's' : g_ex; X o_ex = SET_UID & mode ? 's' : o_ex; X X g_rd = READ_GROUP & mode ? 'r' : '-'; X o_rd = READ_OWNER & mode ? 'r' : '-'; X all_rd = READ_ALL & mode ? 'r' : '-'; X X g_wr = WRITE_GROUP & mode ? 'w' : '-'; X o_wr = WRITE_OWNER & mode ? 'w' : '-'; X all_wr = WRITE_ALL & mode ? 'w' : '-'; X X fprintf(stdout,"%c%c%c",o_rd, o_wr, o_ex); X fprintf(stdout,"%c%c%c",g_rd, g_wr, g_ex); X fprintf(stdout,"%c%c%c",all_rd, all_wr, all_ex); X} X Xprint_header(member) Xstruct ar_hdr *member; X{ X if (verbose) { X print_mode(member->ar_mode); X fprintf(stdout,"%3.3d",member->ar_uid); X fprintf(stdout,"/%-3.3d ",member->ar_gid); X fprintf(stdout,"%5.5D",member->ar_size); /* oops is long - mrw */ X print_date(member->ar_date); X } X fprintf(stdout,"%-14.14s\n",member->ar_name); X} X Xprint(fd,member) Xint fd; Xstruct ar_hdr *member; X{ X int outfd; X long size; X register int cnt, ret; X int do_align; X X if (major & EXTRACT) { X if ((outfd = creat(member->ar_name,0666)) < 0) { X fprintf(stderr,"Error: %s could not creat %-14.14s\n",progname, member->ar_name); X quit(mypid,SIGINT); X } X if (verbose) X fprintf(stdout,"x - %-14.14s\n",member->ar_name); X } X else { X if (verbose) { X fprintf(stdout,"p - %-14.14s\n",member->ar_name); X fflush(stdout); X } X outfd = fileno(stdout); X } X /* changed loop to use long size for correct extracts */ X for (size = member->ar_size; size > 0; size -= ret) { X cnt = (size < BUFFERSIZE ? size : BUFFERSIZE); X ret = read(fd, buffer, cnt); X if (ret > 0) X write(outfd,buffer, ret); X } X if (odd(member->ar_size)) X lseek(fd,1l,1); /* realign ourselves */ X X if (major & EXTRACT) { X close(outfd); X chmod(member->ar_name, member->ar_mode); X } X} X X/* copy a given member from fd1 to fd2 */ Xcopy_member(infd, outfd, member) Xint infd, outfd; Xstruct ar_hdr *member; X{ X int n, cnt; X long m, size; X X /* save copies for our use */ X m = size = member->ar_size; X X /* format for disk usage */ X member->ar_size = swap(member->ar_size); X member->ar_date = swap(member->ar_date); X X mwrite(outfd, member, sizeof(struct ar_hdr)); X for (; m > 0; m -= n) { X cnt = (m < BUFFERSIZE ? m : BUFFERSIZE); X if ((n = read(infd, buffer, cnt)) != cnt) { X fprintf(stderr,"Error: %s - read error on %-14.14s\n",progname, member->ar_name); X quit(mypid, SIGINT); X } X mwrite(outfd, buffer, n); X } X if (odd(size)) { /* pad to word boundary */ X mwrite(outfd, buffer, 1); X lseek(infd,1l,1); /* realign reading fd */ X } X} X X/* insert at current offset - name file */ Xinsert(fd, name, mess, oldmember) Xint fd; Xchar *name, *mess; Xstruct ar_hdr *oldmember; X{ X static struct ar_hdr member; X static struct stat status; X int in_fd; X X if (stat(name, &status) < 0) { X fprintf(stderr,"Error: %s cannot find file %s\n",progname,name); X quit(mypid,SIGINT); X } X else if ((in_fd = open(name, READ)) < 0) { X fprintf(stderr,"Error: %s cannot open file %s\n",progname,name); X quit(mypid,SIGINT); X } X strncpy(member.ar_name, basename(name),14); X member.ar_uid = status.st_uid; X member.ar_gid = status.st_gid; X member.ar_mode = status.st_mode & 07777; X member.ar_date = status.st_mtime; X member.ar_size = status.st_size; X if (only & ONLY) X if (oldmember != (struct ar_hdr *)NULL) X if (member.ar_date <= oldmember->ar_date) { X close(in_fd); X if (verbose) fprintf(stdout, "not %-14.14s - %-14.14s\n",mess, name); X return (-1); X } X X copy_member(in_fd, fd, &member); X if (verbose) X fprintf(stdout, "%s - %-14.14s\n",mess, name); X close(in_fd); X return (1); X} X Xint Xar_move(oldfd, arfd,mov) Xint oldfd, arfd; Xstruct mov_list *mov; X{ X long pos; X int cnt, want, a, newfd; X struct ar_hdr *member; X X if (local) X tmp2 = mktemp("./ar.2.XXXXXX"); X else X tmp2 = mktemp("/tmp/ar.2.XXXXXX"); X X close(oldfd); /* close old temp file */ X signal(SIGINT, insert_abort); /* set new signal handler */ X newfd = open_archive(tmp2, WRITE, 2); /* open new tmp file */ X oldfd = open_archive(tmp1, WRITE, 0); /* reopen old tmp file */ X X /* copy archive till we get to pos_offset */ X for (pos = pos_offset; pos > 0; pos -= cnt) { X want = (pos < BUFFERSIZE ? pos : BUFFERSIZE); X if ((cnt = read(oldfd, buffer, want)) > 0) X mwrite(newfd, buffer, cnt); X } X /* if minor = 'a' then skip over posname */ X if (minor & AFTER) { X if ((member = get_member(oldfd)) != NULL) X copy_member(oldfd, newfd, member); X } X /* move members in the library */ X while (mov != NULL) { X lseek(arfd, mov->pos, 0); X if ((member = get_member(arfd)) != NULL) X copy_member(arfd, newfd, member); X mov = mov->next; X if (verbose) fprintf(stdout, "m - %-14.14s\n", member->ar_name); X } X X /* copy rest of library into new tmp file */ X while ((member = get_member(oldfd)) != NULL) X copy_member(oldfd, newfd, member); X X /* detach old temp file */ X close(oldfd); X unlink(tmp1); X X /* change context temp file */ X tmp1 = tmp2; X return (newfd); X} X Xint Xar_insert(oldfd, ac, argc, argv) Xint oldfd; Xint ac, argc; Xchar **argv; X{ X long pos; X int cnt, want, a, newfd; X struct ar_hdr *member; X X if (local) X tmp2 = mktemp("./ar.2.XXXXXX"); X else X tmp2 = mktemp("/tmp/ar.2.XXXXXX"); X X close(oldfd); /* close old temp file */ X signal(SIGINT, insert_abort); /* set new signal handler */ X newfd = open_archive(tmp2, WRITE, 2); /* open new tmp file */ X oldfd = open_archive(tmp1, WRITE, 0); /* reopen old tmp file */ X X /* copy archive till we get to pos_offset */ X for (pos = pos_offset; pos > 0; pos -= cnt) { X want = (pos < BUFFERSIZE ? pos : BUFFERSIZE); X if ((cnt = read(oldfd, buffer, want)) > 0) X mwrite(newfd, buffer, cnt); X } X /* if minor = 'a' then skip over posname */ X if (minor & AFTER) { X if ((member = get_member(oldfd)) != NULL) X copy_member(oldfd, newfd, member); X } X X /* copy new members into the library */ X for (a = ac+1; a <= argc; ++a) X if (argv[a-1] && *argv[a-1] != '\0') { X insert(newfd, argv[a-1], "a", (struct ar_hdr *)NULL); X *argv[a-1] = '\0'; X } X X /* copy rest of library into new tmp file */ X while ((member = get_member(oldfd)) != NULL) X copy_member(oldfd, newfd, member); X X /* detach old temp file */ X close(oldfd); X unlink(tmp1); X X /* change context temp file */ X tmp1 = tmp2; X return (newfd); X} X Xar_common(ac, argc, argv) Xint ac, argc; Xchar **argv; X{ X int a, fd, did_print; X struct ar_hdr *member; X X fd = open_archive(afile, READ, 0); X while ((member = get_member(fd)) != NULL) { X did_print = 0; X if (ac < argc) { X for (a = ac+1; a <= argc; ++a) { X if (strncmp(basename(argv[a-1]),member->ar_name,14) == 0) { X if (major & TABLE) X print_header(member); X else if (major & (PRINT | EXTRACT)) { X print(fd, member); X did_print = 1; X } X *argv[a-1] = '\0'; X break; X } X } X } X else { X if (major & TABLE) X print_header(member); X else if (major & (PRINT | EXTRACT)) { X print(fd, member); X did_print = 1; X } X } X /* if we didn't print the member or didn't use it we will X * have to seek over its contents X */ X if (!did_print) X lseek(fd, (long)even(member->ar_size), 1); X } X} X Xar_members(ac, argc, argv) Xint ac, argc; Xchar **argv; X{ X int a, fd, tempfd, rc; X struct ar_hdr *member; X long *lpos; X X fd = open_archive(afile, WRITE, 0); X tempfd = open_archive(tmp1, WRITE, 2); X while ((member = get_member(fd)) != NULL) { X X /* if posname specified check for our member */ X /* if our member save his starting pos in our working file*/ X if (posname && strncmp(posname, member->ar_name, 14) == 0) X pos_offset = tell(tempfd) - MAGICSIZE; X X if (ac < argc) { /* we have a list of members to check */ X for (a = ac+1; a <= argc; ++a) X if (strncmp(basename(argv[a-1]),member->ar_name,14) == 0) { X if (major & REPLACE) { X if (insert(tempfd,argv[a-1],"r", member) < 0) X copy_member(fd, tempfd, member); X else X lseek(fd, (long)even(member->ar_size), 1); X } X else if (major & MOVE) { X /* cheat by saving pos in archive */ X addmove((tell(fd) - sizeof(struct ar_hdr))); X lseek(fd, (long)even(member->ar_size), 1); X } X *argv[a-1] = '\0'; X break; X } X } X if (ac >= argc || a > argc) /*nomatch on a member name */ X copy_member(fd, tempfd, member); X else if (major & DELETE) { X if (verbose) fprintf(stdout,"d - %-14.14s\n",member->ar_name); X lseek(fd, (long)even(member->ar_size), 1); X } X } X if (major & MOVE) { X if (posname == NULL) X pos_offset = lseek(fd, 0l, 2); X else if (pos_offset == (-1)) { X fprintf(stderr,"Error: %s cannot find file %-14.14s\n",progname,posname); X quit(mypid,SIGINT); X } X tempfd = ar_move(tempfd, fd, moves); X } X else if (major & REPLACE) { X /* take care to add left overs */ X /* if the posname is not found we just add to end of ar */ X if (posname && pos_offset != (-1)) { X tempfd = ar_insert(tempfd, ac, argc, argv); X } X else { X for (a = ac+1; a <= argc; ++a) X if (*argv[a-1]) { X insert(tempfd, argv[a-1], "a", (struct ar_hdr *)NULL); X *argv[a-1] = '\0'; X } X } X } X fd = rebuild(fd, tempfd); X close(fd); X} X Xappend_members(ac, argc, argv) Xint ac, argc; Xchar **argv; X{ X int a, fd; X struct ar_hdr *member; X X /* quickly append members don't worry about dups in ar */ X fd = open_archive(afile, WRITE, 0); X if (ac < argc) { X if (odd(lseek(fd, 0l, 2))) X mwrite(fd, buffer, 1); X /* while not end of member list insert member at end */ X for (a = ac+1; a <= argc; ++a) { X insert(fd, argv[a-1], "a", (struct ar_hdr *)NULL); X *argv[a-1] = '\0'; X } X } X close(fd); X} X X Xchar *basename(path) Xchar *path; X{ X register char *ptr = path; X register char *last = (char *)NULL; X X while (*ptr != '\0') { X if (*ptr == '/') X last = ptr; X ptr++; X } X if (last == (char *)NULL) X return path; X if (*(last + 1) == '\0') { X *last = '\0'; X return basename(path); X } X return last + 1; X} X X X#define MINUTE 60L X#define HOUR (60L * MINUTE) X#define DAY (24L * HOUR) X#define YEAR (365L * DAY) X#define LYEAR (366L * DAY) X Xint mo[] = { X 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 X}; X Xchar *moname[] = { X " Jan ", " Feb ", " Mar ", " Apr ", " May ", " Jun ", X " Jul ", " Aug ", " Sep ", " Oct ", " Nov ", " Dec " X}; X X/* Print the date. This only works from 1970 to 2099. */ Xprint_date(t) Xlong t; X{ X int i, year, day, month, hour, minute; X long length, time(), original; X X year = 1970; X original = t; X while (t > 0) { X length = (year % 4 == 0 ? LYEAR : YEAR); X if (t < length) X break; X t -= length; X year++; X } X X /* Year has now been determined. Now the rest. */ X day = (int) (t / DAY); X t -= (long) day * DAY; X hour = (int) (t / HOUR); X t -= (long) hour * HOUR; X minute = (int) (t / MINUTE); X X /* Determine the month and day of the month. */ X mo[1] = (year % 4 == 0 ? 29 : 28); X month = 0; X i = 0; X while (day >= mo[i]) { X month++; X day -= mo[i]; X i++; X } X X /* At this point, 'year', 'month', 'day', 'hour', 'minute' ok */ X fprintf(stdout, "%s%2.2d ",moname[month],++day); X if (time((long *)NULL) - original >= YEAR / 2L) X fprintf(stdout,"%4.4D ",(long)year); X else X fprintf(stdout,"%02.2d:%02.2d ",hour, minute); X} X + END-OF-FILE ar.c chmod 'u=rw,g=r,o=r' 'ar.c' set `wc -c 'ar.c'` count=$1 case $count in 19498) :;; *) echo 'Bad character count in ''ar.c' >&2 echo 'Count should be 19498' >&2 esac echo Extracting 'lorder.c' sed 's/^X//' > 'lorder.c' << '+ END-OF-FILE ''lorder.c' X/* X * lorder: find ordering relations for object library X * X * author: Monty Walls X * written: 1/29/88 X * Copyright: Copyright (c) 1988 by Monty Walls. X * Not derived from licensed software. X * X * Permission to copy and/or distribute granted under the X * following conditions: X * X * 1). This notice must remain intact. X * 2). The author is not responsible for the consequences of use X * this software, no matter how awful, even if they X * arise from defects in it. X * 3). Altered version must not be represented as being the X * original software. X * X * change log: X * corrected & rewrote scanner to avoid lex. - 2/22/88 - mrw X * oops reversed output filename order. 3/14/88 - mrw X * progname = argv[0] - should be first. 5/25/88 - mbeck X */ X X#include X#include X#include X#include X X#define MAXLINE 256 X XFILE *lexin; Xchar *yyfile; Xchar *tmpfile; Xchar *progname; Xchar template[] = "lorder.XXXXXX"; X Xstruct filelist { X char *name; X struct filelist *next; X}; X Xstruct node { X char *name; X char *file; X struct filelist *list; X struct node *left, *right; X}; X Xstruct filelist *list; Xstruct node *tree, *lastnode; Xextern char *malloc(), *mktemp(); Xextern FILE *popen(), *fopen(); Xextern char *addfile(); Xextern void user_abort(); X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X int i; X char cmdstr[MAXLINE]; X X progname = argv[0]; X if (argc > 1) { X signal(SIGINT, user_abort); X for (i = 1; argv[i] && *argv[i]; ++i ) { X /* the following code is caused by X * not enough memory on floppy systems. X * X * so instead of ar | libupack ->to us. we use X * ar >tmpfle; libupack to us X */ X if (is_liba(argv[i])) { X tmpfile = mktemp(template); X sprintf(cmdstr,"ar pv %s >%s",argv[i],tmpfile); X system(cmdstr); X sprintf(cmdstr,"libupack <%s",tmpfile); X } X else { X yyfile = addfile(argv[i]); X sprintf(cmdstr, "libupack <%s", argv[i]); X } X if ((lexin = popen(cmdstr, "r")) != (FILE *)NULL) { X while (yylex() != EOF) ; X pclose(lexin); X if (tmpfile) X unlink(tmpfile); X } X else { X fprintf(stderr,"Error: %s could not open %s\n",progname, argv[i]); X exit(1); X } X } X printtree(tree); X /* then print list of files for ar also */ X for (; list; list = list->next) X fprintf(stdout,"%s %s\n",list->name, list->name); X } X else { X fprintf(stderr,"Usage: %s file ....\n",progname); X exit(1); X } X} X Xvoid Xuser_abort() X{ X unlink(tmpfile); X exit(1); X} X Xchar * Xxalloc(n) Xint n; X{ X char *p; X X if ((p = malloc(n)) == (char *)NULL) { X fprintf(stderr, "Error %s - out of memory\n", progname); X exit(1); X } X return (p); X} X Xint Xis_liba(s) /* error handling done later */ Xchar *s; X{ X unsigned short key; X FILE *fp; X int ret = 0; X X if ((fp = fopen(s,"r")) != (FILE *)NULL) { X fread(&key, sizeof(key), 1, fp); X if (key == ARMAG) ret = 1; X fclose(fp); X } X return (ret); X} X Xchar * Xstrsave(s) Xchar *s; X{ X char *p; X X p = xalloc(strlen(s) + 1); X strcpy(p,s); X return (p); X} X Xchar * Xaddfile(s) Xchar *s; X{ X struct filelist *p; X X p = (struct filelist *)xalloc(sizeof(struct filelist)); X p->name = strsave(s); X if (list) X p->next = list; X else X p->next = NULL; X list = p; X return (p->name); X} X Xprinttree(t) Xstruct node *t; X{ X struct filelist *fp; X X if (t) { X if (t->file) { X for (fp = t->list; fp && fp->name; fp = fp->next) X if (t->file != fp->name) X fprintf(stdout,"%s %s\n",fp->name, t->file); X } X printtree(t->right); X printtree(t->left); X } X} X X Xstruct node * Xfinddef(s) Xchar *s; X{ X struct node *n; X int cmp; X X if (tree) { X lastnode = n = tree; X while (n && n->name) { X lastnode = n; X if (!(cmp=strcmp(s,n->name))) X return (n); X else if (cmp > 0) X n = n->left; X else X n = n->right; X } X } X return ((struct node *)NULL); X} X Xstruct node * Xmakedef(s) Xchar *s; X{ X struct node *n; X int cmp; X X n = (struct node *)xalloc(sizeof(struct node)); X n->name = strsave(s); X n->left = (struct node *)NULL; X n->right = (struct node *)NULL; X if (tree) { X cmp = strcmp(s, lastnode->name); X if (cmp > 0) X lastnode->left = n; X else X lastnode->right = n; X } X else X tree = n; X X return (n); X} X Xvoid Xdodef(s) Xchar *s; X{ X struct node *n; X X if (n = finddef(s)) { X if (n->file != NULL) X fprintf(stderr,"Error %s - %s defined twice in %s and %s", progname, s, n->file, yyfile); X else X n->file = yyfile; X } X else { X n = makedef(s); X n->file = yyfile; X n->list = (struct filelist *)NULL; X } X} X Xvoid Xusedef(s) Xchar *s; X{ X struct node *n; X struct filelist *fp, *lastfp; X X if (n = finddef(s)) { X /* scan file list for match */ X if (n->list) { X for (fp = n->list; fp ; fp = fp->next) { X if (fp->name == yyfile) { X return; X } X lastfp = fp; X } X /* reached here with no match */ X lastfp->next = (struct filelist *)xalloc(sizeof(struct filelist)); X lastfp->next->name = yyfile; X lastfp->next->next = (struct filelist *)NULL; X } X else { X /* empty list so far */ X n->list = (struct filelist *)xalloc(sizeof(struct filelist)); X n->list->name = yyfile; X n->list->next = (struct filelist *)NULL; X } X } X else { X n = makedef(s); X n->file = (char *)NULL; X n->list = (struct filelist *) xalloc(sizeof(struct filelist)); X n->list->name = yyfile; X n->list->next = (struct filelist *)NULL; X } X} X X/* X * yylex - scanner for lorder X * X */ X#define MAXNAME 33 X#define is_first_char(c) ((c) == '.' || (c) == '_') X#define is_second_char(c) ((c) == '_' || isalpha((c))) X#define is_other_char(c) ((c) == '_' || isalnum((c))) X Xint yylex() X{ X int col = 0; X int i = 0; X int is_member = 0; X int in_define = 0; X int lastch = 0; X char s[MAXNAME]; X X X while ((lastch = fgetc(lexin)) != EOF) { X col++; /* increment col */ X if (isspace(lastch)) { X EOS: /* eos comes here */ X if (i) { /* we have a string */ X s[i] = '\0'; /* set eos */ X i = 0; X /* X * if we are in a define use dodef to add location X * of defining member and global to symbol table. X */ X if (in_define) X dodef(s); X /* X * if we are on a 'p -' line for an ar lib define X * this member as the file we are using. X */ X else if (is_member > 0) { X is_member = 0; X yyfile = addfile(s); X } X /* X * if we have a '.define' mark this line as in_define. X */ X else if (strcmp(s,".define") == 0) X in_define = 1; X /* X * just a reference in the code to a var, so add this X * reference to our symbol table. X */ X else X usedef(s); X } X /* X * we are at the eol: reset our counters and switches X */ X if (lastch == '\n') { X col = 0; X is_member = 0; X in_define = 0; X } X /* X * lets do another character X */ X continue; X } X /* X * not a space and i == 0 X */ X if (i == 0) { X /* X * are we seeing 'p' in col 1 X */ X if (lastch == 'p' && col == 1) { X is_member = -1; X continue; X } X /* X * are we seeing '-' that follows 'p' in col 1 X */ X else if (lastch == '-' && is_member < 0 && col == 3) { X is_member = 1; X continue; X } X /* X * if we have seen 'p -' now we are reading the name or X * the first character of a global symbol X */ X if (is_member > 0 || is_first_char(lastch)) { X s[i++] = lastch; X if (is_member < 0) X is_member = 0; X } X continue; X } X /* X * do the second char of a name X */ X else if (i == 1) { X if (is_member > 0 || is_second_char(lastch)) { X s[i++] = lastch; X } X else X is_member = 0; X } X /* X * do the rest of a symbol or member name X */ X else if (is_member > 0 || is_other_char(lastch)) { X s[i++] = lastch; X continue; X } X else X goto EOS; X } X /* X * returns EOF on end of file X */ X return (lastch); X} X + END-OF-FILE lorder.c chmod 'u=rw,g=r,o=r' 'lorder.c' set `wc -c 'lorder.c'` count=$1 case $count in 7645) :;; *) echo 'Bad character count in ''lorder.c' >&2 echo 'Count should be 7645' >&2 esac echo Extracting 'tsort.c' sed 's/^X//' > 'tsort.c' << '+ END-OF-FILE ''tsort.c' X/* X * tsort - do a topological sort on the ordered pairs of names X * X * syntax - tsort [ file ] X * X * based on the discussion in 'The AWK programming Language', by X * Aho, Kernighan, & Weinberger. X * X * author: Monty Walls X * written: 1/28/88 X * Copyright: Copyright (c) 1988 by Monty Walls. X * Not derived from licensed software. X * X * Permission to copy and/or distribute granted under the X * following conditions: X * X * 1). This notice must remain intact. X * 2). The author is not responsible for the consequences of use X * this software, no matter how awful, even if they X * arise from defects in it. X * 3). Altered version must not be represented as being the X * original software. X * X * change log: X * possible bug in ungetc(), fixed readone() to avoid - 2/19/88 - mrw X * massive design error, rewrote dump logic - 3/15/88 - mrw X */ X X#include X#include X#include X X#define printmem(_s) (fprintf(stdout,"%s ",(_s))) X#define MAXNAMELEN 32 X#define MAXMEMBERS 1024 X Xstruct dependents { X struct node *nd; X struct dependents *next; X}; X Xstruct node { X char *name; X int pcnt, scnt, visited; X struct dependents *succ, *pred; X struct node *left, *right; X}; X Xchar *progname; X Xextern struct node *readnode(), *findnode(); Xextern char *malloc(), *xalloc(), *readone(), *strsave(); Xextern struct dependents *finddep(); Xextern void dumptree(), walktree(), emptytree(), addqueue(), walklist(); X Xextern int errno; Xextern char *sys_errlist[]; X Xstruct node *tree, *lastnode, *q[MAXMEMBERS]; Xstruct dependents *lastdepd; Xint node_cnt, rc, front, back; X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X progname = argv[0]; X if (argc > 1) X if (freopen(argv[1], "r", stdin) == (FILE *)NULL) { X fprintf(stderr,"Error: %s - %s\n",progname, sys_errlist[errno]); X exit(1); X } X X /* read in the tree of entries */ X while (readnode() != (struct node *)NULL) X ; X dumptree(tree); X fflush(stdout); X X if (node_cnt != back) { X fprintf(stderr,"Error: %s - input contains a cycle\n",progname); X rc = 1; X } X X exit(rc); X} X X Xstruct node * Xreadnode() X{ X char *s1, *s2; X register struct node *n1, *n2; X struct dependents *pd; X X if ((s1 = readone()) != (char *)NULL) { X if ((n1 = findnode(s1)) == (struct node *)NULL) { X /* is a new node so build it */ X n1 = (struct node *)xalloc(sizeof(struct node)); X n1->name = strsave(s1); X n1->succ = (struct dependents *)NULL; X n1->pred = (struct dependents *)NULL; X n1->left = (struct node *)NULL; X n1->right = (struct node *)NULL; X n1->pcnt = 0; X n1->scnt = 0; X n1->visited = 0; X linknode(n1); X } X if ((s2 = readone()) != (char *)NULL) { X if ((n2 = findnode(s2)) == (struct node *)NULL) { X /* is a new node so build it */ X n2 = (struct node *)xalloc(sizeof(struct node)); X n2->name = strsave(s2); X n2->succ = (struct dependents *)NULL; X n2->pred = (struct dependents *)NULL; X n2->left = (struct node *)NULL; X n2->right = (struct node *)NULL; X n2->pcnt = 0; X n2->scnt = 0; X n2->visited = 0; X linknode(n2); X } X if (n1 != n2) { X if (finddep(n2->pred,s1) == (struct dependents *)NULL) { X /* new dependence here */ X pd = (struct dependents *)xalloc(sizeof(struct dependents)); X pd->nd = n1; X pd->next = (struct dependents *)NULL; X n2->pcnt++; X if (n2->pred == (struct dependents *)NULL) X n2->pred = pd; X else X lastdepd->next = pd; X } X if (finddep(n1->succ,s2) == (struct dependents *)NULL) { X /* new dependence here */ X pd = (struct dependents *)xalloc(sizeof(struct dependents)); X pd->nd = n2; X pd->next = (struct dependents *)NULL; X n1->scnt++; X if (n1->succ == (struct dependents *)NULL) X n1->succ = pd; X else X lastdepd->next = pd; X } X } X return (n1); X } X else X return ((struct node *)NULL); X } X else X return ((struct node *)NULL); X} X Xvoid Xdumptree(top) Xregister struct node *top; X{ X walktree(top); /* get all entries in order with no predecessors */ X for (front = 1; front <= back; front++) { X printmem(q[front]->name); X walklist(q[front]->succ); X } X emptytree(top); /* dumps all isolated nodes left over */ X} X Xvoid Xwalklist(s) Xregister struct dependents *s; X{ X for (; s; s = s->next) { X if (--s->nd->pcnt == 0) { X addqueue(s->nd); X s->nd->visited = 1; X walklist(s->nd->succ); X } X } X} X Xvoid Xwalktree(t) Xregister struct node *t; X{ X if (t) { X node_cnt++; X walktree(t->right); X if (t->pcnt == 0) { X addqueue(t); X t->visited = 1; X } X walktree(t->left); X } X} X Xvoid Xemptytree(t) Xregister struct node *t; X{ X struct dependents *s; X X /* t - represents a remaining entry which is in a cycle */ X if (t) { X emptytree(t->right); X if (t->visited == 0) { X t->visited = 1; X printmem(t->name); X for (s = t->succ; s; s = s->next) X if (s->nd->visited == 0) { X fprintf(stderr,"Error: %s - %s and %s are in a cycle\n",progname, t->name, s->nd->name); X } X } X emptytree(t->left); X } X} X Xvoid Xaddqueue(t) Xstruct node *t; X{ X if (++back >= MAXMEMBERS) { X fprintf(stderr,"Error: %s - member queue overflow\n",progname); X exit(1); X } X else X q[back] = t; X} X Xchar * Xreadone() X{ X register int c, n = 0; X static char name[MAXNAMELEN]; X X /* eat up leading spaces */ X while ((c = getchar()) != EOF && isspace(c)) X ; X X if (c != EOF) { X name[n++] = c; /* save into name first non blank */ X while ((c = getchar()) != EOF && !isspace(c)) { X if (n < MAXNAMELEN) X name[n++] = c; X } X name[n] = '\0'; X return (name); X } X else X return ((char *)NULL); X X} X Xstruct node * Xfindnode(s) Xchar *s; X{ X register struct node *n; X register int cmp; X X if (tree) { X lastnode = n = tree; X while (n && n->name) { X lastnode = n; X if (!(cmp = strcmp(s,n->name))) X return (n); X else if (cmp > 0) X n = n->left; X else X n = n->right; X } X } X return ((struct node *)NULL); X} X Xstruct dependents * Xfinddep(dp, s) Xregister struct dependents *dp; Xregister char *s; X{ X lastdepd = (struct dependents *)NULL; X while (dp && dp->nd) { X lastdepd = dp; X if (strcmp(dp->nd->name,s) == 0) X return (dp); X else { X dp = dp->next; X } X } X return ((struct dependents *)NULL); X} X Xlinknode(n) Xregister struct node *n; X{ X register int cmp; X X if (tree) { X cmp = strcmp(n->name,lastnode->name); X if (cmp > 0) X lastnode->left = n; X else X lastnode->right = n; X } X else X tree = n; X} X Xchar * Xxalloc(n) Xint n; X{ X char *p; X X if ((p = malloc(n)) != (char *)NULL) X return (p); X else { X fprintf(stderr,"Error: %s out of memory\n",progname); X exit(1); X } X} X Xchar * Xstrsave(s) Xchar *s; X{ X char *p; X X p = xalloc(strlen(s)+1); X strcpy(p,s); X return (p); X} + END-OF-FILE tsort.c chmod 'u=rw,g=r,o=r' 'tsort.c' set `wc -c 'tsort.c'` count=$1 case $count in 6563) :;; *) echo 'Bad character count in ''tsort.c' >&2 echo 'Count should be 6563' >&2 esac exit 0