| tnew utilities. the .C files compile but are renamed to avoid building automatically. - plan9port - [fork] Plan 9 from user space |
| git clone git://src.adamsgaard.dk/plan9port |
| Log |
| Files |
| Refs |
| README |
| LICENSE |
| --- |
| commit bc7cb1a15a67c859c8c71c4b52bb35fe9425a63d |
| parent f08fdedcee12c06e3ce9ac9bec363915978e8289 |
| Author: rsc |
| Date: Sun, 23 Nov 2003 18:04:47 +0000
new utilities.
tthe .C files compile but are renamed to avoid building automatically.
Diffstat:
A src/cmd/ascii.c | 181 +++++++++++++++++++++++++++++++
A src/cmd/basename.c | 41 +++++++++++++++++++++++++++++++
A src/cmd/cal.c | 313 +++++++++++++++++++++++++++++++
A src/cmd/calendar.c | 195 +++++++++++++++++++++++++++++++
A src/cmd/cat.c | 36 +++++++++++++++++++++++++++++++
A src/cmd/cleanname.c | 44 +++++++++++++++++++++++++++++++
A src/cmd/cmp.c | 112 +++++++++++++++++++++++++++++++
A src/cmd/comm.c | 178 +++++++++++++++++++++++++++++++
A src/cmd/date.c | 30 ++++++++++++++++++++++++++++++
A src/cmd/dc.c | 2300 +++++++++++++++++++++++++++++++
A src/cmd/dd.c | 660 +++++++++++++++++++++++++++++++
A src/cmd/deroff.c | 969 +++++++++++++++++++++++++++++++
A src/cmd/du.C | 194 ++++++++++++++++++++++++++++++
A src/cmd/echo.c | 38 +++++++++++++++++++++++++++++++
A src/cmd/ed.c | 1608 ++++++++++++++++++++++++++++++
A src/cmd/factor.c | 96 +++++++++++++++++++++++++++++++
A src/cmd/freq.c | 111 ++++++++++++++++++++++++++++++
A src/cmd/fsize.c | 32 +++++++++++++++++++++++++++++++
A src/cmd/idiff.c | 335 +++++++++++++++++++++++++++++++
A src/cmd/join.c | 369 ++++++++++++++++++++++++++++++
A src/cmd/ls.C | 305 +++++++++++++++++++++++++++++++
A src/cmd/md5sum.C | 61 +++++++++++++++++++++++++++++++
A src/cmd/mkdir.C | 26 ++++++++++++++++++++++++++
A src/cmd/mkfile | 13 +++++++++++++
A src/cmd/rm.c | 104 +++++++++++++++++++++++++++++++
A src/cmd/seq.c | 92 +++++++++++++++++++++++++++++++
A src/cmd/sha1sum.c | 61 +++++++++++++++++++++++++++++++
A src/cmd/sleep.c | 13 +++++++++++++
A src/cmd/sort.c | 1767 +++++++++++++++++++++++++++++++
A src/cmd/split.c | 189 +++++++++++++++++++++++++++++++
A src/cmd/strings.c | 88 +++++++++++++++++++++++++++++++
A src/cmd/sum.c | 215 +++++++++++++++++++++++++++++++
A src/cmd/tail.c | 362 +++++++++++++++++++++++++++++++
A src/cmd/tar.C | 640 +++++++++++++++++++++++++++++++
A src/cmd/tee.c | 75 +++++++++++++++++++++++++++++++
A src/cmd/test.c | 303 +++++++++++++++++++++++++++++++
A src/cmd/time.c | 101 +++++++++++++++++++++++++++++++
A src/cmd/touch.c | 62 +++++++++++++++++++++++++++++++
A src/cmd/tr.c | 356 +++++++++++++++++++++++++++++++
A src/cmd/unicode.c | 122 +++++++++++++++++++++++++++++++
A src/cmd/uniq.c | 169 +++++++++++++++++++++++++++++++
A src/cmd/unutf.c | 16 ++++++++++++++++
A src/cmd/wc.c | 309 +++++++++++++++++++++++++++++++
A src/cmd/xd.c | 355 +++++++++++++++++++++++++++++++
A src/cmd/yacc.c | 2939 +++++++++++++++++++++++++++++++
45 files changed, 16585 insertions(+), 0 deletions(-)
--- |
| diff --git a/src/cmd/ascii.c b/src/cmd/ascii.c |
| t@@ -0,0 +1,181 @@
+#include
+#include
+#include
+
+#define MAXBASE 36
+
+void usage(void);
+void put(int);
+void putn(int, int);
+void puttext(char *);
+void putnum(char *);
+int btoi(char *);
+int value(int, int);
+int isnum(char *);
+
+char *str[256]={
+ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
+ "bs ", "ht ", "nl ", "vt ", "np ", "cr ", "so ", "si ",
+ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
+ "can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "us ",
+ "sp ", " ! ", " \" ", " # ", " $ ", " % ", " & ", " ' ",
+ " ( ", " ) ", " * ", " + ", " , ", " - ", " . ", " / ",
+ " 0 ", " 1 ", " 2 ", " 3 ", " 4 ", " 5 ", " 6 ", " 7 ",
+ " 8 ", " 9 ", " : ", " ; ", " < ", " = ", " > ", " ? ",
+ " @ ", " A ", " B ", " C ", " D ", " E ", " F ", " G ",
+ " H ", " I ", " J ", " K ", " L ", " M ", " N ", " O ",
+ " P ", " Q ", " R ", " S ", " T ", " U ", " V ", " W ",
+ " X ", " Y ", " Z ", " [ ", " \\ ", " ] ", " ^ ", " _ ",
+ " ` ", " a ", " b ", " c ", " d ", " e ", " f ", " g ",
+ " h ", " i ", " j ", " k ", " l ", " m ", " n ", " o ",
+ " p ", " q ", " r ", " s ", " t ", " u ", " v ", " w ",
+ " x ", " y ", " z ", " { ", " | ", " } ", " ~ ", "del",
+ "x80", "x81", "x82", "x83", "x84", "x85", "x86", "x87",
+ "x88", "x89", "x8a", "x8b", "x8c", "x8d", "x8e", "x8f",
+ "x90", "x91", "x92", "x93", "x94", "x95", "x96", "x97",
+ "x98", "x99", "x9a", "x9b", "x9c", "x9d", "x9e", "x9f",
+ "xa0", " ¡ ", " ¢ ", " £ ", " ¤ ", " ¥ ", " ¦ ", " § ",
+ " ¨ ", " © ", " ª ", " « ", " ¬ ", " ", " ® ", " ¯ ",
+ " ° ", " ± ", " ² ", " ³ ", " ´ ", " µ ", " ¶ ", " · ",
+ " ¸ ", " ¹ ", " º ", " » ", " ¼ ", " ½ ", " ¾ ", " ¿ ",
+ " À ", " Á ", " Â ", " Ã ", " Ä ", " Å ", " Æ ", " Ç ",
+ " È ", " É ", " Ê ", " Ë ", " Ì ", " Í ", " Î ", " Ï ",
+ " Ð ", " Ñ ", " Ò ", " Ó ", " Ô ", " Õ ", " Ö ", " × ",
+ " Ø ", " Ù ", " Ú ", " Û ", " Ü ", " Ý ", " Þ ", " ß ",
+ " à ", " á ", " â ", " ã ", " ä ", " å ", " æ ", " ç ",
+ " è ", " é ", " ê ", " ë ", " ì ", " í ", " î ", " ï ",
+ " ð ", " ñ ", " ò ", " ó ", " ô ", " õ ", " ö ", " ÷ ",
+ " ø ", " ù ", " ú ", " û ", " ü ", " ý ", " þ ", " ÿ "
+};
+
+char Ncol[]={
+ 0,0,7,5,4,4,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+};
+
+int nchars=128;
+int base=16;
+int ncol;
+int text=1;
+int strip=0;
+Biobuf bin;
+
+void
+main(int argc, char **argv)
+{
+ int i;
+
+ Binit(&bin, 1, OWRITE);
+ ARGBEGIN{
+ case '8':
+ nchars=256; break;
+ case 'x':
+ base=16; break;
+ case 'o':
+ base=8; break;
+ case 'd':
+ base=10; break;
+ case 'b':
+ base=strtoul(EARGF(usage()), 0, 0);
+ if(base<2||base>MAXBASE)
+ usage();
+ break;
+ case 'n':
+ text=0; break;
+ case 't':
+ strip=1;
+ /* fall through */
+ case 'c':
+ text=2; break;
+ default:
+ usage();
+ }ARGEND
+
+ ncol=Ncol[base];
+ if(argc==0){
+ for(i=0;i |
| diff --git a/src/cmd/basename.c b/src/cmd/basename.c |
| t@@ -0,0 +1,41 @@
+#include
+#include
+
+void
+main(int argc, char *argv[])
+{
+ char *pr;
+ int n, dflag;
+
+ dflag = 0;
+ if(argc>1 && strcmp(argv[1], "-d") == 0){
+ --argc;
+ ++argv;
+ dflag = 1;
+ }
+ if(argc < 2 || argc > 3){
+ fprint(2, "usage: basename [-d] string [suffix]\n");
+ exits("usage");
+ }
+ pr = utfrrune(argv[1], '/');
+ if(dflag){
+ if(pr){
+ *pr = 0;
+ print("%s\n", argv[1]);
+ exits(0);
+ }
+ print(".\n");
+ exits(0);
+ }
+ if(pr)
+ pr++;
+ else
+ pr = argv[1];
+ if(argc==3){
+ n = strlen(pr)-strlen(argv[2]);
+ if(n >= 0 && !strcmp(pr+n, argv[2]))
+ pr[n] = 0;
+ }
+ print("%s\n", pr);
+ exits(0);
+} |
| diff --git a/src/cmd/cal.c b/src/cmd/cal.c |
| t@@ -0,0 +1,313 @@
+#include
+#include
+#include
+
+char dayw[] =
+{
+ " S M Tu W Th F S"
+};
+char *smon[] =
+{
+ "January", "February", "March", "April",
+ "May", "June", "July", "August",
+ "September", "October", "November", "December",
+};
+char mon[] =
+{
+ 0,
+ 31, 29, 31, 30,
+ 31, 30, 31, 31,
+ 30, 31, 30, 31,
+};
+char string[432];
+Biobuf bout;
+
+void main(int argc, char *argv[]);
+int number(char *str);
+void pstr(char *str, int n);
+void cal(int m, int y, char *p, int w);
+int jan1(int yr);
+int curmo(void);
+int curyr(void);
+
+void
+main(int argc, char *argv[])
+{
+ int y, i, j, m;
+
+ if(argc > 3) {
+ fprint(2, "usage: cal [month] [year]\n");
+ exits("usage");
+ }
+ Binit(&bout, 1, OWRITE);
+
+/*
+ * no arg, print current month
+ */
+ if(argc == 1) {
+ m = curmo();
+ y = curyr();
+ goto xshort;
+ }
+
+/*
+ * one arg
+ * if looks like a month, print month
+ * else print year
+ */
+ if(argc == 2) {
+ y = number(argv[1]);
+ if(y < 0)
+ y = -y;
+ if(y >= 1 && y <= 12) {
+ m = y;
+ y = curyr();
+ goto xshort;
+ }
+ goto xlong;
+ }
+
+/*
+ * two arg, month and year
+ */
+ m = number(argv[1]);
+ if(m < 0)
+ m = -m;
+ y = number(argv[2]);
+ goto xshort;
+
+/*
+ * print out just month
+ */
+xshort:
+ if(m < 1 || m > 12)
+ goto badarg;
+ if(y < 1 || y > 9999)
+ goto badarg;
+ Bprint(&bout, " %s %ud\n", smon[m-1], y);
+ Bprint(&bout, "%s\n", dayw);
+ cal(m, y, string, 24);
+ for(i=0; i<6*24; i+=24)
+ pstr(string+i, 24);
+ exits(0);
+
+/*
+ * print out complete year
+ */
+xlong:
+ y = number(argv[1]);
+ if(y<1 || y>9999)
+ goto badarg;
+ Bprint(&bout, "\n\n\n");
+ Bprint(&bout, " %ud\n", y);
+ Bprint(&bout, "\n");
+ for(i=0; i<12; i+=3) {
+ for(j=0; j<6*72; j++)
+ string[j] = '\0';
+ Bprint(&bout, " %.3s", smon[i]);
+ Bprint(&bout, " %.3s", smon[i+1]);
+ Bprint(&bout, " %.3s\n", smon[i+2]);
+ Bprint(&bout, "%s %s %s\n", dayw, dayw, dayw);
+ cal(i+1, y, string, 72);
+ cal(i+2, y, string+23, 72);
+ cal(i+3, y, string+46, 72);
+ for(j=0; j<6*72; j+=72)
+ pstr(string+j, 72);
+ }
+ Bprint(&bout, "\n\n\n");
+ exits(0);
+
+badarg:
+ Bprint(&bout, "cal: bad argument\n");
+}
+
+struct
+{
+ char* word;
+ int val;
+} dict[] =
+{
+ "jan", 1,
+ "january", 1,
+ "feb", 2,
+ "february", 2,
+ "mar", 3,
+ "march", 3,
+ "apr", 4,
+ "april", 4,
+ "may", 5,
+ "jun", 6,
+ "june", 6,
+ "jul", 7,
+ "july", 7,
+ "aug", 8,
+ "august", 8,
+ "sep", 9,
+ "sept", 9,
+ "september", 9,
+ "oct", 10,
+ "october", 10,
+ "nov", 11,
+ "november", 11,
+ "dec", 12,
+ "december", 12,
+ 0
+};
+
+/*
+ * convert to a number.
+ * if its a dictionary word,
+ * return negative number
+ */
+int
+number(char *str)
+{
+ int n, c;
+ char *s;
+
+ for(n=0; s=dict[n].word; n++)
+ if(strcmp(s, str) == 0)
+ return -dict[n].val;
+ n = 0;
+ s = str;
+ while(c = *s++) {
+ if(c<'0' || c>'9')
+ return 0;
+ n = n*10 + c-'0';
+ }
+ return n;
+}
+
+void
+pstr(char *str, int n)
+{
+ int i;
+ char *s;
+
+ s = str;
+ i = n;
+ while(i--)
+ if(*s++ == '\0')
+ s[-1] = ' ';
+ i = n+1;
+ while(i--)
+ if(*--s != ' ')
+ break;
+ s[1] = '\0';
+ Bprint(&bout, "%s\n", str);
+}
+
+void
+cal(int m, int y, char *p, int w)
+{
+ int d, i;
+ char *s;
+
+ s = p;
+ d = jan1(y);
+ mon[2] = 29;
+ mon[9] = 30;
+
+ switch((jan1(y+1)+7-d)%7) {
+
+ /*
+ * non-leap year
+ */
+ case 1:
+ mon[2] = 28;
+ break;
+
+ /*
+ * 1752
+ */
+ default:
+ mon[9] = 19;
+ break;
+
+ /*
+ * leap year
+ */
+ case 2:
+ ;
+ }
+ for(i=1; i 9)
+ *s = i/10+'0';
+ s++;
+ *s++ = i%10+'0';
+ s++;
+ if(++d == 7) {
+ d = 0;
+ s = p+w;
+ p = s;
+ }
+ }
+}
+
+/*
+ * return day of the week
+ * of jan 1 of given year
+ */
+int
+jan1(int yr)
+{
+ int y, d;
+
+/*
+ * normal gregorian calendar
+ * one extra day per four years
+ */
+
+ y = yr;
+ d = 4+y+(y+3)/4;
+
+/*
+ * julian calendar
+ * regular gregorian
+ * less three days per 400
+ */
+
+ if(y > 1800) {
+ d -= (y-1701)/100;
+ d += (y-1601)/400;
+ }
+
+/*
+ * great calendar changeover instant
+ */
+
+ if(y > 1752)
+ d += 3;
+
+ return d%7;
+}
+
+/*
+ * system dependent
+ * get current month and year
+ */
+int
+curmo(void)
+{
+ Tm *tm;
+
+ tm = localtime(time(0));
+ return tm->mon+1;
+}
+
+int
+curyr(void)
+{
+ Tm *tm;
+
+ tm = localtime(time(0));
+ return tm->year+1900;
+} |
| diff --git a/src/cmd/calendar.c b/src/cmd/calendar.c |
| t@@ -0,0 +1,195 @@
+#include
+#include
+#include
+#include
+#include
+
+typedef struct Date Date;
+struct Date {
+ Reprog *p; /* an RE to match this date */
+ Date *next; /* pointer to next in list */
+};
+
+enum{
+ Secondsperday = 24*60*60
+};
+
+Biobuf in;
+int debug, matchyear;
+
+Date *dates(Date**, Tm*);
+void upper2lower(char*, char*, int);
+void *alloc(unsigned int);
+
+void
+main(int argc, char *argv[])
+{
+ int i, fd, ahead;
+ long now;
+ char *line;
+ Tm *tm;
+ Date *first, *last, *d;
+ char buf[1024];
+
+ ahead = 0;
+ ARGBEGIN{
+ case 'y':
+ matchyear = 1;
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'p':
+ ahead = atoi(ARGF());
+ break;
+ default:
+ fprint(2, "usage: calendar [-y] [-d] [files ...]\n");
+ exits("usage");
+ }ARGEND;
+
+ /* make a list of dates */
+ now = time(0);
+ tm = localtime(now);
+ last = nil;
+ first = dates(&last, tm);
+ now += Secondsperday;
+ tm = localtime(now);
+ dates(&last, tm);
+ if(tm->wday == 6){
+ now += Secondsperday;
+ tm = localtime(now);
+ dates(&last, tm);
+ }
+ if(tm->wday == 0){
+ now += Secondsperday;
+ tm = localtime(now);
+ dates(&last, tm);
+ }
+ if(ahead){
+ now = time(0);
+ now += ahead * Secondsperday;
+ tm = localtime(now);
+ dates(&last, tm);
+ }
+
+ for(i=0; inext)
+ if(regexec(d->p, buf, 0, 0)){
+ print("%s\n", line);
+ break;
+ }
+ }
+ close(fd);
+ }
+ exits("");
+}
+
+char *months[] =
+{
+ "january",
+ "february",
+ "march",
+ "april",
+ "may",
+ "june",
+ "july",
+ "august",
+ "september",
+ "october",
+ "november",
+ "december"
+};
+
+/*
+ * Generate two Date structures. First has month followed by day;
+ * second has day followed by month. Link them into list after
+ * last, and return the first.
+ */
+Date*
+dates(Date **last, Tm *tm)
+{
+ Date *first;
+ Date *nd;
+ char mo[128], buf[128];
+
+ if(utflen(months[tm->mon]) > 3)
+ snprint(mo, sizeof mo, "%3.3s(%s)?",
+ months[tm->mon], months[tm->mon]+3);
+ else
+ snprint(mo, sizeof mo, "%3.3s", months[tm->mon]);
+ if (matchyear)
+ snprint(buf, sizeof buf,
+ "(^| |\t)((%s( |\t)+)|(%d/))%d( |\t|$)(((%d|%d)( |\t|$))|[^0-9]|([0-9]+[^0-9 \t]))",
+ mo, tm->mon+1, tm->mday, tm->year+1900, tm->year%100);
+ else
+ snprint(buf, sizeof buf,
+ "(^| |\t)((%s( |\t)+)|(%d/))%d( |\t|$)",
+ mo, tm->mon+1, tm->mday);
+ if(debug)
+ print("%s\n", buf);
+
+ first = alloc(sizeof(Date));
+ if(*last)
+ (*last)->next = first;
+ first->p = regcomp(buf);
+
+ if (matchyear)
+ snprint(buf, sizeof buf,
+ "(^| |\t)%d( |\t)+(%s)( |\t|$)(((%d|%d)( |\t|$))|[^0-9]|([0-9]+[^0-9 \t]))",
+ tm->mday, mo, tm->year+1900, tm->year%100);
+ else
+ snprint(buf, sizeof buf,
+ "(^| |\t)%d( |\t)+(%s)( |\t|$)",
+ tm->mday, mo);
+ if(debug)
+ print("%s\n", buf);
+ nd = alloc(sizeof(Date));
+ nd->p = regcomp(buf);
+ nd->next = 0;
+ first->next = nd;
+ *last = nd;
+
+ return first;
+}
+
+/*
+ * Copy 'from' to 'to', converting to lower case
+ */
+void
+upper2lower(char *to, char *from, int len)
+{
+ while(--len>0 && *from!='\0')
+ *to++ = tolower(*from++);
+ *to = 0;
+}
+
+/*
+ * Call malloc and check for errors
+ */
+void*
+alloc(unsigned int n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == 0){
+ fprint(2, "calendar: malloc failed: %r\n");
+ exits("malloc");
+ }
+ return p;
+} |
| diff --git a/src/cmd/cat.c b/src/cmd/cat.c |
| t@@ -0,0 +1,36 @@
+#include
+#include
+
+void
+cat(int f, char *s)
+{
+ char buf[8192];
+ long n;
+
+ while((n=read(f, buf, (long)sizeof buf))>0)
+ if(write(1, buf, n)!=n)
+ sysfatal("write error copying %s: %r", s);
+ if(n < 0)
+ sysfatal("error reading %s: %r", s);
+}
+
+void
+main(int argc, char *argv[])
+{
+ int f, i;
+
+ argv0 = "cat";
+ if(argc == 1)
+ cat(0, "");
+ else for(i=1; i |
| diff --git a/src/cmd/cleanname.c b/src/cmd/cleanname.c |
| t@@ -0,0 +1,44 @@
+#include
+#include
+
+void
+main(int argc, char **argv)
+{
+ char *dir;
+ char *name;
+ int i;
+
+ dir = nil;
+ ARGBEGIN{
+ case 'd':
+ if((dir=ARGF()) == nil)
+ goto Usage;
+ break;
+ default:
+ goto Usage;
+ }ARGEND;
+
+ if(argc < 1) {
+ Usage:
+ fprint(2, "usage: cleanname [-d pwd] name...\n");
+ exits("usage");
+ }
+
+ for(i=0; i |
| diff --git a/src/cmd/cmp.c b/src/cmd/cmp.c |
| t@@ -0,0 +1,112 @@
+#include
+#include
+
+#define BUF 65536
+
+int sflag = 0;
+int lflag = 0;
+int Lflag = 0;
+
+static void usage(void);
+
+void
+main(int argc, char *argv[])
+{
+ int n, i;
+ uchar *p, *q;
+ uchar buf1[BUF], buf2[BUF];
+ int f1, f2;
+ vlong nc = 1, o, l = 1;
+ char *name1, *name2;
+ uchar *b1s, *b1e, *b2s, *b2e;
+
+ ARGBEGIN{
+ case 's': sflag = 1; break;
+ case 'l': lflag = 1; break;
+ case 'L': Lflag = 1; break;
+ default: usage();
+ }ARGEND
+ if(argc < 2)
+ usage();
+ if((f1 = open(name1 = *argv++, OREAD)) == -1){
+ if(!sflag) perror(name1);
+ exits("open");
+ }
+ if((f2 = open(name2 = *argv++, OREAD)) == -1){
+ if(!sflag) perror(name2);
+ exits("open");
+ }
+ if(*argv){
+ o = strtoll(*argv++, 0, 0);
+ if(seek(f1, o, 0) < 0){
+ if(!sflag) perror("cmp: seek by offset1");
+ exits("seek 1");
+ }
+ }
+ if(*argv){
+ o = strtoll(*argv++, 0, 0);
+ if(seek(f2, o, 0) < 0){
+ if(!sflag) perror("cmp: seek by offset2");
+ exits("seek 2");
+ }
+ }
+ if(*argv)
+ usage();
+ b1s = b1e = buf1;
+ b2s = b2e = buf2;
+ for(;;){
+ if(b1s >= b1e){
+ if(b1s >= &buf1[BUF])
+ b1s = buf1;
+ n = read(f1, b1s, &buf1[BUF] - b1s);
+ b1e = b1s + n;
+ }
+ if(b2s >= b2e){
+ if(b2s >= &buf2[BUF])
+ b2s = buf2;
+ n = read(f2, b2s, &buf2[BUF] - b2s);
+ b2e = b2s + n;
+ }
+ n = b2e - b2s;
+ if(n > b1e - b1s)
+ n = b1e - b1s;
+ if(n <= 0)
+ break;
+ if(memcmp((void *)b1s, (void *)b2s, n) != 0){
+ if(sflag)
+ exits("differ");
+ for(p = b1s, q = b2s, i = 0; i < n; p++, q++, i++) {
+ if(*p == '\n')
+ l++;
+ if(*p != *q){
+ if(!lflag){
+ print("%s %s differ: char %lld",
+ name1, name2, nc+i);
+ print(Lflag?" line %lld\n":"\n", l);
+ exits("differ");
+ }
+ print("%6lld 0x%.2x 0x%.2x\n", nc+i, *p, *q);
+ }
+ }
+ }
+ if(Lflag)
+ for(p = b1s; p < b1e;)
+ if(*p++ == '\n')
+ l++;
+ nc += n;
+ b1s += n;
+ b2s += n;
+ }
+ if(b1e - b1s == b2e - b2s)
+ exits((char *)0);
+ if(!sflag)
+ print("EOF on %s\n", (b1e - b1s > b2e - b2s)? name2 : name1);
+ exits("EOF");
+}
+
+static void
+usage(void)
+{
+ print("Usage: cmp [-lsL] file1 file2 [offset1 [offset2] ]\n");
+ exits("usage");
+} |
| diff --git a/src/cmd/comm.c b/src/cmd/comm.c |
| t@@ -0,0 +1,178 @@
+#include
+#include
+#include
+
+#define LB 2048
+int one;
+int two;
+int three;
+
+char *ldr[3];
+
+Biobuf *ib1;
+Biobuf *ib2;
+Biobuf *openfil(char*);
+int rd(Biobuf*, char*);
+void wr(char*, int);
+void copy(Biobuf*, char*, int);
+int compare(char*, char*);
+
+void
+main(int argc, char *argv[])
+{
+ int l;
+ char lb1[LB],lb2[LB];
+
+ ldr[0] = "";
+ ldr[1] = "\t";
+ ldr[2] = "\t\t";
+ l = 2;
+ ARGBEGIN{
+ case '1':
+ if(!one) {
+ one = 1;
+ ldr[1][0] =
+ ldr[2][l--] = '\0';
+ }
+ break;
+
+ case '2':
+ if(!two) {
+ two = 1;
+ ldr[2][l--] = '\0';
+ }
+ break;
+
+ case '3':
+ three = 1;
+ break;
+
+ default:
+ goto Usage;
+
+ }ARGEND
+
+ if(argc < 2) {
+ Usage:
+ fprint(2, "usage: comm [-123] file1 file2\n");
+ exits("usage");
+ }
+
+ ib1 = openfil(argv[0]);
+ ib2 = openfil(argv[1]);
+
+
+ if(rd(ib1,lb1) < 0){
+ if(rd(ib2,lb2) < 0)
+ exits(0);
+ copy(ib2,lb2,2);
+ }
+ if(rd(ib2,lb2) < 0)
+ copy(ib1,lb1,1);
+
+ for(;;){
+ switch(compare(lb1,lb2)) {
+ case 0:
+ wr(lb1,3);
+ if(rd(ib1,lb1) < 0) {
+ if(rd(ib2,lb2) < 0)
+ exits(0);
+ copy(ib2,lb2,2);
+ }
+ if(rd(ib2,lb2) < 0)
+ copy(ib1,lb1,1);
+ continue;
+
+ case 1:
+ wr(lb1,1);
+ if(rd(ib1,lb1) < 0)
+ copy(ib2,lb2,2);
+ continue;
+
+ case 2:
+ wr(lb2,2);
+ if(rd(ib2,lb2) < 0)
+ copy(ib1,lb1,1);
+ continue;
+ }
+ }
+ exits(0);
+}
+
+int
+rd(Biobuf *file, char *buf)
+{
+ int i, c;
+
+ i = 0;
+ while((c = Bgetc(file)) != Beof) {
+ *buf = c;
+ if(c == '\n' || i > LB-2) {
+ *buf = '\0';
+ return 0;
+ }
+ i++;
+ buf++;
+ }
+ return -1;
+}
+
+void
+wr(char *str, int n)
+{
+
+ switch(n){
+ case 1:
+ if(one)
+ return;
+ break;
+
+ case 2:
+ if(two)
+ return;
+ break;
+
+ case 3:
+ if(three)
+ return;
+ }
+ print("%s%s\n", ldr[n-1],str);
+}
+
+void
+copy(Biobuf *ibuf, char *lbuf, int n)
+{
+ do
+ wr(lbuf,n);
+ while(rd(ibuf,lbuf) >= 0);
+ exits(0);
+}
+
+int
+compare(char *a, char *b)
+{
+ while(*a == *b){
+ if(*a == '\0')
+ return 0;
+ a++;
+ b++;
+ }
+ if(*a < *b)
+ return 1;
+ return 2;
+}
+
+Biobuf*
+openfil(char *s)
+{
+ Biobuf *b;
+
+ if(s[0]=='-' && s[1]==0)
+ s = "/fd/0";
+ b = Bopen(s, OREAD);
+ if(b)
+ return b;
+ fprint(2,"comm: cannot open %s: %r\n",s);
+ exits("open");
+ return 0; /* shut up ken */
+} |
| diff --git a/src/cmd/date.c b/src/cmd/date.c |
| t@@ -0,0 +1,30 @@
+#include
+#include
+
+int uflg, nflg;
+
+void
+main(int argc, char *argv[])
+{
+ ulong now;
+
+ ARGBEGIN{
+ case 'n': nflg = 1; break;
+ case 'u': uflg = 1; break;
+ default: fprint(2, "usage: date [-un] [seconds]\n"); exits("usage");
+ }ARGEND
+
+ if(argc == 1)
+ now = strtoul(*argv, 0, 0);
+ else
+ now = time(0);
+
+ if(nflg)
+ print("%ld\n", now);
+ else if(uflg)
+ print("%s", asctime(gmtime(now)));
+ else
+ print("%s", ctime(now));
+
+ exits(0);
+} |
| diff --git a/src/cmd/dc.c b/src/cmd/dc.c |
| t@@ -0,0 +1,2300 @@
+#include
+#include
+#include
+
+typedef void* pointer;
+
+#define div dcdiv
+
+#define FATAL 0
+#define NFATAL 1
+#define BLK sizeof(Blk)
+#define PTRSZ sizeof(int*)
+#define HEADSZ 1024
+#define STKSZ 100
+#define RDSKSZ 100
+#define TBLSZ 256
+#define ARRAYST 221
+#define MAXIND 2048
+#define NL 1
+#define NG 2
+#define NE 3
+#define length(p) ((p)->wt-(p)->beg)
+#define rewind(p) (p)->rd=(p)->beg
+#define create(p) (p)->rd = (p)->wt = (p)->beg
+#define fsfile(p) (p)->rd = (p)->wt
+#define truncate(p) (p)->wt = (p)->rd
+#define sfeof(p) (((p)->rd==(p)->wt)?1:0)
+#define sfbeg(p) (((p)->rd==(p)->beg)?1:0)
+#define sungetc(p,c) *(--(p)->rd)=c
+#define sgetc(p) (((p)->rd==(p)->wt)?-1:*(p)->rd++)
+#define skipc(p) {if((p)->rd<(p)->wt)(p)->rd++;}
+#define slookc(p) (((p)->rd==(p)->wt)?-1:*(p)->rd)
+#define sbackc(p) (((p)->rd==(p)->beg)?-1:*(--(p)->rd))
+#define backc(p) {if((p)->rd>(p)->beg) --(p)->rd;}
+#define sputc(p,c) {if((p)->wt==(p)->last)more(p);\
+ *(p)->wt++ = c; }
+#define salterc(p,c) {if((p)->rd==(p)->last)more(p);\
+ *(p)->rd++ = c;\
+ if((p)->rd>(p)->wt)(p)->wt=(p)->rd;}
+#define sunputc(p) (*((p)->rd = --(p)->wt))
+#define sclobber(p) ((p)->rd = --(p)->wt)
+#define zero(p) for(pp=(p)->beg;pp<(p)->last;)\
+ *pp++='\0'
+#define OUTC(x) {Bputc(&bout,x); if(--count == 0){Bprint(&bout,"\\\n"); count=ll;} }
+#define TEST2 {if((count -= 2) <=0){Bprint(&bout,"\\\n");count=ll;}}
+#define EMPTY if(stkerr != 0){Bprint(&bout,"stack empty\n"); continue; }
+#define EMPTYR(x) if(stkerr!=0){pushp(x);Bprint(&bout,"stack empty\n");continue;}
+#define EMPTYS if(stkerr != 0){Bprint(&bout,"stack empty\n"); return(1);}
+#define EMPTYSR(x) if(stkerr !=0){Bprint(&bout,"stack empty\n");pushp(x);return(1);}
+#define error(p) {Bprint(&bout,p); continue; }
+#define errorrt(p) {Bprint(&bout,p); return(1); }
+#define LASTFUN 026
+
+typedef struct Blk Blk;
+struct Blk
+{
+ char *rd;
+ char *wt;
+ char *beg;
+ char *last;
+};
+typedef struct Sym Sym;
+struct Sym
+{
+ Sym *next;
+ Blk *val;
+};
+typedef struct Wblk Wblk;
+struct Wblk
+{
+ Blk **rdw;
+ Blk **wtw;
+ Blk **begw;
+ Blk **lastw;
+};
+
+Biobuf *curfile, *fsave;
+Blk *arg1, *arg2;
+uchar savk;
+int dbg;
+int ifile;
+Blk *scalptr, *basptr, *tenptr, *inbas;
+Blk *sqtemp, *chptr, *strptr, *divxyz;
+Blk *stack[STKSZ];
+Blk **stkptr,**stkbeg;
+Blk **stkend;
+Blk *hfree;
+int stkerr;
+int lastchar;
+Blk *readstk[RDSKSZ];
+Blk **readptr;
+Blk *rem;
+int k;
+Blk *irem;
+int skd,skr;
+int neg;
+Sym symlst[TBLSZ];
+Sym *stable[TBLSZ];
+Sym *sptr, *sfree;
+long rel;
+long nbytes;
+long all;
+long headmor;
+long obase;
+int fw,fw1,ll;
+void (*outdit)(Blk *p, int flg);
+int logo;
+int logten;
+int count;
+char *pp;
+char *dummy;
+long longest, maxsize, active;
+int lall, lrel, lcopy, lmore, lbytes;
+int inside;
+Biobuf bin;
+Biobuf bout;
+
+void main(int argc, char *argv[]);
+void commnds(void);
+Blk* readin(void);
+Blk* div(Blk *ddivd, Blk *ddivr);
+int dscale(void);
+Blk* removr(Blk *p, int n);
+Blk* dcsqrt(Blk *p);
+void init(int argc, char *argv[]);
+void onintr(void);
+void pushp(Blk *p);
+Blk* pop(void);
+Blk* readin(void);
+Blk* add0(Blk *p, int ct);
+Blk* mult(Blk *p, Blk *q);
+void chsign(Blk *p);
+int readc(void);
+void unreadc(char c);
+void binop(char c);
+void dcprint(Blk *hptr);
+Blk* dcexp(Blk *base, Blk *ex);
+Blk* getdec(Blk *p, int sc);
+void tenot(Blk *p, int sc);
+void oneot(Blk *p, int sc, char ch);
+void hexot(Blk *p, int flg);
+void bigot(Blk *p, int flg);
+Blk* add(Blk *a1, Blk *a2);
+int eqk(void);
+Blk* removc(Blk *p, int n);
+Blk* scalint(Blk *p);
+Blk* scale(Blk *p, int n);
+int subt(void);
+int command(void);
+int cond(char c);
+void load(void);
+int log2(long n);
+Blk* salloc(int size);
+Blk* morehd(void);
+Blk* copy(Blk *hptr, int size);
+void sdump(char *s1, Blk *hptr);
+void seekc(Blk *hptr, int n);
+void salterwd(Blk *hptr, Blk *n);
+void more(Blk *hptr);
+void ospace(char *s);
+void garbage(char *s);
+void release(Blk *p);
+Blk* dcgetwd(Blk *p);
+void putwd(Blk *p, Blk *c);
+Blk* lookwd(Blk *p);
+char* nalloc(char *p, unsigned nbytes);
+int getstk(void);
+
+/********debug only**/
+void
+tpr(char *cp, Blk *bp)
+{
+ print("%s-> ", cp);
+ print("beg: %lx rd: %lx wt: %lx last: %lx\n", bp->beg, bp->rd,
+ bp->wt, bp->last);
+ for (cp = bp->beg; cp != bp->wt; cp++) {
+ print("%d", *cp);
+ if (cp != bp->wt-1)
+ print("/");
+ }
+ print("\n");
+}
+/************/
+
+void
+main(int argc, char *argv[])
+{
+ Binit(&bin, 0, OREAD);
+ Binit(&bout, 1, OWRITE);
+ init(argc,argv);
+ commnds();
+ exits(0);
+}
+
+void
+commnds(void)
+{
+ Blk *p, *q, **ptr, *s, *t;
+ long l;
+ Sym *sp;
+ int sk, sk1, sk2, c, sign, n, d;
+
+ while(1) {
+ Bflush(&bout);
+ if(((c = readc())>='0' && c <= '9') ||
+ (c>='A' && c <='F') || c == '.') {
+ unreadc(c);
+ p = readin();
+ pushp(p);
+ continue;
+ }
+ switch(c) {
+ case ' ':
+ case '\n':
+ case -1:
+ continue;
+ case 'Y':
+ sdump("stk",*stkptr);
+ Bprint(&bout, "all %ld rel %ld headmor %ld\n",all,rel,headmor);
+ Bprint(&bout, "nbytes %ld\n",nbytes);
+ Bprint(&bout, "longest %ld active %ld maxsize %ld\n", longest,
+ active, maxsize);
+ Bprint(&bout, "new all %d rel %d copy %d more %d lbytes %d\n",
+ lall, lrel, lcopy, lmore, lbytes);
+ lall = lrel = lcopy = lmore = lbytes = 0;
+ continue;
+ case '_':
+ p = readin();
+ savk = sunputc(p);
+ chsign(p);
+ sputc(p,savk);
+ pushp(p);
+ continue;
+ case '-':
+ subt();
+ continue;
+ case '+':
+ if(eqk() != 0)
+ continue;
+ binop('+');
+ continue;
+ case '*':
+ arg1 = pop();
+ EMPTY;
+ arg2 = pop();
+ EMPTYR(arg1);
+ sk1 = sunputc(arg1);
+ sk2 = sunputc(arg2);
+ savk = sk1+sk2;
+ binop('*');
+ p = pop();
+ if(savk>k && savk>sk1 && savk>sk2) {
+ sclobber(p);
+ sk = sk1;
+ if(sk=3) {
+ error("exp too big\n");
+ }
+ savk = sunputc(arg2);
+ p = dcexp(arg2,arg1);
+ release(arg2);
+ rewind(arg1);
+ c = sgetc(arg1);
+ if(c == -1)
+ c = 0;
+ else
+ if(sfeof(arg1) == 0)
+ c = sgetc(arg1)*100 + c;
+ d = c*savk;
+ release(arg1);
+ /* if(neg == 0) { removed to fix -exp bug*/
+ if(k>=savk)
+ n = k;
+ else
+ n = savk;
+ if(n= 100) {
+ sputc(p,n/100);
+ n %= 100;
+ }
+ sputc(p,n);
+ sputc(p,0);
+ pushp(p);
+ continue;
+ case 'Z':
+ p = pop();
+ EMPTY;
+ n = (length(p)-1)<<1;
+ fsfile(p);
+ backc(p);
+ if(sfbeg(p) == 0) {
+ if((c = sbackc(p))<0) {
+ n -= 2;
+ if(sfbeg(p) == 1)
+ n++;
+ else {
+ if((c = sbackc(p)) == 0)
+ n++;
+ else
+ if(c > 90)
+ n--;
+ }
+ } else
+ if(c < 10)
+ n--;
+ }
+ release(p);
+ q = salloc(1);
+ if(n >= 100) {
+ sputc(q,n%100);
+ n /= 100;
+ }
+ sputc(q,n);
+ sputc(q,0);
+ pushp(q);
+ continue;
+ case 'i':
+ p = pop();
+ EMPTY;
+ p = scalint(p);
+ release(inbas);
+ inbas = p;
+ continue;
+ case 'I':
+ p = copy(inbas,length(inbas)+1);
+ sputc(p,0);
+ pushp(p);
+ continue;
+ case 'o':
+ p = pop();
+ EMPTY;
+ p = scalint(p);
+ sign = 0;
+ n = length(p);
+ q = copy(p,n);
+ fsfile(q);
+ l = c = sbackc(q);
+ if(n != 1) {
+ if(c<0) {
+ sign = 1;
+ chsign(q);
+ n = length(q);
+ fsfile(q);
+ l = c = sbackc(q);
+ }
+ if(n != 1) {
+ while(sfbeg(q) == 0)
+ l = l*100+sbackc(q);
+ }
+ }
+ logo = log2(l);
+ obase = l;
+ release(basptr);
+ if(sign == 1)
+ obase = -l;
+ basptr = p;
+ outdit = bigot;
+ if(n == 1 && sign == 0) {
+ if(c <= 16) {
+ outdit = hexot;
+ fw = 1;
+ fw1 = 0;
+ ll = 70;
+ release(q);
+ continue;
+ }
+ }
+ n = 0;
+ if(sign == 1)
+ n++;
+ p = salloc(1);
+ sputc(p,-1);
+ t = add(p,q);
+ n += length(t)*2;
+ fsfile(t);
+ if(sbackc(t)>9)
+ n++;
+ release(t);
+ release(q);
+ release(p);
+ fw = n;
+ fw1 = n-1;
+ ll = 70;
+ if(fw>=ll)
+ continue;
+ ll = (70/fw)*fw;
+ continue;
+ case 'O':
+ p = copy(basptr,length(basptr)+1);
+ sputc(p,0);
+ pushp(p);
+ continue;
+ case '[':
+ n = 0;
+ p = salloc(0);
+ for(;;) {
+ if((c = readc()) == ']') {
+ if(n == 0)
+ break;
+ n--;
+ }
+ sputc(p,c);
+ if(c == '[')
+ n++;
+ }
+ pushp(p);
+ continue;
+ case 'k':
+ p = pop();
+ EMPTY;
+ p = scalint(p);
+ if(length(p)>1) {
+ error("scale too big\n");
+ }
+ rewind(p);
+ k = 0;
+ if(!sfeof(p))
+ k = sgetc(p);
+ release(scalptr);
+ scalptr = p;
+ continue;
+ case 'K':
+ p = copy(scalptr,length(scalptr)+1);
+ sputc(p,0);
+ pushp(p);
+ continue;
+ case 'X':
+ p = pop();
+ EMPTY;
+ fsfile(p);
+ n = sbackc(p);
+ release(p);
+ p = salloc(2);
+ sputc(p,n);
+ sputc(p,0);
+ pushp(p);
+ continue;
+ case 'Q':
+ p = pop();
+ EMPTY;
+ if(length(p)>2) {
+ error("Q?\n");
+ }
+ rewind(p);
+ if((c = sgetc(p))<0) {
+ error("neg Q\n");
+ }
+ release(p);
+ while(c-- > 0) {
+ if(readptr == &readstk[0]) {
+ error("readstk?\n");
+ }
+ if(*readptr != 0)
+ release(*readptr);
+ readptr--;
+ }
+ continue;
+ case 'q':
+ if(readptr <= &readstk[1])
+ exits(0);
+ if(*readptr != 0)
+ release(*readptr);
+ readptr--;
+ if(*readptr != 0)
+ release(*readptr);
+ readptr--;
+ continue;
+ case 'f':
+ if(stkptr == &stack[0])
+ Bprint(&bout,"empty stack\n");
+ else {
+ for(ptr = stkptr; ptr > &stack[0];) {
+ dcprint(*ptr--);
+ }
+ }
+ continue;
+ case 'p':
+ if(stkptr == &stack[0])
+ Bprint(&bout,"empty stack\n");
+ else {
+ dcprint(*stkptr);
+ }
+ continue;
+ case 'P':
+ p = pop();
+ EMPTY;
+ sputc(p,0);
+ Bprint(&bout,"%s",p->beg);
+ release(p);
+ continue;
+ case 'd':
+ if(stkptr == &stack[0]) {
+ Bprint(&bout,"empty stack\n");
+ continue;
+ }
+ q = *stkptr;
+ n = length(q);
+ p = copy(*stkptr,n);
+ pushp(p);
+ continue;
+ case 'c':
+ while(stkerr == 0) {
+ p = pop();
+ if(stkerr == 0)
+ release(p);
+ }
+ continue;
+ case 'S':
+ if(stkptr == &stack[0]) {
+ error("save: args\n");
+ }
+ c = getstk() & 0377;
+ sptr = stable[c];
+ sp = stable[c] = sfree;
+ sfree = sfree->next;
+ if(sfree == 0)
+ goto sempty;
+ sp->next = sptr;
+ p = pop();
+ EMPTY;
+ if(c >= ARRAYST) {
+ q = copy(p,length(p)+PTRSZ);
+ for(n = 0;n < PTRSZ;n++) {
+ sputc(q,0);
+ }
+ release(p);
+ p = q;
+ }
+ sp->val = p;
+ continue;
+ sempty:
+ error("symbol table overflow\n");
+ case 's':
+ if(stkptr == &stack[0]) {
+ error("save:args\n");
+ }
+ c = getstk() & 0377;
+ sptr = stable[c];
+ if(sptr != 0) {
+ p = sptr->val;
+ if(c >= ARRAYST) {
+ rewind(p);
+ while(sfeof(p) == 0)
+ release(dcgetwd(p));
+ }
+ release(p);
+ } else {
+ sptr = stable[c] = sfree;
+ sfree = sfree->next;
+ if(sfree == 0)
+ goto sempty;
+ sptr->next = 0;
+ }
+ p = pop();
+ sptr->val = p;
+ continue;
+ case 'l':
+ load();
+ continue;
+ case 'L':
+ c = getstk() & 0377;
+ sptr = stable[c];
+ if(sptr == 0) {
+ error("L?\n");
+ }
+ stable[c] = sptr->next;
+ sptr->next = sfree;
+ sfree = sptr;
+ p = sptr->val;
+ if(c >= ARRAYST) {
+ rewind(p);
+ while(sfeof(p) == 0) {
+ q = dcgetwd(p);
+ if(q != 0)
+ release(q);
+ }
+ }
+ pushp(p);
+ continue;
+ case ':':
+ p = pop();
+ EMPTY;
+ q = scalint(p);
+ fsfile(q);
+ c = 0;
+ if((sfbeg(q) == 0) && ((c = sbackc(q))<0)) {
+ error("neg index\n");
+ }
+ if(length(q)>2) {
+ error("index too big\n");
+ }
+ if(sfbeg(q) == 0)
+ c = c*100+sbackc(q);
+ if(c >= MAXIND) {
+ error("index too big\n");
+ }
+ release(q);
+ n = getstk() & 0377;
+ sptr = stable[n];
+ if(sptr == 0) {
+ sptr = stable[n] = sfree;
+ sfree = sfree->next;
+ if(sfree == 0)
+ goto sempty;
+ sptr->next = 0;
+ p = salloc((c+PTRSZ)*PTRSZ);
+ zero(p);
+ } else {
+ p = sptr->val;
+ if(length(p)-PTRSZ < c*PTRSZ) {
+ q = copy(p,(c+PTRSZ)*PTRSZ);
+ release(p);
+ p = q;
+ }
+ }
+ seekc(p,c*PTRSZ);
+ q = lookwd(p);
+ if(q!=0)
+ release(q);
+ s = pop();
+ EMPTY;
+ salterwd(p, s);
+ sptr->val = p;
+ continue;
+ case ';':
+ p = pop();
+ EMPTY;
+ q = scalint(p);
+ fsfile(q);
+ c = 0;
+ if((sfbeg(q) == 0) && ((c = sbackc(q))<0)) {
+ error("neg index\n");
+ }
+ if(length(q)>2) {
+ error("index too big\n");
+ }
+ if(sfbeg(q) == 0)
+ c = c*100+sbackc(q);
+ if(c >= MAXIND) {
+ error("index too big\n");
+ }
+ release(q);
+ n = getstk() & 0377;
+ sptr = stable[n];
+ if(sptr != 0){
+ p = sptr->val;
+ if(length(p)-PTRSZ >= c*PTRSZ) {
+ seekc(p,c*PTRSZ);
+ s = dcgetwd(p);
+ if(s != 0) {
+ q = copy(s,length(s));
+ pushp(q);
+ continue;
+ }
+ }
+ }
+ q = salloc(1); /*so uninitialized array elt prints as 0*/
+ sputc(q, 0);
+ pushp(q);
+ continue;
+ case 'x':
+ execute:
+ p = pop();
+ EMPTY;
+ if((readptr != &readstk[0]) && (*readptr != 0)) {
+ if((*readptr)->rd == (*readptr)->wt)
+ release(*readptr);
+ else {
+ if(readptr++ == &readstk[RDSKSZ]) {
+ error("nesting depth\n");
+ }
+ }
+ } else
+ readptr++;
+ *readptr = p;
+ if(p != 0)
+ rewind(p);
+ else {
+ if((c = readc()) != '\n')
+ unreadc(c);
+ }
+ continue;
+ case '?':
+ if(++readptr == &readstk[RDSKSZ]) {
+ error("nesting depth\n");
+ }
+ *readptr = 0;
+ fsave = curfile;
+ curfile = &bin;
+ while((c = readc()) == '!')
+ command();
+ p = salloc(0);
+ sputc(p,c);
+ while((c = readc()) != '\n') {
+ sputc(p,c);
+ if(c == '\\')
+ sputc(p,readc());
+ }
+ curfile = fsave;
+ *readptr = p;
+ continue;
+ case '!':
+ if(command() == 1)
+ goto execute;
+ continue;
+ case '<':
+ case '>':
+ case '=':
+ if(cond(c) == 1)
+ goto execute;
+ continue;
+ default:
+ Bprint(&bout,"%o is unimplemented\n",c);
+ }
+ }
+}
+
+Blk*
+div(Blk *ddivd, Blk *ddivr)
+{
+ int divsign, remsign, offset, divcarry,
+ carry, dig, magic, d, dd, under, first;
+ long c, td, cc;
+ Blk *ps, *px, *p, *divd, *divr;
+
+ dig = 0;
+ under = 0;
+ divcarry = 0;
+ rem = 0;
+ p = salloc(0);
+ if(length(ddivr) == 0) {
+ pushp(ddivr);
+ Bprint(&bout,"divide by 0\n");
+ return(p);
+ }
+ divsign = remsign = first = 0;
+ divr = ddivr;
+ fsfile(divr);
+ if(sbackc(divr) == -1) {
+ divr = copy(ddivr,length(ddivr));
+ chsign(divr);
+ divsign = ~divsign;
+ }
+ divd = copy(ddivd,length(ddivd));
+ fsfile(divd);
+ if(sfbeg(divd) == 0 && sbackc(divd) == -1) {
+ chsign(divd);
+ divsign = ~divsign;
+ remsign = ~remsign;
+ }
+ offset = length(divd) - length(divr);
+ if(offset < 0)
+ goto ddone;
+ seekc(p,offset+1);
+ sputc(divd,0);
+ magic = 0;
+ fsfile(divr);
+ c = sbackc(divr);
+ if(c < 10)
+ magic++;
+ c = c * 100 + (sfbeg(divr)?0:sbackc(divr));
+ if(magic>0){
+ c = (c * 100 +(sfbeg(divr)?0:sbackc(divr)))*2;
+ c /= 25;
+ }
+ while(offset >= 0) {
+ first++;
+ fsfile(divd);
+ td = sbackc(divd) * 100;
+ dd = sfbeg(divd)?0:sbackc(divd);
+ td = (td + dd) * 100;
+ dd = sfbeg(divd)?0:sbackc(divd);
+ td = td + dd;
+ cc = c;
+ if(offset == 0)
+ td++;
+ else
+ cc++;
+ if(magic != 0)
+ td = td<<3;
+ dig = td/cc;
+ under=0;
+ if(td%cc < 8 && dig > 0 && magic) {
+ dig--;
+ under=1;
+ }
+ rewind(divr);
+ rewind(divxyz);
+ carry = 0;
+ while(sfeof(divr) == 0) {
+ d = sgetc(divr)*dig+carry;
+ carry = d / 100;
+ salterc(divxyz,d%100);
+ }
+ salterc(divxyz,carry);
+ rewind(divxyz);
+ seekc(divd,offset);
+ carry = 0;
+ while(sfeof(divd) == 0) {
+ d = slookc(divd);
+ d = d-(sfeof(divxyz)?0:sgetc(divxyz))-carry;
+ carry = 0;
+ if(d < 0) {
+ d += 100;
+ carry = 1;
+ }
+ salterc(divd,d);
+ }
+ divcarry = carry;
+ backc(p);
+ salterc(p,dig);
+ backc(p);
+ fsfile(divd);
+ d=sbackc(divd);
+ if((d != 0) && /*!divcarry*/ (offset != 0)) {
+ d = sbackc(divd) + 100;
+ salterc(divd,d);
+ }
+ if(--offset >= 0)
+ divd->wt--;
+ }
+ if(under) { /* undershot last - adjust*/
+ px = copy(divr,length(divr)); /*11/88 don't corrupt ddivr*/
+ chsign(px);
+ ps = add(px,divd);
+ fsfile(ps);
+ if(length(ps) > 0 && sbackc(ps) < 0) {
+ release(ps); /*only adjust in really undershot*/
+ } else {
+ release(divd);
+ salterc(p, dig+1);
+ divd=ps;
+ }
+ }
+ if(divcarry != 0) {
+ salterc(p,dig-1);
+ salterc(divd,-1);
+ ps = add(divr,divd);
+ release(divd);
+ divd = ps;
+ }
+
+ rewind(p);
+ divcarry = 0;
+ while(sfeof(p) == 0){
+ d = slookc(p)+divcarry;
+ divcarry = 0;
+ if(d >= 100){
+ d -= 100;
+ divcarry = 1;
+ }
+ salterc(p,d);
+ }
+ if(divcarry != 0)salterc(p,divcarry);
+ fsfile(p);
+ while(sfbeg(p) == 0) {
+ if(sbackc(p) != 0)
+ break;
+ truncate(p);
+ }
+ if(divsign < 0)
+ chsign(p);
+ fsfile(divd);
+ while(sfbeg(divd) == 0) {
+ if(sbackc(divd) != 0)
+ break;
+ truncate(divd);
+ }
+ddone:
+ if(remsign<0)
+ chsign(divd);
+ if(divr != ddivr)
+ release(divr);
+ rem = divd;
+ return(p);
+}
+
+int
+dscale(void)
+{
+ Blk *dd, *dr, *r;
+ int c;
+
+ dr = pop();
+ EMPTYS;
+ dd = pop();
+ EMPTYSR(dr);
+ fsfile(dd);
+ skd = sunputc(dd);
+ fsfile(dr);
+ skr = sunputc(dr);
+ if(sfbeg(dr) == 1 || (sfbeg(dr) == 0 && sbackc(dr) == 0)) {
+ sputc(dr,skr);
+ pushp(dr);
+ Bprint(&bout,"divide by 0\n");
+ return(1);
+ }
+ if(sfbeg(dd) == 1 || (sfbeg(dd) == 0 && sbackc(dd) == 0)) {
+ sputc(dd,skd);
+ pushp(dd);
+ return(1);
+ }
+ c = k-skd+skr;
+ if(c < 0)
+ r = removr(dd,-c);
+ else {
+ r = add0(dd,c);
+ irem = 0;
+ }
+ arg1 = r;
+ arg2 = dr;
+ savk = k;
+ return(0);
+}
+
+Blk*
+removr(Blk *p, int n)
+{
+ int nn, neg;
+ Blk *q, *s, *r;
+
+ fsfile(p);
+ neg = sbackc(p);
+ if(neg < 0)
+ chsign(p);
+ rewind(p);
+ nn = (n+1)/2;
+ q = salloc(nn);
+ while(n>1) {
+ sputc(q,sgetc(p));
+ n -= 2;
+ }
+ r = salloc(2);
+ while(sfeof(p) == 0)
+ sputc(r,sgetc(p));
+ release(p);
+ if(n == 1){
+ s = div(r,tenptr);
+ release(r);
+ rewind(rem);
+ if(sfeof(rem) == 0)
+ sputc(q,sgetc(rem));
+ release(rem);
+ if(neg < 0){
+ chsign(s);
+ chsign(q);
+ irem = q;
+ return(s);
+ }
+ irem = q;
+ return(s);
+ }
+ if(neg < 0) {
+ chsign(r);
+ chsign(q);
+ irem = q;
+ return(r);
+ }
+ irem = q;
+ return(r);
+}
+
+Blk*
+dcsqrt(Blk *p)
+{
+ Blk *t, *r, *q, *s;
+ int c, n, nn;
+
+ n = length(p);
+ fsfile(p);
+ c = sbackc(p);
+ if((n&1) != 1)
+ c = c*100+(sfbeg(p)?0:sbackc(p));
+ n = (n+1)>>1;
+ r = salloc(n);
+ zero(r);
+ seekc(r,n);
+ nn=1;
+ while((c -= nn)>=0)
+ nn+=2;
+ c=(nn+1)>>1;
+ fsfile(r);
+ backc(r);
+ if(c>=100) {
+ c -= 100;
+ salterc(r,c);
+ sputc(r,1);
+ } else
+ salterc(r,c);
+ for(;;){
+ q = div(p,r);
+ s = add(q,r);
+ release(q);
+ release(rem);
+ q = div(s,sqtemp);
+ release(s);
+ release(rem);
+ s = copy(r,length(r));
+ chsign(s);
+ t = add(s,q);
+ release(s);
+ fsfile(t);
+ nn = sfbeg(t)?0:sbackc(t);
+ if(nn>=0)
+ break;
+ release(r);
+ release(t);
+ r = q;
+ }
+ release(t);
+ release(q);
+ release(p);
+ return(r);
+}
+
+Blk*
+dcexp(Blk *base, Blk *ex)
+{
+ Blk *r, *e, *p, *e1, *t, *cp;
+ int temp, c, n;
+
+ r = salloc(1);
+ sputc(r,1);
+ p = copy(base,length(base));
+ e = copy(ex,length(ex));
+ fsfile(e);
+ if(sfbeg(e) != 0)
+ goto edone;
+ temp=0;
+ c = sbackc(e);
+ if(c<0) {
+ temp++;
+ chsign(e);
+ }
+ while(length(e) != 0) {
+ e1=div(e,sqtemp);
+ release(e);
+ e = e1;
+ n = length(rem);
+ release(rem);
+ if(n != 0) {
+ e1=mult(p,r);
+ release(r);
+ r = e1;
+ }
+ t = copy(p,length(p));
+ cp = mult(p,t);
+ release(p);
+ release(t);
+ p = cp;
+ }
+ if(temp != 0) {
+ if((c = length(base)) == 0) {
+ goto edone;
+ }
+ if(c>1)
+ create(r);
+ else {
+ rewind(base);
+ if((c = sgetc(base))<=1) {
+ create(r);
+ sputc(r,c);
+ } else
+ create(r);
+ }
+ }
+edone:
+ release(p);
+ release(e);
+ return(r);
+}
+
+void
+init(int argc, char *argv[])
+{
+ Sym *sp;
+ Dir *d;
+
+ ARGBEGIN {
+ default:
+ dbg = 1;
+ break;
+ } ARGEND
+ ifile = 1;
+ curfile = &bin;
+ if(*argv){
+ d = dirstat(*argv);
+ if(d == nil) {
+ fprint(2, "dc: can't open file %s\n", *argv);
+ exits("open");
+ }
+ if(d->mode & DMDIR) {
+ fprint(2, "dc: file %s is a directory\n", *argv);
+ exits("open");
+ }
+ free(d);
+ if((curfile = Bopen(*argv, OREAD)) == 0) {
+ fprint(2,"dc: can't open file %s\n", *argv);
+ exits("open");
+ }
+ }
+/* dummy = malloc(0); *//* prepare for garbage-collection */
+ scalptr = salloc(1);
+ sputc(scalptr,0);
+ basptr = salloc(1);
+ sputc(basptr,10);
+ obase=10;
+ logten=log2(10L);
+ ll=70;
+ fw=1;
+ fw1=0;
+ tenptr = salloc(1);
+ sputc(tenptr,10);
+ obase=10;
+ inbas = salloc(1);
+ sputc(inbas,10);
+ sqtemp = salloc(1);
+ sputc(sqtemp,2);
+ chptr = salloc(0);
+ strptr = salloc(0);
+ divxyz = salloc(0);
+ stkbeg = stkptr = &stack[0];
+ stkend = &stack[STKSZ];
+ stkerr = 0;
+ readptr = &readstk[0];
+ k=0;
+ sp = sptr = &symlst[0];
+ while(sptr < &symlst[TBLSZ]) {
+ sptr->next = ++sp;
+ sptr++;
+ }
+ sptr->next=0;
+ sfree = &symlst[0];
+}
+
+void
+pushp(Blk *p)
+{
+ if(stkptr == stkend) {
+ Bprint(&bout,"out of stack space\n");
+ return;
+ }
+ stkerr=0;
+ *++stkptr = p;
+ return;
+}
+
+Blk*
+pop(void)
+{
+ if(stkptr == stack) {
+ stkerr=1;
+ return(0);
+ }
+ return(*stkptr--);
+}
+
+Blk*
+readin(void)
+{
+ Blk *p, *q;
+ int dp, dpct, c;
+
+ dp = dpct=0;
+ p = salloc(0);
+ for(;;){
+ c = readc();
+ switch(c) {
+ case '.':
+ if(dp != 0)
+ goto gotnum;
+ dp++;
+ continue;
+ case '\\':
+ readc();
+ continue;
+ default:
+ if(c >= 'A' && c <= 'F')
+ c = c - 'A' + 10;
+ else
+ if(c >= '0' && c <= '9')
+ c -= '0';
+ else
+ goto gotnum;
+ if(dp != 0) {
+ if(dpct >= 99)
+ continue;
+ dpct++;
+ }
+ create(chptr);
+ if(c != 0)
+ sputc(chptr,c);
+ q = mult(p,inbas);
+ release(p);
+ p = add(chptr,q);
+ release(q);
+ }
+ }
+gotnum:
+ unreadc(c);
+ if(dp == 0) {
+ sputc(p,0);
+ return(p);
+ } else {
+ q = scale(p,dpct);
+ return(q);
+ }
+}
+
+/*
+ * returns pointer to struct with ct 0's & p
+ */
+Blk*
+add0(Blk *p, int ct)
+{
+ Blk *q, *t;
+
+ q = salloc(length(p)+(ct+1)/2);
+ while(ct>1) {
+ sputc(q,0);
+ ct -= 2;
+ }
+ rewind(p);
+ while(sfeof(p) == 0) {
+ sputc(q,sgetc(p));
+ }
+ release(p);
+ if(ct == 1) {
+ t = mult(tenptr,q);
+ release(q);
+ return(t);
+ }
+ return(q);
+}
+
+Blk*
+mult(Blk *p, Blk *q)
+{
+ Blk *mp, *mq, *mr;
+ int sign, offset, carry;
+ int cq, cp, mt, mcr;
+
+ offset = sign = 0;
+ fsfile(p);
+ mp = p;
+ if(sfbeg(p) == 0) {
+ if(sbackc(p)<0) {
+ mp = copy(p,length(p));
+ chsign(mp);
+ sign = ~sign;
+ }
+ }
+ fsfile(q);
+ mq = q;
+ if(sfbeg(q) == 0){
+ if(sbackc(q)<0) {
+ mq = copy(q,length(q));
+ chsign(mq);
+ sign = ~sign;
+ }
+ }
+ mr = salloc(length(mp)+length(mq));
+ zero(mr);
+ rewind(mq);
+ while(sfeof(mq) == 0) {
+ cq = sgetc(mq);
+ rewind(mp);
+ rewind(mr);
+ mr->rd += offset;
+ carry=0;
+ while(sfeof(mp) == 0) {
+ cp = sgetc(mp);
+ mcr = sfeof(mr)?0:slookc(mr);
+ mt = cp*cq + carry + mcr;
+ carry = mt/100;
+ salterc(mr,mt%100);
+ }
+ offset++;
+ if(carry != 0) {
+ mcr = sfeof(mr)?0:slookc(mr);
+ salterc(mr,mcr+carry);
+ }
+ }
+ if(sign < 0) {
+ chsign(mr);
+ }
+ if(mp != p)
+ release(mp);
+ if(mq != q)
+ release(mq);
+ return(mr);
+}
+
+void
+chsign(Blk *p)
+{
+ int carry;
+ char ct;
+
+ carry=0;
+ rewind(p);
+ while(sfeof(p) == 0) {
+ ct=100-slookc(p)-carry;
+ carry=1;
+ if(ct>=100) {
+ ct -= 100;
+ carry=0;
+ }
+ salterc(p,ct);
+ }
+ if(carry != 0) {
+ sputc(p,-1);
+ fsfile(p);
+ backc(p);
+ ct = sbackc(p);
+ if(ct == 99 /*&& !sfbeg(p)*/) {
+ truncate(p);
+ sputc(p,-1);
+ }
+ } else{
+ fsfile(p);
+ ct = sbackc(p);
+ if(ct == 0)
+ truncate(p);
+ }
+ return;
+}
+
+int
+readc(void)
+{
+loop:
+ if((readptr != &readstk[0]) && (*readptr != 0)) {
+ if(sfeof(*readptr) == 0)
+ return(lastchar = sgetc(*readptr));
+ release(*readptr);
+ readptr--;
+ goto loop;
+ }
+ lastchar = Bgetc(curfile);
+ if(lastchar != -1)
+ return(lastchar);
+ if(readptr != &readptr[0]) {
+ readptr--;
+ if(*readptr == 0)
+ curfile = &bin;
+ goto loop;
+ }
+ if(curfile != &bin) {
+ Bterm(curfile);
+ curfile = &bin;
+ goto loop;
+ }
+ exits(0);
+ return 0; /* shut up ken */
+}
+
+void
+unreadc(char c)
+{
+
+ if((readptr != &readstk[0]) && (*readptr != 0)) {
+ sungetc(*readptr,c);
+ } else
+ Bungetc(curfile);
+ return;
+}
+
+void
+binop(char c)
+{
+ Blk *r;
+
+ r = 0;
+ switch(c) {
+ case '+':
+ r = add(arg1,arg2);
+ break;
+ case '*':
+ r = mult(arg1,arg2);
+ break;
+ case '/':
+ r = div(arg1,arg2);
+ break;
+ }
+ release(arg1);
+ release(arg2);
+ sputc(r,savk);
+ pushp(r);
+}
+
+void
+dcprint(Blk *hptr)
+{
+ Blk *p, *q, *dec;
+ int dig, dout, ct, sc;
+
+ rewind(hptr);
+ while(sfeof(hptr) == 0) {
+ if(sgetc(hptr)>99) {
+ rewind(hptr);
+ while(sfeof(hptr) == 0) {
+ Bprint(&bout,"%c",sgetc(hptr));
+ }
+ Bprint(&bout,"\n");
+ return;
+ }
+ }
+ fsfile(hptr);
+ sc = sbackc(hptr);
+ if(sfbeg(hptr) != 0) {
+ Bprint(&bout,"0\n");
+ return;
+ }
+ count = ll;
+ p = copy(hptr,length(hptr));
+ sclobber(p);
+ fsfile(p);
+ if(sbackc(p)<0) {
+ chsign(p);
+ OUTC('-');
+ }
+ if((obase == 0) || (obase == -1)) {
+ oneot(p,sc,'d');
+ return;
+ }
+ if(obase == 1) {
+ oneot(p,sc,'1');
+ return;
+ }
+ if(obase == 10) {
+ tenot(p,sc);
+ return;
+ }
+ /* sleazy hack to scale top of stack - divide by 1 */
+ pushp(p);
+ sputc(p, sc);
+ p=salloc(0);
+ create(p);
+ sputc(p, 1);
+ sputc(p, 0);
+ pushp(p);
+ if(dscale() != 0)
+ return;
+ p = div(arg1, arg2);
+ release(arg1);
+ release(arg2);
+ sc = savk;
+
+ create(strptr);
+ dig = logten*sc;
+ dout = ((dig/10) + dig) / logo;
+ dec = getdec(p,sc);
+ p = removc(p,sc);
+ while(length(p) != 0) {
+ q = div(p,basptr);
+ release(p);
+ p = q;
+ (*outdit)(rem,0);
+ }
+ release(p);
+ fsfile(strptr);
+ while(sfbeg(strptr) == 0)
+ OUTC(sbackc(strptr));
+ if(sc == 0) {
+ release(dec);
+ Bprint(&bout,"\n");
+ return;
+ }
+ create(strptr);
+ OUTC('.');
+ ct=0;
+ do {
+ q = mult(basptr,dec);
+ release(dec);
+ dec = getdec(q,sc);
+ p = removc(q,sc);
+ (*outdit)(p,1);
+ } while(++ct < dout);
+ release(dec);
+ rewind(strptr);
+ while(sfeof(strptr) == 0)
+ OUTC(sgetc(strptr));
+ Bprint(&bout,"\n");
+}
+
+Blk*
+getdec(Blk *p, int sc)
+{
+ int cc;
+ Blk *q, *t, *s;
+
+ rewind(p);
+ if(length(p)*2 < sc) {
+ q = copy(p,length(p));
+ return(q);
+ }
+ q = salloc(length(p));
+ while(sc >= 1) {
+ sputc(q,sgetc(p));
+ sc -= 2;
+ }
+ if(sc != 0) {
+ t = mult(q,tenptr);
+ s = salloc(cc = length(q));
+ release(q);
+ rewind(t);
+ while(cc-- > 0)
+ sputc(s,sgetc(t));
+ sputc(s,0);
+ release(t);
+ t = div(s,tenptr);
+ release(s);
+ release(rem);
+ return(t);
+ }
+ return(q);
+}
+
+void
+tenot(Blk *p, int sc)
+{
+ int c, f;
+
+ fsfile(p);
+ f=0;
+ while((sfbeg(p) == 0) && ((p->rd-p->beg-1)*2 >= sc)) {
+ c = sbackc(p);
+ if((c<10) && (f == 1))
+ Bprint(&bout,"0%d",c);
+ else
+ Bprint(&bout,"%d",c);
+ f=1;
+ TEST2;
+ }
+ if(sc == 0) {
+ Bprint(&bout,"\n");
+ release(p);
+ return;
+ }
+ if((p->rd-p->beg)*2 > sc) {
+ c = sbackc(p);
+ Bprint(&bout,"%d.",c/10);
+ TEST2;
+ OUTC(c%10 +'0');
+ sc--;
+ } else {
+ OUTC('.');
+ }
+ while(sc>(p->rd-p->beg)*2) {
+ OUTC('0');
+ sc--;
+ }
+ while(sc > 1) {
+ c = sbackc(p);
+ if(c<10)
+ Bprint(&bout,"0%d",c);
+ else
+ Bprint(&bout,"%d",c);
+ sc -= 2;
+ TEST2;
+ }
+ if(sc == 1) {
+ OUTC(sbackc(p)/10 +'0');
+ }
+ Bprint(&bout,"\n");
+ release(p);
+}
+
+void
+oneot(Blk *p, int sc, char ch)
+{
+ Blk *q;
+
+ q = removc(p,sc);
+ create(strptr);
+ sputc(strptr,-1);
+ while(length(q)>0) {
+ p = add(strptr,q);
+ release(q);
+ q = p;
+ OUTC(ch);
+ }
+ release(q);
+ Bprint(&bout,"\n");
+}
+
+void
+hexot(Blk *p, int flg)
+{
+ int c;
+
+ USED(flg);
+ rewind(p);
+ if(sfeof(p) != 0) {
+ sputc(strptr,'0');
+ release(p);
+ return;
+ }
+ c = sgetc(p);
+ release(p);
+ if(c >= 16) {
+ Bprint(&bout,"hex digit > 16");
+ return;
+ }
+ sputc(strptr,c<10?c+'0':c-10+'a');
+}
+
+void
+bigot(Blk *p, int flg)
+{
+ Blk *t, *q;
+ int neg, l;
+
+ if(flg == 1) {
+ t = salloc(0);
+ l = 0;
+ } else {
+ t = strptr;
+ l = length(strptr)+fw-1;
+ }
+ neg=0;
+ if(length(p) != 0) {
+ fsfile(p);
+ if(sbackc(p)<0) {
+ neg=1;
+ chsign(p);
+ }
+ while(length(p) != 0) {
+ q = div(p,tenptr);
+ release(p);
+ p = q;
+ rewind(rem);
+ sputc(t,sfeof(rem)?'0':sgetc(rem)+'0');
+ release(rem);
+ }
+ }
+ release(p);
+ if(flg == 1) {
+ l = fw1-length(t);
+ if(neg != 0) {
+ l--;
+ sputc(strptr,'-');
+ }
+ fsfile(t);
+ while(l-- > 0)
+ sputc(strptr,'0');
+ while(sfbeg(t) == 0)
+ sputc(strptr,sbackc(t));
+ release(t);
+ } else {
+ l -= length(strptr);
+ while(l-- > 0)
+ sputc(strptr,'0');
+ if(neg != 0) {
+ sclobber(strptr);
+ sputc(strptr,'-');
+ }
+ }
+ sputc(strptr,' ');
+}
+
+Blk*
+add(Blk *a1, Blk *a2)
+{
+ Blk *p;
+ int carry, n, size, c, n1, n2;
+
+ size = length(a1)>length(a2)?length(a1):length(a2);
+ p = salloc(size);
+ rewind(a1);
+ rewind(a2);
+ carry=0;
+ while(--size >= 0) {
+ n1 = sfeof(a1)?0:sgetc(a1);
+ n2 = sfeof(a2)?0:sgetc(a2);
+ n = n1 + n2 + carry;
+ if(n>=100) {
+ carry=1;
+ n -= 100;
+ } else
+ if(n<0) {
+ carry = -1;
+ n += 100;
+ } else
+ carry = 0;
+ sputc(p,n);
+ }
+ if(carry != 0)
+ sputc(p,carry);
+ fsfile(p);
+ if(sfbeg(p) == 0) {
+ c = 0;
+ while(sfbeg(p) == 0 && (c = sbackc(p)) == 0)
+ ;
+ if(c != 0)
+ salterc(p,c);
+ truncate(p);
+ }
+ fsfile(p);
+ if(sfbeg(p) == 0 && sbackc(p) == -1) {
+ while((c = sbackc(p)) == 99) {
+ if(c == -1)
+ break;
+ }
+ skipc(p);
+ salterc(p,-1);
+ truncate(p);
+ }
+ return(p);
+}
+
+int
+eqk(void)
+{
+ Blk *p, *q;
+ int skp, skq;
+
+ p = pop();
+ EMPTYS;
+ q = pop();
+ EMPTYSR(p);
+ skp = sunputc(p);
+ skq = sunputc(q);
+ if(skp == skq) {
+ arg1=p;
+ arg2=q;
+ savk = skp;
+ return(0);
+ }
+ if(skp < skq) {
+ savk = skq;
+ p = add0(p,skq-skp);
+ } else {
+ savk = skp;
+ q = add0(q,skp-skq);
+ }
+ arg1=p;
+ arg2=q;
+ return(0);
+}
+
+Blk*
+removc(Blk *p, int n)
+{
+ Blk *q, *r;
+
+ rewind(p);
+ while(n>1) {
+ skipc(p);
+ n -= 2;
+ }
+ q = salloc(2);
+ while(sfeof(p) == 0)
+ sputc(q,sgetc(p));
+ if(n == 1) {
+ r = div(q,tenptr);
+ release(q);
+ release(rem);
+ q = r;
+ }
+ release(p);
+ return(q);
+}
+
+Blk*
+scalint(Blk *p)
+{
+ int n;
+
+ n = sunputc(p);
+ p = removc(p,n);
+ return(p);
+}
+
+Blk*
+scale(Blk *p, int n)
+{
+ Blk *q, *s, *t;
+
+ t = add0(p,n);
+ q = salloc(1);
+ sputc(q,n);
+ s = dcexp(inbas,q);
+ release(q);
+ q = div(t,s);
+ release(t);
+ release(s);
+ release(rem);
+ sputc(q,n);
+ return(q);
+}
+
+int
+subt(void)
+{
+ arg1=pop();
+ EMPTYS;
+ savk = sunputc(arg1);
+ chsign(arg1);
+ sputc(arg1,savk);
+ pushp(arg1);
+ if(eqk() != 0)
+ return(1);
+ binop('+');
+ return(0);
+}
+
+int
+command(void)
+{
+ char line[100], *sl;
+ int pid, p, c;
+
+ switch(c = readc()) {
+ case '<':
+ return(cond(NL));
+ case '>':
+ return(cond(NG));
+ case '=':
+ return(cond(NE));
+ default:
+ sl = line;
+ *sl++ = c;
+ while((c = readc()) != '\n')
+ *sl++ = c;
+ *sl = 0;
+ if((pid = fork()) == 0) {
+ execl("/bin/rc","rc","-c",line,0);
+ exits("shell");
+ }
+ for(;;) {
+ if((p = waitpid()) < 0)
+ break;
+ if(p== pid)
+ break;
+ }
+ Bprint(&bout,"!\n");
+ return(0);
+ }
+}
+
+int
+cond(char c)
+{
+ Blk *p;
+ int cc;
+
+ if(subt() != 0)
+ return(1);
+ p = pop();
+ sclobber(p);
+ if(length(p) == 0) {
+ release(p);
+ if(c == '<' || c == '>' || c == NE) {
+ getstk();
+ return(0);
+ }
+ load();
+ return(1);
+ }
+ if(c == '='){
+ release(p);
+ getstk();
+ return(0);
+ }
+ if(c == NE) {
+ release(p);
+ load();
+ return(1);
+ }
+ fsfile(p);
+ cc = sbackc(p);
+ release(p);
+ if((cc<0 && (c == '<' || c == NG)) ||
+ (cc >0) && (c == '>' || c == NL)) {
+ getstk();
+ return(0);
+ }
+ load();
+ return(1);
+}
+
+void
+load(void)
+{
+ int c;
+ Blk *p, *q, *t, *s;
+
+ c = getstk() & 0377;
+ sptr = stable[c];
+ if(sptr != 0) {
+ p = sptr->val;
+ if(c >= ARRAYST) {
+ q = salloc(length(p));
+ rewind(p);
+ while(sfeof(p) == 0) {
+ s = dcgetwd(p);
+ if(s == 0) {
+ putwd(q, (Blk*)0);
+ } else {
+ t = copy(s,length(s));
+ putwd(q,t);
+ }
+ }
+ pushp(q);
+ } else {
+ q = copy(p,length(p));
+ pushp(q);
+ }
+ } else {
+ q = salloc(1);
+ if(c <= LASTFUN) {
+ Bprint(&bout,"function %c undefined\n",c+'a'-1);
+ sputc(q,'c');
+ sputc(q,'0');
+ sputc(q,' ');
+ sputc(q,'1');
+ sputc(q,'Q');
+ }
+ else
+ sputc(q,0);
+ pushp(q);
+ }
+}
+
+int
+log2(long n)
+{
+ int i;
+
+ if(n == 0)
+ return(0);
+ i=31;
+ if(n<0)
+ return(i);
+ while((n= n<<1) >0)
+ i--;
+ return i-1;
+}
+
+Blk*
+salloc(int size)
+{
+ Blk *hdr;
+ char *ptr;
+
+ all++;
+ lall++;
+ if(all - rel > active)
+ active = all - rel;
+ nbytes += size;
+ lbytes += size;
+ if(nbytes >maxsize)
+ maxsize = nbytes;
+ if(size > longest)
+ longest = size;
+ ptr = malloc((unsigned)size);
+ if(ptr == 0){
+ garbage("salloc");
+ if((ptr = malloc((unsigned)size)) == 0)
+ ospace("salloc");
+ }
+ if((hdr = hfree) == 0)
+ hdr = morehd();
+ hfree = (Blk *)hdr->rd;
+ hdr->rd = hdr->wt = hdr->beg = ptr;
+ hdr->last = ptr+size;
+ return(hdr);
+}
+
+Blk*
+morehd(void)
+{
+ Blk *h, *kk;
+
+ headmor++;
+ nbytes += HEADSZ;
+ hfree = h = (Blk *)malloc(HEADSZ);
+ if(hfree == 0) {
+ garbage("morehd");
+ if((hfree = h = (Blk*)malloc(HEADSZ)) == 0)
+ ospace("headers");
+ }
+ kk = h;
+ while(hrd = (char*)++kk;
+ (h-1)->rd=0;
+ return(hfree);
+}
+
+Blk*
+copy(Blk *hptr, int size)
+{
+ Blk *hdr;
+ unsigned sz;
+ char *ptr;
+
+ all++;
+ lall++;
+ lcopy++;
+ nbytes += size;
+ lbytes += size;
+ if(size > longest)
+ longest = size;
+ if(size > maxsize)
+ maxsize = size;
+ sz = length(hptr);
+ ptr = nalloc(hptr->beg, size);
+ if(ptr == 0) {
+ garbage("copy");
+ if((ptr = nalloc(hptr->beg, size)) == 0) {
+ Bprint(&bout,"copy size %d\n",size);
+ ospace("copy");
+ }
+ }
+ if((hdr = hfree) == 0)
+ hdr = morehd();
+ hfree = (Blk *)hdr->rd;
+ hdr->rd = hdr->beg = ptr;
+ hdr->last = ptr+size;
+ hdr->wt = ptr+sz;
+ ptr = hdr->wt;
+ while(ptrlast)
+ *ptr++ = '\0';
+ return(hdr);
+}
+
+void
+sdump(char *s1, Blk *hptr)
+{
+ char *p;
+
+ Bprint(&bout,"%s %lx rd %lx wt %lx beg %lx last %lx\n",
+ s1,hptr,hptr->rd,hptr->wt,hptr->beg,hptr->last);
+ p = hptr->beg;
+ while(p < hptr->wt)
+ Bprint(&bout,"%d ",*p++);
+ Bprint(&bout,"\n");
+}
+
+void
+seekc(Blk *hptr, int n)
+{
+ char *nn,*p;
+
+ nn = hptr->beg+n;
+ if(nn > hptr->last) {
+ nbytes += nn - hptr->last;
+ if(nbytes > maxsize)
+ maxsize = nbytes;
+ lbytes += nn - hptr->last;
+ if(n > longest)
+ longest = n;
+/* free(hptr->beg); *//**/
+ p = realloc(hptr->beg, n);
+ if(p == 0) {
+/* hptr->beg = realloc(hptr->beg, hptr->last-hptr->beg);
+** garbage("seekc");
+** if((p = realloc(hptr->beg, n)) == 0)
+*/ ospace("seekc");
+ }
+ hptr->beg = p;
+ hptr->wt = hptr->last = hptr->rd = p+n;
+ return;
+ }
+ hptr->rd = nn;
+ if(nn>hptr->wt)
+ hptr->wt = nn;
+}
+
+void
+salterwd(Blk *ahptr, Blk *n)
+{
+ Wblk *hptr;
+
+ hptr = (Wblk*)ahptr;
+ if(hptr->rdw == hptr->lastw)
+ more(ahptr);
+ *hptr->rdw++ = n;
+ if(hptr->rdw > hptr->wtw)
+ hptr->wtw = hptr->rdw;
+}
+
+void
+more(Blk *hptr)
+{
+ unsigned size;
+ char *p;
+
+ if((size=(hptr->last-hptr->beg)*2) == 0)
+ size=2;
+ nbytes += size/2;
+ if(nbytes > maxsize)
+ maxsize = nbytes;
+ if(size > longest)
+ longest = size;
+ lbytes += size/2;
+ lmore++;
+/* free(hptr->beg);*//**/
+ p = realloc(hptr->beg, size);
+
+ if(p == 0) {
+/* hptr->beg = realloc(hptr->beg, (hptr->last-hptr->beg));
+** garbage("more");
+** if((p = realloc(hptr->beg,size)) == 0)
+*/ ospace("more");
+ }
+ hptr->rd = p + (hptr->rd - hptr->beg);
+ hptr->wt = p + (hptr->wt - hptr->beg);
+ hptr->beg = p;
+ hptr->last = p+size;
+}
+
+void
+ospace(char *s)
+{
+ Bprint(&bout,"out of space: %s\n",s);
+ Bprint(&bout,"all %ld rel %ld headmor %ld\n",all,rel,headmor);
+ Bprint(&bout,"nbytes %ld\n",nbytes);
+ sdump("stk",*stkptr);
+ abort();
+}
+
+void
+garbage(char *s)
+{
+ USED(s);
+}
+
+void
+release(Blk *p)
+{
+ rel++;
+ lrel++;
+ nbytes -= p->last - p->beg;
+ p->rd = (char*)hfree;
+ hfree = p;
+ free(p->beg);
+}
+
+Blk*
+dcgetwd(Blk *p)
+{
+ Wblk *wp;
+
+ wp = (Wblk*)p;
+ if(wp->rdw == wp->wtw)
+ return(0);
+ return(*wp->rdw++);
+}
+
+void
+putwd(Blk *p, Blk *c)
+{
+ Wblk *wp;
+
+ wp = (Wblk*)p;
+ if(wp->wtw == wp->lastw)
+ more(p);
+ *wp->wtw++ = c;
+}
+
+Blk*
+lookwd(Blk *p)
+{
+ Wblk *wp;
+
+ wp = (Wblk*)p;
+ if(wp->rdw == wp->wtw)
+ return(0);
+ return(*wp->rdw);
+}
+
+char*
+nalloc(char *p, unsigned nbytes)
+{
+ char *q, *r;
+
+ q = r = malloc(nbytes);
+ if(q==0)
+ return(0);
+ while(nbytes--)
+ *q++ = *p++;
+ return(r);
+}
+
+int
+getstk(void)
+{
+ int n;
+ uchar c;
+
+ c = readc();
+ if(c != '<')
+ return c;
+ n = 0;
+ while(1) {
+ c = readc();
+ if(c == '>')
+ break;
+ n = n*10+c-'0';
+ }
+ return n;
+} |
| diff --git a/src/cmd/dd.c b/src/cmd/dd.c |
| t@@ -0,0 +1,660 @@
+#include
+#include
+
+#define BIG 2147483647
+#define LCASE (1<<0)
+#define UCASE (1<<1)
+#define SWAB (1<<2)
+#define NERR (1<<3)
+#define SYNC (1<<4)
+int cflag;
+int fflag;
+char *string;
+char *ifile;
+char *ofile;
+char *ibuf;
+char *obuf;
+vlong skip;
+vlong oseekn;
+vlong iseekn;
+vlong count;
+long files = 1;
+long ibs = 512;
+long obs = 512;
+long bs;
+long cbs;
+long ibc;
+long obc;
+long cbc;
+long nifr;
+long nipr;
+long nofr;
+long nopr;
+long ntrunc;
+int dotrunc = 1;
+int ibf;
+int obf;
+char *op;
+int nspace;
+uchar etoa[256];
+uchar atoe[256];
+uchar atoibm[256];
+
+void flsh(void);
+int match(char *s);
+vlong number(long big);
+void cnull(int cc);
+void null(int c);
+void ascii(int cc);
+void unblock(int cc);
+void ebcdic(int cc);
+void ibm(int cc);
+void block(int cc);
+void term(void);
+void stats(void);
+
+#define iskey(s) ((key[0] == '-') && (strcmp(key+1, s) == 0))
+
+void
+main(int argc, char *argv[])
+{
+ void (*conv)(int);
+ char *ip;
+ char *key;
+ int a, c;
+
+ conv = null;
+ for(c=1; c= argc){
+ fprint(2, "dd: arg %s needs a value\n", key);
+ exits("arg");
+ }
+ string = argv[c];
+ if(iskey("ibs")) {
+ ibs = number(BIG);
+ continue;
+ }
+ if(iskey("obs")) {
+ obs = number(BIG);
+ continue;
+ }
+ if(iskey("cbs")) {
+ cbs = number(BIG);
+ continue;
+ }
+ if(iskey("bs")) {
+ bs = number(BIG);
+ continue;
+ }
+ if(iskey("if")) {
+ ifile = string;
+ continue;
+ }
+ if(iskey("of")) {
+ ofile = string;
+ continue;
+ }
+ if(iskey("trunc")) {
+ dotrunc = number(BIG);
+ continue;
+ }
+ if(iskey("skip")) {
+ skip = number(BIG);
+ continue;
+ }
+ if(iskey("seek") || iskey("oseek")) {
+ oseekn = number(BIG);
+ continue;
+ }
+ if(iskey("iseek")) {
+ iseekn = number(BIG);
+ continue;
+ }
+ if(iskey("count")) {
+ count = number(BIG);
+ continue;
+ }
+ if(iskey("files")) {
+ files = number(BIG);
+ continue;
+ }
+ if(iskey("conv")) {
+ cloop:
+ if(match(","))
+ goto cloop;
+ if(*string == '\0')
+ continue;
+ if(match("ebcdic")) {
+ conv = ebcdic;
+ goto cloop;
+ }
+ if(match("ibm")) {
+ conv = ibm;
+ goto cloop;
+ }
+ if(match("ascii")) {
+ conv = ascii;
+ goto cloop;
+ }
+ if(match("block")) {
+ conv = block;
+ goto cloop;
+ }
+ if(match("unblock")) {
+ conv = unblock;
+ goto cloop;
+ }
+ if(match("lcase")) {
+ cflag |= LCASE;
+ goto cloop;
+ }
+ if(match("ucase")) {
+ cflag |= UCASE;
+ goto cloop;
+ }
+ if(match("swab")) {
+ cflag |= SWAB;
+ goto cloop;
+ }
+ if(match("noerror")) {
+ cflag |= NERR;
+ goto cloop;
+ }
+ if(match("sync")) {
+ cflag |= SYNC;
+ goto cloop;
+ }
+ }
+ fprint(2, "dd: bad arg: %s\n", key);
+ exits("arg");
+ }
+ if(conv == null && cflag&(LCASE|UCASE))
+ conv = cnull;
+ if(ifile)
+ ibf = open(ifile, 0);
+ else
+ ibf = dup(0, -1);
+ if(ibf < 0) {
+ fprint(2, "dd: open %s: %r\n", ifile);
+ exits("open");
+ }
+ if(ofile){
+ if(dotrunc)
+ obf = create(ofile, 1, 0664);
+ else
+ obf = open(ofile, 1);
+ if(obf < 0) {
+ fprint(2, "dd: create %s: %r\n", ofile);
+ exits("create");
+ }
+ }else{
+ obf = dup(1, -1);
+ if(obf < 0) {
+ fprint(2, "dd: can't dup file descriptor: %s: %r\n", ofile);
+ exits("dup");
+ }
+ }
+ if(bs)
+ ibs = obs = bs;
+ if(ibs == obs && conv == null)
+ fflag++;
+ if(ibs == 0 || obs == 0) {
+ fprint(2, "dd: counts: cannot be zero\n");
+ exits("counts");
+ }
+ ibuf = sbrk(ibs);
+ if(fflag)
+ obuf = ibuf;
+ else
+ obuf = sbrk(obs);
+ sbrk(64); /* For good measure */
+ if(ibuf == (char *)-1 || obuf == (char *)-1) {
+ fprint(2, "dd: not enough memory: %r\n");
+ exits("memory");
+ }
+ ibc = 0;
+ obc = 0;
+ cbc = 0;
+ op = obuf;
+
+/*
+ if(signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, term);
+*/
+ seek(obf, obs*oseekn, 1);
+ seek(ibf, ibs*iseekn, 1);
+ while(skip) {
+ read(ibf, ibuf, ibs);
+ skip--;
+ }
+
+ ip = 0;
+loop:
+ if(ibc-- == 0) {
+ ibc = 0;
+ if(count==0 || nifr+nipr!=count) {
+ if(cflag&(NERR|SYNC))
+ for(ip=ibuf+ibs; ip>ibuf;)
+ *--ip = 0;
+ ibc = read(ibf, ibuf, ibs);
+ }
+ if(ibc == -1) {
+ perror("read");
+ if((cflag&NERR) == 0) {
+ flsh();
+ term();
+ }
+ ibc = 0;
+ for(c=0; c>1) & ~1;
+ if(cflag&SWAB && c)
+ do {
+ a = *ip++;
+ ip[-1] = *ip;
+ *ip++ = a;
+ } while(--c);
+ ip = ibuf;
+ if(fflag) {
+ obc = ibc;
+ flsh();
+ ibc = 0;
+ }
+ goto loop;
+ }
+ c = 0;
+ c |= *ip++;
+ c &= 0377;
+ (*conv)(c);
+ goto loop;
+}
+
+void
+flsh(void)
+{
+ int c;
+
+ if(obc) {
+ c = write(obf, obuf, obc);
+ if(c != obc) {
+ if(c > 0)
+ ++nopr;
+ perror("write");
+ term();
+ }
+ if(obc == obs)
+ nofr++;
+ else
+ nopr++;
+ obc = 0;
+ }
+}
+
+int
+match(char *s)
+{
+ char *cs;
+
+ cs = string;
+ while(*cs++ == *s)
+ if(*s++ == '\0')
+ goto true;
+ if(*s != '\0')
+ return 0;
+
+true:
+ cs--;
+ string = cs;
+ return 1;
+}
+
+vlong
+number(long big)
+{
+ char *cs;
+ vlong n;
+
+ cs = string;
+ n = 0;
+ while(*cs >= '0' && *cs <= '9')
+ n = n*10 + *cs++ - '0';
+ for(;;)
+ switch(*cs++) {
+
+ case 'k':
+ n *= 1024;
+ continue;
+
+/* case 'w':
+ n *= sizeof(int);
+ continue;
+*/
+
+ case 'b':
+ n *= 512;
+ continue;
+
+/* case '*':*/
+ case 'x':
+ string = cs;
+ n *= number(BIG);
+
+ case '\0':
+ if(n>=big || n<0) {
+ fprint(2, "dd: argument %lld out of range\n", n);
+ exits("range");
+ }
+ return n;
+ }
+ /* never gets here */
+}
+
+void
+cnull(int cc)
+{
+ int c;
+
+ c = cc;
+ if((cflag&UCASE) && c>='a' && c<='z')
+ c += 'A'-'a';
+ if((cflag&LCASE) && c>='A' && c<='Z')
+ c += 'a'-'A';
+ null(c);
+}
+
+void
+null(int c)
+{
+
+ *op = c;
+ op++;
+ if(++obc >= obs) {
+ flsh();
+ op = obuf;
+ }
+}
+
+void
+ascii(int cc)
+{
+ int c;
+
+ c = etoa[cc];
+ if(cbs == 0) {
+ cnull(c);
+ return;
+ }
+ if(c == ' ') {
+ nspace++;
+ goto out;
+ }
+ while(nspace > 0) {
+ null(' ');
+ nspace--;
+ }
+ cnull(c);
+
+out:
+ if(++cbc >= cbs) {
+ null('\n');
+ cbc = 0;
+ nspace = 0;
+ }
+}
+
+void
+unblock(int cc)
+{
+ int c;
+
+ c = cc & 0377;
+ if(cbs == 0) {
+ cnull(c);
+ return;
+ }
+ if(c == ' ') {
+ nspace++;
+ goto out;
+ }
+ while(nspace > 0) {
+ null(' ');
+ nspace--;
+ }
+ cnull(c);
+
+out:
+ if(++cbc >= cbs) {
+ null('\n');
+ cbc = 0;
+ nspace = 0;
+ }
+}
+
+void
+ebcdic(int cc)
+{
+ int c;
+
+ c = cc;
+ if(cflag&UCASE && c>='a' && c<='z')
+ c += 'A'-'a';
+ if(cflag&LCASE && c>='A' && c<='Z')
+ c += 'a'-'A';
+ c = atoe[c];
+ if(cbs == 0) {
+ null(c);
+ return;
+ }
+ if(cc == '\n') {
+ while(cbc < cbs) {
+ null(atoe[' ']);
+ cbc++;
+ }
+ cbc = 0;
+ return;
+ }
+ if(cbc == cbs)
+ ntrunc++;
+ cbc++;
+ if(cbc <= cbs)
+ null(c);
+}
+
+void
+ibm(int cc)
+{
+ int c;
+
+ c = cc;
+ if(cflag&UCASE && c>='a' && c<='z')
+ c += 'A'-'a';
+ if(cflag&LCASE && c>='A' && c<='Z')
+ c += 'a'-'A';
+ c = atoibm[c] & 0377;
+ if(cbs == 0) {
+ null(c);
+ return;
+ }
+ if(cc == '\n') {
+ while(cbc < cbs) {
+ null(atoibm[' ']);
+ cbc++;
+ }
+ cbc = 0;
+ return;
+ }
+ if(cbc == cbs)
+ ntrunc++;
+ cbc++;
+ if(cbc <= cbs)
+ null(c);
+}
+
+void
+block(int cc)
+{
+ int c;
+
+ c = cc;
+ if(cflag&UCASE && c>='a' && c<='z')
+ c += 'A'-'a';
+ if(cflag&LCASE && c>='A' && c<='Z')
+ c += 'a'-'A';
+ c &= 0377;
+ if(cbs == 0) {
+ null(c);
+ return;
+ }
+ if(cc == '\n') {
+ while(cbc < cbs) {
+ null(' ');
+ cbc++;
+ }
+ cbc = 0;
+ return;
+ }
+ if(cbc == cbs)
+ ntrunc++;
+ cbc++;
+ if(cbc <= cbs)
+ null(c);
+}
+
+void
+term(void)
+{
+
+ stats();
+ exits(0);
+}
+
+void
+stats(void)
+{
+
+ fprint(2, "%lud+%lud records in\n", nifr, nipr);
+ fprint(2, "%lud+%lud records out\n", nofr, nopr);
+ if(ntrunc)
+ fprint(2, "%lud truncated records\n", ntrunc);
+}
+
+uchar etoa[] =
+{
+ 0000,0001,0002,0003,0234,0011,0206,0177,
+ 0227,0215,0216,0013,0014,0015,0016,0017,
+ 0020,0021,0022,0023,0235,0205,0010,0207,
+ 0030,0031,0222,0217,0034,0035,0036,0037,
+ 0200,0201,0202,0203,0204,0012,0027,0033,
+ 0210,0211,0212,0213,0214,0005,0006,0007,
+ 0220,0221,0026,0223,0224,0225,0226,0004,
+ 0230,0231,0232,0233,0024,0025,0236,0032,
+ 0040,0240,0241,0242,0243,0244,0245,0246,
+ 0247,0250,0133,0056,0074,0050,0053,0041,
+ 0046,0251,0252,0253,0254,0255,0256,0257,
+ 0260,0261,0135,0044,0052,0051,0073,0136,
+ 0055,0057,0262,0263,0264,0265,0266,0267,
+ 0270,0271,0174,0054,0045,0137,0076,0077,
+ 0272,0273,0274,0275,0276,0277,0300,0301,
+ 0302,0140,0072,0043,0100,0047,0075,0042,
+ 0303,0141,0142,0143,0144,0145,0146,0147,
+ 0150,0151,0304,0305,0306,0307,0310,0311,
+ 0312,0152,0153,0154,0155,0156,0157,0160,
+ 0161,0162,0313,0314,0315,0316,0317,0320,
+ 0321,0176,0163,0164,0165,0166,0167,0170,
+ 0171,0172,0322,0323,0324,0325,0326,0327,
+ 0330,0331,0332,0333,0334,0335,0336,0337,
+ 0340,0341,0342,0343,0344,0345,0346,0347,
+ 0173,0101,0102,0103,0104,0105,0106,0107,
+ 0110,0111,0350,0351,0352,0353,0354,0355,
+ 0175,0112,0113,0114,0115,0116,0117,0120,
+ 0121,0122,0356,0357,0360,0361,0362,0363,
+ 0134,0237,0123,0124,0125,0126,0127,0130,
+ 0131,0132,0364,0365,0366,0367,0370,0371,
+ 0060,0061,0062,0063,0064,0065,0066,0067,
+ 0070,0071,0372,0373,0374,0375,0376,0377,
+};
+uchar atoe[] =
+{
+ 0000,0001,0002,0003,0067,0055,0056,0057,
+ 0026,0005,0045,0013,0014,0015,0016,0017,
+ 0020,0021,0022,0023,0074,0075,0062,0046,
+ 0030,0031,0077,0047,0034,0035,0036,0037,
+ 0100,0117,0177,0173,0133,0154,0120,0175,
+ 0115,0135,0134,0116,0153,0140,0113,0141,
+ 0360,0361,0362,0363,0364,0365,0366,0367,
+ 0370,0371,0172,0136,0114,0176,0156,0157,
+ 0174,0301,0302,0303,0304,0305,0306,0307,
+ 0310,0311,0321,0322,0323,0324,0325,0326,
+ 0327,0330,0331,0342,0343,0344,0345,0346,
+ 0347,0350,0351,0112,0340,0132,0137,0155,
+ 0171,0201,0202,0203,0204,0205,0206,0207,
+ 0210,0211,0221,0222,0223,0224,0225,0226,
+ 0227,0230,0231,0242,0243,0244,0245,0246,
+ 0247,0250,0251,0300,0152,0320,0241,0007,
+ 0040,0041,0042,0043,0044,0025,0006,0027,
+ 0050,0051,0052,0053,0054,0011,0012,0033,
+ 0060,0061,0032,0063,0064,0065,0066,0010,
+ 0070,0071,0072,0073,0004,0024,0076,0341,
+ 0101,0102,0103,0104,0105,0106,0107,0110,
+ 0111,0121,0122,0123,0124,0125,0126,0127,
+ 0130,0131,0142,0143,0144,0145,0146,0147,
+ 0150,0151,0160,0161,0162,0163,0164,0165,
+ 0166,0167,0170,0200,0212,0213,0214,0215,
+ 0216,0217,0220,0232,0233,0234,0235,0236,
+ 0237,0240,0252,0253,0254,0255,0256,0257,
+ 0260,0261,0262,0263,0264,0265,0266,0267,
+ 0270,0271,0272,0273,0274,0275,0276,0277,
+ 0312,0313,0314,0315,0316,0317,0332,0333,
+ 0334,0335,0336,0337,0352,0353,0354,0355,
+ 0356,0357,0372,0373,0374,0375,0376,0377,
+};
+uchar atoibm[] =
+{
+ 0000,0001,0002,0003,0067,0055,0056,0057,
+ 0026,0005,0045,0013,0014,0015,0016,0017,
+ 0020,0021,0022,0023,0074,0075,0062,0046,
+ 0030,0031,0077,0047,0034,0035,0036,0037,
+ 0100,0132,0177,0173,0133,0154,0120,0175,
+ 0115,0135,0134,0116,0153,0140,0113,0141,
+ 0360,0361,0362,0363,0364,0365,0366,0367,
+ 0370,0371,0172,0136,0114,0176,0156,0157,
+ 0174,0301,0302,0303,0304,0305,0306,0307,
+ 0310,0311,0321,0322,0323,0324,0325,0326,
+ 0327,0330,0331,0342,0343,0344,0345,0346,
+ 0347,0350,0351,0255,0340,0275,0137,0155,
+ 0171,0201,0202,0203,0204,0205,0206,0207,
+ 0210,0211,0221,0222,0223,0224,0225,0226,
+ 0227,0230,0231,0242,0243,0244,0245,0246,
+ 0247,0250,0251,0300,0117,0320,0241,0007,
+ 0040,0041,0042,0043,0044,0025,0006,0027,
+ 0050,0051,0052,0053,0054,0011,0012,0033,
+ 0060,0061,0032,0063,0064,0065,0066,0010,
+ 0070,0071,0072,0073,0004,0024,0076,0341,
+ 0101,0102,0103,0104,0105,0106,0107,0110,
+ 0111,0121,0122,0123,0124,0125,0126,0127,
+ 0130,0131,0142,0143,0144,0145,0146,0147,
+ 0150,0151,0160,0161,0162,0163,0164,0165,
+ 0166,0167,0170,0200,0212,0213,0214,0215,
+ 0216,0217,0220,0232,0233,0234,0235,0236,
+ 0237,0240,0252,0253,0254,0255,0256,0257,
+ 0260,0261,0262,0263,0264,0265,0266,0267,
+ 0270,0271,0272,0273,0274,0275,0276,0277,
+ 0312,0313,0314,0315,0316,0317,0332,0333,
+ 0334,0335,0336,0337,0352,0353,0354,0355,
+ 0356,0357,0372,0373,0374,0375,0376,0377,
+}; |
| diff --git a/src/cmd/deroff.c b/src/cmd/deroff.c |
| t@@ -0,0 +1,969 @@
+#include
+#include
+#include
+
+/*
+ * Deroff command -- strip troff, eqn, and tbl sequences from
+ * a file. Has three flags argument, -w, to cause output one word per line
+ * rather than in the original format.
+ * -mm (or -ms) causes the corresponding macro's to be interpreted
+ * so that just sentences are output
+ * -ml also gets rid of lists.
+ * -i causes deroff to ignore .so and .nx commands.
+ * Deroff follows .so and .nx commands, removes contents of macro
+ * definitions, equations (both .EQ ... .EN and $...$),
+ * Tbl command sequences, and Troff backslash vconstructions.
+ *
+ * All input is through the C macro; the most recently read character is in c.
+ */
+
+/*
+#define C ((c = Bgetrune(infile)) < 0?\
+ eof():\
+ ((c == ldelim) && (filesp == files)?\
+ skeqn():\
+ (c == '\n'?\
+ (linect++,c):\
+ c)))
+
+#define C1 ((c = Bgetrune(infile)) == Beof?\
+ eof():\
+ (c == '\n'?\
+ (linect++,c):\
+ c))
+*/
+
+/* lose those macros! */
+#define C fC()
+#define C1 fC1()
+
+#define SKIP while(C != '\n')
+#define SKIP1 while(C1 != '\n')
+#define SKIP_TO_COM SKIP;\
+ SKIP;\
+ pc=c;\
+ while(C != '.' || pc != '\n' || C > 'Z')\
+ pc=c
+
+#define YES 1
+#define NO 0
+#define MS 0
+#define MM 1
+#define ONE 1
+#define TWO 2
+
+#define NOCHAR -2
+#define EXTENDED -1 /* All runes above 0x7F */
+#define SPECIAL 0
+#define APOS 1
+#define PUNCT 2
+#define DIGIT 3
+#define LETTER 4
+
+
+int linect = 0;
+int wordflag= NO;
+int underscoreflag = NO;
+int msflag = NO;
+int iflag = NO;
+int mac = MM;
+int disp = 0;
+int inmacro = NO;
+int intable = NO;
+int eqnflag = 0;
+
+#define MAX_ASCII 0X80
+
+char chars[MAX_ASCII]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
+
+Rune line[30000];
+Rune* lp;
+
+long c;
+long pc;
+int ldelim = NOCHAR;
+int rdelim = NOCHAR;
+
+
+char** argv;
+
+char fname[50];
+Biobuf* files[15];
+Biobuf**filesp;
+Biobuf* infile;
+char* devnull = "/dev/null";
+Biobuf *infile;
+Biobuf bout;
+
+long skeqn(void);
+Biobuf* opn(char *p);
+int eof(void);
+int charclass(int);
+void getfname(void);
+void fatal(char *s, char *p);
+void usage(void);
+void work(void);
+void putmac(Rune *rp, int vconst);
+void regline(int macline, int vconst);
+void putwords(void);
+void comline(void);
+void macro(void);
+void eqn(void);
+void tbl(void);
+void stbl(void);
+void sdis(char a1, char a2);
+void sce(void);
+void backsl(void);
+char* copys(char *s);
+void refer(int c1);
+void inpic(void);
+
+int
+fC(void)
+{
+ c = Bgetrune(infile);
+ if(c < 0)
+ return eof();
+ if(c == ldelim && filesp == files)
+ return skeqn();
+ if(c == '\n')
+ linect++;
+ return c;
+}
+
+int
+fC1(void)
+{
+ c = Bgetrune(infile);
+ if(c == Beof)
+ return eof();
+ if(c == '\n')
+ linect++;
+ return c;
+}
+
+void
+main(int argc, char *av[])
+{
+ int i;
+ char *f;
+
+ argv = av;
+ Binit(&bout, 1, OWRITE);
+ ARGBEGIN{
+ case 'w':
+ wordflag = YES;
+ break;
+ case '_':
+ wordflag = YES;
+ underscoreflag = YES;
+ break;
+ case 'm':
+ msflag = YES;
+ if(f = ARGF())
+ switch(*f)
+ {
+ case 'm': mac = MM; break;
+ case 's': mac = MS; break;
+ case 'l': disp = 1; break;
+ default: usage();
+ }
+ else
+ usage();
+ break;
+ case 'i':
+ iflag = YES;
+ break;
+ default:
+ usage();
+ }ARGEND
+ if(*argv)
+ infile = opn(*argv++);
+ else{
+ infile = malloc(sizeof(Biobuf));
+ Binit(infile, 0, OREAD);
+ }
+ files[0] = infile;
+ filesp = &files[0];
+
+ for(i='a'; i<='z' ; ++i)
+ chars[i] = LETTER;
+ for(i='A'; i<='Z'; ++i)
+ chars[i] = LETTER;
+ for(i='0'; i<='9'; ++i)
+ chars[i] = DIGIT;
+ chars['\''] = APOS;
+ chars['&'] = APOS;
+ chars['\b'] = APOS;
+ chars['.'] = PUNCT;
+ chars[','] = PUNCT;
+ chars[';'] = PUNCT;
+ chars['?'] = PUNCT;
+ chars[':'] = PUNCT;
+ work();
+}
+
+long
+skeqn(void)
+{
+ while(C1 != rdelim)
+ if(c == '\\')
+ c = C1;
+ else if(c == '"')
+ while(C1 != '"')
+ if(c == '\\')
+ C1;
+ if (msflag)
+ eqnflag = 1;
+ return(c = ' ');
+}
+
+Biobuf*
+opn(char *p)
+{
+ Biobuf *fd;
+
+ while ((fd = Bopen(p, OREAD)) == 0) {
+ if(msflag || p == devnull)
+ fatal("Cannot open file %s - quitting\n", p);
+ else {
+ fprint(2, "Deroff: Cannot open file %s - continuing\n", p);
+ p = devnull;
+ }
+ }
+ linect = 0;
+ return(fd);
+}
+
+int
+eof(void)
+{
+ if(Bfildes(infile) != 0)
+ Bterm(infile);
+ if(filesp > files)
+ infile = *--filesp;
+ else
+ if(*argv)
+ infile = opn(*argv++);
+ else
+ exits(0);
+ return(C);
+}
+
+void
+getfname(void)
+{
+ char *p;
+ Rune r;
+ Dir *dir;
+ struct chain
+ {
+ struct chain* nextp;
+ char* datap;
+ } *q;
+
+ static struct chain *namechain= 0;
+
+ while(C == ' ')
+ ;
+ for(p = fname; (r=c) != '\n' && r != ' ' && r != '\t' && r != '\\'; C)
+ p += runetochar(p, &r);
+ *p = '\0';
+ while(c != '\n')
+ C;
+ if(!strcmp(fname, "/sys/lib/tmac/tmac.cs")
+ || !strcmp(fname, "/sys/lib/tmac/tmac.s")) {
+ fname[0] = '\0';
+ return;
+ }
+ dir = dirstat(fname);
+ if(dir!=nil && ((dir->mode & DMDIR) || dir->type != 'M')) {
+ free(dir);
+ fname[0] = '\0';
+ return;
+ }
+ free(dir);
+ /*
+ * see if this name has already been used
+ */
+
+ for(q = namechain; q; q = q->nextp)
+ if( !strcmp(fname, q->datap)) {
+ fname[0] = '\0';
+ return;
+ }
+ q = (struct chain*)malloc(sizeof(struct chain));
+ q->nextp = namechain;
+ q->datap = copys(fname);
+ namechain = q;
+}
+
+void
+usage(void)
+{
+ fprint(2,"usage: deroff [-nw_pi] [-m (m s l)] [file ...] \n");
+ exits("usage");
+}
+
+void
+fatal(char *s, char *p)
+{
+ fprint(2, "deroff: ");
+ fprint(2, s, p);
+ exits(s);
+}
+
+void
+work(void)
+{
+
+ for(;;) {
+ eqnflag = 0;
+ if(C == '.' || c == '\'')
+ comline();
+ else
+ regline(NO, TWO);
+ }
+}
+
+void
+regline(int macline, int vconst)
+{
+ line[0] = c;
+ lp = line;
+ for(;;) {
+ if(c == '\\') {
+ *lp = ' ';
+ backsl();
+ if(c == '%') /* no blank for hyphenation char */
+ lp--;
+ }
+ if(c == '\n')
+ break;
+ if(intable && c=='T') {
+ *++lp = C;
+ if(c=='{' || c=='}') {
+ lp[-1] = ' ';
+ *lp = C;
+ }
+ } else {
+ if(msflag == 1 && eqnflag == 1) {
+ eqnflag = 0;
+ *++lp = 'x';
+ }
+ *++lp = C;
+ }
+ }
+ *lp = '\0';
+ if(lp != line) {
+ if(wordflag)
+ putwords();
+ else
+ if(macline)
+ putmac(line,vconst);
+ else
+ Bprint(&bout, "%S\n", line);
+ }
+}
+
+void
+putmac(Rune *rp, int vconst)
+{
+ Rune *t;
+ int found;
+ Rune last;
+
+ found = 0;
+ last = 0;
+ while(*rp) {
+ while(*rp == ' ' || *rp == '\t')
+ Bputrune(&bout, *rp++);
+ for(t = rp; *t != ' ' && *t != '\t' && *t != '\0'; t++)
+ ;
+ if(*rp == '\"')
+ rp++;
+ if(t > rp+vconst && charclass(*rp) == LETTER
+ && charclass(rp[1]) == LETTER) {
+ while(rp < t)
+ if(*rp == '\"')
+ rp++;
+ else
+ Bputrune(&bout, *rp++);
+ last = t[-1];
+ found++;
+ } else
+ if(found && charclass(*rp) == PUNCT && rp[1] == '\0')
+ Bputrune(&bout, *rp++);
+ else {
+ last = t[-1];
+ rp = t;
+ }
+ }
+ Bputc(&bout, '\n');
+ if(msflag && charclass(last) == PUNCT)
+ Bprint(&bout, " %C\n", last);
+}
+
+/*
+ * break into words for -w option
+ */
+void
+putwords(void)
+{
+ Rune *p, *p1;
+ int i, nlet;
+
+
+ for(p1 = line;;) {
+ /*
+ * skip initial specials ampersands and apostrophes
+ */
+ while((i = charclass(*p1)) != EXTENDED && i < DIGIT)
+ if(*p1++ == '\0')
+ return;
+ nlet = 0;
+ for(p = p1; (i = charclass(*p)) != SPECIAL || (underscoreflag && *p=='_'); p++)
+ if(i == LETTER || (underscoreflag && *p == '_'))
+ nlet++;
+ /*
+ * MDM definition of word
+ */
+ if(nlet > 1) {
+ /*
+ * delete trailing ampersands and apostrophes
+ */
+ while(*--p == '\'' || *p == '&'
+ || charclass(*p) == PUNCT)
+ ;
+ while(p1 <= p)
+ Bputrune(&bout, *p1++);
+ Bputc(&bout, '\n');
+ } else
+ p1 = p;
+ }
+}
+
+void
+comline(void)
+{
+ long c1, c2;
+
+ while(C==' ' || c=='\t')
+ ;
+comx:
+ if((c1=c) == '\n')
+ return;
+ c2 = C;
+ if(c1=='.' && c2!='.')
+ inmacro = NO;
+ if(msflag && c1 == '['){
+ refer(c2);
+ return;
+ }
+ if(c2 == '\n')
+ return;
+ if(c1 == '\\' && c2 == '\"')
+ SKIP;
+ else
+ if (filesp==files && c1=='E' && c2=='Q')
+ eqn();
+ else
+ if(filesp==files && c1=='T' && (c2=='S' || c2=='C' || c2=='&')) {
+ if(msflag)
+ stbl();
+ else
+ tbl();
+ }
+ else
+ if(c1=='T' && c2=='E')
+ intable = NO;
+ else if (!inmacro &&
+ ((c1 == 'd' && c2 == 'e') ||
+ (c1 == 'i' && c2 == 'g') ||
+ (c1 == 'a' && c2 == 'm')))
+ macro();
+ else
+ if(c1=='s' && c2=='o') {
+ if(iflag)
+ SKIP;
+ else {
+ getfname();
+ if(fname[0]) {
+ if(infile = opn(fname))
+ *++filesp = infile;
+ else infile = *filesp;
+ }
+ }
+ }
+ else
+ if(c1=='n' && c2=='x')
+ if(iflag)
+ SKIP;
+ else {
+ getfname();
+ if(fname[0] == '\0')
+ exits(0);
+ if(Bfildes(infile) != 0)
+ Bterm(infile);
+ infile = *filesp = opn(fname);
+ }
+ else
+ if(c1 == 't' && c2 == 'm')
+ SKIP;
+ else
+ if(c1=='h' && c2=='w')
+ SKIP;
+ else
+ if(msflag && c1 == 'T' && c2 == 'L') {
+ SKIP_TO_COM;
+ goto comx;
+ }
+ else
+ if(msflag && c1=='N' && c2 == 'R')
+ SKIP;
+ else
+ if(msflag && c1 == 'A' && (c2 == 'U' || c2 == 'I')){
+ if(mac==MM)SKIP;
+ else {
+ SKIP_TO_COM;
+ goto comx;
+ }
+ } else
+ if(msflag && c1=='F' && c2=='S') {
+ SKIP_TO_COM;
+ goto comx;
+ }
+ else
+ if(msflag && (c1=='S' || c1=='N') && c2=='H') {
+ SKIP_TO_COM;
+ goto comx;
+ } else
+ if(c1 == 'U' && c2 == 'X') {
+ if(wordflag)
+ Bprint(&bout, "UNIX\n");
+ else
+ Bprint(&bout, "UNIX ");
+ } else
+ if(msflag && c1=='O' && c2=='K') {
+ SKIP_TO_COM;
+ goto comx;
+ } else
+ if(msflag && c1=='N' && c2=='D')
+ SKIP;
+ else
+ if(msflag && mac==MM && c1=='H' && (c2==' '||c2=='U'))
+ SKIP;
+ else
+ if(msflag && mac==MM && c2=='L') {
+ if(disp || c1=='R')
+ sdis('L', 'E');
+ else {
+ SKIP;
+ Bprint(&bout, " .");
+ }
+ } else
+ if(!msflag && c1=='P' && c2=='S') {
+ inpic();
+ } else
+ if(msflag && (c1=='D' || c1=='N' || c1=='K'|| c1=='P') && c2=='S') {
+ sdis(c1, 'E');
+ } else
+ if(msflag && (c1 == 'K' && c2 == 'F')) {
+ sdis(c1,'E');
+ } else
+ if(msflag && c1=='n' && c2=='f')
+ sdis('f','i');
+ else
+ if(msflag && c1=='c' && c2=='e')
+ sce();
+ else {
+ if(c1=='.' && c2=='.') {
+ if(msflag) {
+ SKIP;
+ return;
+ }
+ while(C == '.')
+ ;
+ }
+ inmacro++;
+ if(c1 <= 'Z' && msflag)
+ regline(YES,ONE);
+ else {
+ if(wordflag)
+ C;
+ regline(YES,TWO);
+ }
+ inmacro--;
+ }
+}
+
+void
+macro(void)
+{
+ if(msflag) {
+ do {
+ SKIP1;
+ } while(C1 != '.' || C1 != '.' || C1 == '.');
+ if(c != '\n')
+ SKIP;
+ return;
+ }
+ SKIP;
+ inmacro = YES;
+}
+
+void
+sdis(char a1, char a2)
+{
+ int c1, c2;
+ int eqnf;
+ int lct;
+
+ if(a1 == 'P'){
+ while(C1 == ' ')
+ ;
+ if(c == '<') {
+ SKIP1;
+ return;
+ }
+ }
+ lct = 0;
+ eqnf = 1;
+ if(c != '\n')
+ SKIP1;
+ for(;;) {
+ while(C1 != '.')
+ if(c == '\n')
+ continue;
+ else
+ SKIP1;
+ if((c1=C1) == '\n')
+ continue;
+ if((c2=C1) == '\n') {
+ if(a1 == 'f' && (c1 == 'P' || c1 == 'H'))
+ return;
+ continue;
+ }
+ if(c1==a1 && c2 == a2) {
+ SKIP1;
+ if(lct != 0){
+ lct--;
+ continue;
+ }
+ if(eqnf)
+ Bprint(&bout, " .");
+ Bputc(&bout, '\n');
+ return;
+ } else
+ if(a1 == 'L' && c2 == 'L') {
+ lct++;
+ SKIP1;
+ } else
+ if(a1 == 'D' && c1 == 'E' && c2 == 'Q') {
+ eqn();
+ eqnf = 0;
+ } else
+ if(a1 == 'f') {
+ if((mac == MS && c2 == 'P') ||
+ (mac == MM && c1 == 'H' && c2 == 'U')){
+ SKIP1;
+ return;
+ }
+ SKIP1;
+ }
+ else
+ SKIP1;
+ }
+}
+
+void
+tbl(void)
+{
+ while(C != '.')
+ ;
+ SKIP;
+ intable = YES;
+}
+
+void
+stbl(void)
+{
+ while(C != '.')
+ ;
+ SKIP_TO_COM;
+ if(c != 'T' || C != 'E') {
+ SKIP;
+ pc = c;
+ while(C != '.' || pc != '\n' || C != 'T' || C != 'E')
+ pc = c;
+ }
+}
+
+void
+eqn(void)
+{
+ long c1, c2;
+ int dflg;
+ char last;
+
+ last = 0;
+ dflg = 1;
+ SKIP;
+
+ for(;;) {
+ if(C1 == '.' || c == '\'') {
+ while(C1==' ' || c=='\t')
+ ;
+ if(c=='E' && C1=='N') {
+ SKIP;
+ if(msflag && dflg) {
+ Bputc(&bout, 'x');
+ Bputc(&bout, ' ');
+ if(last) {
+ Bputc(&bout, last);
+ Bputc(&bout, '\n');
+ }
+ }
+ return;
+ }
+ } else
+ if(c == 'd') {
+ if(C1=='e' && C1=='l')
+ if(C1=='i' && C1=='m') {
+ while(C1 == ' ')
+ ;
+ if((c1=c)=='\n' || (c2=C1)=='\n' ||
+ (c1=='o' && c2=='f' && C1=='f')) {
+ ldelim = NOCHAR;
+ rdelim = NOCHAR;
+ } else {
+ ldelim = c1;
+ rdelim = c2;
+ }
+ }
+ dflg = 0;
+ }
+ if(c != '\n')
+ while(C1 != '\n') {
+ if(chars[c] == PUNCT)
+ last = c;
+ else
+ if(c != ' ')
+ last = 0;
+ }
+ }
+}
+
+/*
+ * skip over a complete backslash vconstruction
+ */
+void
+backsl(void)
+{
+ int bdelim;
+
+sw:
+ switch(C1)
+ {
+ case '"':
+ SKIP1;
+ return;
+
+ case 's':
+ if(C1 == '\\')
+ backsl();
+ else {
+ while(C1>='0' && c<='9')
+ ;
+ Bungetrune(infile);
+ c = '0';
+ }
+ lp--;
+ return;
+
+ case 'f':
+ case 'n':
+ case '*':
+ if(C1 != '(')
+ return;
+
+ case '(':
+ if(msflag) {
+ if(C == 'e') {
+ if(C1 == 'm') {
+ *lp = '-';
+ return;
+ }
+ } else
+ if(c != '\n')
+ C1;
+ return;
+ }
+ if(C1 != '\n')
+ C1;
+ return;
+
+ case '$':
+ C1; /* discard argument number */
+ return;
+
+ case 'b':
+ case 'x':
+ case 'v':
+ case 'h':
+ case 'w':
+ case 'o':
+ case 'l':
+ case 'L':
+ if((bdelim=C1) == '\n')
+ return;
+ while(C1!='\n' && c!=bdelim)
+ if(c == '\\')
+ backsl();
+ return;
+
+ case '\\':
+ if(inmacro)
+ goto sw;
+ default:
+ return;
+ }
+}
+
+char*
+copys(char *s)
+{
+ char *t, *t0;
+
+ if((t0 = t = malloc((strlen(s)+1))) == 0)
+ fatal("Cannot allocate memory", (char*)0);
+ while(*t++ = *s++)
+ ;
+ return(t0);
+}
+
+void
+sce(void)
+{
+ int n = 1;
+
+ while (C != L'\n' && !(L'0' <= c && c <= L'9'))
+ ;
+ if (c != L'\n') {
+ for (n = c-L'0';'0' <= C && c <= L'9';)
+ n = n*10 + c-L'0';
+ }
+ while(n) {
+ if(C == '.') {
+ if(C == 'c') {
+ if(C == 'e') {
+ while(C == ' ')
+ ;
+ if(c == '0') {
+ SKIP;
+ break;
+ } else
+ SKIP;
+ } else
+ SKIP;
+ } else
+ if(c == 'P' || C == 'P') {
+ if(c != '\n')
+ SKIP;
+ break;
+ } else
+ if(c != '\n')
+ SKIP;
+ } else {
+ SKIP;
+ n--;
+ }
+ }
+}
+
+void
+refer(int c1)
+{
+ int c2;
+
+ if(c1 != '\n')
+ SKIP;
+ c2 = 0;
+ for(;;) {
+ if(C != '.')
+ SKIP;
+ else {
+ if(C != ']')
+ SKIP;
+ else {
+ while(C != '\n')
+ c2 = c;
+ if(charclass(c2) == PUNCT)
+ Bprint(&bout, " %C",c2);
+ return;
+ }
+ }
+ }
+}
+
+void
+inpic(void)
+{
+ int c1;
+ Rune *p1;
+
+/* SKIP1;*/
+ while(C1 != '\n')
+ if(c == '<'){
+ SKIP1;
+ return;
+ }
+ p1 = line;
+ c = '\n';
+ for(;;) {
+ c1 = c;
+ if(C1 == '.' && c1 == '\n') {
+ if(C1 != 'P' || C1 != 'E') {
+ if(c != '\n'){
+ SKIP1;
+ c = '\n';
+ }
+ continue;
+ }
+ SKIP1;
+ return;
+ } else
+ if(c == '\"') {
+ while(C1 != '\"') {
+ if(c == '\\') {
+ if(C1 == '\"')
+ continue;
+ Bungetrune(infile);
+ backsl();
+ } else
+ *p1++ = c;
+ }
+ *p1++ = ' ';
+ } else
+ if(c == '\n' && p1 != line) {
+ *p1 = '\0';
+ if(wordflag)
+ putwords();
+ else
+ Bprint(&bout, "%S\n\n", line);
+ p1 = line;
+ }
+ }
+}
+
+int
+charclass(int c)
+{
+ if(c < MAX_ASCII)
+ return chars[c];
+ switch(c){
+ case 0x2013: case 0x2014: /* en dash, em dash */
+ return SPECIAL;
+ }
+ return EXTENDED;
+} |
| diff --git a/src/cmd/du.C b/src/cmd/du.C |
| t@@ -0,0 +1,194 @@
+#include
+#include
+
+extern vlong du(char*, Dir*);
+extern vlong k(vlong);
+extern void err(char*);
+extern int warn(char*);
+extern int seen(Dir*);
+
+int aflag;
+int fflag;
+int nflag;
+int sflag;
+int tflag;
+int uflag;
+int qflag;
+char *fmt = "%llud\t%s\n";
+vlong blocksize = 1024LL;
+
+void
+main(int argc, char *argv[])
+{
+ int i;
+ char *s, *ss;
+
+ ARGBEGIN {
+ case 'a': /* all files */
+ aflag = 1;
+ break;
+ case 's': /* only top level */
+ sflag = 1;
+ break;
+ case 'f': /* ignore errors */
+ fflag = 1;
+ break;
+ case 'n': /* all files, number of bytes */
+ aflag = 1;
+ nflag = 1;
+ break;
+ case 't': /* return modified/accessed time */
+ tflag = 1;
+ break;
+ case 'u': /* accessed time */
+ uflag = 1;
+ break;
+ case 'q': /* qid */
+ fmt = "%.16llux\t%s\n";
+ qflag = 1;
+ break;
+ case 'b': /* block size */
+ s = ARGF();
+ if(s) {
+ blocksize = strtoul(s, &ss, 0);
+ if(s == ss)
+ blocksize = 1;
+ if(*ss == 'k')
+ blocksize *= 1024;
+ }
+ break;
+ } ARGEND
+ if(argc==0)
+ print(fmt, du(".", dirstat(".")), ".");
+ else
+ for(i=0; iqid.type&QTDIR) == 0)
+ nk = k(dir->length);
+ else{
+ nk = 0;
+ while((n=dirread(fd, &buf)) > 0) {
+ d = buf;
+ for(i=0; iqid.type&QTDIR) == 0) {
+ t = k(d->length);
+ nk += t;
+ if(aflag) {
+ sprint(file, "%s/%s", name, d->name);
+ if(tflag) {
+ t = d->mtime;
+ if(uflag)
+ t = d->atime;
+ }
+ if(qflag)
+ t = d->qid.path;
+ print(fmt, t, file);
+ }
+ continue;
+ }
+ if(strcmp(d->name, ".") == 0 ||
+ strcmp(d->name, "..") == 0 ||
+ seen(d))
+ continue;
+ sprint(file, "%s/%s", name, d->name);
+ t = du(file, d);
+ nk += t;
+ if(tflag) {
+ t = d->mtime;
+ if(uflag)
+ t = d->atime;
+ }
+ if(qflag)
+ t = d->qid.path;
+ if(!sflag)
+ print(fmt, t, file);
+ }
+ free(buf);
+ }
+ if(n < 0)
+ warn(name);
+ }
+ close(fd);
+ if(tflag) {
+ if(uflag)
+ return dir->atime;
+ return dir->mtime;
+ }
+ if(qflag)
+ return dir->qid.path;
+ return nk;
+}
+
+#define NCACHE 128 /* must be power of two */
+typedef struct Cache Cache;
+struct Cache
+{
+ Dir* cache;
+ int n;
+ int max;
+} cache[NCACHE];
+
+int
+seen(Dir *dir)
+{
+ Dir *dp;
+ int i;
+ Cache *c;
+
+ c = &cache[dir->qid.path&(NCACHE-1)];
+ dp = c->cache;
+ for(i=0; in; i++, dp++)
+ if(dir->qid.path == dp->qid.path &&
+ dir->type == dp->type &&
+ dir->dev == dp->dev)
+ return 1;
+ if(c->n == c->max){
+ c->cache = realloc(c->cache, (c->max+=20)*sizeof(Dir));
+ if(cache == 0)
+ err("malloc failure");
+ }
+ c->cache[c->n++] = *dir;
+ return 0;
+}
+
+void
+err(char *s)
+{
+ fprint(2, "du: %s: %r\n", s);
+ exits(s);
+}
+
+int
+warn(char *s)
+{
+ if(fflag == 0)
+ fprint(2, "du: %s: %r\n", s);
+ return 0;
+}
+
+vlong
+k(vlong n)
+{
+ if(nflag)
+ return n;
+ n = (n+blocksize-1)/blocksize;
+ return n*blocksize/1024LL;
+} |
| diff --git a/src/cmd/echo.c b/src/cmd/echo.c |
| t@@ -0,0 +1,38 @@
+#include
+#include
+
+void
+main(int argc, char *argv[])
+{
+ int nflag;
+ int i, len;
+ char *buf, *p;
+
+ nflag = 0;
+ if(argc > 1 && strcmp(argv[1], "-n") == 0)
+ nflag = 1;
+
+ len = 1;
+ for(i = 1+nflag; i < argc; i++)
+ len += strlen(argv[i])+1;
+
+ buf = malloc(len);
+ if(buf == 0)
+ exits("no memory");
+
+ p = buf;
+ for(i = 1+nflag; i < argc; i++){
+ strcpy(p, argv[i]);
+ p += strlen(p);
+ if(i < argc-1)
+ *p++ = ' ';
+ }
+
+ if(!nflag)
+ *p++ = '\n';
+
+ if(write(1, buf, p-buf) < 0)
+ fprint(2, "echo: write error: %r\n");
+
+ exits((char *)0);
+} |
| diff --git a/src/cmd/ed.c b/src/cmd/ed.c |
| t@@ -0,0 +1,1608 @@
+/*
+ * Editor
+ */
+#include
+#include
+#include
+#include
+
+enum
+{
+ FNSIZE = 128, /* file name */
+ LBSIZE = 4096, /* max line size */
+ BLKSIZE = 4096, /* block size in temp file */
+ NBLK = 8191, /* max size of temp file */
+ ESIZE = 256, /* max size of reg exp */
+ GBSIZE = 256, /* max size of global command */
+ MAXSUB = 9, /* max number of sub reg exp */
+ ESCFLG = 0xFFFF, /* escape Rune - user defined code */
+ EOF = -1,
+};
+
+void (*oldhup)(int);
+void (*oldquit)(int);
+int* addr1;
+int* addr2;
+int anymarks;
+int col;
+long count;
+int* dol;
+int* dot;
+int fchange;
+char file[FNSIZE];
+Rune genbuf[LBSIZE];
+int given;
+Rune* globp;
+int iblock;
+int ichanged;
+int io;
+Biobuf iobuf;
+int lastc;
+char line[70];
+Rune* linebp;
+Rune linebuf[LBSIZE];
+int listf;
+int listn;
+Rune* loc1;
+Rune* loc2;
+int names[26];
+int nleft;
+int oblock;
+int oflag;
+Reprog *pattern;
+int peekc;
+int pflag;
+int rescuing;
+Rune rhsbuf[LBSIZE/2];
+char savedfile[FNSIZE];
+jmp_buf savej;
+int subnewa;
+int subolda;
+Resub subexp[MAXSUB];
+char* tfname;
+int tline;
+int waiting;
+int wrapp;
+int* zero;
+
+char Q[] = "";
+char T[] = "TMP";
+char WRERR[] = "WRITE ERROR";
+int bpagesize = 20;
+char hex[] = "0123456789abcdef";
+char* linp = line;
+ulong nlall = 128;
+int tfile = -1;
+int vflag = 1;
+
+void add(int);
+int* address(void);
+int append(int(*)(void), int*);
+void browse(void);
+void callunix(void);
+void commands(void);
+void compile(int);
+int compsub(void);
+void dosub(void);
+void error(char*);
+int match(int*);
+void exfile(int);
+void filename(int);
+Rune* getblock(int, int);
+int getchr(void);
+int getcopy(void);
+int getfile(void);
+Rune* getline(int);
+int getnum(void);
+int getsub(void);
+int gettty(void);
+void global(int);
+void init(void);
+void join(void);
+void move(int);
+void newline(void);
+void nonzero(void);
+void notifyf(void*, char*);
+Rune* place(Rune*, Rune*, Rune*);
+void printcom(void);
+void putchr(int);
+void putd(void);
+void putfile(void);
+int putline(void);
+void putshst(Rune*);
+void putst(char*);
+void quit(void);
+void rdelete(int*, int*);
+void regerror(char *);
+void reverse(int*, int*);
+void setnoaddr(void);
+void setwide(void);
+void squeeze(int);
+void substitute(int);
+
+Rune La[] = { 'a', 0 };
+Rune Lr[] = { 'r', 0 };
+
+char tmp[] = "/tmp/eXXXXX";
+
+void
+main(int argc, char *argv[])
+{
+ char *p1, *p2;
+
+ notify(notifyf);
+ ARGBEGIN {
+ case 'o':
+ oflag = 1;
+ vflag = 0;
+ break;
+ } ARGEND
+
+ USED(argc);
+ if(*argv && (strcmp(*argv, "-") == 0)) {
+ argv++;
+ vflag = 0;
+ }
+ if(oflag) {
+ p1 = "/fd/1";
+ p2 = savedfile;
+ while(*p2++ = *p1++)
+ ;
+ globp = La;
+ } else
+ if(*argv) {
+ p1 = *argv;
+ p2 = savedfile;
+ while(*p2++ = *p1++)
+ if(p2 >= &savedfile[sizeof(savedfile)])
+ p2--;
+ globp = Lr;
+ }
+ zero = malloc((nlall+5)*sizeof(int*));
+ tfname = mktemp(tmp);
+ init();
+ setjmp(savej);
+ commands();
+ quit();
+}
+
+void
+commands(void)
+{
+ int *a1, c, temp;
+ char lastsep;
+ Dir *d;
+
+ for(;;) {
+ if(pflag) {
+ pflag = 0;
+ addr1 = addr2 = dot;
+ printcom();
+ }
+ c = '\n';
+ for(addr1 = 0;;) {
+ lastsep = c;
+ a1 = address();
+ c = getchr();
+ if(c != ',' && c != ';')
+ break;
+ if(lastsep == ',')
+ error(Q);
+ if(a1 == 0) {
+ a1 = zero+1;
+ if(a1 > dol)
+ a1--;
+ }
+ addr1 = a1;
+ if(c == ';')
+ dot = a1;
+ }
+ if(lastsep != '\n' && a1 == 0)
+ a1 = dol;
+ if((addr2=a1) == 0) {
+ given = 0;
+ addr2 = dot;
+ } else
+ given = 1;
+ if(addr1 == 0)
+ addr1 = addr2;
+ switch(c) {
+
+ case 'a':
+ add(0);
+ continue;
+
+ case 'b':
+ nonzero();
+ browse();
+ continue;
+
+ case 'c':
+ nonzero();
+ newline();
+ rdelete(addr1, addr2);
+ append(gettty, addr1-1);
+ continue;
+
+ case 'd':
+ nonzero();
+ newline();
+ rdelete(addr1, addr2);
+ continue;
+
+ case 'E':
+ fchange = 0;
+ c = 'e';
+ case 'e':
+ setnoaddr();
+ if(vflag && fchange) {
+ fchange = 0;
+ error(Q);
+ }
+ filename(c);
+ init();
+ addr2 = zero;
+ goto caseread;
+
+ case 'f':
+ setnoaddr();
+ filename(c);
+ putst(savedfile);
+ continue;
+
+ case 'g':
+ global(1);
+ continue;
+
+ case 'i':
+ add(-1);
+ continue;
+
+
+ case 'j':
+ if(!given)
+ addr2++;
+ newline();
+ join();
+ continue;
+
+ case 'k':
+ nonzero();
+ c = getchr();
+ if(c < 'a' || c > 'z')
+ error(Q);
+ newline();
+ names[c-'a'] = *addr2 & ~01;
+ anymarks |= 01;
+ continue;
+
+ case 'm':
+ move(0);
+ continue;
+
+ case 'n':
+ listn++;
+ newline();
+ printcom();
+ continue;
+
+ case '\n':
+ if(a1==0) {
+ a1 = dot+1;
+ addr2 = a1;
+ addr1 = a1;
+ }
+ if(lastsep==';')
+ addr1 = a1;
+ printcom();
+ continue;
+
+ case 'l':
+ listf++;
+ case 'p':
+ case 'P':
+ newline();
+ printcom();
+ continue;
+
+ case 'Q':
+ fchange = 0;
+ case 'q':
+ setnoaddr();
+ newline();
+ quit();
+
+ case 'r':
+ filename(c);
+ caseread:
+ if((io=open(file, OREAD)) < 0) {
+ lastc = '\n';
+ error(file);
+ }
+ if((d = dirfstat(io)) != nil){
+ if(d->mode & DMAPPEND)
+ print("warning: %s is append only\n", file);
+ free(d);
+ }
+ Binit(&iobuf, io, OREAD);
+ setwide();
+ squeeze(0);
+ c = zero != dol;
+ append(getfile, addr2);
+ exfile(OREAD);
+
+ fchange = c;
+ continue;
+
+ case 's':
+ nonzero();
+ substitute(globp != 0);
+ continue;
+
+ case 't':
+ move(1);
+ continue;
+
+ case 'u':
+ nonzero();
+ newline();
+ if((*addr2&~01) != subnewa)
+ error(Q);
+ *addr2 = subolda;
+ dot = addr2;
+ continue;
+
+ case 'v':
+ global(0);
+ continue;
+
+ case 'W':
+ wrapp++;
+ case 'w':
+ setwide();
+ squeeze(dol>zero);
+ temp = getchr();
+ if(temp != 'q' && temp != 'Q') {
+ peekc = temp;
+ temp = 0;
+ }
+ filename(c);
+ if(!wrapp ||
+ ((io = open(file, OWRITE)) == -1) ||
+ ((seek(io, 0L, 2)) == -1))
+ if((io = create(file, OWRITE, 0666)) < 0)
+ error(file);
+ Binit(&iobuf, io, OWRITE);
+ wrapp = 0;
+ if(dol > zero)
+ putfile();
+ exfile(OWRITE);
+ if(addr1<=zero+1 && addr2==dol)
+ fchange = 0;
+ if(temp == 'Q')
+ fchange = 0;
+ if(temp)
+ quit();
+ continue;
+
+ case '=':
+ setwide();
+ squeeze(0);
+ newline();
+ count = addr2 - zero;
+ putd();
+ putchr(L'\n');
+ continue;
+
+ case '!':
+ callunix();
+ continue;
+
+ case EOF:
+ return;
+
+ }
+ error(Q);
+ }
+}
+
+void
+printcom(void)
+{
+ int *a1;
+
+ nonzero();
+ a1 = addr1;
+ do {
+ if(listn) {
+ count = a1-zero;
+ putd();
+ putchr(L'\t');
+ }
+ putshst(getline(*a1++));
+ } while(a1 <= addr2);
+ dot = addr2;
+ listf = 0;
+ listn = 0;
+ pflag = 0;
+}
+
+int*
+address(void)
+{
+ int sign, *a, opcnt, nextopand, *b, c;
+
+ nextopand = -1;
+ sign = 1;
+ opcnt = 0;
+ a = dot;
+ do {
+ do {
+ c = getchr();
+ } while(c == ' ' || c == '\t');
+ if(c >= '0' && c <= '9') {
+ peekc = c;
+ if(!opcnt)
+ a = zero;
+ a += sign*getnum();
+ } else
+ switch(c) {
+ case '$':
+ a = dol;
+ case '.':
+ if(opcnt)
+ error(Q);
+ break;
+ case '\'':
+ c = getchr();
+ if(opcnt || c < 'a' || c > 'z')
+ error(Q);
+ a = zero;
+ do {
+ a++;
+ } while(a <= dol && names[c-'a'] != (*a & ~01));
+ break;
+ case '?':
+ sign = -sign;
+ case '/':
+ compile(c);
+ b = a;
+ for(;;) {
+ a += sign;
+ if(a <= zero)
+ a = dol;
+ if(a > dol)
+ a = zero;
+ if(match(a))
+ break;
+ if(a == b)
+ error(Q);
+ }
+ break;
+ default:
+ if(nextopand == opcnt) {
+ a += sign;
+ if(a < zero || dol < a)
+ continue; /* error(Q); */
+ }
+ if(c != '+' && c != '-' && c != '^') {
+ peekc = c;
+ if(opcnt == 0)
+ a = 0;
+ return a;
+ }
+ sign = 1;
+ if(c != '+')
+ sign = -sign;
+ nextopand = ++opcnt;
+ continue;
+ }
+ sign = 1;
+ opcnt++;
+ } while(zero <= a && a <= dol);
+ error(Q);
+ return 0;
+}
+
+int
+getnum(void)
+{
+ int r, c;
+
+ r = 0;
+ for(;;) {
+ c = getchr();
+ if(c < '0' || c > '9')
+ break;
+ r = r*10 + (c-'0');
+ }
+ peekc = c;
+ return r;
+}
+
+void
+setwide(void)
+{
+ if(!given) {
+ addr1 = zero + (dol>zero);
+ addr2 = dol;
+ }
+}
+
+void
+setnoaddr(void)
+{
+ if(given)
+ error(Q);
+}
+
+void
+nonzero(void)
+{
+ squeeze(1);
+}
+
+void
+squeeze(int i)
+{
+ if(addr1 < zero+i || addr2 > dol || addr1 > addr2)
+ error(Q);
+}
+
+void
+newline(void)
+{
+ int c;
+
+ c = getchr();
+ if(c == '\n' || c == EOF)
+ return;
+ if(c == 'p' || c == 'l' || c == 'n') {
+ pflag++;
+ if(c == 'l')
+ listf++;
+ else
+ if(c == 'n')
+ listn++;
+ c = getchr();
+ if(c == '\n')
+ return;
+ }
+ error(Q);
+}
+
+void
+filename(int comm)
+{
+ char *p1, *p2;
+ Rune rune;
+ int c;
+
+ count = 0;
+ c = getchr();
+ if(c == '\n' || c == EOF) {
+ p1 = savedfile;
+ if(*p1 == 0 && comm != 'f')
+ error(Q);
+ p2 = file;
+ while(*p2++ = *p1++)
+ ;
+ return;
+ }
+ if(c != ' ')
+ error(Q);
+ while((c=getchr()) == ' ')
+ ;
+ if(c == '\n')
+ error(Q);
+ p1 = file;
+ do {
+ if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)
+ error(Q);
+ rune = c;
+ p1 += runetochar(p1, &rune);
+ } while((c=getchr()) != '\n');
+ *p1 = 0;
+ if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {
+ p1 = savedfile;
+ p2 = file;
+ while(*p1++ = *p2++)
+ ;
+ }
+}
+
+void
+exfile(int om)
+{
+
+ if(om == OWRITE)
+ if(Bflush(&iobuf) < 0)
+ error(Q);
+ close(io);
+ io = -1;
+ if(vflag) {
+ putd();
+ putchr(L'\n');
+ }
+}
+
+void
+error1(char *s)
+{
+ int c;
+
+ wrapp = 0;
+ listf = 0;
+ listn = 0;
+ count = 0;
+ seek(0, 0, 2);
+ pflag = 0;
+ if(globp)
+ lastc = '\n';
+ globp = 0;
+ peekc = lastc;
+ if(lastc)
+ for(;;) {
+ c = getchr();
+ if(c == '\n' || c == EOF)
+ break;
+ }
+ if(io > 0) {
+ close(io);
+ io = -1;
+ }
+ putchr(L'?');
+ putst(s);
+}
+
+void
+error(char *s)
+{
+ error1(s);
+ longjmp(savej, 1);
+}
+
+void
+rescue(void)
+{
+ rescuing = 1;
+ if(dol > zero) {
+ addr1 = zero+1;
+ addr2 = dol;
+ io = create("ed.hup", OWRITE, 0666);
+ if(io > 0){
+ Binit(&iobuf, io, OWRITE);
+ putfile();
+ }
+ }
+ fchange = 0;
+ quit();
+}
+
+void
+notifyf(void *a, char *s)
+{
+ if(strcmp(s, "interrupt") == 0){
+ if(rescuing || waiting)
+ noted(NCONT);
+ putchr(L'\n');
+ lastc = '\n';
+ error1(Q);
+ notejmp(a, savej, 0);
+ }
+ if(strcmp(s, "hangup") == 0){
+ if(rescuing)
+ noted(NDFLT);
+ rescue();
+ }
+ fprint(2, "ed: note: %s\n", s);
+ abort();
+}
+
+int
+getchr(void)
+{
+ char s[UTFmax];
+ int i;
+ Rune r;
+
+ if(lastc = peekc) {
+ peekc = 0;
+ return lastc;
+ }
+ if(globp) {
+ if((lastc=*globp++) != 0)
+ return lastc;
+ globp = 0;
+ return EOF;
+ }
+ for(i=0;;) {
+ if(read(0, s+i, 1) <= 0)
+ return lastc = EOF;
+ i++;
+ if(fullrune(s, i))
+ break;
+
+ }
+ chartorune(&r, s);
+ lastc = r;
+ return lastc;
+}
+
+int
+gety(void)
+{
+ int c;
+ Rune *gf, *p;
+
+ p = linebuf;
+ gf = globp;
+ for(;;) {
+ c = getchr();
+ if(c == '\n') {
+ *p = 0;
+ return 0;
+ }
+ if(c == EOF) {
+ if(gf)
+ peekc = c;
+ return c;
+ }
+ if(c == 0)
+ continue;
+ *p++ = c;
+ if(p >= &linebuf[LBSIZE-2])
+ error(Q);
+ }
+ return 0;
+}
+
+int
+gettty(void)
+{
+ int rc;
+
+ rc = gety();
+ if(rc)
+ return rc;
+ if(linebuf[0] == '.' && linebuf[1] == 0)
+ return EOF;
+ return 0;
+}
+
+int
+getfile(void)
+{
+ int c;
+ Rune *lp;
+
+ lp = linebuf;
+ do {
+ c = Bgetrune(&iobuf);
+ if(c < 0) {
+ if(lp > linebuf) {
+ putst("'\\n' appended");
+ c = '\n';
+ } else
+ return EOF;
+ }
+ if(lp >= &linebuf[LBSIZE]) {
+ lastc = '\n';
+ error(Q);
+ }
+ *lp++ = c;
+ count++;
+ } while(c != '\n');
+ lp[-1] = 0;
+ return 0;
+}
+
+void
+putfile(void)
+{
+ int *a1;
+ Rune *lp;
+ long c;
+
+ a1 = addr1;
+ do {
+ lp = getline(*a1++);
+ for(;;) {
+ count++;
+ c = *lp++;
+ if(c == 0) {
+ if(Bputrune(&iobuf, '\n') < 0)
+ error(Q);
+ break;
+ }
+ if(Bputrune(&iobuf, c) < 0)
+ error(Q);
+ }
+ } while(a1 <= addr2);
+ if(Bflush(&iobuf) < 0)
+ error(Q);
+}
+
+int
+append(int (*f)(void), int *a)
+{
+ int *a1, *a2, *rdot, nline, tl;
+
+ nline = 0;
+ dot = a;
+ while((*f)() == 0) {
+ if((dol-zero) >= nlall) {
+ nlall += 512;
+ a1 = realloc(zero, (nlall+5)*sizeof(int*));
+ if(a1 == 0) {
+ error("MEM?");
+ rescue();
+ }
+ tl = a1 - zero; /* relocate pointers */
+ zero += tl;
+ addr1 += tl;
+ addr2 += tl;
+ dol += tl;
+ dot += tl;
+ }
+ tl = putline();
+ nline++;
+ a1 = ++dol;
+ a2 = a1+1;
+ rdot = ++dot;
+ while(a1 > rdot)
+ *--a2 = *--a1;
+ *rdot = tl;
+ }
+ return nline;
+}
+
+void
+add(int i)
+{
+ if(i && (given || dol > zero)) {
+ addr1--;
+ addr2--;
+ }
+ squeeze(0);
+ newline();
+ append(gettty, addr2);
+}
+
+void
+browse(void)
+{
+ int forward, n;
+ static int bformat, bnum; /* 0 */
+
+ forward = 1;
+ peekc = getchr();
+ if(peekc != '\n'){
+ if(peekc == '-' || peekc == '+') {
+ if(peekc == '-')
+ forward = 0;
+ getchr();
+ }
+ n = getnum();
+ if(n > 0)
+ bpagesize = n;
+ }
+ newline();
+ if(pflag) {
+ bformat = listf;
+ bnum = listn;
+ } else {
+ listf = bformat;
+ listn = bnum;
+ }
+ if(forward) {
+ addr1 = addr2;
+ addr2 += bpagesize;
+ if(addr2 > dol)
+ addr2 = dol;
+ } else {
+ addr1 = addr2-bpagesize;
+ if(addr1 <= zero)
+ addr1 = zero+1;
+ }
+ printcom();
+}
+
+void
+callunix(void)
+{
+ int c, pid;
+ Rune rune;
+ char buf[512];
+ char *p;
+
+ setnoaddr();
+ p = buf;
+ while((c=getchr()) != EOF && c != '\n')
+ if(p < &buf[sizeof(buf) - 6]) {
+ rune = c;
+ p += runetochar(p, &rune);
+ }
+ *p = 0;
+ pid = fork();
+ if(pid == 0) {
+ execl("/bin/rc", "rc", "-c", buf, 0);
+ exits("execl failed");
+ }
+ waiting = 1;
+ while(waitpid() != pid)
+ ;
+ waiting = 0;
+ if(vflag)
+ putst("!");
+}
+
+void
+quit(void)
+{
+ if(vflag && fchange && dol!=zero) {
+ fchange = 0;
+ error(Q);
+ }
+ remove(tfname);
+ exits(0);
+}
+
+void
+onquit(int sig)
+{
+ USED(sig);
+ quit();
+}
+
+void
+rdelete(int *ad1, int *ad2)
+{
+ int *a1, *a2, *a3;
+
+ a1 = ad1;
+ a2 = ad2+1;
+ a3 = dol;
+ dol -= a2 - a1;
+ do {
+ *a1++ = *a2++;
+ } while(a2 <= a3);
+ a1 = ad1;
+ if(a1 > dol)
+ a1 = dol;
+ dot = a1;
+ fchange = 1;
+}
+
+void
+gdelete(void)
+{
+ int *a1, *a2, *a3;
+
+ a3 = dol;
+ for(a1=zero; (*a1&01)==0; a1++)
+ if(a1>=a3)
+ return;
+ for(a2=a1+1; a2<=a3;) {
+ if(*a2 & 01) {
+ a2++;
+ dot = a1;
+ } else
+ *a1++ = *a2++;
+ }
+ dol = a1-1;
+ if(dot > dol)
+ dot = dol;
+ fchange = 1;
+}
+
+Rune*
+getline(int tl)
+{
+ Rune *lp, *bp;
+ int nl;
+
+ lp = linebuf;
+ bp = getblock(tl, OREAD);
+ nl = nleft;
+ tl &= ~((BLKSIZE/2) - 1);
+ while(*lp++ = *bp++) {
+ nl -= sizeof(Rune);
+ if(nl == 0) {
+ bp = getblock(tl += BLKSIZE/2, OREAD);
+ nl = nleft;
+ }
+ }
+ return linebuf;
+}
+
+int
+putline(void)
+{
+ Rune *lp, *bp;
+ int nl, tl;
+
+ fchange = 1;
+ lp = linebuf;
+ tl = tline;
+ bp = getblock(tl, OWRITE);
+ nl = nleft;
+ tl &= ~((BLKSIZE/2)-1);
+ while(*bp = *lp++) {
+ if(*bp++ == '\n') {
+ bp[-1] = 0;
+ linebp = lp;
+ break;
+ }
+ nl -= sizeof(Rune);
+ if(nl == 0) {
+ tl += BLKSIZE/2;
+ bp = getblock(tl, OWRITE);
+ nl = nleft;
+ }
+ }
+ nl = tline;
+ tline += ((lp-linebuf) + 03) & 077776;
+ return nl;
+}
+
+void
+blkio(int b, uchar *buf, int isread)
+{
+ int n;
+
+ seek(tfile, b*BLKSIZE, 0);
+ if(isread)
+ n = read(tfile, buf, BLKSIZE);
+ else
+ n = write(tfile, buf, BLKSIZE);
+ if(n != BLKSIZE)
+ error(T);
+}
+
+Rune*
+getblock(int atl, int iof)
+{
+ int bno, off;
+
+ static uchar ibuff[BLKSIZE];
+ static uchar obuff[BLKSIZE];
+
+ bno = atl / (BLKSIZE/2);
+ off = (atl<<1) & (BLKSIZE-1) & ~03;
+ if(bno >= NBLK) {
+ lastc = '\n';
+ error(T);
+ }
+ nleft = BLKSIZE - off;
+ if(bno == iblock) {
+ ichanged |= iof;
+ return (Rune*)(ibuff+off);
+ }
+ if(bno == oblock)
+ return (Rune*)(obuff+off);
+ if(iof == OREAD) {
+ if(ichanged)
+ blkio(iblock, ibuff, 0);
+ ichanged = 0;
+ iblock = bno;
+ blkio(bno, ibuff, 1);
+ return (Rune*)(ibuff+off);
+ }
+ if(oblock >= 0)
+ blkio(oblock, obuff, 0);
+ oblock = bno;
+ return (Rune*)(obuff+off);
+}
+
+void
+init(void)
+{
+ int *markp;
+
+ close(tfile);
+ tline = 2;
+ for(markp = names; markp < &names[26]; )
+ *markp++ = 0;
+ subnewa = 0;
+ anymarks = 0;
+ iblock = -1;
+ oblock = -1;
+ ichanged = 0;
+ if((tfile = create(tfname, ORDWR, 0600)) < 0){
+ error1(T);
+ exits(0);
+ }
+ dot = dol = zero;
+}
+
+void
+global(int k)
+{
+ Rune *gp, globuf[GBSIZE];
+ int c, *a1;
+
+ if(globp)
+ error(Q);
+ setwide();
+ squeeze(dol > zero);
+ c = getchr();
+ if(c == '\n')
+ error(Q);
+ compile(c);
+ gp = globuf;
+ while((c=getchr()) != '\n') {
+ if(c == EOF)
+ error(Q);
+ if(c == '\\') {
+ c = getchr();
+ if(c != '\n')
+ *gp++ = '\\';
+ }
+ *gp++ = c;
+ if(gp >= &globuf[GBSIZE-2])
+ error(Q);
+ }
+ if(gp == globuf)
+ *gp++ = 'p';
+ *gp++ = '\n';
+ *gp = 0;
+ for(a1=zero; a1<=dol; a1++) {
+ *a1 &= ~01;
+ if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
+ *a1 |= 01;
+ }
+
+ /*
+ * Special case: g/.../d (avoid n^2 algorithm)
+ */
+ if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
+ gdelete();
+ return;
+ }
+ for(a1=zero; a1<=dol; a1++) {
+ if(*a1 & 01) {
+ *a1 &= ~01;
+ dot = a1;
+ globp = globuf;
+ commands();
+ a1 = zero;
+ }
+ }
+}
+
+void
+join(void)
+{
+ Rune *gp, *lp;
+ int *a1;
+
+ nonzero();
+ gp = genbuf;
+ for(a1=addr1; a1<=addr2; a1++) {
+ lp = getline(*a1);
+ while(*gp = *lp++)
+ if(gp++ >= &genbuf[LBSIZE-2])
+ error(Q);
+ }
+ lp = linebuf;
+ gp = genbuf;
+ while(*lp++ = *gp++)
+ ;
+ *addr1 = putline();
+ if(addr1 < addr2)
+ rdelete(addr1+1, addr2);
+ dot = addr1;
+}
+
+void
+substitute(int inglob)
+{
+ int *mp, *a1, nl, gsubf, n;
+
+ n = getnum(); /* OK even if n==0 */
+ gsubf = compsub();
+ for(a1 = addr1; a1 <= addr2; a1++) {
+ if(match(a1)){
+ int *ozero;
+ int m = n;
+
+ do {
+ int span = loc2-loc1;
+
+ if(--m <= 0) {
+ dosub();
+ if(!gsubf)
+ break;
+ if(span == 0) { /* null RE match */
+ if(*loc2 == 0)
+ break;
+ loc2++;
+ }
+ }
+ } while(match(0));
+ if(m <= 0) {
+ inglob |= 01;
+ subnewa = putline();
+ *a1 &= ~01;
+ if(anymarks) {
+ for(mp=names; mp<&names[26]; mp++)
+ if(*mp == *a1)
+ *mp = subnewa;
+ }
+ subolda = *a1;
+ *a1 = subnewa;
+ ozero = zero;
+ nl = append(getsub, a1);
+ addr2 += nl;
+ nl += zero-ozero;
+ a1 += nl;
+ }
+ }
+ }
+ if(inglob == 0)
+ error(Q);
+}
+
+int
+compsub(void)
+{
+ int seof, c;
+ Rune *p;
+
+ seof = getchr();
+ if(seof == '\n' || seof == ' ')
+ error(Q);
+ compile(seof);
+ p = rhsbuf;
+ for(;;) {
+ c = getchr();
+ if(c == '\\') {
+ c = getchr();
+ *p++ = ESCFLG;
+ if(p >= &rhsbuf[LBSIZE/2])
+ error(Q);
+ } else
+ if(c == '\n' && (!globp || !globp[0])) {
+ peekc = c;
+ pflag++;
+ break;
+ } else
+ if(c == seof)
+ break;
+ *p++ = c;
+ if(p >= &rhsbuf[LBSIZE/2])
+ error(Q);
+ }
+ *p = 0;
+ peekc = getchr();
+ if(peekc == 'g') {
+ peekc = 0;
+ newline();
+ return 1;
+ }
+ newline();
+ return 0;
+}
+
+int
+getsub(void)
+{
+ Rune *p1, *p2;
+
+ p1 = linebuf;
+ if((p2 = linebp) == 0)
+ return EOF;
+ while(*p1++ = *p2++)
+ ;
+ linebp = 0;
+ return 0;
+}
+
+void
+dosub(void)
+{
+ Rune *lp, *sp, *rp;
+ int c, n;
+
+ lp = linebuf;
+ sp = genbuf;
+ rp = rhsbuf;
+ while(lp < loc1)
+ *sp++ = *lp++;
+ while(c = *rp++) {
+ if(c == '&'){
+ sp = place(sp, loc1, loc2);
+ continue;
+ }
+ if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
+ n = c-'0';
+ if(subexp[n].s.rsp && subexp[n].e.rep) {
+ sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
+ continue;
+ }
+ error(Q);
+ }
+ *sp++ = c;
+ if(sp >= &genbuf[LBSIZE])
+ error(Q);
+ }
+ lp = loc2;
+ loc2 = sp - genbuf + linebuf;
+ while(*sp++ = *lp++)
+ if(sp >= &genbuf[LBSIZE])
+ error(Q);
+ lp = linebuf;
+ sp = genbuf;
+ while(*lp++ = *sp++)
+ ;
+}
+
+Rune*
+place(Rune *sp, Rune *l1, Rune *l2)
+{
+
+ while(l1 < l2) {
+ *sp++ = *l1++;
+ if(sp >= &genbuf[LBSIZE])
+ error(Q);
+ }
+ return sp;
+}
+
+void
+move(int cflag)
+{
+ int *adt, *ad1, *ad2;
+
+ nonzero();
+ if((adt = address())==0) /* address() guarantees addr is in range */
+ error(Q);
+ newline();
+ if(cflag) {
+ int *ozero, delta;
+ ad1 = dol;
+ ozero = zero;
+ append(getcopy, ad1++);
+ ad2 = dol;
+ delta = zero - ozero;
+ ad1 += delta;
+ adt += delta;
+ } else {
+ ad2 = addr2;
+ for(ad1 = addr1; ad1 <= ad2;)
+ *ad1++ &= ~01;
+ ad1 = addr1;
+ }
+ ad2++;
+ if(adt= ad2) {
+ dot = adt++;
+ reverse(ad1, ad2);
+ reverse(ad2, adt);
+ reverse(ad1, adt);
+ } else
+ error(Q);
+ fchange = 1;
+}
+
+void
+reverse(int *a1, int *a2)
+{
+ int t;
+
+ for(;;) {
+ t = *--a2;
+ if(a2 <= a1)
+ return;
+ *a2 = *a1;
+ *a1++ = t;
+ }
+}
+
+int
+getcopy(void)
+{
+ if(addr1 > addr2)
+ return EOF;
+ getline(*addr1++);
+ return 0;
+}
+
+void
+compile(int eof)
+{
+ Rune c;
+ char *ep;
+ char expbuf[ESIZE];
+
+ if((c = getchr()) == '\n') {
+ peekc = c;
+ c = eof;
+ }
+ if(c == eof) {
+ if(!pattern)
+ error(Q);
+ return;
+ }
+ if(pattern) {
+ free(pattern);
+ pattern = 0;
+ }
+ ep = expbuf;
+ do {
+ if(c == '\\') {
+ if(ep >= expbuf+sizeof(expbuf)) {
+ error(Q);
+ return;
+ }
+ ep += runetochar(ep, &c);
+ if((c = getchr()) == '\n') {
+ error(Q);
+ return;
+ }
+ }
+ if(ep >= expbuf+sizeof(expbuf)) {
+ error(Q);
+ return;
+ }
+ ep += runetochar(ep, &c);
+ } while((c = getchr()) != eof && c != '\n');
+ if(c == '\n')
+ peekc = c;
+ *ep = 0;
+ pattern = regcomp(expbuf);
+}
+
+int
+match(int *addr)
+{
+ if(!pattern)
+ return 0;
+ if(addr){
+ if(addr == zero)
+ return 0;
+ subexp[0].s.rsp = getline(*addr);
+ } else
+ subexp[0].s.rsp = loc2;
+ subexp[0].e.rep = 0;
+ if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
+ loc1 = subexp[0].s.rsp;
+ loc2 = subexp[0].e.rep;
+ return 1;
+ }
+ loc1 = loc2 = 0;
+ return 0;
+
+}
+
+void
+putd(void)
+{
+ int r;
+
+ r = count%10;
+ count /= 10;
+ if(count)
+ putd();
+ putchr(r + L'0');
+}
+
+void
+putst(char *sp)
+{
+ Rune r;
+
+ col = 0;
+ for(;;) {
+ sp += chartorune(&r, sp);
+ if(r == 0)
+ break;
+ putchr(r);
+ }
+ putchr(L'\n');
+}
+
+void
+putshst(Rune *sp)
+{
+ col = 0;
+ while(*sp)
+ putchr(*sp++);
+ putchr(L'\n');
+}
+
+void
+putchr(int ac)
+{
+ char *lp;
+ int c;
+ Rune rune;
+
+ lp = linp;
+ c = ac;
+ if(listf) {
+ if(c == '\n') {
+ if(linp != line && linp[-1] == ' ') {
+ *lp++ = '\\';
+ *lp++ = 'n';
+ }
+ } else {
+ if(col > (72-6-2)) {
+ col = 8;
+ *lp++ = '\\';
+ *lp++ = '\n';
+ *lp++ = '\t';
+ }
+ col++;
+ if(c=='\b' || c=='\t' || c=='\\') {
+ *lp++ = '\\';
+ if(c == '\b')
+ c = 'b';
+ else
+ if(c == '\t')
+ c = 't';
+ col++;
+ } else
+ if(c<' ' || c>='\177') {
+ *lp++ = '\\';
+ *lp++ = 'x';
+ *lp++ = hex[c>>12];
+ *lp++ = hex[c>>8&0xF];
+ *lp++ = hex[c>>4&0xF];
+ c = hex[c&0xF];
+ col += 5;
+ }
+ }
+ }
+
+ rune = c;
+ lp += runetochar(lp, &rune);
+
+ if(c == '\n' || lp >= &line[sizeof(line)-5]) {
+ linp = line;
+ write(oflag? 2: 1, line, lp-line);
+ return;
+ }
+ linp = lp;
+}
+
+char*
+mktemp(char *as)
+{
+ char *s;
+ unsigned pid;
+ int i;
+
+ pid = getpid();
+ s = as;
+ while(*s++)
+ ;
+ s--;
+ while(*--s == 'X') {
+ *s = pid % 10 + '0';
+ pid /= 10;
+ }
+ s++;
+ i = 'a';
+ while(access(as, 0) != -1) {
+ if(i == 'z')
+ return "/";
+ *s = i++;
+ }
+ return as;
+}
+
+void
+regerror(char *s)
+{
+ USED(s);
+ error(Q);
+} |
| diff --git a/src/cmd/factor.c b/src/cmd/factor.c |
| t@@ -0,0 +1,96 @@
+#include
+#include
+#include
+
+#define whsiz (sizeof(wheel)/sizeof(wheel[0]))
+
+double wheel[] =
+{
+ 2,10, 2, 4, 2, 4, 6, 2, 6, 4,
+ 2, 4, 6, 6, 2, 6, 4, 2, 6, 4,
+ 6, 8, 4, 2, 4, 2, 4, 8, 6, 4,
+ 6, 2, 4, 6, 2, 6, 6, 4, 2, 4,
+ 6, 2, 6, 4, 2, 4, 2,10,
+};
+
+Biobuf bin;
+
+void factor(double);
+
+void
+main(int argc, char *argv[])
+{
+ double n;
+ int i;
+ char *l;
+
+ if(argc > 1) {
+ for(i=1; i= whsiz) {
+ i = 0;
+ if(d > s)
+ break;
+ }
+ }
+ if(n > 1)
+ print(" %.0f\n",n);
+ print("\n");
+} |
| diff --git a/src/cmd/freq.c b/src/cmd/freq.c |
| t@@ -0,0 +1,111 @@
+#include
+#include
+#include
+
+long count[1<<16];
+Biobuf bout;
+
+void freq(int, char*);
+long flag;
+enum
+{
+ Fdec = 1<<0,
+ Fhex = 1<<1,
+ Foct = 1<<2,
+ Fchar = 1<<3,
+ Frune = 1<<4,
+};
+
+void
+main(int argc, char *argv[])
+{
+ int f, i;
+
+ flag = 0;
+ Binit(&bout, 1, OWRITE);
+ ARGBEGIN{
+ default:
+ fprint(2, "freq: unknown option %c\n", ARGC());
+ exits("usage");
+ case 'd':
+ flag |= Fdec;
+ break;
+ case 'x':
+ flag |= Fhex;
+ break;
+ case 'o':
+ flag |= Foct;
+ break;
+ case 'c':
+ flag |= Fchar;
+ break;
+ case 'r':
+ flag |= Frune;
+ break;
+ }ARGEND
+ if((flag&(Fdec|Fhex|Foct|Fchar)) == 0)
+ flag |= Fdec | Fhex | Foct | Fchar;
+ if(argc < 1) {
+ freq(0, "-");
+ exits(0);
+ }
+ for(i=0; i= 0x7f && i < 0xa0 ||
+ i > 0xff && !(flag & Frune))
+ Bprint(&bout, "- ");
+ else
+ Bprint(&bout, "%C ", (int)i);
+ }
+ Bprint(&bout, "%8ld\n", count[i]);
+ }
+ Bflush(&bout);
+} |
| diff --git a/src/cmd/fsize.c b/src/cmd/fsize.c |
| t@@ -0,0 +1,32 @@
+#include
+#include
+
+void
+usage(void)
+{
+ fprint(2, "usage: fsize file...\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int i;
+ Dir *d;
+
+ ARGBEGIN{
+ default:
+ usage();
+ }ARGEND
+ if(argc == 0)
+ usage();
+
+ for(i=0; ilength);
+ free(d);
+ }
+ }
+} |
| diff --git a/src/cmd/idiff.c b/src/cmd/idiff.c |
| t@@ -0,0 +1,335 @@
+/*
+ * interactive diff, inspired/stolen from
+ * kernighan and pike, _unix programming environment_.
+ */
+
+#include
+#include
+#include
+
+int diffbflag;
+int diffwflag;
+
+void copy(Biobuf*, char*, Biobuf*, char*);
+void idiff(Biobuf*, char*, Biobuf*, char*, Biobuf*, char*, Biobuf*, char*);
+int opentemp(char*, int, long);
+void rundiff(char*, char*, int);
+
+void
+usage(void)
+{
+ fprint(2, "usage: idiff [-bw] file1 file2\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int fd, ofd;
+ char diffout[40], idiffout[40];
+ Biobuf *b1, *b2, bdiff, bout, bstdout;
+ Dir *d;
+
+ ARGBEGIN{
+ default:
+ usage();
+ case 'b':
+ diffbflag++;
+ break;
+ case 'w':
+ diffwflag++;
+ break;
+ }ARGEND
+
+ if(argc != 2)
+ usage();
+
+ if((d = dirstat(argv[0])) == nil)
+ sysfatal("stat %s: %r", argv[0]);
+ if(d->mode&DMDIR)
+ sysfatal("%s is a directory", argv[0]);
+ free(d);
+ if((d = dirstat(argv[1])) == nil)
+ sysfatal("stat %s: %r", argv[1]);
+ if(d->mode&DMDIR)
+ sysfatal("%s is a directory", argv[1]);
+ free(d);
+
+ if((b1 = Bopen(argv[0], OREAD)) == nil)
+ sysfatal("open %s: %r", argv[0]);
+ if((b2 = Bopen(argv[1], OREAD)) == nil)
+ sysfatal("open %s: %r", argv[1]);
+
+ strcpy(diffout, "/tmp/idiff.XXXXXX");
+ fd = opentemp(diffout, ORDWR|ORCLOSE, 0);
+ strcpy(idiffout, "/tmp/idiff.XXXXXX");
+ ofd = opentemp(idiffout, ORDWR|ORCLOSE, 0);
+ rundiff(argv[0], argv[1], fd);
+ seek(fd, 0, 0);
+ Binit(&bdiff, fd, OREAD);
+ Binit(&bout, ofd, OWRITE);
+ idiff(b1, argv[0], b2, argv[1], &bdiff, diffout, &bout, idiffout);
+ Bterm(&bdiff);
+ Bflush(&bout);
+ seek(ofd, 0, 0);
+ Binit(&bout, ofd, OREAD);
+ Binit(&bstdout, 1, OWRITE);
+ copy(&bout, idiffout, &bstdout, "");
+ exits(nil);
+}
+
+int
+opentemp(char *template, int mode, long perm)
+{
+ int fd, i;
+ char *p;
+
+ p = strdup(template);
+ if(p == nil)
+ sysfatal("strdup out of memory");
+ fd = -1;
+ for(i=0; i<10; i++){
+ mktemp(p);
+ if(access(p, 0) < 0 && (fd=create(p, mode, perm)) >= 0)
+ break;
+ strcpy(p, template);
+ }
+ if(fd < 0)
+ sysfatal("could not create temporary file");
+ strcpy(template, p);
+ free(p);
+
+ return fd;
+}
+
+void
+rundiff(char *arg1, char *arg2, int outfd)
+{
+ char *arg[10], *p;
+ int narg, pid;
+ Waitmsg *w;
+
+ narg = 0;
+ arg[narg++] = "/bin/diff";
+ arg[narg++] = "-n";
+ if(diffbflag)
+ arg[narg++] = "-b";
+ if(diffwflag)
+ arg[narg++] = "-w";
+ arg[narg++] = arg1;
+ arg[narg++] = arg2;
+ arg[narg] = nil;
+
+ switch(pid = fork()){
+ case -1:
+ sysfatal("fork: %r");
+
+ case 0:
+ dup(outfd, 1);
+ close(0);
+ exec("/bin/diff", arg);
+ sysfatal("exec: %r");
+
+ default:
+ w = wait();
+ if(w==nil)
+ sysfatal("wait: %r");
+ if(w->pid != pid)
+ sysfatal("wait got unexpected pid %d", w->pid);
+ if((p = strchr(w->msg, ':')) && strcmp(p, ": some") != 0)
+ sysfatal("%s", w->msg);
+ free(w);
+ }
+}
+
+void
+runcmd(char *cmd)
+{
+ char *arg[10];
+ int narg, pid, wpid;
+
+ narg = 0;
+ arg[narg++] = "/bin/rc";
+ arg[narg++] = "-c";
+ arg[narg++] = cmd;
+ arg[narg] = nil;
+
+ switch(pid = fork()){
+ case -1:
+ sysfatal("fork: %r");
+
+ case 0:
+ exec("/bin/rc", arg);
+ sysfatal("exec: %r");
+
+ default:
+ wpid = waitpid();
+ if(wpid < 0)
+ sysfatal("wait: %r");
+ if(wpid != pid)
+ sysfatal("wait got unexpected pid %d", wpid);
+ }
+}
+
+void
+parse(char *s, int *pfrom1, int *pto1, int *pcmd, int *pfrom2, int *pto2)
+{
+ *pfrom1 = *pto1 = *pfrom2 = *pto2 = 0;
+
+ s = strchr(s, ':');
+ if(s == nil)
+ sysfatal("bad diff output0");
+ s++;
+ *pfrom1 = strtol(s, &s, 10);
+ if(*s == ','){
+ s++;
+ *pto1 = strtol(s, &s, 10);
+ }else
+ *pto1 = *pfrom1;
+ if(*s++ != ' ')
+ sysfatal("bad diff output1");
+ *pcmd = *s++;
+ if(*s++ != ' ')
+ sysfatal("bad diff output2");
+ s = strchr(s, ':');
+ if(s == nil)
+ sysfatal("bad diff output3");
+ s++;
+ *pfrom2 = strtol(s, &s, 10);
+ if(*s == ','){
+ s++;
+ *pto2 = strtol(s, &s, 10);
+ }else
+ *pto2 = *pfrom2;
+}
+
+void
+skiplines(Biobuf *b, char *name, int n)
+{
+ int i;
+
+ for(i=0; i sizeof buf)
+ m = sizeof buf;
+ m = Bread(bin, buf, m);
+ if(Bwrite(bout, buf, m) != m)
+ sysfatal("error writing %s: %r", nout);
+ }
+ if(Bwrite(bout, p, Blinelen(bin)) != Blinelen(bin))
+ sysfatal("error writing %s: %r", nout);
+ }
+}
+
+void
+copy(Biobuf *bin, char *nin, Biobuf *bout, char *nout)
+{
+ char buf[4096];
+ int m;
+
+ USED(nin);
+ while((m = Bread(bin, buf, sizeof buf)) > 0)
+ if(Bwrite(bout, buf, m) != m)
+ sysfatal("error writing %s: %r", nout);
+}
+
+void
+idiff(Biobuf *b1, char *name1, Biobuf *b2, char *name2, Biobuf *bdiff, char *namediff, Biobuf *bout, char *nameout)
+{
+ char buf[256], *p;
+ int interactive, defaultanswer, cmd, diffoffset;
+ int n, from1, to1, from2, to2, nf1, nf2;
+ Biobuf berr;
+
+ nf1 = 1;
+ nf2 = 1;
+ interactive = 1;
+ defaultanswer = 0;
+ Binit(&berr, 2, OWRITE);
+ while(diffoffset = Boffset(bdiff), p = Brdline(bdiff, '\n')){
+ p[Blinelen(bdiff)-1] = '\0';
+ parse(p, &from1, &to1, &cmd, &from2, &to2);
+ p[Blinelen(bdiff)-1] = '\n';
+ n = to1-from1 + to2-from2 + 1; /* #lines from diff */
+ if(cmd == 'c')
+ n += 2;
+ else if(cmd == 'a')
+ from1++;
+ else if(cmd == 'd')
+ from2++;
+ to1++; /* make half-open intervals */
+ to2++;
+ if(interactive){
+ p[Blinelen(bdiff)-1] = '\0';
+ fprint(2, "%s\n", p);
+ p[Blinelen(bdiff)-1] = '\n';
+ copylines(bdiff, namediff, &berr, "", n);
+ Bflush(&berr);
+ }else
+ skiplines(bdiff, namediff, n);
+ do{
+ if(interactive){
+ fprint(2, "? ");
+ memset(buf, 0, sizeof buf);
+ if(read(0, buf, sizeof buf - 1) < 0)
+ sysfatal("read console: %r");
+ }else
+ buf[0] = defaultanswer;
+
+ switch(buf[0]){
+ case '>':
+ copylines(b1, name1, bout, nameout, from1-nf1);
+ skiplines(b1, name1, to1-from1);
+ skiplines(b2, name2, from2-nf2);
+ copylines(b2, name2, bout, nameout, to2-from2);
+ break;
+ case '<':
+ copylines(b1, name1, bout, nameout, to1-nf1);
+ skiplines(b2, name2, to2-nf2);
+ break;
+ case '=':
+ copylines(b1, name1, bout, nameout, from1-nf1);
+ skiplines(b1, name1, to1-from1);
+ skiplines(b2, name2, to2-nf2);
+ if(Bseek(bdiff, diffoffset, 0) != diffoffset)
+ sysfatal("seek in diff output: %r");
+ copylines(bdiff, namediff, bout, nameout, n+1);
+ break;
+ case '!':
+ runcmd(buf+1);
+ break;
+ case 'q':
+ if(buf[1]=='<' || buf[1]=='>' || buf[1]=='='){
+ interactive = 0;
+ defaultanswer = buf[1];
+ }else
+ fprint(2, "must be q<, q>, or q=\n");
+ break;
+ default:
+ fprint(2, "expect: <, >, =, q<, q>, q=, !cmd\n");
+ break;
+ }
+ }while(buf[0] != '<' && buf[0] != '>' && buf[0] != '=');
+ nf1 = to1;
+ nf2 = to2;
+ }
+ copy(b1, name1, bout, nameout);
+} |
| diff --git a/src/cmd/join.c b/src/cmd/join.c |
| t@@ -0,0 +1,369 @@
+/* join F1 F2 on stuff */
+#include
+#include
+#include
+#include
+#define F1 0
+#define F2 1
+#define F0 3
+#define NFLD 100 /* max field per line */
+#define comp() runecmp(ppi[F1][j1],ppi[F2][j2])
+FILE *f[2];
+Rune buf[2][BUFSIZ]; /*input lines */
+Rune *ppi[2][NFLD+1]; /* pointers to fields in lines */
+Rune *s1,*s2;
+#define j1 joinj1
+#define j2 joinj2
+
+int j1 = 1; /* join of this field of file 1 */
+int j2 = 1; /* join of this field of file 2 */
+int olist[2*NFLD]; /* output these fields */
+int olistf[2*NFLD]; /* from these files */
+int no; /* number of entries in olist */
+Rune sep1 = ' '; /* default field separator */
+Rune sep2 = '\t';
+char *sepstr=" ";
+int discard; /* count of truncated lines */
+Rune null[BUFSIZ]/* = L""*/;
+int a1;
+int a2;
+
+char *getoptarg(int*, char***);
+void output(int, int);
+int input(int);
+void oparse(char*);
+void error(char*, char*);
+void seek1(void), seek2(void);
+Rune *strtorune(Rune *, char *);
+
+
+void
+main(int argc, char **argv)
+{
+ int i;
+
+ while (argc > 1 && argv[1][0] == '-') {
+ if (argv[1][1] == '\0')
+ break;
+ switch (argv[1][1]) {
+ case '-':
+ argc--;
+ argv++;
+ goto proceed;
+ case 'a':
+ switch(*getoptarg(&argc, &argv)) {
+ case '1':
+ a1++;
+ break;
+ case '2':
+ a2++;
+ break;
+ default:
+ error("incomplete option -a","");
+ }
+ break;
+ case 'e':
+ strtorune(null, getoptarg(&argc, &argv));
+ break;
+ case 't':
+ sepstr=getoptarg(&argc, &argv);
+ chartorune(&sep1, sepstr);
+ sep2 = sep1;
+ break;
+ case 'o':
+ if(argv[1][2]!=0 ||
+ argc>2 && strchr(argv[2],',')!=0)
+ oparse(getoptarg(&argc, &argv));
+ else for (no = 0; no<2*NFLD && argc>2; no++){
+ if (argv[2][0] == '1' && argv[2][1] == '.') {
+ olistf[no] = F1;
+ olist[no] = atoi(&argv[2][2]);
+ } else if (argv[2][0] == '2' && argv[2][1] == '.') {
+ olist[no] = atoi(&argv[2][2]);
+ olistf[no] = F2;
+ } else if (argv[2][0] == '0')
+ olistf[no] = F0;
+ else
+ break;
+ argc--;
+ argv++;
+ }
+ break;
+ case 'j':
+ if(argc <= 2)
+ break;
+ if (argv[1][2] == '1')
+ j1 = atoi(argv[2]);
+ else if (argv[1][2] == '2')
+ j2 = atoi(argv[2]);
+ else
+ j1 = j2 = atoi(argv[2]);
+ argc--;
+ argv++;
+ break;
+ case '1':
+ j1 = atoi(getoptarg(&argc, &argv));
+ break;
+ case '2':
+ j2 = atoi(getoptarg(&argc, &argv));
+ break;
+ }
+ argc--;
+ argv++;
+ }
+proceed:
+ for (i = 0; i < no; i++)
+ if (olist[i]-- > NFLD) /* 0 origin */
+ error("field number too big in -o","");
+ if (argc != 3)
+ error("usage: join [-1 x -2 y] [-o list] file1 file2","");
+ j1--;
+ j2--; /* everyone else believes in 0 origin */
+ s1 = ppi[F1][j1];
+ s2 = ppi[F2][j2];
+ if (strcmp(argv[1], "-") == 0)
+ f[F1] = stdin;
+ else if ((f[F1] = fopen(argv[1], "r")) == 0)
+ error("can't open %s", argv[1]);
+ if(strcmp(argv[2], "-") == 0) {
+ f[F2] = stdin;
+ } else if ((f[F2] = fopen(argv[2], "r")) == 0)
+ error("can't open %s", argv[2]);
+
+ if(ftell(f[F2]) >= 0)
+ seek2();
+ else if(ftell(f[F1]) >= 0)
+ seek1();
+ else
+ error("neither file is randomly accessible","");
+ if (discard)
+ error("some input line was truncated", "");
+ exits("");
+}
+int runecmp(Rune *a, Rune *b){
+ while(*a==*b){
+ if(*a=='\0') return 0;
+ a++;
+ b++;
+ }
+ if(*a<*b) return -1;
+ return 1;
+}
+char *runetostr(char *buf, Rune *r){
+ char *s;
+ for(s=buf;*r;r++) s+=runetochar(s, r);
+ *s='\0';
+ return buf;
+}
+Rune *strtorune(Rune *buf, char *s){
+ Rune *r;
+ for(r=buf;*s;r++) s+=chartorune(r, s);
+ *r='\0';
+ return buf;
+}
+/* lazy. there ought to be a clean way to combine seek1 & seek2 */
+#define get1() n1=input(F1)
+#define get2() n2=input(F2)
+void
+seek2()
+{
+ int n1, n2;
+ int top2=0;
+ int bot2 = ftell(f[F2]);
+ get1();
+ get2();
+ while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
+ if(n1>0 && n2>0 && comp()>0 || n1==0) {
+ if(a2) output(0, n2);
+ bot2 = ftell(f[F2]);
+ get2();
+ } else if(n1>0 && n2>0 && comp()<0 || n2==0) {
+ if(a1) output(n1, 0);
+ get1();
+ } else /*(n1>0 && n2>0 && comp()==0)*/ {
+ while(n2>0 && comp()==0) {
+ output(n1, n2);
+ top2 = ftell(f[F2]);
+ get2();
+ }
+ fseek(f[F2], bot2, 0);
+ get2();
+ get1();
+ for(;;) {
+ if(n1>0 && n2>0 && comp()==0) {
+ output(n1, n2);
+ get2();
+ } else if(n1>0 && n2>0 && comp()<0 || n2==0) {
+ fseek(f[F2], bot2, 0);
+ get2();
+ get1();
+ } else /*(n1>0 && n2>0 && comp()>0 || n1==0)*/{
+ fseek(f[F2], top2, 0);
+ bot2 = top2;
+ get2();
+ break;
+ }
+ }
+ }
+ }
+}
+void
+seek1()
+{
+ int n1, n2;
+ int top1=0;
+ int bot1 = ftell(f[F1]);
+ get1();
+ get2();
+ while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
+ if(n1>0 && n2>0 && comp()>0 || n1==0) {
+ if(a2) output(0, n2);
+ get2();
+ } else if(n1>0 && n2>0 && comp()<0 || n2==0) {
+ if(a1) output(n1, 0);
+ bot1 = ftell(f[F1]);
+ get1();
+ } else /*(n1>0 && n2>0 && comp()==0)*/ {
+ while(n2>0 && comp()==0) {
+ output(n1, n2);
+ top1 = ftell(f[F1]);
+ get1();
+ }
+ fseek(f[F1], bot1, 0);
+ get2();
+ get1();
+ for(;;) {
+ if(n1>0 && n2>0 && comp()==0) {
+ output(n1, n2);
+ get1();
+ } else if(n1>0 && n2>0 && comp()>0 || n1==0) {
+ fseek(f[F1], bot1, 0);
+ get2();
+ get1();
+ } else /*(n1>0 && n2>0 && comp()<0 || n2==0)*/{
+ fseek(f[F1], top1, 0);
+ bot1 = top1;
+ get1();
+ break;
+ }
+ }
+ }
+ }
+}
+
+int
+input(int n) /* get input line and split into fields */
+{
+ register int i, c;
+ Rune *bp;
+ Rune **pp;
+ char line[BUFSIZ];
+
+ bp = buf[n];
+ pp = ppi[n];
+ if (fgets(line, BUFSIZ, f[n]) == 0)
+ return(0);
+ strtorune(bp, line);
+ i = 0;
+ do {
+ i++;
+ if (sep1 == ' ') /* strip multiples */
+ while ((c = *bp) == sep1 || c == sep2)
+ bp++; /* skip blanks */
+ *pp++ = bp; /* record beginning */
+ while ((c = *bp) != sep1 && c != '\n' && c != sep2 && c != '\0')
+ bp++;
+ *bp++ = '\0'; /* mark end by overwriting blank */
+ } while (c != '\n' && c != '\0' && i < NFLD-1);
+ if (c != '\n')
+ discard++;
+
+ *pp = 0;
+ return(i);
+}
+
+void
+output(int on1, int on2) /* print items from olist */
+{
+ int i;
+ Rune *temp;
+ char buf[BUFSIZ];
+
+ if (no <= 0) { /* default case */
+ printf("%s", runetostr(buf, on1? ppi[F1][j1]: ppi[F2][j2]));
+ for (i = 0; i < on1; i++)
+ if (i != j1)
+ printf("%s%s", sepstr, runetostr(buf, ppi[F1][i]));
+ for (i = 0; i < on2; i++)
+ if (i != j2)
+ printf("%s%s", sepstr, runetostr(buf, ppi[F2][i]));
+ printf("\n");
+ } else {
+ for (i = 0; i < no; i++) {
+ if (olistf[i]==F0 && on1>j1)
+ temp = ppi[F1][j1];
+ else if (olistf[i]==F0 && on2>j2)
+ temp = ppi[F2][j2];
+ else {
+ temp = ppi[olistf[i]][olist[i]];
+ if(olistf[i]==F1 && on1<=olist[i] ||
+ olistf[i]==F2 && on2<=olist[i] ||
+ *temp==0)
+ temp = null;
+ }
+ printf("%s", runetostr(buf, temp));
+ if (i == no - 1)
+ printf("\n");
+ else
+ printf("%s", sepstr);
+ }
+ }
+}
+
+void
+error(char *s1, char *s2)
+{
+ fprintf(stderr, "join: ");
+ fprintf(stderr, s1, s2);
+ fprintf(stderr, "\n");
+ exits(s1);
+}
+
+char *
+getoptarg(int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ if(argv[1][2] != 0)
+ return &argv[1][2];
+ if(argc<=2 || argv[2][0]=='-')
+ error("incomplete option %s", argv[1]);
+ *argcp = argc-1;
+ *argvp = ++argv;
+ return argv[1];
+}
+
+void
+oparse(char *s)
+{
+ for (no = 0; no<2*NFLD && *s; no++, s++) {
+ switch(*s) {
+ case 0:
+ return;
+ case '0':
+ olistf[no] = F0;
+ break;
+ case '1':
+ case '2':
+ if(s[1] == '.' && isdigit(s[2])) {
+ olistf[no] = *s=='1'? F1: F2;
+ olist[no] = atoi(s += 2);
+ break;
+ } /* fall thru */
+ default:
+ error("invalid -o list", "");
+ }
+ if(s[1] == ',')
+ s++;
+ }
+} |
| diff --git a/src/cmd/ls.C b/src/cmd/ls.C |
| t@@ -0,0 +1,305 @@
+#include
+#include
+#include
+
+typedef struct NDir NDir;
+struct NDir
+{
+ Dir *d;
+ char *prefix;
+};
+
+int errs = 0;
+int dflag;
+int lflag;
+int mflag;
+int nflag;
+int pflag;
+int qflag;
+int Qflag;
+int rflag;
+int sflag;
+int tflag;
+int uflag;
+int Fflag;
+int ndirbuf;
+int ndir;
+NDir* dirbuf;
+int ls(char*, int);
+int compar(NDir*, NDir*);
+char* asciitime(long);
+char* darwx(long);
+void rwx(long, char*);
+void growto(long);
+void dowidths(Dir*);
+void format(Dir*, char*);
+void output(void);
+ulong clk;
+int swidth; /* max width of -s size */
+int qwidth; /* max width of -q version */
+int vwidth; /* max width of dev */
+int uwidth; /* max width of userid */
+int mwidth; /* max width of muid */
+int glwidth; /* max width of groupid and length */
+Biobuf bin;
+
+void
+main(int argc, char *argv[])
+{
+ int i;
+
+ Binit(&bin, 1, OWRITE);
+ ARGBEGIN{
+ case 'F': Fflag++; break;
+ case 'd': dflag++; break;
+ case 'l': lflag++; break;
+ case 'm': mflag++; break;
+ case 'n': nflag++; break;
+ case 'p': pflag++; break;
+ case 'q': qflag++; break;
+ case 'Q': Qflag++; break;
+ case 'r': rflag++; break;
+ case 's': sflag++; break;
+ case 't': tflag++; break;
+ case 'u': uflag++; break;
+ default: fprint(2, "usage: ls [-dlmnpqrstuFQ] [file ...]\n");
+ exits("usage");
+ }ARGEND
+
+ doquote = needsrcquote;
+ quotefmtinstall();
+ fmtinstall('M', dirmodefmt);
+
+ if(lflag)
+ clk = time(0);
+ if(argc == 0)
+ errs = ls(".", 0);
+ else for(i=0; iqid.type&QTDIR && dflag==0){
+ output();
+ fd = open(s, OREAD);
+ if(fd == -1)
+ goto error;
+ n = dirreadall(fd, &db);
+ if(n < 0)
+ goto error;
+ growto(ndir+n);
+ for(i=0; iname = strdup(p+1);
+ }
+ ndir++;
+ }
+ return 0;
+}
+
+void
+output(void)
+{
+ int i;
+ char buf[4096];
+ char *s;
+
+ if(!nflag)
+ qsort(dirbuf, ndir, sizeof dirbuf[0], (int (*)(const void*, const void*))compar);
+ for(i=0; iname);
+ format(dirbuf[i].d, buf);
+ } else
+ format(dirbuf[i].d, dirbuf[i].d->name);
+ }
+ ndir = 0;
+ Bflush(&bin);
+}
+
+void
+dowidths(Dir *db)
+{
+ char buf[256];
+ int n;
+
+ if(sflag) {
+ n = sprint(buf, "%llud", (db->length+1023)/1024);
+ if(n > swidth)
+ swidth = n;
+ }
+ if(qflag) {
+ n = sprint(buf, "%lud", db->qid.vers);
+ if(n > qwidth)
+ qwidth = n;
+ }
+ if(mflag) {
+ n = snprint(buf, sizeof buf, "[%s]", db->muid);
+ if(n > mwidth)
+ mwidth = n;
+ }
+ if(lflag) {
+ n = sprint(buf, "%ud", db->dev);
+ if(n > vwidth)
+ vwidth = n;
+ n = strlen(db->uid);
+ if(n > uwidth)
+ uwidth = n;
+ n = sprint(buf, "%llud", db->length);
+ n += strlen(db->gid);
+ if(n > glwidth)
+ glwidth = n;
+ }
+}
+
+char*
+fileflag(Dir *db)
+{
+ if(Fflag == 0)
+ return "";
+ if(QTDIR & db->qid.type)
+ return "/";
+ if(0111 & db->mode)
+ return "*";
+ return "";
+}
+
+void
+format(Dir *db, char *name)
+{
+ int i;
+
+ if(sflag)
+ Bprint(&bin, "%*llud ",
+ swidth, (db->length+1023)/1024);
+ if(mflag){
+ Bprint(&bin, "[%s] ", db->muid);
+ for(i=2+strlen(db->muid); iqid.path,
+ qwidth, db->qid.vers,
+ db->qid.type);
+ if(lflag)
+ Bprint(&bin,
+ Qflag? "%M %C %*ud %*s %s %*llud %s %s\n" : "%M %C %*ud %*s %s %*llud %s %q\n",
+ db->mode, db->type,
+ vwidth, db->dev,
+ -uwidth, db->uid,
+ db->gid,
+ (int)(glwidth-strlen(db->gid)), db->length,
+ asciitime(uflag? db->atime : db->mtime), name);
+ else
+ Bprint(&bin,
+ Qflag? "%s%s\n" : "%q%s\n",
+ name, fileflag(db));
+}
+
+void
+growto(long n)
+{
+ if(n <= ndirbuf)
+ return;
+ ndirbuf = n;
+ dirbuf=(NDir *)realloc(dirbuf, ndirbuf*sizeof(NDir));
+ if(dirbuf == 0){
+ fprint(2, "ls: malloc fail\n");
+ exits("malloc fail");
+ }
+}
+
+int
+compar(NDir *a, NDir *b)
+{
+ long i;
+ Dir *ad, *bd;
+
+ ad = a->d;
+ bd = b->d;
+
+ if(tflag){
+ if(uflag)
+ i = bd->atime-ad->atime;
+ else
+ i = bd->mtime-ad->mtime;
+ }else{
+ if(a->prefix && b->prefix){
+ i = strcmp(a->prefix, b->prefix);
+ if(i == 0)
+ i = strcmp(ad->name, bd->name);
+ }else if(a->prefix){
+ i = strcmp(a->prefix, bd->name);
+ if(i == 0)
+ i = 1; /* a is longer than b */
+ }else if(b->prefix){
+ i = strcmp(ad->name, b->prefix);
+ if(i == 0)
+ i = -1; /* b is longer than a */
+ }else
+ i = strcmp(ad->name, bd->name);
+ }
+ if(i == 0)
+ i = (a |
| diff --git a/src/cmd/md5sum.C b/src/cmd/md5sum.C |
| t@@ -0,0 +1,61 @@
+#include
+#include
+#include
+#include
+
+static int
+digestfmt(Fmt *fmt)
+{
+ char buf[MD5dlen*2+1];
+ uchar *p;
+ int i;
+
+ p = va_arg(fmt->args, uchar*);
+ for(i=0; i 0)
+ md5(buf, n, nil, s);
+ md5(nil, 0, digest, s);
+ if(name == nil)
+ print("%M\n", digest);
+ else
+ print("%M\t%s\n", digest, name);
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i, fd;
+
+ ARGBEGIN{
+ default:
+ fprint(2, "usage: md5sum [file...]\n");
+ exits("usage");
+ }ARGEND
+
+ fmtinstall('M', digestfmt);
+
+ if(argc == 0)
+ sum(0, nil);
+ else for(i = 0; i < argc; i++){
+ fd = open(argv[i], OREAD);
+ if(fd < 0){
+ fprint(2, "md5sum: can't open %s: %r\n", argv[i]);
+ continue;
+ }
+ sum(fd, argv[i]);
+ close(fd);
+ }
+ exits(nil);
+} |
| diff --git a/src/cmd/mkdir.C b/src/cmd/mkdir.C |
| t@@ -0,0 +1,26 @@
+#include
+#include
+
+void
+main(int argc, char *argv[])
+{
+ int i, f;
+ char *e;
+
+ e = nil;
+ for(i=1; i |
| diff --git a/src/cmd/mkfile b/src/cmd/mkfile |
| t@@ -0,0 +1,13 @@
+PLAN9=../..
+<$PLAN9/src/mkhdr
+
+TARG=`ls *.c | sed 's/\.c//'`
+LDFLAGS=$LDFLAGS -lsec -lregexp9 -l9 -lbio -lfmt -lutf
+
+<$PLAN9/src/mkmany
+
+BUGGERED='CVS|oplumb|plumb|plumb2|mk|vac'
+DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "$BUGGERED"`
+
+<$PLAN9/src/mkdirs
+ |
| diff --git a/src/cmd/rm.c b/src/cmd/rm.c |
| t@@ -0,0 +1,104 @@
+#include
+#include
+
+#define rmdir p9rmdir
+
+char errbuf[ERRMAX];
+int ignerr = 0;
+
+void
+err(char *f)
+{
+ if(!ignerr){
+ errbuf[0] = '\0';
+ errstr(errbuf, sizeof errbuf);
+ fprint(2, "rm: %s: %s\n", f, errbuf);
+ }
+}
+
+/*
+ * f is a non-empty directory. Remove its contents and then it.
+ */
+void
+rmdir(char *f)
+{
+ char *name;
+ int fd, i, j, n, ndir, nname;
+ Dir *dirbuf;
+
+ fd = open(f, OREAD);
+ if(fd < 0){
+ err(f);
+ return;
+ }
+ n = dirreadall(fd, &dirbuf);
+ close(fd);
+ if(n < 0){
+ err("dirreadall");
+ return;
+ }
+
+ nname = strlen(f)+1+STATMAX+1; /* plenty! */
+ name = malloc(nname);
+ if(name == 0){
+ err("memory allocation");
+ return;
+ }
+
+ ndir = 0;
+ for(i=0; iqid.type&QTDIR))
+ rmdir(f);
+ else
+ err(f);
+ free(db);
+ }
+ exits(errbuf);
+} |
| diff --git a/src/cmd/seq.c b/src/cmd/seq.c |
| t@@ -0,0 +1,92 @@
+#include
+#include
+
+double min = 1.0;
+double max = 0.0;
+double incr = 1.0;
+int constant = 0;
+int nsteps;
+char *format;
+
+void
+usage(void)
+{
+ fprint(2, "usage: seq [-fformat] [-w] [first [incr]] last\n");
+ exits("usage");
+}
+
+void
+buildfmt(void)
+{
+ int i;
+ char *dp;
+ int w, p, maxw, maxp;
+ static char fmt[16];
+ char buf[32];
+
+ format = "%g\n";
+ if(!constant)
+ return;
+ maxw = 0;
+ maxp = 0;
+ for(i=0; i<=nsteps; i++){
+ sprint(buf, "%g", min+i*incr);
+ if(strchr(buf, 'e')!=0)
+ return;
+ dp = strchr(buf,'.');
+ w = dp==0? strlen(buf): dp-buf;
+ p = dp==0? 0: strlen(strchr(buf,'.')+1);
+ if(w>maxw)
+ maxw = w;
+ if(p>maxp)
+ maxp = p;
+ }
+ if(maxp > 0)
+ maxw += maxp+1;
+ sprint(fmt,"%%%d.%df\n", maxw, maxp);
+ format = fmt;
+}
+
+void
+main(int argc, char *argv[]){
+ int i, j, n;
+ char buf[256], ffmt[4096];
+
+ ARGBEGIN{
+ case 'w':
+ constant++;
+ break;
+ case 'f':
+ format = ARGF();
+ if(format[strlen(format)-1] != '\n'){
+ sprint(ffmt, "%s\n", format);
+ format = ffmt;
+ }
+ break;
+ default:
+ goto out;
+ }ARGEND
+ out:
+ if(argc<1 || argc>3)
+ usage();
+ max = atof(argv[argc-1]);
+ if(argc > 1)
+ min = atof(argv[0]);
+ if(argc > 2)
+ incr = atof(argv[1]);
+ if(incr == 0){
+ fprint(2, "seq: zero increment\n");
+ exits("zero increment");
+ }
+ nsteps = (max-min)/incr+.5;
+ if(!format)
+ buildfmt();
+ for(i=0; i<=nsteps; i++){
+ n = sprint(buf, format, min+i*incr);
+ if(constant)
+ for(j=0; buf[j]==' '; j++)
+ buf[j] ='0';
+ write(1, buf, n);
+ }
+ exits(0);
+} |
| diff --git a/src/cmd/sha1sum.c b/src/cmd/sha1sum.c |
| t@@ -0,0 +1,61 @@
+#include
+#include
+#include
+#include
+
+static int
+digestfmt(Fmt *fmt)
+{
+ char buf[SHA1dlen*2+1];
+ uchar *p;
+ int i;
+
+ p = va_arg(fmt->args, uchar*);
+ for(i=0; i 0)
+ sha1(buf, n, nil, s);
+ sha1(nil, 0, digest, s);
+ if(name == nil)
+ print("%M\n", digest);
+ else
+ print("%M\t%s\n", digest, name);
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i, fd;
+
+ ARGBEGIN{
+ default:
+ fprint(2, "usage: sha1sum [file...]\n");
+ exits("usage");
+ }ARGEND
+
+ fmtinstall('M', digestfmt);
+
+ if(argc == 0)
+ sum(0, nil);
+ else for(i = 0; i < argc; i++){
+ fd = open(argv[i], OREAD);
+ if(fd < 0){
+ fprint(2, "sha1sum: can't open %s: %r\n", argv[i]);
+ continue;
+ }
+ sum(fd, argv[i]);
+ close(fd);
+ }
+ exits(nil);
+} |
| diff --git a/src/cmd/sleep.c b/src/cmd/sleep.c |
| t@@ -0,0 +1,13 @@
+#include
+#include
+
+void
+main(int argc, char *argv[])
+{
+ long secs;
+
+ if(argc>1)
+ for(secs = atol(argv[1]); secs > 0; secs--)
+ sleep(1000);
+ exits(0);
+} |
| diff --git a/src/cmd/sort.c b/src/cmd/sort.c |
| t@@ -0,0 +1,1767 @@
+#include
+#include
+#include
+
+/*
+bugs:
+ 00/ff for end of file can conflict with 00/ff characters
+*/
+
+enum
+{
+ Nline = 100000, /* default max number of lines saved in memory */
+ Nmerge = 10, /* max number of temporary files merged */
+ Nfield = 20, /* max number of argument fields */
+
+ Bflag = 1<<0, /* flags per field */
+ B1flag = 1<<1,
+
+ Dflag = 1<<2,
+ Fflag = 1<<3,
+ Gflag = 1<<4,
+ Iflag = 1<<5,
+ Mflag = 1<<6,
+ Nflag = 1<<7,
+ Rflag = 1<<8,
+ Wflag = 1<<9,
+
+ NSstart = 0, /* states for number to key decoding */
+ NSsign,
+ NSzero,
+ NSdigit,
+ NSpoint,
+ NSfract,
+ NSzerofract,
+ NSexp,
+ NSexpsign,
+ NSexpdigit,
+};
+
+typedef struct Line Line;
+typedef struct Key Key;
+typedef struct Merge Merge;
+typedef struct Field Field;
+
+struct Line
+{
+ Key* key;
+ int llen; /* always >= 1 */
+ uchar line[1]; /* always ends in '\n' */
+};
+
+struct Merge
+{
+ Key* key; /* copy of line->key so (Line*) looks like (Merge*) */
+ Line* line; /* line at the head of a merged temp file */
+ int fd; /* file descriptor */
+ Biobuf b; /* iobuf for reading a temp file */
+};
+
+struct Key
+{
+ int klen;
+ uchar key[1];
+};
+
+struct Field
+{
+ int beg1;
+ int beg2;
+ int end1;
+ int end2;
+
+ long flags;
+ uchar mapto[256];
+
+ void (*dokey)(Key*, uchar*, uchar*, Field*);
+};
+
+struct args
+{
+ char* ofile;
+ char* tname;
+ Rune tabchar;
+ char cflag;
+ char uflag;
+ char vflag;
+ int nfield;
+ int nfile;
+ Field field[Nfield];
+
+ Line** linep;
+ long nline; /* number of lines in this temp file */
+ long lineno; /* overall ordinal for -s option */
+ int ntemp;
+ long mline; /* max lines per file */
+} args;
+
+extern int latinmap[];
+extern Rune* month[12];
+
+void buildkey(Line*);
+void doargs(int, char*[]);
+void dofield(char*, int*, int*, int, int);
+void dofile(Biobuf*);
+void dokey_(Key*, uchar*, uchar*, Field*);
+void dokey_dfi(Key*, uchar*, uchar*, Field*);
+void dokey_gn(Key*, uchar*, uchar*, Field*);
+void dokey_m(Key*, uchar*, uchar*, Field*);
+void dokey_r(Key*, uchar*, uchar*, Field*);
+void done(char*);
+int kcmp(Key*, Key*);
+void makemapd(Field*);
+void makemapm(Field*);
+void mergefiles(int, int, Biobuf*);
+void mergeout(Biobuf*);
+void newfield(void);
+Line* newline(Biobuf*);
+void nomem(void);
+void notifyf(void*, char*);
+void printargs(void);
+void printout(Biobuf*);
+void setfield(int, int);
+uchar* skip(uchar*, int, int, int, int);
+void sort4(void*, ulong);
+char* tempfile(int);
+void tempout(void);
+void lineout(Biobuf*, Line*);
+
+void
+main(int argc, char *argv[])
+{
+ int i, f;
+ char *s;
+ Biobuf bbuf;
+
+ notify(notifyf); /**/
+ doargs(argc, argv);
+ if(args.vflag)
+ printargs();
+
+ for(i=1; ikey, l->key);
+ if(n > 0 || (n == 0 && args.uflag)) {
+ fprint(2, "sort: -c file not in sort\n"); /**/
+ done("order");
+ }
+ free(ol->key);
+ free(ol);
+ ol = l;
+ }
+ return;
+ }
+
+ if(args.linep == 0) {
+ args.linep = malloc(args.mline * sizeof(args.linep));
+ if(args.linep == 0)
+ nomem();
+ }
+ for(;;) {
+ l = newline(b);
+ if(l == 0)
+ break;
+ if(args.nline >= args.mline)
+ tempout();
+ args.linep[args.nline] = l;
+ args.nline++;
+ args.lineno++;
+ }
+}
+
+void
+notifyf(void *a, char *s)
+{
+ USED(a);
+ if(strcmp(s, "interrupt") == 0)
+ done(0);
+ if(strcmp(s, "hangup") == 0)
+ done(0);
+ if(strcmp(s, "kill") == 0)
+ done(0);
+ if(strncmp(s, "sys: write on closed pipe", 25) == 0)
+ done(0);
+ fprint(2, "sort: note: %s\n", s);
+ abort();
+}
+
+Line*
+newline(Biobuf *b)
+{
+ Line *l;
+ char *p;
+ int n, c;
+
+ p = Brdline(b, '\n');
+ n = Blinelen(b);
+ if(p == 0) {
+ if(n == 0)
+ return 0;
+ l = 0;
+ for(n=0;;) {
+ if((n & 31) == 0) {
+ l = realloc(l, sizeof(Line) +
+ (n+31)*sizeof(l->line[0]));
+ if(l == 0)
+ nomem();
+ }
+ c = Bgetc(b);
+ if(c < 0) {
+ fprint(2, "sort: newline added\n");
+ c = '\n';
+ }
+ l->line[n++] = c;
+ if(c == '\n')
+ break;
+ }
+ l->llen = n;
+ buildkey(l);
+ return l;
+ }
+ l = malloc(sizeof(Line) +
+ (n-1)*sizeof(l->line[0]));
+ if(l == 0)
+ nomem();
+ l->llen = n;
+ memmove(l->line, p, n);
+ buildkey(l);
+ return l;
+}
+
+void
+lineout(Biobuf *b, Line *l)
+{
+ int n, m;
+
+ n = l->llen;
+ m = Bwrite(b, l->line, n);
+ if(n != m)
+ exits("write");
+}
+
+void
+tempout(void)
+{
+ long n;
+ Line **lp, *l;
+ char *tf;
+ int f;
+ Biobuf tb;
+
+ sort4(args.linep, args.nline);
+ tf = tempfile(args.ntemp);
+ args.ntemp++;
+ f = create(tf, OWRITE, 0666);
+ if(f < 0) {
+ fprint(2, "sort: create %s: %r\n", tf);
+ done("create");
+ }
+
+ Binit(&tb, f, OWRITE);
+ lp = args.linep;
+ for(n=args.nline; n>0; n--) {
+ l = *lp++;
+ lineout(&tb, l);
+ free(l->key);
+ free(l);
+ }
+ args.nline = 0;
+ Bterm(&tb);
+ close(f);
+}
+
+void
+done(char *xs)
+{
+ int i;
+
+ for(i=0; i= nelem(file)-20) {
+ fprint(2, "temp file directory name is too long: %s\n", dir);
+ done("tdir");
+ }
+
+ if(pid == 0) {
+ pid = getpid();
+ if(pid == 0) {
+ pid = time(0);
+ if(pid == 0)
+ pid = 1;
+ }
+ }
+
+ sprint(file, "%s/sort.%.4d.%.4d", dir, pid%10000, n);
+ return file;
+}
+
+void
+mergeout(Biobuf *b)
+{
+ int n, i, f;
+ char *tf;
+ Biobuf tb;
+
+ for(i=0; i Nmerge) {
+ tf = tempfile(args.ntemp);
+ args.ntemp++;
+ f = create(tf, OWRITE, 0666);
+ if(f < 0) {
+ fprint(2, "sort: create %s: %r\n", tf);
+ done("create");
+ }
+ Binit(&tb, f, OWRITE);
+
+ n = Nmerge;
+ mergefiles(i, n, &tb);
+
+ Bterm(&tb);
+ close(f);
+ } else
+ mergefiles(i, n, b);
+ }
+}
+
+void
+mergefiles(int t, int n, Biobuf *b)
+{
+ Merge *m, *mp, **mmp;
+ Key *ok;
+ Line *l;
+ char *tf;
+ int i, f, nn;
+
+ mmp = malloc(n*sizeof(*mmp));
+ mp = malloc(n*sizeof(*mp));
+ if(mmp == 0 || mp == 0)
+ nomem();
+
+ nn = 0;
+ m = mp;
+ for(i=0; ifd = f;
+ Binit(&m->b, f, OREAD);
+ mmp[nn] = m;
+
+ l = newline(&m->b);
+ if(l == 0)
+ continue;
+ nn++;
+ m->line = l;
+ m->key = l->key;
+ }
+
+ ok = 0;
+ for(;;) {
+ sort4(mmp, nn);
+ m = *mmp;
+ if(nn == 0)
+ break;
+ for(;;) {
+ l = m->line;
+ if(args.uflag && ok && kcmp(ok, l->key) == 0) {
+ free(l->key);
+ free(l);
+ } else {
+ lineout(b, l);
+ if(ok)
+ free(ok);
+ ok = l->key;
+ free(l);
+ }
+
+ l = newline(&m->b);
+ if(l == 0) {
+ nn--;
+ mmp[0] = mmp[nn];
+ break;
+ }
+ m->line = l;
+ m->key = l->key;
+ if(nn > 1 && kcmp(mmp[0]->key, mmp[1]->key) > 0)
+ break;
+ }
+ }
+ if(ok)
+ free(ok);
+
+ m = mp;
+ for(i=0; ib);
+ close(m->fd);
+ }
+
+ free(mp);
+ free(mmp);
+}
+
+int
+kcmp(Key *ka, Key *kb)
+{
+ int n, m;
+
+ /*
+ * set n to length of smaller key
+ */
+ n = ka->klen;
+ m = kb->klen;
+ if(n > m)
+ n = m;
+ return memcmp(ka->key, kb->key, n);
+}
+
+void
+printout(Biobuf *b)
+{
+ long n;
+ Line **lp, *l;
+ Key *ok;
+
+ sort4(args.linep, args.nline);
+ lp = args.linep;
+ ok = 0;
+ for(n=args.nline; n>0; n--) {
+ l = *lp++;
+ if(args.uflag && ok && kcmp(ok, l->key) == 0)
+ continue;
+ lineout(b, l);
+ ok = l->key;
+ }
+}
+
+void
+setfield(int n, int c)
+{
+ Field *f;
+
+ f = &args.field[n];
+ switch(c) {
+ default:
+ fprint(2, "sort: unknown option: field.%C\n", c);
+ done("option");
+ case 'b': /* skip blanks */
+ f->flags |= Bflag;
+ break;
+ case 'd': /* directory order */
+ f->flags |= Dflag;
+ break;
+ case 'f': /* fold case */
+ f->flags |= Fflag;
+ break;
+ case 'g': /* floating point -n case */
+ f->flags |= Gflag;
+ break;
+ case 'i': /* ignore non-ascii */
+ f->flags |= Iflag;
+ break;
+ case 'M': /* month */
+ f->flags |= Mflag;
+ break;
+ case 'n': /* numbers */
+ f->flags |= Nflag;
+ break;
+ case 'r': /* reverse */
+ f->flags |= Rflag;
+ break;
+ case 'w': /* ignore white */
+ f->flags |= Wflag;
+ break;
+ }
+}
+
+void
+dofield(char *s, int *n1, int *n2, int off1, int off2)
+{
+ int c, n;
+
+ c = *s++;
+ if(c >= '0' && c <= '9') {
+ n = 0;
+ while(c >= '0' && c <= '9') {
+ n = n*10 + (c-'0');
+ c = *s++;
+ }
+ n -= off1; /* posix committee: rot in hell */
+ if(n < 0) {
+ fprint(2, "sort: field offset must be positive\n");
+ done("option");
+ }
+ *n1 = n;
+ }
+ if(c == '.') {
+ c = *s++;
+ if(c >= '0' && c <= '9') {
+ n = 0;
+ while(c >= '0' && c <= '9') {
+ n = n*10 + (c-'0');
+ c = *s++;
+ }
+ n -= off2;
+ if(n < 0) {
+ fprint(2, "sort: character offset must be positive\n");
+ done("option");
+ }
+ *n2 = n;
+ }
+ }
+ while(c != 0) {
+ setfield(args.nfield, c);
+ c = *s++;
+ }
+}
+
+void
+printargs(void)
+{
+ int i, n;
+ Field *f;
+ char *prefix;
+
+ fprint(2, "sort");
+ for(i=0; i<=args.nfield; i++) {
+ f = &args.field[i];
+ prefix = " -";
+ if(i) {
+ n = f->beg1;
+ if(n >= 0)
+ fprint(2, " +%d", n);
+ else
+ fprint(2, " +*");
+ n = f->beg2;
+ if(n >= 0)
+ fprint(2, ".%d", n);
+ else
+ fprint(2, ".*");
+
+ if(f->flags & B1flag)
+ fprint(2, "b");
+
+ n = f->end1;
+ if(n >= 0)
+ fprint(2, " -%d", n);
+ else
+ fprint(2, " -*");
+ n = f->end2;
+ if(n >= 0)
+ fprint(2, ".%d", n);
+ else
+ fprint(2, ".*");
+ prefix = "";
+ }
+ if(f->flags & Bflag)
+ fprint(2, "%sb", prefix);
+ if(f->flags & Dflag)
+ fprint(2, "%sd", prefix);
+ if(f->flags & Fflag)
+ fprint(2, "%sf", prefix);
+ if(f->flags & Gflag)
+ fprint(2, "%sg", prefix);
+ if(f->flags & Iflag)
+ fprint(2, "%si", prefix);
+ if(f->flags & Mflag)
+ fprint(2, "%sM", prefix);
+ if(f->flags & Nflag)
+ fprint(2, "%sn", prefix);
+ if(f->flags & Rflag)
+ fprint(2, "%sr", prefix);
+ if(f->flags & Wflag)
+ fprint(2, "%sw", prefix);
+ }
+ if(args.cflag)
+ fprint(2, " -c");
+ if(args.uflag)
+ fprint(2, " -u");
+ if(args.ofile)
+ fprint(2, " -o %s", args.ofile);
+ if(args.mline != Nline)
+ fprint(2, " -l %ld", args.mline);
+ fprint(2, "\n");
+}
+
+void
+newfield(void)
+{
+ int n;
+ Field *f;
+
+ n = args.nfield + 1;
+ if(n >= Nfield) {
+ fprint(2, "sort: too many fields specified\n");
+ done("option");
+ }
+ args.nfield = n;
+ f = &args.field[n];
+ f->beg1 = -1;
+ f->beg2 = -1;
+ f->end1 = -1;
+ f->end2 = -1;
+}
+
+void
+doargs(int argc, char *argv[])
+{
+ int i, c, hadplus;
+ char *s, *p, *q;
+ Field *f;
+
+ hadplus = 0;
+ args.mline = Nline;
+ for(i=1; i= '0' && c <= '9')) {
+ if(!hadplus)
+ newfield();
+ f = &args.field[args.nfield];
+ dofield(s, &f->end1, &f->end2, 0, 0);
+ hadplus = 0;
+ continue;
+ }
+
+ while(c = *s++)
+ switch(c) {
+ case '-': /* end of options */
+ i = argc;
+ continue;
+ case 'T': /* temp directory */
+ if(*s == 0) {
+ i++;
+ if(i < argc) {
+ args.tname = argv[i];
+ argv[i] = 0;
+ }
+ } else
+ args.tname = s;
+ s = strchr(s, 0);
+ break;
+ case 'o': /* output file */
+ if(*s == 0) {
+ i++;
+ if(i < argc) {
+ args.ofile = argv[i];
+ argv[i] = 0;
+ }
+ } else
+ args.ofile = s;
+ s = strchr(s, 0);
+ break;
+ case 'k': /* posix key (what were they thinking?) */
+ p = 0;
+ if(*s == 0) {
+ i++;
+ if(i < argc) {
+ p = argv[i];
+ argv[i] = 0;
+ }
+ } else
+ p = s;
+ s = strchr(s, 0);
+ if(p == 0)
+ break;
+
+ newfield();
+ q = strchr(p, ',');
+ if(q)
+ *q++ = 0;
+ f = &args.field[args.nfield];
+ dofield(p, &f->beg1, &f->beg2, 1, 1);
+ if(f->flags & Bflag) {
+ f->flags |= B1flag;
+ f->flags &= ~Bflag;
+ }
+ if(q) {
+ dofield(q, &f->end1, &f->end2, 1, 0);
+ if(f->end2 <= 0)
+ f->end1++;
+ }
+ hadplus = 0;
+ break;
+ case 't': /* tab character */
+ if(*s == 0) {
+ i++;
+ if(i < argc) {
+ chartorune(&args.tabchar, argv[i]);
+ argv[i] = 0;
+ }
+ } else
+ s += chartorune(&args.tabchar, s);
+ if(args.tabchar == '\n') {
+ fprint(2, "aw come on, rob\n");
+ done("rob");
+ }
+ break;
+ case 'c': /* check order */
+ args.cflag = 1;
+ break;
+ case 'u': /* unique */
+ args.uflag = 1;
+ break;
+ case 'v': /* debugging noise */
+ args.vflag = 1;
+ break;
+ case 'l':
+ if(*s == 0) {
+ i++;
+ if(i < argc) {
+ args.mline = atol(argv[i]);
+ argv[i] = 0;
+ }
+ } else
+ args.mline = atol(s);
+ s = strchr(s, 0);
+ break;
+
+ case 'M': /* month */
+ case 'b': /* skip blanks */
+ case 'd': /* directory order */
+ case 'f': /* fold case */
+ case 'g': /* floating numbers */
+ case 'i': /* ignore non-ascii */
+ case 'n': /* numbers */
+ case 'r': /* reverse */
+ case 'w': /* ignore white */
+ if(args.nfield > 0)
+ fprint(2, "sort: global field set after -k\n");
+ setfield(0, c);
+ break;
+ case 'm':
+ /* option m silently ignored but required by posix */
+ break;
+ default:
+ fprint(2, "sort: unknown option: -%C\n", c);
+ done("option");
+ }
+ continue;
+ }
+ if(c == '+') {
+ argv[i] = 0; /* clobber args processed */
+ c = *s;
+ if(c == '.' || (c >= '0' && c <= '9')) {
+ newfield();
+ f = &args.field[args.nfield];
+ dofield(s, &f->beg1, &f->beg2, 0, 0);
+ if(f->flags & Bflag) {
+ f->flags |= B1flag;
+ f->flags &= ~Bflag;
+ }
+ hadplus = 1;
+ continue;
+ }
+ fprint(2, "sort: unknown option: +%C\n", c);
+ done("option");
+ }
+ args.nfile++;
+ }
+
+ for(i=0; i<=args.nfield; i++) {
+ f = &args.field[i];
+
+ /*
+ * global options apply to fields that
+ * specify no options
+ */
+ if(f->flags == 0) {
+ f->flags = args.field[0].flags;
+ if(args.field[0].flags & Bflag)
+ f->flags |= B1flag;
+ }
+
+
+ /*
+ * build buildkey specification
+ */
+ switch(f->flags & ~(Bflag|B1flag)) {
+ default:
+ fprint(2, "sort: illegal combination of flags: %lx\n", f->flags);
+ done("option");
+ case 0:
+ f->dokey = dokey_;
+ break;
+ case Rflag:
+ f->dokey = dokey_r;
+ break;
+ case Gflag:
+ case Nflag:
+ case Gflag|Nflag:
+ case Gflag|Rflag:
+ case Nflag|Rflag:
+ case Gflag|Nflag|Rflag:
+ f->dokey = dokey_gn;
+ break;
+ case Mflag:
+ case Mflag|Rflag:
+ f->dokey = dokey_m;
+ makemapm(f);
+ break;
+ case Dflag:
+ case Dflag|Fflag:
+ case Dflag|Fflag|Iflag:
+ case Dflag|Fflag|Iflag|Rflag:
+ case Dflag|Fflag|Iflag|Rflag|Wflag:
+ case Dflag|Fflag|Iflag|Wflag:
+ case Dflag|Fflag|Rflag:
+ case Dflag|Fflag|Rflag|Wflag:
+ case Dflag|Fflag|Wflag:
+ case Dflag|Iflag:
+ case Dflag|Iflag|Rflag:
+ case Dflag|Iflag|Rflag|Wflag:
+ case Dflag|Iflag|Wflag:
+ case Dflag|Rflag:
+ case Dflag|Rflag|Wflag:
+ case Dflag|Wflag:
+ case Fflag:
+ case Fflag|Iflag:
+ case Fflag|Iflag|Rflag:
+ case Fflag|Iflag|Rflag|Wflag:
+ case Fflag|Iflag|Wflag:
+ case Fflag|Rflag:
+ case Fflag|Rflag|Wflag:
+ case Fflag|Wflag:
+ case Iflag:
+ case Iflag|Rflag:
+ case Iflag|Rflag|Wflag:
+ case Iflag|Wflag:
+ case Wflag:
+ f->dokey = dokey_dfi;
+ makemapd(f);
+ break;
+ }
+ }
+
+ /*
+ * random spot checks
+ */
+ if(args.nfile > 1 && args.cflag) {
+ fprint(2, "sort: -c can have at most one input file\n");
+ done("option");
+ }
+ return;
+}
+
+uchar*
+skip(uchar *l, int n1, int n2, int bflag, int endfield)
+{
+ int i, c, tc;
+ Rune r;
+
+ if(endfield && n1 < 0)
+ return 0;
+
+ c = *l++;
+ tc = args.tabchar;
+ if(tc) {
+ if(tc < Runeself) {
+ for(i=n1; i>0; i--) {
+ while(c != tc) {
+ if(c == '\n')
+ return 0;
+ c = *l++;
+ }
+ if(!(endfield && i == 1))
+ c = *l++;
+ }
+ } else {
+ l--;
+ l += chartorune(&r, (char*)l);
+ for(i=n1; i>0; i--) {
+ while(r != tc) {
+ if(r == '\n')
+ return 0;
+ l += chartorune(&r, (char*)l);
+ }
+ if(!(endfield && i == 1))
+ l += chartorune(&r, (char*)l);
+ }
+ c = r;
+ }
+ } else {
+ for(i=n1; i>0; i--) {
+ while(c == ' ' || c == '\t')
+ c = *l++;
+ while(c != ' ' && c != '\t') {
+ if(c == '\n')
+ return 0;
+ c = *l++;
+ }
+ }
+ }
+
+ if(bflag)
+ while(c == ' ' || c == '\t')
+ c = *l++;
+
+ l--;
+ for(i=n2; i>0; i--) {
+ c = *l;
+ if(c < Runeself) {
+ if(c == '\n')
+ return 0;
+ l++;
+ continue;
+ }
+ l += chartorune(&r, (char*)l);
+ }
+ return l;
+}
+
+void
+dokey_gn(Key *k, uchar *lp, uchar *lpe, Field *f)
+{
+ uchar *kp;
+ int c, cl, dp;
+ int state, nzero, exp, expsign, rflag;
+
+ cl = k->klen + 3;
+ kp = k->key + cl; /* skip place for sign, exponent[2] */
+
+ nzero = 0; /* number of trailing zeros */
+ exp = 0; /* value of the exponent */
+ expsign = 0; /* sign of the exponent */
+ dp = 0x4040; /* location of decimal point */
+ rflag = f->flags&Rflag; /* xor of rflag and - sign */
+ state = NSstart;
+
+ for(;; lp++) {
+ if(lp >= lpe)
+ break;
+ c = *lp;
+
+ if(c == ' ' || c == '\t') {
+ switch(state) {
+ case NSstart:
+ case NSsign:
+ continue;
+ }
+ break;
+ }
+ if(c == '+' || c == '-') {
+ switch(state) {
+ case NSstart:
+ state = NSsign;
+ if(c == '-')
+ rflag = !rflag;
+ continue;
+ case NSexp:
+ state = NSexpsign;
+ if(c == '-')
+ expsign = 1;
+ continue;
+ }
+ break;
+ }
+ if(c == '0') {
+ switch(state) {
+ case NSdigit:
+ if(rflag)
+ c = ~c;
+ *kp++ = c;
+ cl++;
+ nzero++;
+ dp++;
+ state = NSdigit;
+ continue;
+ case NSfract:
+ if(rflag)
+ c = ~c;
+ *kp++ = c;
+ cl++;
+ nzero++;
+ state = NSfract;
+ continue;
+ case NSstart:
+ case NSsign:
+ case NSzero:
+ state = NSzero;
+ continue;
+ case NSzerofract:
+ case NSpoint:
+ dp--;
+ state = NSzerofract;
+ continue;
+ case NSexpsign:
+ case NSexp:
+ case NSexpdigit:
+ exp = exp*10 + (c - '0');
+ state = NSexpdigit;
+ continue;
+ }
+ break;
+ }
+ if(c >= '1' && c <= '9') {
+ switch(state) {
+ case NSzero:
+ case NSstart:
+ case NSsign:
+ case NSdigit:
+ if(rflag)
+ c = ~c;
+ *kp++ = c;
+ cl++;
+ nzero = 0;
+ dp++;
+ state = NSdigit;
+ continue;
+ case NSzerofract:
+ case NSpoint:
+ case NSfract:
+ if(rflag)
+ c = ~c;
+ *kp++ = c;
+ cl++;
+ nzero = 0;
+ state = NSfract;
+ continue;
+ case NSexpsign:
+ case NSexp:
+ case NSexpdigit:
+ exp = exp*10 + (c - '0');
+ state = NSexpdigit;
+ continue;
+ }
+ break;
+ }
+ if(c == '.') {
+ switch(state) {
+ case NSstart:
+ case NSsign:
+ state = NSpoint;
+ continue;
+ case NSzero:
+ state = NSzerofract;
+ continue;
+ case NSdigit:
+ state = NSfract;
+ continue;
+ }
+ break;
+ }
+ if((f->flags & Gflag) && (c == 'e' || c == 'E')) {
+ switch(state) {
+ case NSdigit:
+ case NSfract:
+ state = NSexp;
+ continue;
+ }
+ break;
+ }
+ break;
+ }
+
+ switch(state) {
+ /*
+ * result is zero
+ */
+ case NSstart:
+ case NSsign:
+ case NSzero:
+ case NSzerofract:
+ case NSpoint:
+ kp = k->key + k->klen;
+ k->klen += 2;
+ kp[0] = 0x20; /* between + and - */
+ kp[1] = 0;
+ return;
+ /*
+ * result has exponent
+ */
+ case NSexpsign:
+ case NSexp:
+ case NSexpdigit:
+ if(expsign)
+ exp = -exp;
+ dp += exp;
+
+ /*
+ * result is fixed point number
+ */
+ case NSdigit:
+ case NSfract:
+ kp -= nzero;
+ cl -= nzero;
+ break;
+ }
+
+ /*
+ * end of number
+ */
+ c = 0;
+ if(rflag)
+ c = ~c;
+ *kp = c;
+
+ /*
+ * sign and exponent
+ */
+ c = 0x30;
+ if(rflag) {
+ c = 0x10;
+ dp = ~dp;
+ }
+ kp = k->key + k->klen;
+ kp[0] = c;
+ kp[1] = (dp >> 8);
+ kp[2] = dp;
+ k->klen = cl+1;
+}
+
+void
+dokey_m(Key *k, uchar *lp, uchar *lpe, Field *f)
+{
+ uchar *kp;
+ Rune r, place[3];
+ int c, cl, pc;
+ int rflag;
+
+ rflag = f->flags&Rflag;
+ pc = 0;
+
+ cl = k->klen;
+ kp = k->key + cl;
+
+ for(;;) {
+ /*
+ * get the character
+ */
+ if(lp >= lpe)
+ break;
+ c = *lp;
+ if(c >= Runeself) {
+ lp += chartorune(&r, (char*)lp);
+ c = r;
+ } else
+ lp++;
+
+ if(c < nelem(f->mapto)) {
+ c = f->mapto[c];
+ if(c == 0)
+ continue;
+ }
+ place[pc++] = c;
+ if(pc < 3)
+ continue;
+ for(c=11; c>=0; c--)
+ if(memcmp(month[c], place, sizeof(place)) == 0)
+ break;
+ c += 10;
+ if(rflag)
+ c = ~c;
+ *kp++ = c;
+ cl++;
+ break;
+ }
+
+ c = 0;
+ if(rflag)
+ c = ~c;
+ *kp = c;
+ k->klen = cl+1;
+}
+
+void
+dokey_dfi(Key *k, uchar *lp, uchar *lpe, Field *f)
+{
+ uchar *kp;
+ Rune r;
+ int c, cl, n, rflag;
+
+ cl = k->klen;
+ kp = k->key + cl;
+ rflag = f->flags & Rflag;
+
+ for(;;) {
+ /*
+ * get the character
+ */
+ if(lp >= lpe)
+ break;
+ c = *lp;
+ if(c >= Runeself) {
+ lp += chartorune(&r, (char*)lp);
+ c = r;
+ } else
+ lp++;
+
+ /*
+ * do the various mappings.
+ * the common case is handled
+ * completely by the table.
+ */
+ if(c != 0 && c < Runeself) {
+ c = f->mapto[c];
+ if(c) {
+ *kp++ = c;
+ cl++;
+ }
+ continue;
+ }
+
+ /*
+ * for characters out of range,
+ * the table does not do Rflag.
+ * ignore is based on mapto[255]
+ */
+ if(c != 0 && c < nelem(f->mapto)) {
+ c = f->mapto[c];
+ if(c == 0)
+ continue;
+ } else
+ if(f->mapto[nelem(f->mapto)-1] == 0)
+ continue;
+
+ /*
+ * put it in the key
+ */
+ r = c;
+ n = runetochar((char*)kp, &r);
+ kp += n;
+ cl += n;
+ if(rflag)
+ while(n > 0) {
+ kp[-n] = ~kp[-n];
+ n--;
+ }
+ }
+
+ /*
+ * end of key
+ */
+ k->klen = cl+1;
+ if(rflag) {
+ *kp = ~0;
+ return;
+ }
+ *kp = 0;
+}
+
+void
+dokey_r(Key *k, uchar *lp, uchar *lpe, Field *f)
+{
+ int cl, n;
+ uchar *kp;
+
+ USED(f);
+ n = lpe - lp;
+ if(n < 0)
+ n = 0;
+ cl = k->klen;
+ kp = k->key + cl;
+ k->klen = cl+n+1;
+
+ lpe -= 3;
+ while(lp < lpe) {
+ kp[0] = ~lp[0];
+ kp[1] = ~lp[1];
+ kp[2] = ~lp[2];
+ kp[3] = ~lp[3];
+ kp += 4;
+ lp += 4;
+ }
+
+ lpe += 3;
+ while(lp < lpe)
+ *kp++ = ~*lp++;
+ *kp = ~0;
+}
+
+void
+dokey_(Key *k, uchar *lp, uchar *lpe, Field *f)
+{
+ int n, cl;
+ uchar *kp;
+
+ USED(f);
+ n = lpe - lp;
+ if(n < 0)
+ n = 0;
+ cl = k->klen;
+ kp = k->key + cl;
+ k->klen = cl+n+1;
+ memmove(kp, lp, n);
+ kp[n] = 0;
+}
+
+void
+buildkey(Line *l)
+{
+ Key *k;
+ uchar *lp, *lpe;
+ int ll, kl, cl, i, n;
+ Field *f;
+
+ ll = l->llen - 1;
+ kl = 0; /* allocated length */
+ cl = 0; /* current length */
+ k = 0;
+
+ for(i=1; i<=args.nfield; i++) {
+ f = &args.field[i];
+ lp = skip(l->line, f->beg1, f->beg2, f->flags&B1flag, 0);
+ if(lp == 0)
+ lp = l->line + ll;
+ lpe = skip(l->line, f->end1, f->end2, f->flags&Bflag, 1);
+ if(lpe == 0)
+ lpe = l->line + ll;
+ n = (lpe - lp) + 1;
+ if(n <= 0)
+ n = 1;
+ if(cl+(n+4) > kl) {
+ kl = cl+(n+4);
+ k = realloc(k, sizeof(Key) +
+ (kl-1)*sizeof(k->key[0]));
+ if(k == 0)
+ nomem();
+ }
+ k->klen = cl;
+ (*f->dokey)(k, lp, lpe, f);
+ cl = k->klen;
+ }
+
+ /*
+ * global comparisons
+ */
+ if(!(args.uflag && cl > 0)) {
+ f = &args.field[0];
+ if(cl+(ll+4) > kl) {
+ kl = cl+(ll+4);
+ k = realloc(k, sizeof(Key) +
+ (kl-1)*sizeof(k->key[0]));
+ if(k == 0)
+ nomem();
+ }
+ k->klen = cl;
+ (*f->dokey)(k, l->line, l->line+ll, f);
+ cl = k->klen;
+ }
+
+ l->key = k;
+ k->klen = cl;
+
+ if(args.vflag) {
+ write(2, l->line, l->llen);
+ for(i=0; iklen; i++) {
+ fprint(2, " %.2x", k->key[i]);
+ if(k->key[i] == 0x00 || k->key[i] == 0xff)
+ fprint(2, "\n");
+ }
+ }
+}
+
+void
+makemapm(Field *f)
+{
+ int i, c;
+
+ for(i=0; imapto); i++) {
+ c = 1;
+ if(i == ' ' || i == '\t')
+ c = 0;
+ if(i >= 'a' && i <= 'z')
+ c = i + ('A' - 'a');
+ if(i >= 'A' && i <= 'Z')
+ c = i;
+ f->mapto[i] = c;
+ if(args.vflag) {
+ if((i & 15) == 0)
+ fprint(2, " ");
+ fprint(2, " %.2x", c);
+ if((i & 15) == 15)
+ fprint(2, "\n");
+ }
+ }
+}
+
+void
+makemapd(Field *f)
+{
+ int i, j, c;
+
+ for(i=0; imapto); i++) {
+ c = i;
+ if(f->flags & Iflag)
+ if(c < 040 || c > 0176)
+ c = -1;
+ if((f->flags & Wflag) && c >= 0)
+ if(c == ' ' || c == '\t')
+ c = -1;
+ if((f->flags & Dflag) && c >= 0)
+ if(!(c == ' ' || c == '\t' ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9'))) {
+ for(j=0; latinmap[j]; j+=3)
+ if(c == latinmap[j+0] ||
+ c == latinmap[j+1])
+ break;
+ if(latinmap[j] == 0)
+ c = -1;
+ }
+ if((f->flags & Fflag) && c >= 0) {
+ if(c >= 'a' && c <= 'z')
+ c += 'A' - 'a';
+ for(j=0; latinmap[j]; j+=3)
+ if(c == latinmap[j+0] ||
+ c == latinmap[j+1]) {
+ c = latinmap[j+2];
+ break;
+ }
+ }
+ if((f->flags & Rflag) && c >= 0 && i > 0 && i < Runeself)
+ c = ~c & 0xff;
+ if(c < 0)
+ c = 0;
+ f->mapto[i] = c;
+ if(args.vflag) {
+ if((i & 15) == 0)
+ fprint(2, " ");
+ fprint(2, " %.2x", c);
+ if((i & 15) == 15)
+ fprint(2, "\n");
+ }
+ }
+}
+
+int latinmap[] =
+{
+/* lcase ucase fold */
+ 0xe0, 0xc0, 0x41, /* L'à', L'À', L'A', */
+ 0xe1, 0xc1, 0x41, /* L'á', L'Á', L'A', */
+ 0xe2, 0xc2, 0x41, /* L'â', L'Â', L'A', */
+ 0xe4, 0xc4, 0x41, /* L'ä', L'Ä', L'A', */
+ 0xe3, 0xc3, 0x41, /* L'ã', L'Ã', L'A', */
+ 0xe5, 0xc5, 0x41, /* L'å', L'Å', L'A', */
+ 0xe8, 0xc8, 0x45, /* L'è', L'È', L'E', */
+ 0xe9, 0xc9, 0x45, /* L'é', L'É', L'E', */
+ 0xea, 0xca, 0x45, /* L'ê', L'Ê', L'E', */
+ 0xeb, 0xcb, 0x45, /* L'ë', L'Ë', L'E', */
+ 0xec, 0xcc, 0x49, /* L'ì', L'Ì', L'I', */
+ 0xed, 0xcd, 0x49, /* L'í', L'Í', L'I', */
+ 0xee, 0xce, 0x49, /* L'î', L'Î', L'I', */
+ 0xef, 0xcf, 0x49, /* L'ï', L'Ï', L'I', */
+ 0xf2, 0xd2, 0x4f, /* L'ò', L'Ò', L'O', */
+ 0xf3, 0xd3, 0x4f, /* L'ó', L'Ó', L'O', */
+ 0xf4, 0xd4, 0x4f, /* L'ô', L'Ô', L'O', */
+ 0xf6, 0xd6, 0x4f, /* L'ö', L'Ö', L'O', */
+ 0xf5, 0xd5, 0x4f, /* L'õ', L'Õ', L'O', */
+ 0xf8, 0xd8, 0x4f, /* L'ø', L'Ø', L'O', */
+ 0xf9, 0xd9, 0x55, /* L'ù', L'Ù', L'U', */
+ 0xfa, 0xda, 0x55, /* L'ú', L'Ú', L'U', */
+ 0xfb, 0xdb, 0x55, /* L'û', L'Û', L'U', */
+ 0xfc, 0xdc, 0x55, /* L'ü', L'Ü', L'U', */
+ 0xe6, 0xc6, 0x41, /* L'æ', L'Æ', L'A', */
+ 0xf0, 0xd0, 0x44, /* L'ð', L'Ð', L'D', */
+ 0xf1, 0xd1, 0x4e, /* L'ñ', L'Ñ', L'N', */
+ 0xfd, 0xdd, 0x59, /* L'ý', L'Ý', L'Y', */
+ 0xe7, 0xc7, 0x43, /* L'ç', L'Ç', L'C', */
+ 0,
+};
+
+Rune LJAN[] = { 'J', 'A', 'N', 0 };
+Rune LFEB[] = { 'F', 'E', 'B', 0 };
+Rune LMAR[] = { 'M', 'A', 'R', 0 };
+Rune LAPR[] = { 'A', 'P', 'R', 0 };
+Rune LMAY[] = { 'M', 'A', 'Y', 0 };
+Rune LJUN[] = { 'J', 'U', 'N', 0 };
+Rune LJUL[] = { 'J', 'U', 'L', 0 };
+Rune LAUG[] = { 'A', 'U', 'G', 0 };
+Rune LSEP[] = { 'S', 'E', 'P', 0 };
+Rune LOCT[] = { 'O', 'C', 'T', 0 };
+Rune LNOV[] = { 'N', 'O', 'V', 0 };
+Rune LDEC[] = { 'D', 'E', 'C', 0 };
+
+Rune* month[12] =
+{
+ LJAN,
+ LFEB,
+ LMAR,
+ LAPR,
+ LMAY,
+ LJUN,
+ LJUL,
+ LAUG,
+ LSEP,
+ LOCT,
+ LNOV,
+ LDEC,
+};
+
+/************** radix sort ***********/
+
+enum
+{
+ Threshold = 14,
+};
+
+void rsort4(Key***, ulong, int);
+void bsort4(Key***, ulong, int);
+
+void
+sort4(void *a, ulong n)
+{
+ if(n > Threshold)
+ rsort4((Key***)a, n, 0);
+ else
+ bsort4((Key***)a, n, 0);
+}
+
+void
+rsort4(Key ***a, ulong n, int b)
+{
+ Key ***ea, ***t, ***u, **t1, **u1, *k;
+ Key ***part[257];
+ static long count[257];
+ long clist[257+257], *cp, *cp1;
+ int c, lowc, higc;
+
+ /*
+ * pass 1 over all keys,
+ * count the number of each key[b].
+ * find low count and high count.
+ */
+ lowc = 256;
+ higc = 0;
+ ea = a+n;
+ for(t=a; tklen;
+ if(b >= n) {
+ count[256]++;
+ continue;
+ }
+ c = k->key[b];
+ n = count[c]++;
+ if(n == 0) {
+ if(c < lowc)
+ lowc = c;
+ if(c > higc)
+ higc = c;
+ }
+ }
+
+ /*
+ * pass 2 over all counts,
+ * put partition pointers in part[c].
+ * save compacted indexes and counts
+ * in clist[].
+ */
+ t = a;
+ n = count[256];
+ clist[0] = n;
+ part[256] = t;
+ t += n;
+
+ cp1 = clist+1;
+ cp = count+lowc;
+ for(c=lowc; c<=higc; c++,cp++) {
+ n = *cp;
+ if(n) {
+ cp1[0] = n;
+ cp1[1] = c;
+ cp1 += 2;
+ part[c] = t;
+ t += n;
+ }
+ }
+ *cp1 = 0;
+
+ /*
+ * pass 3 over all counts.
+ * chase lowest pointer in each partition
+ * around a permutation until it comes
+ * back and is stored where it started.
+ * static array, count[], should be
+ * reduced to zero entries except maybe
+ * count[256].
+ */
+ for(cp1=clist+1; cp1[0]; cp1+=2) {
+ c = cp1[1];
+ cp = count+c;
+ while(*cp) {
+ t1 = *part[c];
+ for(;;) {
+ k = *t1;
+ n = 256;
+ if(b < k->klen)
+ n = k->key[b];
+ u = part[n]++;
+ count[n]--;
+ u1 = *u;
+ *u = t1;
+ if(n == c)
+ break;
+ t1 = u1;
+ }
+ }
+ }
+
+ /*
+ * pass 4 over all partitions.
+ * call recursively.
+ */
+ b++;
+ t = a + clist[0];
+ count[256] = 0;
+ for(cp1=clist+1; n=cp1[0]; cp1+=2) {
+ if(n > Threshold)
+ rsort4(t, n, b);
+ else
+ if(n > 1)
+ bsort4(t, n, b);
+ t += n;
+ }
+}
+
+/*
+ * bubble sort to pick up
+ * the pieces.
+ */
+void
+bsort4(Key ***a, ulong n, int b)
+{
+ Key ***i, ***j, ***k, ***l, **t;
+ Key *ka, *kb;
+ int n1, n2;
+
+ l = a+n;
+ j = a;
+
+loop:
+ i = j;
+ j++;
+ if(j >= l)
+ return;
+
+ ka = **i;
+ kb = **j;
+ n1 = ka->klen - b;
+ n2 = kb->klen - b;
+ if(n1 > n2)
+ n1 = n2;
+ if(n1 <= 0)
+ goto loop;
+ n2 = ka->key[b] - kb->key[b];
+ if(n2 == 0)
+ n2 = memcmp(ka->key+b, kb->key+b, n1);
+ if(n2 <= 0)
+ goto loop;
+
+ for(;;) {
+ k = i+1;
+
+ t = *k;
+ *k = *i;
+ *i = t;
+
+ if(i <= a)
+ goto loop;
+
+ i--;
+ ka = **i;
+ kb = *t;
+ n1 = ka->klen - b;
+ n2 = kb->klen - b;
+ if(n1 > n2)
+ n1 = n2;
+ if(n1 <= 0)
+ goto loop;
+ n2 = ka->key[b] - kb->key[b];
+ if(n2 == 0)
+ n2 = memcmp(ka->key+b, kb->key+b, n1);
+ if(n2 <= 0)
+ goto loop;
+ }
+} |
| diff --git a/src/cmd/split.c b/src/cmd/split.c |
| t@@ -0,0 +1,189 @@
+#include
+#include
+#include
+#include
+#include
+
+char digit[] = "0123456789";
+char *suffix = "";
+char *stem = "x";
+char suff[] = "aa";
+char name[200];
+Biobuf bout;
+Biobuf *output = &bout;
+
+extern int nextfile(void);
+extern int matchfile(Resub*);
+extern void openf(void);
+extern char *fold(char*,int);
+extern void usage(void);
+extern void badexp(void);
+
+void
+main(int argc, char *argv[])
+{
+ Reprog *exp;
+ char *pattern = 0;
+ int n = 1000;
+ char *line;
+ int xflag = 0;
+ int iflag = 0;
+ Biobuf bin;
+ Biobuf *b = &bin;
+ char buf[256];
+
+ ARGBEGIN {
+ case 'l':
+ case 'n':
+ n=atoi(EARGF(usage()));
+ break;
+ case 'e':
+ pattern = strdup(EARGF(usage()));
+ break;
+ case 'f':
+ stem = strdup(EARGF(usage()));
+ break;
+ case 's':
+ suffix = strdup(EARGF(usage()));
+ break;
+ case 'x':
+ xflag++;
+ break;
+ case 'i':
+ iflag++;
+ break;
+ default:
+ usage();
+ break;
+
+ } ARGEND;
+
+ if(argc < 0 || argc > 1)
+ usage();
+
+ if(argc != 0) {
+ b = Bopen(argv[0], OREAD);
+ if(b == nil) {
+ fprint(2, "split: can't open %s: %r\n", argv[0]);
+ exits("open");
+ }
+ } else
+ Binit(b, 0, OREAD);
+
+ if(pattern) {
+ if(!(exp = regcomp(iflag? fold(pattern,strlen(pattern)): pattern)))
+ badexp();
+ while((line=Brdline(b,'\n')) != 0) {
+ Resub match[2];
+ memset(match, 0, sizeof match);
+ line[Blinelen(b)-1] = 0;
+ if(regexec(exp,iflag?fold(line,Blinelen(b)-1):line,match,2)) {
+ if(matchfile(match) && xflag)
+ continue;
+ } else if(output == 0)
+ nextfile(); /* at most once */
+ Bwrite(output, line, Blinelen(b)-1);
+ Bputc(output, '\n');
+ }
+ } else {
+ int linecnt = n;
+
+ while((line=Brdline(b,'\n')) != 0) {
+ if(++linecnt > n) {
+ nextfile();
+ linecnt = 1;
+ }
+ Bwrite(output, line, Blinelen(b));
+ }
+
+ /*
+ * in case we didn't end with a newline, tack whatever's
+ * left onto the last file
+ */
+ while((n = Bread(b, buf, sizeof(buf))) > 0)
+ Bwrite(output, buf, n);
+ }
+ if(b != nil)
+ Bterm(b);
+ exits(0);
+}
+
+int
+nextfile(void)
+{
+ static int canopen = 1;
+ if(suff[0] > 'z') {
+ if(canopen)
+ fprint(2, "split: file %szz not split\n",stem);
+ canopen = 0;
+ } else {
+ strcpy(name, stem);
+ strcat(name, suff);
+ if(++suff[1] > 'z')
+ suff[1] = 'a', ++suff[0];
+ openf();
+ }
+ return canopen;
+}
+
+int
+matchfile(Resub *match)
+{
+ if(match[1].s.sp) {
+ int len = match[1].e.ep - match[1].s.sp;
+ strncpy(name, match[1].s.sp, len);
+ strcpy(name+len, suffix);
+ openf();
+ return 1;
+ }
+ return nextfile();
+}
+
+void
+openf(void)
+{
+ static int fd = 0;
+ Bflush(output);
+ Bterm(output);
+ if(fd > 0)
+ close(fd);
+ fd = create(name,OWRITE,0666);
+ if(fd < 0) {
+ fprint(2, "grep: can't create %s: %r\n", name);
+ exits("create");
+ }
+ Binit(output, fd, OWRITE);
+}
+
+char *
+fold(char *s, int n)
+{
+ static char *fline;
+ static int linesize = 0;
+ char *t;
+
+ if(linesize < n+1){
+ fline = realloc(fline,n+1);
+ linesize = n+1;
+ }
+ for(t=fline; *t++ = tolower(*s++); )
+ continue;
+ /* we assume the 'A'-'Z' only appear as themselves
+ * in a utf encoding.
+ */
+ return fline;
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: split [-n num] [-e exp] [-f stem] [-s suff] [-x] [-i] [file]\n");
+ exits("usage");
+}
+
+void
+badexp(void)
+{
+ fprint(2, "split: bad regular expression\n");
+ exits("bad regular expression");
+} |
| diff --git a/src/cmd/strings.c b/src/cmd/strings.c |
| t@@ -0,0 +1,88 @@
+#include
+#include
+#include
+
+Biobuf *fin;
+Biobuf fout;
+
+#define MINSPAN 6 /* Min characters in string */
+
+#define BUFSIZE 70
+
+void stringit(char *);
+int isprint(Rune);
+
+void
+main(int argc, char **argv)
+{
+ int i;
+
+ Binit(&fout, 1, OWRITE);
+ if(argc < 2) {
+ stringit("/fd/0");
+ exits(0);
+ }
+
+ for(i = 1; i < argc; i++) {
+ if(argc > 2)
+ print("%s:\n", argv[i]);
+
+ stringit(argv[i]);
+ }
+
+ exits(0);
+}
+
+void
+stringit(char *str)
+{
+ long posn, start;
+ int cnt = 0;
+ long c;
+
+ Rune buf[BUFSIZE];
+
+ if ((fin = Bopen(str, OREAD)) == 0) {
+ perror("open");
+ return;
+ }
+
+ start = 0;
+ posn = Boffset(fin);
+ while((c = Bgetrune(fin)) >= 0) {
+ if(isprint(c)) {
+ if(start == 0)
+ start = posn;
+ buf[cnt++] = c;
+ if(cnt == BUFSIZE-1) {
+ buf[cnt] = 0;
+ Bprint(&fout, "%8ld: %S ...\n", start, buf);
+ start = 0;
+ cnt = 0;
+ }
+ } else {
+ if(cnt >= MINSPAN) {
+ buf[cnt] = 0;
+ Bprint(&fout, "%8ld: %S\n", start, buf);
+ }
+ start = 0;
+ cnt = 0;
+ }
+ posn = Boffset(fin);
+ }
+
+ if(cnt >= MINSPAN){
+ buf[cnt] = 0;
+ Bprint(&fout, "%8ld: %S\n", start, buf);
+ }
+ Bterm(fin);
+}
+
+int
+isprint(Rune r)
+{
+ if ((r >= ' ' && r <0x7f) || r > 0xA0)
+ return 1;
+ else
+ return 0;
+} |
| diff --git a/src/cmd/sum.c b/src/cmd/sum.c |
| t@@ -0,0 +1,215 @@
+#include
+#include
+
+typedef ulong Sumfn(ulong, void*, uvlong);
+extern Sumfn sumr, sum5, sum32;
+char *sumfile(char*, Sumfn*);
+
+void
+usage(void)
+{
+ fprint(2, "Usage: %s [-r5] [files]\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ Sumfn *fn = sum32;
+ char *exitstr=0, *s;
+
+ ARGBEGIN{
+ case 'r':
+ fn = sumr;
+ break;
+ case '5':
+ fn = sum5;
+ break;
+ default:
+ usage();
+ break;
+ }ARGEND
+ if(*argv){
+ while(*argv)
+ if(s = sumfile(*argv++, fn)) /* assign = */
+ exitstr = s;
+ }else
+ exitstr = sumfile(0, fn);
+ exits(exitstr);
+}
+
+char*
+sumfile(char *file, Sumfn *fn)
+{
+ int fd;
+ int n;
+ ulong sum;
+ uvlong fsize;
+ char buf[8*1024];
+
+ if(file){
+ if((fd = open(file, OREAD)) < 0){
+ errstr(buf, sizeof buf);
+ fprint(2, "%s: %s: %s\n", argv0, file, buf);
+ return "can't open";
+ }
+ }else
+ fd = 0;
+ fsize = 0;
+ sum = 0;
+ while((n=read(fd, buf, sizeof buf)) > 0){
+ fsize += n;
+ sum = (*fn)(sum, buf, n);
+ }
+ if(n < 0){
+ errstr(buf, sizeof buf);
+ fprint(2, "%s: %s: read error: %s\n", argv0, file? file:"", buf);
+ if(file)
+ close(fd);
+ return "read error";
+ }
+ if(file)
+ close(fd);
+ (*fn)(sum, (char*)0, fsize);
+ if(file)
+ print(" %s", file);
+ print("\n");
+ return 0;
+}
+
+#define VBSIZE 512 /* system v */
+
+ulong
+sum5(ulong sum, void *buf, uvlong uvn)
+{
+ uchar *s, *send;
+ int n;
+
+ if(buf == 0){
+ sum = ((sum>>16)+sum) & 0xFFFF;
+ print("%.5lud%6lld", sum, (uvn+(VBSIZE-1))/VBSIZE);
+ return 0;
+ }
+ n = uvn;
+ for(s=buf, send=s+n; s>1)+*s+0x8000);
+ else
+ sum = 0xffff & ((sum>>1)+*s);
+ return sum;
+}
+
+extern ulong crc_table[256];
+
+ulong
+sum32(ulong lcrc, void *buf, uvlong uvn)
+{
+ uchar *s = buf;
+ ulong crc = lcrc;
+ int n;
+
+ n = uvn;
+ if(buf == 0){
+ char x[4];
+
+ x[0] = (n>>24)^0xCC; /* encode the length but make n==0 not 0 */
+ x[1] = (n>>16)^0x55;
+ x[2] = (n>>8)^0xCC;
+ x[3] = (n)^0x55;
+ crc = sum32(lcrc, x, 4);
+ print("%.8lux %6lld", crc, uvn);
+ return 0;
+ }
+ while(n-- > 0)
+ crc = crc_table[(crc^*s++)&0xff] ^ (crc>>8);
+ return crc;
+}
+
+/*
+ * CRC 035556101440
+ */
+ulong crc_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+}; |
| diff --git a/src/cmd/tail.c b/src/cmd/tail.c |
| t@@ -0,0 +1,362 @@
+#include
+#include
+#include
+#include
+
+/*
+ * tail command, posix plus v10 option -r.
+ * the simple command tail -c, legal in v10, is illegal
+ */
+
+long count;
+int anycount;
+int follow;
+int file = 0;
+char* umsg = "usage: tail [-n N] [-c N] [-f] [-r] [+-N[bc][fr]] [file]";
+
+Biobuf bout;
+enum
+{
+ BEG,
+ END
+} origin = END;
+enum
+{
+ CHARS,
+ LINES
+} units = LINES;
+enum
+{
+ FWD,
+ REV
+} dir = FWD;
+
+extern void copy(void);
+extern void fatal(char*);
+extern int getnumber(char*);
+extern void keep(void);
+extern void reverse(void);
+extern void skip(void);
+extern void suffix(char*);
+extern long tread(char*, long);
+extern void trunc(Dir*, Dir**);
+extern long tseek(long, int);
+extern void twrite(char*, long);
+extern void usage(void);
+
+#define JUMP(o,p) tseek(o,p), copy()
+
+void
+main(int argc, char **argv)
+{
+ int seekable, c;
+
+ Binit(&bout, 1, OWRITE);
+ for(; argc > 1 && ((c=*argv[1])=='-'||c=='+'); argc--,argv++ ) {
+ if(getnumber(argv[1])) {
+ suffix(argv[1]);
+ continue;
+ } else
+ if(c == '-')
+ switch(argv[1][1]) {
+ case 'c':
+ units = CHARS;
+ case 'n':
+ if(getnumber(argv[1]+2))
+ continue;
+ else
+ if(argc > 2 && getnumber(argv[2])) {
+ argc--, argv++;
+ continue;
+ } else
+ usage();
+ case 'r':
+ dir = REV;
+ continue;
+ case 'f':
+ follow++;
+ continue;
+ case '-':
+ argc--, argv++;
+ }
+ break;
+ }
+ if(dir==REV && (units==CHARS || follow || origin==BEG))
+ fatal("incompatible options");
+ if(!anycount)
+ count = dir==REV? ~0UL>>1: 10;
+ if(origin==BEG && units==LINES && count>0)
+ count--;
+ if(argc > 2)
+ usage();
+ if(argc > 1 && (file=open(argv[1],0)) < 0)
+ fatal(argv[1]);
+ seekable = seek(file,0L,0) == 0;
+
+ if(!seekable && origin==END)
+ keep();
+ else
+ if(!seekable && origin==BEG)
+ skip();
+ else
+ if(units==CHARS && origin==END)
+ JUMP(-count, 2);
+ else
+ if(units==CHARS && origin==BEG)
+ JUMP(count, 0);
+ else
+ if(units==LINES && origin==END)
+ reverse();
+ else
+ if(units==LINES && origin==BEG)
+ skip();
+ if(follow && seekable)
+ for(;;) {
+ static Dir *sb0, *sb1;
+ trunc(sb1, &sb0);
+ copy();
+ trunc(sb0, &sb1);
+ sleep(5000);
+ }
+ exits(0);
+}
+
+void
+trunc(Dir *old, Dir **new)
+{
+ Dir *d;
+ ulong olength;
+
+ d = dirfstat(file);
+ if(d == nil)
+ return;
+ olength = 0;
+ if(old)
+ olength = old->length;
+ if(d->length < olength)
+ d->length = tseek(0L, 0);
+ free(*new);
+ *new = d;
+}
+
+void
+suffix(char *s)
+{
+ while(*s && strchr("0123456789+-", *s))
+ s++;
+ switch(*s) {
+ case 'b':
+ if((count *= 1024) < 0)
+ fatal("too big");
+ case 'c':
+ units = CHARS;
+ case 'l':
+ s++;
+ }
+ switch(*s) {
+ case 'r':
+ dir = REV;
+ return;
+ case 'f':
+ follow++;
+ return;
+ case 0:
+ return;
+ }
+ usage();
+}
+
+/*
+ * read past head of the file to find tail
+ */
+void
+skip(void)
+{
+ int i;
+ long n;
+ char buf[Bsize];
+ if(units == CHARS) {
+ for( ; count>0; count -=n) {
+ n = count 0) {
+ if(!(n = tread(buf, Bsize)))
+ return;
+ for(i=0; i0; i++)
+ if(buf[i]=='\n')
+ count--;
+ }
+ twrite(buf+i, n-i);
+ }
+ copy();
+}
+
+void
+copy(void)
+{
+ long n;
+ char buf[Bsize];
+ while((n=tread(buf, Bsize)) > 0) {
+ twrite(buf, n);
+ Bflush(&bout); /* for FWD on pipe; else harmless */
+ }
+}
+
+/*
+ * read whole file, keeping the tail
+ * complexity is length(file)*length(tail).
+ * could be linear.
+ */
+void
+keep(void)
+{
+ int len = 0;
+ long bufsiz = 0;
+ char *buf = 0;
+ int j, k, n;
+
+ for(n=1; n;) {
+ if(len+Bsize > bufsiz) {
+ bufsiz += 2*Bsize;
+ if(!(buf = realloc(buf, bufsiz+1)))
+ fatal("out of space");
+ }
+ for(; n && len= len)
+ continue;
+ if(units == CHARS)
+ j = len - count;
+ else {
+ /* units == LINES */
+ j = buf[len-1]=='\n'? len-1: len;
+ for(k=0; j>0; j--)
+ if(buf[j-1] == '\n')
+ if(++k >= count)
+ break;
+ }
+ memmove(buf, buf+j, len-=j);
+ }
+ if(dir == REV) {
+ if(len>0 && buf[len-1]!='\n')
+ buf[len++] = '\n';
+ for(j=len-1 ; j>0; j--)
+ if(buf[j-1] == '\n') {
+ twrite(buf+j, len-j);
+ if(--count <= 0)
+ return;
+ len = j;
+ }
+ }
+ if(count > 0)
+ twrite(buf, len);
+}
+
+/*
+ * count backward and print tail of file
+ */
+void
+reverse(void)
+{
+ int first;
+ long len = 0;
+ long n = 0;
+ long bufsiz = 0;
+ char *buf = 0;
+ long pos = tseek(0L, 2);
+
+ for(first=1; pos>0 && count>0; first=0) {
+ n = pos>Bsize? Bsize: (int)pos;
+ pos -= n;
+ if(len+n > bufsiz) {
+ bufsiz += 2*Bsize;
+ if(!(buf = realloc(buf, bufsiz+1)))
+ fatal("out of space");
+ }
+ memmove(buf+n, buf, len);
+ len += n;
+ tseek(pos, 0);
+ if(tread(buf, n) != n)
+ fatal("length error");
+ if(first && buf[len-1]!='\n')
+ buf[len++] = '\n';
+ for(n=len-1 ; n>0 && count>0; n--)
+ if(buf[n-1] == '\n') {
+ count--;
+ if(dir == REV)
+ twrite(buf+n, len-n);
+ len = n;
+ }
+ }
+ if(dir == FWD) {
+ tseek(n==0? 0 : pos+n+1, 0);
+ copy();
+ } else
+ if(count > 0)
+ twrite(buf, len);
+}
+
+long
+tseek(long o, int p)
+{
+ o = seek(file, o, p);
+ if(o == -1)
+ fatal("");
+ return o;
+}
+
+long
+tread(char *buf, long n)
+{
+ int r = read(file, buf, n);
+ if(r == -1)
+ fatal("");
+ return r;
+}
+
+void
+twrite(char *s, long n)
+{
+ if(Bwrite(&bout, s, n) != n)
+ fatal("");
+}
+
+int
+getnumber(char *s)
+{
+ if(*s=='-' || *s=='+')
+ s++;
+ if(!isdigit(*s))
+ return 0;
+ if(s[-1] == '+')
+ origin = BEG;
+ if(anycount++)
+ fatal("excess option");
+ count = atol(s);
+
+ /* check range of count */
+ if(count < 0 || (int)count != count)
+ fatal("too big");
+ return 1;
+}
+
+void
+fatal(char *s)
+{
+ char buf[ERRMAX];
+
+ errstr(buf, sizeof buf);
+ fprint(2, "tail: %s: %s\n", s, buf);
+ exits(s);
+}
+
+void
+usage(void)
+{
+ fprint(2, "%s\n", umsg);
+ exits("usage");
+} |
| diff --git a/src/cmd/tar.C b/src/cmd/tar.C |
| t@@ -0,0 +1,640 @@
+#include
+#include
+#include
+
+#define TBLOCK 512
+#define NBLOCK 40 /* maximum blocksize */
+#define DBLOCK 20 /* default blocksize */
+#define NAMSIZ 100
+union hblock
+{
+ char dummy[TBLOCK];
+ struct header
+ {
+ char name[NAMSIZ];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char linkflag;
+ char linkname[NAMSIZ];
+ } dbuf;
+} dblock, tbuf[NBLOCK];
+
+Dir *stbuf;
+Biobuf bout;
+
+int rflag, xflag, vflag, tflag, mt, cflag, fflag, Tflag, Rflag;
+int uflag, gflag;
+int chksum, recno, first;
+int nblock = DBLOCK;
+
+void usage(void);
+void dorep(char **);
+int endtar(void);
+void getdir(void);
+void passtar(void);
+void putfile(char*, char *, char *);
+void doxtract(char **);
+void dotable(void);
+void putempty(void);
+void longt(Dir *);
+int checkdir(char *, int, Qid*);
+void tomodes(Dir *);
+int checksum(void);
+int checkupdate(char *);
+int prefix(char *, char *);
+int readtar(char *);
+int writetar(char *);
+void backtar(void);
+void flushtar(void);
+void affix(int, char *);
+int volprompt(void);
+void
+main(int argc, char **argv)
+{
+ char *usefile;
+ char *cp, *ap;
+
+ if (argc < 2)
+ usage();
+
+ Binit(&bout, 1, OWRITE);
+ usefile = 0;
+ argv[argc] = 0;
+ argv++;
+ for (cp = *argv++; *cp; cp++)
+ switch(*cp) {
+ case 'f':
+ usefile = *argv++;
+ if(!usefile)
+ usage();
+ fflag++;
+ break;
+ case 'u':
+ ap = *argv++;
+ if(!ap)
+ usage();
+ uflag = strtoul(ap, 0, 0);
+ break;
+ case 'g':
+ ap = *argv++;
+ if(!ap)
+ usage();
+ gflag = strtoul(ap, 0, 0);
+ break;
+ case 'c':
+ cflag++;
+ rflag++;
+ break;
+ case 'r':
+ rflag++;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case 'x':
+ xflag++;
+ break;
+ case 'T':
+ Tflag++;
+ break;
+ case 't':
+ tflag++;
+ break;
+ case 'R':
+ Rflag++;
+ break;
+ case '-':
+ break;
+ default:
+ fprint(2, "tar: %c: unknown option\n", *cp);
+ usage();
+ }
+
+ fmtinstall('M', dirmodefmt);
+
+ if (rflag) {
+ if (!usefile) {
+ if (cflag == 0) {
+ fprint(2, "tar: can only create standard output archives\n");
+ exits("arg error");
+ }
+ mt = dup(1, -1);
+ nblock = 1;
+ }
+ else if ((mt = open(usefile, ORDWR)) < 0) {
+ if (cflag == 0 || (mt = create(usefile, OWRITE, 0666)) < 0) {
+ fprint(2, "tar: cannot open %s: %r\n", usefile);
+ exits("open");
+ }
+ }
+ dorep(argv);
+ }
+ else if (xflag) {
+ if (!usefile) {
+ mt = dup(0, -1);
+ nblock = 1;
+ }
+ else if ((mt = open(usefile, OREAD)) < 0) {
+ fprint(2, "tar: cannot open %s: %r\n", usefile);
+ exits("open");
+ }
+ doxtract(argv);
+ }
+ else if (tflag) {
+ if (!usefile) {
+ mt = dup(0, -1);
+ nblock = 1;
+ }
+ else if ((mt = open(usefile, OREAD)) < 0) {
+ fprint(2, "tar: cannot open %s: %r\n", usefile);
+ exits("open");
+ }
+ dotable();
+ }
+ else
+ usage();
+ exits(0);
+}
+
+void
+usage(void)
+{
+ fprint(2, "tar: usage tar {txrc}[Rvf] [tarfile] file1 file2...\n");
+ exits("usage");
+}
+
+void
+dorep(char **argv)
+{
+ char cwdbuf[2048], *cwd, thisdir[2048];
+ char *cp, *cp2;
+ int cd;
+
+ if (getwd(cwdbuf, sizeof(cwdbuf)) == 0) {
+ fprint(2, "tar: can't find current directory: %r\n");
+ exits("cwd");
+ }
+ cwd = cwdbuf;
+
+ if (!cflag) {
+ getdir();
+ do {
+ passtar();
+ getdir();
+ } while (!endtar());
+ }
+
+ while (*argv) {
+ cp2 = *argv;
+ if (!strcmp(cp2, "-C") && argv[1]) {
+ argv++;
+ if (chdir(*argv) < 0)
+ perror(*argv);
+ cwd = *argv;
+ argv++;
+ continue;
+ }
+ cd = 0;
+ for (cp = *argv; *cp; cp++)
+ if (*cp == '/')
+ cp2 = cp;
+ if (cp2 != *argv) {
+ *cp2 = '\0';
+ chdir(*argv);
+ if(**argv == '/')
+ strncpy(thisdir, *argv, sizeof(thisdir));
+ else
+ snprint(thisdir, sizeof(thisdir), "%s/%s", cwd, *argv);
+ *cp2 = '/';
+ cp2++;
+ cd = 1;
+ } else
+ strncpy(thisdir, cwd, sizeof(thisdir));
+ putfile(thisdir, *argv++, cp2);
+ if(cd && chdir(cwd) < 0) {
+ fprint(2, "tar: can't cd back to %s: %r\n", cwd);
+ exits("cwd");
+ }
+ }
+ putempty();
+ putempty();
+ flushtar();
+}
+
+int
+endtar(void)
+{
+ if (dblock.dbuf.name[0] == '\0') {
+ backtar();
+ return(1);
+ }
+ else
+ return(0);
+}
+
+void
+getdir(void)
+{
+ Dir *sp;
+
+ readtar((char*)&dblock);
+ if (dblock.dbuf.name[0] == '\0')
+ return;
+ if(stbuf == nil){
+ stbuf = malloc(sizeof(Dir));
+ if(stbuf == nil) {
+ fprint(2, "tar: can't malloc: %r\n");
+ exits("malloc");
+ }
+ }
+ sp = stbuf;
+ sp->mode = strtol(dblock.dbuf.mode, 0, 8);
+ sp->uid = "adm";
+ sp->gid = "adm";
+ sp->length = strtol(dblock.dbuf.size, 0, 8);
+ sp->mtime = strtol(dblock.dbuf.mtime, 0, 8);
+ chksum = strtol(dblock.dbuf.chksum, 0, 8);
+ if (chksum != checksum()) {
+ fprint(2, "directory checksum error\n");
+ exits("checksum error");
+ }
+ sp->qid.type = 0;
+ /* the mode test is ugly but sometimes necessary */
+ if (dblock.dbuf.linkflag == '5' || (sp->mode&0170000) == 040000) {
+ sp->qid.type |= QTDIR;
+ sp->mode |= DMDIR;
+ }
+}
+
+void
+passtar(void)
+{
+ long blocks;
+ char buf[TBLOCK];
+
+ if (dblock.dbuf.linkflag == '1' || dblock.dbuf.linkflag == 's')
+ return;
+ blocks = stbuf->length;
+ blocks += TBLOCK-1;
+ blocks /= TBLOCK;
+
+ while (blocks-- > 0)
+ readtar(buf);
+}
+
+void
+putfile(char *dir, char *longname, char *sname)
+{
+ int infile;
+ long blocks;
+ char buf[TBLOCK];
+ char curdir[4096];
+ char shortname[4096];
+ char *cp, *cp2;
+ Dir *db;
+ int i, n;
+
+ if(strlen(sname) > sizeof shortname - 3){
+ fprint(2, "tar: %s: name too long (max %d)\n", sname, sizeof shortname - 3);
+ return;
+ }
+
+ snprint(shortname, sizeof shortname, "./%s", sname);
+ infile = open(shortname, OREAD);
+ if (infile < 0) {
+ fprint(2, "tar: %s: cannot open file - %r\n", longname);
+ return;
+ }
+
+ if(stbuf != nil)
+ free(stbuf);
+ stbuf = dirfstat(infile);
+
+ if (stbuf->qid.type & QTDIR) {
+ /* Directory */
+ for (i = 0, cp = buf; *cp++ = longname[i++];);
+ *--cp = '/';
+ *++cp = 0;
+ if( (cp - buf) >= NAMSIZ) {
+ fprint(2, "tar: %s: file name too long\n", longname);
+ close(infile);
+ return;
+ }
+ stbuf->length = 0;
+ tomodes(stbuf);
+ strcpy(dblock.dbuf.name,buf);
+ dblock.dbuf.linkflag = '5'; /* Directory */
+ sprint(dblock.dbuf.chksum, "%6o", checksum());
+ writetar( (char *) &dblock);
+ if (chdir(shortname) < 0) {
+ fprint(2, "tar: can't cd to %s: %r\n", shortname);
+ snprint(curdir, sizeof(curdir), "cd %s", shortname);
+ exits(curdir);
+ }
+ sprint(curdir, "%s/%s", dir, sname);
+ while ((n = dirread(infile, &db)) > 0) {
+ for(i = 0; i < n; i++){
+ strncpy(cp, db[i].name, sizeof buf - (cp-buf));
+ putfile(curdir, buf, db[i].name);
+ }free(db);
+ }
+ close(infile);
+ if (chdir(dir) < 0 && chdir("..") < 0) {
+ fprint(2, "tar: can't cd to ..(%s): %r\n", dir);
+ snprint(curdir, sizeof(curdir), "cd ..(%s)", dir);
+ exits(curdir);
+ }
+ return;
+ }
+
+
+ tomodes(stbuf);
+
+ cp2 = longname;
+ for (cp = dblock.dbuf.name, i=0; (*cp++ = *cp2++) && i < NAMSIZ; i++);
+ if (i >= NAMSIZ) {
+ fprint(2, "%s: file name too long\n", longname);
+ close(infile);
+ return;
+ }
+
+ blocks = (stbuf->length + (TBLOCK-1)) / TBLOCK;
+ if (vflag) {
+ fprint(2, "a %s ", longname);
+ fprint(2, "%ld blocks\n", blocks);
+ }
+ dblock.dbuf.linkflag = 0; /* Regular file */
+ sprint(dblock.dbuf.chksum, "%6o", checksum());
+ writetar( (char *) &dblock);
+
+ while ((i = readn(infile, buf, TBLOCK)) > 0 && blocks > 0) {
+ writetar(buf);
+ blocks--;
+ }
+ close(infile);
+ if (blocks != 0 || i != 0)
+ fprint(2, "%s: file changed size\n", longname);
+ while (blocks-- > 0)
+ putempty();
+}
+
+
+void
+doxtract(char **argv)
+{
+ Dir null;
+ long blocks, bytes;
+ char buf[TBLOCK], outname[NAMSIZ+4];
+ char **cp;
+ int ofile;
+
+ for (;;) {
+ getdir();
+ if (endtar())
+ break;
+
+ if (*argv == 0)
+ goto gotit;
+
+ for (cp = argv; *cp; cp++)
+ if (prefix(*cp, dblock.dbuf.name))
+ goto gotit;
+ passtar();
+ continue;
+
+gotit:
+ if(checkdir(dblock.dbuf.name, stbuf->mode, &(stbuf->qid)))
+ continue;
+
+ if (dblock.dbuf.linkflag == '1') {
+ fprint(2, "tar: can't link %s %s\n",
+ dblock.dbuf.linkname, dblock.dbuf.name);
+ remove(dblock.dbuf.name);
+ continue;
+ }
+ if (dblock.dbuf.linkflag == 's') {
+ fprint(2, "tar: %s: cannot symlink\n", dblock.dbuf.name);
+ continue;
+ }
+ if(dblock.dbuf.name[0] != '/' || Rflag)
+ sprint(outname, "./%s", dblock.dbuf.name);
+ else
+ strcpy(outname, dblock.dbuf.name);
+ if ((ofile = create(outname, OWRITE, stbuf->mode & 0777)) < 0) {
+ fprint(2, "tar: %s - cannot create: %r\n", outname);
+ passtar();
+ continue;
+ }
+
+ blocks = ((bytes = stbuf->length) + TBLOCK-1)/TBLOCK;
+ if (vflag)
+ fprint(2, "x %s, %ld bytes\n",
+ dblock.dbuf.name, bytes);
+ while (blocks-- > 0) {
+ readtar(buf);
+ if (bytes > TBLOCK) {
+ if (write(ofile, buf, TBLOCK) < 0) {
+ fprint(2, "tar: %s: HELP - extract write error: %r\n", dblock.dbuf.name);
+ exits("extract write");
+ }
+ } else
+ if (write(ofile, buf, bytes) < 0) {
+ fprint(2, "tar: %s: HELP - extract write error: %r\n", dblock.dbuf.name);
+ exits("extract write");
+ }
+ bytes -= TBLOCK;
+ }
+ if(Tflag){
+ nulldir(&null);
+ null.mtime = stbuf->mtime;
+ dirfwstat(ofile, &null);
+ }
+ close(ofile);
+ }
+}
+
+void
+dotable(void)
+{
+ for (;;) {
+ getdir();
+ if (endtar())
+ break;
+ if (vflag)
+ longt(stbuf);
+ Bprint(&bout, "%s", dblock.dbuf.name);
+ if (dblock.dbuf.linkflag == '1')
+ Bprint(&bout, " linked to %s", dblock.dbuf.linkname);
+ if (dblock.dbuf.linkflag == 's')
+ Bprint(&bout, " -> %s", dblock.dbuf.linkname);
+ Bprint(&bout, "\n");
+ passtar();
+ }
+}
+
+void
+putempty(void)
+{
+ char buf[TBLOCK];
+
+ memset(buf, 0, TBLOCK);
+ writetar(buf);
+}
+
+void
+longt(Dir *st)
+{
+ char *cp;
+
+ Bprint(&bout, "%M %4d/%1d ", st->mode, 0, 0); /* 0/0 uid/gid */
+ Bprint(&bout, "%8lld", st->length);
+ cp = ctime(st->mtime);
+ Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
+}
+
+int
+checkdir(char *name, int mode, Qid *qid)
+{
+ char *cp;
+ int f;
+ Dir *d, null;
+
+ if(Rflag && *name == '/')
+ name++;
+ cp = name;
+ if(*cp == '/')
+ cp++;
+ for (; *cp; cp++) {
+ if (*cp == '/') {
+ *cp = '\0';
+ if (access(name, 0) < 0) {
+ f = create(name, OREAD, DMDIR + 0775L);
+ if(f < 0)
+ fprint(2, "tar: mkdir %s failed: %r\n", name);
+ close(f);
+ }
+ *cp = '/';
+ }
+ }
+
+ /* if this is a directory, chmod it to the mode in the tar plus 700 */
+ if(cp[-1] == '/' || (qid->type&QTDIR)){
+ if((d=dirstat(name)) != 0){
+ nulldir(&null);
+ null.mode = DMDIR | (mode & 0777) | 0700;
+ dirwstat(name, &null);
+ free(d);
+ }
+ return 1;
+ } else
+ return 0;
+}
+
+void
+tomodes(Dir *sp)
+{
+ char *cp;
+
+ for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
+ *cp = '\0';
+ sprint(dblock.dbuf.mode, "%6lo ", sp->mode & 0777);
+ sprint(dblock.dbuf.uid, "%6o ", uflag);
+ sprint(dblock.dbuf.gid, "%6o ", gflag);
+ sprint(dblock.dbuf.size, "%11llo ", sp->length);
+ sprint(dblock.dbuf.mtime, "%11lo ", sp->mtime);
+}
+
+int
+checksum(void)
+{
+ int i;
+ char *cp;
+
+ for (cp = dblock.dbuf.chksum; cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
+ *cp = ' ';
+ i = 0;
+ for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
+ i += *cp & 0xff;
+ return(i);
+}
+
+int
+prefix(char *s1, char *s2)
+{
+ while (*s1)
+ if (*s1++ != *s2++)
+ return(0);
+ if (*s2)
+ return(*s2 == '/');
+ return(1);
+}
+
+int
+readtar(char *buffer)
+{
+ int i;
+
+ if (recno >= nblock || first == 0) {
+ if ((i = readn(mt, tbuf, TBLOCK*nblock)) <= 0) {
+ fprint(2, "tar: archive read error: %r\n");
+ exits("archive read");
+ }
+ if (first == 0) {
+ if ((i % TBLOCK) != 0) {
+ fprint(2, "tar: archive blocksize error: %r\n");
+ exits("blocksize");
+ }
+ i /= TBLOCK;
+ if (i != nblock) {
+ fprint(2, "tar: blocksize = %d\n", i);
+ nblock = i;
+ }
+ }
+ recno = 0;
+ }
+ first = 1;
+ memmove(buffer, &tbuf[recno++], TBLOCK);
+ return(TBLOCK);
+}
+
+int
+writetar(char *buffer)
+{
+ first = 1;
+ if (recno >= nblock) {
+ if (write(mt, tbuf, TBLOCK*nblock) != TBLOCK*nblock) {
+ fprint(2, "tar: archive write error: %r\n");
+ exits("write");
+ }
+ recno = 0;
+ }
+ memmove(&tbuf[recno++], buffer, TBLOCK);
+ if (recno >= nblock) {
+ if (write(mt, tbuf, TBLOCK*nblock) != TBLOCK*nblock) {
+ fprint(2, "tar: archive write error: %r\n");
+ exits("write");
+ }
+ recno = 0;
+ }
+ return(TBLOCK);
+}
+
+/*
+ * backup over last tar block
+ */
+void
+backtar(void)
+{
+ seek(mt, -TBLOCK*nblock, 1);
+ recno--;
+}
+
+void
+flushtar(void)
+{
+ write(mt, tbuf, TBLOCK*nblock);
+} |
| diff --git a/src/cmd/tee.c b/src/cmd/tee.c |
| t@@ -0,0 +1,75 @@
+/*
+ * tee-- pipe fitting
+ */
+
+#include
+#include
+
+int uflag;
+int aflag;
+int openf[100];
+
+char in[8192];
+
+int intignore(void*, char*);
+
+void
+main(int argc, char **argv)
+{
+ int i;
+ int r, n;
+
+ ARGBEGIN {
+ case 'a':
+ aflag++;
+ break;
+
+ case 'i':
+ atnotify(intignore, 1);
+ break;
+
+ case 'u':
+ uflag++;
+ /* uflag is ignored and undocumented; it's a relic from Unix */
+ break;
+
+ default:
+ fprint(2, "usage: tee [-ai] [file ...]\n");
+ exits("usage");
+ } ARGEND
+
+ USED(argc);
+ n = 0;
+ while(*argv) {
+ if(aflag) {
+ openf[n] = open(argv[0], OWRITE);
+ if(openf[n] < 0)
+ openf[n] = create(argv[0], OWRITE, 0666);
+ seek(openf[n], 0L, 2);
+ } else
+ openf[n] = create(argv[0], OWRITE, 0666);
+ if(openf[n] < 0) {
+ fprint(2, "tee: cannot open %s: %r\n", argv[0]);
+ } else
+ n++;
+ argv++;
+ }
+ openf[n++] = 1;
+
+ for(;;) {
+ r = read(0, in, sizeof in);
+ if(r <= 0)
+ exits(nil);
+ for(i=0; i |
| diff --git a/src/cmd/test.c b/src/cmd/test.c |
| t@@ -0,0 +1,303 @@
+/*
+ * POSIX standard
+ * test expression
+ * [ expression ]
+ *
+ * Plan 9 additions:
+ * -A file exists and is append-only
+ * -L file exists and is exclusive-use
+ */
+
+#include
+#include
+#define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0))
+
+int ap;
+int ac;
+char **av;
+char *tmp;
+
+void synbad(char *, char *);
+int fsizep(char *);
+int isdir(char *);
+int isreg(char *);
+int isatty(int);
+int isint(char *, int *);
+int hasmode(char *, ulong);
+int tio(char *, int);
+int e(void), e1(void), e2(void), e3(void);
+
+void
+main(int argc, char *argv[])
+{
+
+ ac = argc; av = argv; ap = 1;
+ if(EQ(argv[0],"[")) {
+ if(!EQ(argv[--ac],"]"))
+ synbad("] missing","");
+ }
+ argv[ac] = 0;
+ if (ac<=1) exits("usage");
+ exits(e()?0:"false");
+}
+
+char *
+nxtarg(int mt)
+{
+ if(ap>=ac){
+ if(mt){
+ ap++;
+ return(0);
+ }
+ synbad("argument expected","");
+ }
+ return(av[ap++]);
+}
+
+int
+nxtintarg(int *pans)
+{
+ if(ap=ac || !nxtintarg(&int1))
+ return(isatty(1));
+ else
+ return(isatty(int1));
+
+ if(EQ(a, "-n"))
+ return(!EQ(nxtarg(0), ""));
+ if(EQ(a, "-z"))
+ return(EQ(nxtarg(0), ""));
+
+ p2 = nxtarg(1);
+ if (p2==0)
+ return(!EQ(a,""));
+ if(EQ(p2, "="))
+ return(EQ(nxtarg(0), a));
+
+ if(EQ(p2, "!="))
+ return(!EQ(nxtarg(0), a));
+
+ if(!isint(a, &int1))
+ return(!EQ(a,""));
+
+ if(nxtintarg(&int2)){
+ if(EQ(p2, "-eq"))
+ return(int1==int2);
+ if(EQ(p2, "-ne"))
+ return(int1!=int2);
+ if(EQ(p2, "-gt"))
+ return(int1>int2);
+ if(EQ(p2, "-lt"))
+ return(int1=int2);
+ if(EQ(p2, "-le"))
+ return(int1<=int2);
+ }
+
+ synbad("unknown operator ",p2);
+ return 0; /* to shut ken up */
+}
+
+int
+tio(char *a, int f)
+{
+ return access (a, f) >= 0;
+}
+
+/* copy to local memory; clear names for safety */
+int
+localstat(char *f, Dir *dir)
+{
+ Dir *d;
+
+ d = dirstat(f);
+ if(d == 0)
+ return(-1);
+ *dir = *d;
+ dir->name = 0;
+ dir->uid = 0;
+ dir->gid = 0;
+ dir->muid = 0;
+ return 0;
+}
+
+/* copy to local memory; clear names for safety */
+int
+localfstat(int f, Dir *dir)
+{
+ Dir *d;
+
+ d = dirfstat(f);
+ if(d == 0)
+ return(-1);
+ *dir = *d;
+ dir->name = 0;
+ dir->uid = 0;
+ dir->gid = 0;
+ dir->muid = 0;
+ return 0;
+}
+
+int
+hasmode(char *f, ulong m)
+{
+ Dir dir;
+
+ if(localstat(f,&dir)<0)
+ return(0);
+ return(dir.mode&m);
+}
+
+int
+isdir(char *f)
+{
+ Dir dir;
+
+ if(localstat(f,&dir)<0)
+ return(0);
+ return(dir.mode&DMDIR);
+}
+
+int
+isreg(char *f)
+{
+ Dir dir;
+
+ if(localstat(f,&dir)<0)
+ return(0);
+ return(!(dir.mode&DMDIR));
+}
+
+int
+isatty(int fd)
+{
+ Dir d1, d2;
+
+ if(localfstat(fd, &d1) < 0)
+ return 0;
+ if(localstat("/dev/cons", &d2) < 0)
+ return 0;
+ return d1.type==d2.type && d1.dev==d2.dev && d1.qid.path==d2.qid.path;
+}
+
+int
+fsizep(char *f)
+{
+ Dir dir;
+
+ if(localstat(f,&dir)<0)
+ return(0);
+ return(dir.length>0);
+}
+
+void
+synbad(char *s1, char *s2)
+{
+ int len;
+
+ write(2, "test: ", 6);
+ if ((len = strlen(s1)) != 0)
+ write(2, s1, len);
+ if ((len = strlen(s2)) != 0)
+ write(2, s2, len);
+ write(2, "\n", 1);
+ exits("bad syntax");
+}
+
+int
+isint(char *s, int *pans)
+{
+ char *ep;
+
+ *pans = strtol(s, &ep, 0);
+ return (*ep == 0);
+} |
| diff --git a/src/cmd/time.c b/src/cmd/time.c |
| t@@ -0,0 +1,101 @@
+#include
+#include
+
+char output[4096];
+void add(char*, ...);
+void error(char*);
+void notifyf(void*, char*);
+
+void
+main(int argc, char *argv[])
+{
+ int i;
+ Waitmsg *w;
+ long l;
+ char *p;
+ char err[ERRMAX];
+
+ if(argc <= 1){
+ fprint(2, "usage: time command\n");
+ exits("usage");
+ }
+
+ switch(fork()){
+ case -1:
+ error("fork");
+ case 0:
+ exec(argv[1], &argv[1]);
+ if(argv[1][0] != '/' && strncmp(argv[1], "./", 2) &&
+ strncmp(argv[1], "../", 3)){
+ sprint(output, "/bin/%s", argv[1]);
+ exec(output, &argv[1]);
+ }
+ error(argv[1]);
+ }
+
+ notify(notifyf);
+
+ loop:
+ w = wait();
+ if(w == nil){
+ errstr(err, sizeof err);
+ if(strcmp(err, "interrupted") == 0)
+ goto loop;
+ error("wait");
+ }
+ l = w->time[0];
+ add("%ld.%.2ldu", l/1000, (l%1000)/10);
+ l = w->time[1];
+ add("%ld.%.2lds", l/1000, (l%1000)/10);
+ l = w->time[2];
+ add("%ld.%.2ldr", l/1000, (l%1000)/10);
+ add("\t");
+ for(i=1; i4){
+ add("...");
+ break;
+ }
+ }
+ if(w->msg[0]){
+ p = utfrune(w->msg, ':');
+ if(p && p[1])
+ p++;
+ else
+ p = w->msg;
+ add(" # status=%s", p);
+ }
+ fprint(2, "%s\n", output);
+ exits(w->msg);
+}
+
+void
+add(char *a, ...)
+{
+ static int beenhere=0;
+ va_list arg;
+
+ if(beenhere)
+ strcat(output, " ");
+ va_start(arg, a);
+ vseprint(output+strlen(output), output+sizeof(output), a, arg);
+ va_end(arg);
+ beenhere++;
+}
+
+void
+error(char *s)
+{
+
+ fprint(2, "time: %s: %r\n", s);
+ exits(s);
+}
+
+void
+notifyf(void *a, char *s)
+{
+ USED(a);
+ if(strcmp(s, "interrupt") == 0)
+ noted(NCONT);
+ noted(NDFLT);
+} |
| diff --git a/src/cmd/touch.c b/src/cmd/touch.c |
| t@@ -0,0 +1,62 @@
+#include
+#include
+
+int touch(int, char *);
+ulong now;
+
+void
+usage(void)
+{
+ fprint(2, "usage: touch [-c] [-t time] files\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int nocreate = 0;
+ int status = 0;
+
+ now = time(0);
+ ARGBEGIN{
+ case 't':
+ now = strtoul(EARGF(usage()), 0, 0);
+ break;
+ case 'c':
+ nocreate = 1;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(!*argv)
+ usage();
+ while(*argv)
+ status += touch(nocreate, *argv++);
+ if(status)
+ exits("touch");
+ exits(0);
+}
+
+int
+touch(int nocreate, char *name)
+{
+ Dir stbuff;
+ int fd;
+
+ nulldir(&stbuff);
+ stbuff.mtime = now;
+ if(dirwstat(name, &stbuff) >= 0)
+ return 0;
+ if(nocreate){
+ fprint(2, "touch: %s: cannot wstat: %r\n", name);
+ return 1;
+ }
+ if ((fd = create(name, OREAD, 0666)) < 0) {
+ fprint(2, "touch: %s: cannot create: %r\n", name);
+ return 1;
+ }
+ dirfwstat(fd, &stbuff);
+ close(fd);
+ return 0;
+} |
| diff --git a/src/cmd/tr.c b/src/cmd/tr.c |
| t@@ -0,0 +1,356 @@
+#include
+#include
+
+typedef struct PCB /* Control block controlling specification parse */
+{
+ char *base; /* start of specification */
+ char *current; /* current parse point */
+ long last; /* last Rune returned */
+ long final; /* final Rune in a span */
+} Pcb;
+
+uchar bits[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+#define SETBIT(a, c) ((a)[(c)/8] |= bits[(c)&07])
+#define CLEARBIT(a,c) ((a)[(c)/8] &= ~bits[(c)&07])
+#define BITSET(a,c) ((a)[(c)/8] & bits[(c)&07])
+
+#define MAXRUNE 0xFFFF
+
+uchar f[(MAXRUNE+1)/8];
+uchar t[(MAXRUNE+1)/8];
+char wbuf[4096];
+char *wptr;
+
+Pcb pfrom, pto;
+
+int cflag;
+int dflag;
+int sflag;
+
+void complement(void);
+void delete(void);
+void squeeze(void);
+void translit(void);
+void error(char*);
+long canon(Pcb*);
+char *getrune(char*, Rune*);
+void Pinit(Pcb*, char*);
+void Prewind(Pcb *p);
+int readrune(int, long*);
+void wflush(int);
+void writerune(int, Rune);
+
+void
+main(int argc, char **argv)
+{
+ ARGBEGIN{
+ case 's': sflag++; break;
+ case 'd': dflag++; break;
+ case 'c': cflag++; break;
+ default: error("bad option");
+ }ARGEND
+ if(argc>0)
+ Pinit(&pfrom, argv[0]);
+ if(argc>1)
+ Pinit(&pto, argv[1]);
+ if(argc>2)
+ error("arg count");
+ if(dflag) {
+ if ((sflag && argc != 2) || (!sflag && argc != 1))
+ error("arg count");
+ delete();
+ } else {
+ if (argc != 2)
+ error("arg count");
+ if (cflag)
+ complement();
+ else translit();
+ }
+ exits(0);
+}
+
+void
+delete(void)
+{
+ long c, last;
+
+ if (cflag) {
+ memset((char *) f, 0xff, sizeof f);
+ while ((c = canon(&pfrom)) >= 0)
+ CLEARBIT(f, c);
+ } else {
+ while ((c = canon(&pfrom)) >= 0)
+ SETBIT(f, c);
+ }
+ if (sflag) {
+ while ((c = canon(&pto)) >= 0)
+ SETBIT(t, c);
+ }
+
+ last = 0x10000;
+ while (readrune(0, &c) > 0) {
+ if(!BITSET(f, c) && (c != last || !BITSET(t,c))) {
+ last = c;
+ writerune(1, (Rune) c);
+ }
+ }
+ wflush(1);
+}
+
+void
+complement(void)
+{
+ Rune *p;
+ int i;
+ long from, to, lastc, high;
+
+ lastc = 0;
+ high = 0;
+ while ((from = canon(&pfrom)) >= 0) {
+ if (from > high) high = from;
+ SETBIT(f, from);
+ }
+ while ((to = canon(&pto)) > 0) {
+ if (to > high) high = to;
+ SETBIT(t,to);
+ }
+ Prewind(&pto);
+ if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0)
+ error("can't allocate memory");
+ for (i = 0; i <= high; i++){
+ if (!BITSET(f,i)) {
+ if ((to = canon(&pto)) < 0)
+ to = lastc;
+ else lastc = to;
+ p[i] = to;
+ }
+ else p[i] = i;
+ }
+ if (sflag){
+ lastc = 0x10000;
+ while (readrune(0, &from) > 0) {
+ if (from > high)
+ from = to;
+ else
+ from = p[from];
+ if (from != lastc || !BITSET(t,from)) {
+ lastc = from;
+ writerune(1, (Rune) from);
+ }
+ }
+
+ } else {
+ while (readrune(0, &from) > 0){
+ if (from > high)
+ from = to;
+ else
+ from = p[from];
+ writerune(1, (Rune) from);
+ }
+ }
+ wflush(1);
+}
+
+void
+translit(void)
+{
+ Rune *p;
+ int i;
+ long from, to, lastc, high;
+
+ lastc = 0;
+ high = 0;
+ while ((from = canon(&pfrom)) >= 0)
+ if (from > high) high = from;
+ Prewind(&pfrom);
+ if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0)
+ error("can't allocate memory");
+ for (i = 0; i <= high; i++)
+ p[i] = i;
+ while ((from = canon(&pfrom)) >= 0) {
+ if ((to = canon(&pto)) < 0)
+ to = lastc;
+ else lastc = to;
+ if (BITSET(f,from) && p[from] != to)
+ error("ambiguous translation");
+ SETBIT(f,from);
+ p[from] = to;
+ SETBIT(t,to);
+ }
+ while ((to = canon(&pto)) >= 0) {
+ SETBIT(t,to);
+ }
+ if (sflag){
+ lastc = 0x10000;
+ while (readrune(0, &from) > 0) {
+ if (from <= high)
+ from = p[from];
+ if (from != lastc || !BITSET(t,from)) {
+ lastc = from;
+ writerune(1, (Rune) from);
+ }
+ }
+
+ } else {
+ while (readrune(0, &from) > 0) {
+ if (from <= high)
+ from = p[from];
+ writerune(1, (Rune) from);
+ }
+ }
+ wflush(1);
+}
+
+int
+readrune(int fd, long *rp)
+{
+ Rune r;
+ int j;
+ static int i, n;
+ static char buf[4096];
+
+ j = i;
+ for (;;) {
+ if (i >= n) {
+ wflush(1);
+ if (j != i)
+ memcpy(buf, buf+j, n-j);
+ i = n-j;
+ n = read(fd, &buf[i], sizeof(buf)-i);
+ if (n < 0)
+ error("read error");
+ if (n == 0)
+ return 0;
+ j = 0;
+ n += i;
+ }
+ i++;
+ if (fullrune(&buf[j], i-j))
+ break;
+ }
+ chartorune(&r, &buf[j]);
+ *rp = r;
+ return 1;
+}
+
+void
+writerune(int fd, Rune r)
+{
+ char buf[UTFmax];
+ int n;
+
+ if (!wptr)
+ wptr = wbuf;
+ n = runetochar(buf, (Rune*)&r);
+ if (wptr+n >= wbuf+sizeof(wbuf))
+ wflush(fd);
+ memcpy(wptr, buf, n);
+ wptr += n;
+}
+
+void
+wflush(int fd)
+{
+ if (wptr && wptr > wbuf)
+ if (write(fd, wbuf, wptr-wbuf) != wptr-wbuf)
+ error("write error");
+ wptr = wbuf;
+}
+
+char *
+getrune(char *s, Rune *rp)
+{
+ Rune r;
+ char *save;
+ int i, n;
+
+ s += chartorune(rp, s);
+ if((r = *rp) == '\\' && *s){
+ n = 0;
+ if (*s == 'x') {
+ s++;
+ for (i = 0; i < 4; i++) {
+ save = s;
+ s += chartorune(&r, s);
+ if ('0' <= r && r <= '9')
+ n = 16*n + r - '0';
+ else if ('a' <= r && r <= 'f')
+ n = 16*n + r - 'a' + 10;
+ else if ('A' <= r && r <= 'F')
+ n = 16*n + r - 'A' + 10;
+ else {
+ if (i == 0)
+ *rp = 'x';
+ else *rp = n;
+ return save;
+ }
+ }
+ } else {
+ for(i = 0; i < 3; i++) {
+ save = s;
+ s += chartorune(&r, s);
+ if('0' <= r && r <= '7')
+ n = 8*n + r - '0';
+ else {
+ if (i == 0)
+ {
+ *rp = r;
+ return s;
+ }
+ *rp = n;
+ return save;
+ }
+ }
+ if(n > 0377)
+ error("char>0377");
+ }
+ *rp = n;
+ }
+ return s;
+}
+
+long
+canon(Pcb *p)
+{
+ Rune r;
+
+ if (p->final >= 0) {
+ if (p->last < p->final)
+ return ++p->last;
+ p->final = -1;
+ }
+ if (*p->current == '\0')
+ return -1;
+ if(*p->current == '-' && p->last >= 0 && p->current[1]){
+ p->current = getrune(p->current+1, &r);
+ if (r < p->last)
+ error ("Invalid range specification");
+ if (r > p->last) {
+ p->final = r;
+ return ++p->last;
+ }
+ }
+ p->current = getrune(p->current, &r);
+ p->last = r;
+ return p->last;
+}
+
+void
+Pinit(Pcb *p, char *cp)
+{
+ p->current = p->base = cp;
+ p->last = p->final = -1;
+}
+void
+Prewind(Pcb *p)
+{
+ p->current = p->base;
+ p->last = p->final = -1;
+}
+void
+error(char *s)
+{
+ fprint(2, "%s: %s\n", argv0, s);
+ exits(s);
+} |
| diff --git a/src/cmd/unicode.c b/src/cmd/unicode.c |
| t@@ -0,0 +1,122 @@
+#include
+#include
+#include
+
+char usage[] = "unicode { [-t] hex hex ... | hexmin-hexmax ... | [-n] char ... }";
+char hex[] = "0123456789abcdefABCDEF";
+int numout = 0;
+int text = 0;
+char *err;
+Biobuf bout;
+
+char *range(char*[]);
+char *nums(char*[]);
+char *chars(char*[]);
+
+void
+main(int argc, char *argv[])
+{
+ ARGBEGIN{
+ case 'n':
+ numout = 1;
+ break;
+ case 't':
+ text = 1;
+ break;
+ }ARGEND
+ Binit(&bout, 1, OWRITE);
+ if(argc == 0){
+ fprint(2, "usage: %s\n", usage);
+ exits("usage");
+ }
+ if(!numout && utfrune(argv[0], '-'))
+ exits(range(argv));
+ if(numout || strchr(hex, argv[0][0])==0)
+ exits(nums(argv));
+ exits(chars(argv));
+}
+
+char*
+range(char *argv[])
+{
+ char *q;
+ int min, max;
+ int i;
+
+ while(*argv){
+ q = *argv;
+ if(strchr(hex, q[0]) == 0){
+ err:
+ fprint(2, "unicode: bad range %s\n", *argv);
+ return "bad range";
+ }
+ min = strtoul(q, &q, 16);
+ if(min<0 || min>0xFFFF || *q!='-')
+ goto err;
+ q++;
+ if(strchr(hex, *q) == 0)
+ goto err;
+ max = strtoul(q, &q, 16);
+ if(max<0 || max>0xFFFF || max0xFFFF || *q!=0)
+ goto err;
+ Bprint(&bout, "%C", m);
+ if(!text)
+ Bprint(&bout, "\n");
+ argv++;
+ }
+ return 0;
+} |
| diff --git a/src/cmd/uniq.c b/src/cmd/uniq.c |
| t@@ -0,0 +1,169 @@
+/*
+ * Deal with duplicated lines in a file
+ */
+#include
+#include
+#include
+#include
+
+#define SIZE 8000
+
+int fields = 0;
+int letters = 0;
+int linec = 0;
+char mode;
+int uniq;
+char *b1, *b2;
+long bsize;
+Biobuf fin;
+Biobuf fout;
+
+int gline(char *buf);
+void pline(char *buf);
+int equal(char *b1, char *b2);
+char* skip(char *s);
+
+void
+main(int argc, char *argv[])
+{
+ int f;
+
+ bsize = SIZE;
+ b1 = malloc(bsize);
+ b2 = malloc(bsize);
+ f = 0;
+ while(argc > 1) {
+ if(*argv[1] == '-') {
+ if(isdigit(argv[1][1]))
+ fields = atoi(&argv[1][1]);
+ else
+ mode = argv[1][1];
+ argc--;
+ argv++;
+ continue;
+ }
+ if(*argv[1] == '+') {
+ letters = atoi(&argv[1][1]);
+ argc--;
+ argv++;
+ continue;
+ }
+ f = open(argv[1], 0);
+ if(f < 0) {
+ fprint(2, "cannot open %s\n", argv[1]);
+ exits("open");
+ }
+ break;
+ }
+ if(argc > 2) {
+ fprint(2, "unexpected argument %s\n", argv[2]);
+ exits("arg");
+ }
+ Binit(&fin, f, OREAD);
+ Binit(&fout, 1, OWRITE);
+
+ if(gline(b1))
+ exits(0);
+ for(;;) {
+ linec++;
+ if(gline(b2)) {
+ pline(b1);
+ exits(0);
+ }
+ if(!equal(b1, b2)) {
+ pline(b1);
+ linec = 0;
+ do {
+ linec++;
+ if(gline(b1)) {
+ pline(b2);
+ exits(0);
+ }
+ } while(equal(b2, b1));
+ pline(b2);
+ linec = 0;
+ }
+ }
+}
+
+int
+gline(char *buf)
+{
+ char *p;
+
+ p = Brdline(&fin, '\n');
+ if(p == 0)
+ return 1;
+ if(fin.rdline >= bsize-1) {
+ fprint(2, "line too long\n");
+ exits("too long");
+ }
+ memmove(buf, p, fin.rdline);
+ buf[fin.rdline-1] = 0;
+ return 0;
+}
+
+void
+pline(char *buf)
+{
+
+ switch(mode) {
+
+ case 'u':
+ if(uniq) {
+ uniq = 0;
+ return;
+ }
+ break;
+
+ case 'd':
+ if(uniq)
+ break;
+ return;
+
+ case 'c':
+ Bprint(&fout, "%4d ", linec);
+ }
+ uniq = 0;
+ Bprint(&fout, "%s\n", buf);
+}
+
+int
+equal(char *b1, char *b2)
+{
+ char c;
+
+ if(fields || letters) {
+ b1 = skip(b1);
+ b2 = skip(b2);
+ }
+ for(;;) {
+ c = *b1++;
+ if(c != *b2++) {
+ if(c == 0 && mode == 's')
+ return 1;
+ return 0;
+ }
+ if(c == 0) {
+ uniq++;
+ return 1;
+ }
+ }
+}
+
+char*
+skip(char *s)
+{
+ int nf, nl;
+
+ nf = nl = 0;
+ while(nf++ < fields) {
+ while(*s == ' ' || *s == '\t')
+ s++;
+ while(!(*s == ' ' || *s == '\t' || *s == 0) )
+ s++;
+ }
+ while(nl++ < letters && *s != 0)
+ s++;
+ return s;
+} |
| diff --git a/src/cmd/unutf.c b/src/cmd/unutf.c |
| t@@ -0,0 +1,16 @@
+#include
+#include
+#include
+
+Biobuf bin;
+
+void
+main(void)
+{
+ int c;
+
+ Binit(&bin, 0, OREAD);
+ while((c = Bgetrune(&bin)) >= 0)
+ print("0x%ux\n", c);
+ exits(0);
+} |
| diff --git a/src/cmd/wc.c b/src/cmd/wc.c |
| t@@ -0,0 +1,309 @@
+/*
+ * wc -- count things in utf-encoded text files
+ * Bugs:
+ * The only white space characters recognized are ' ', '\t' and '\n', even though
+ * ISO 10646 has many more blanks scattered through it.
+ * Should count characters that cannot occur in any rune (hex f0-ff) separately.
+ * Should count non-canonical runes (e.g. hex c1,80 instead of hex 40).
+ */
+#include
+#include
+#define NBUF (8*1024)
+uvlong nline, tnline, pline;
+uvlong nword, tnword, pword;
+uvlong nrune, tnrune, prune;
+uvlong nbadr, tnbadr, pbadr;
+uvlong nchar, tnchar, pchar;
+void count(int, char *);
+void report(uvlong, uvlong, uvlong, uvlong, uvlong, char *);
+void
+main(int argc, char *argv[])
+{
+ char *status="";
+ int i, f;
+ ARGBEGIN {
+ case 'l': pline++; break;
+ case 'w': pword++; break;
+ case 'r': prune++; break;
+ case 'b': pbadr++; break;
+ case 'c': pchar++; break;
+ default:
+ fprint(2, "Usage: %s [-lwrbc] [file ...]\n", argv0);
+ exits("usage");
+ } ARGEND
+ if(pline+pword+prune+pbadr+pchar == 0) {
+ pline = 1;
+ pword = 1;
+ pchar = 1;
+ }
+ if(argc==0)
+ count(0, 0);
+ else{
+ for(i=0;i1)
+ report(tnline, tnword, tnrune, tnbadr, tnchar, "total");
+ }
+ exits(status);
+}
+void
+report(uvlong nline, uvlong nword, uvlong nrune, uvlong nbadr, uvlong nchar, char *fname)
+{
+ char line[1024], word[128];
+ line[0] = '\0';
+ if(pline){
+ sprint(word, " %7llud", nline);
+ strcat(line, word);
+ }
+ if(pword){
+ sprint(word, " %7llud", nword);
+ strcat(line, word);
+ }
+ if(prune){
+ sprint(word, " %7llud", nrune);
+ strcat(line, word);
+ }
+ if(pbadr){
+ sprint(word, " %7llud", nbadr);
+ strcat(line, word);
+ }
+ if(pchar){
+ sprint(word, " %7llud", nchar);
+ strcat(line, word);
+ }
+ if(fname){
+ sprint(word, " %s", fname);
+ strcat(line, word);
+ }
+ print("%s\n", line+1);
+}
+/*
+ * How it works. Start in statesp. Each time we read a character,
+ * increment various counts, and do state transitions according to the
+ * following table. If we're not in statesp or statewd when done, the
+ * file ends with a partial rune.
+ * | character
+ * state |09,20| 0a |00-7f|80-bf|c0-df|e0-ef|f0-ff
+ * -------+-----+-----+-----+-----+-----+-----+-----
+ * statesp|ASP |ASPN |AWDW |AWDWX|AC2W |AC3W |AWDWX
+ * statewd|ASP |ASPN |AWD |AWDX |AC2 |AC3 |AWDX
+ * statec2|ASPX |ASPNX|AWDX |AWDR |AC2X |AC3X |AWDX
+ * statec3|ASPX |ASPNX|AWDX |AC2R |AC2X |AC3X |AWDX
+ */
+enum{ /* actions */
+ AC2, /* enter statec2 */
+ AC2R, /* enter statec2, don't count a rune */
+ AC2W, /* enter statec2, count a word */
+ AC2X, /* enter statec2, count a bad rune */
+ AC3, /* enter statec3 */
+ AC3W, /* enter statec3, count a word */
+ AC3X, /* enter statec3, count a bad rune */
+ ASP, /* enter statesp */
+ ASPN, /* enter statesp, count a newline */
+ ASPNX, /* enter statesp, count a newline, count a bad rune */
+ ASPX, /* enter statesp, count a bad rune */
+ AWD, /* enter statewd */
+ AWDR, /* enter statewd, don't count a rune */
+ AWDW, /* enter statewd, count a word */
+ AWDWX, /* enter statewd, count a word, count a bad rune */
+ AWDX, /* enter statewd, count a bad rune */
+};
+uchar statesp[256]={ /* looking for the start of a word */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 00-07 */
+AWDW, ASP, ASPN, AWDW, AWDW, AWDW, AWDW, AWDW, /* 08-0f */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 10-17 */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 18-1f */
+ASP, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 20-27 */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 28-2f */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 30-37 */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 38-3f */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 40-47 */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 48-4f */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 50-57 */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 58-5f */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 60-67 */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 68-6f */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 70-77 */
+AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, AWDW, /* 78-7f */
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,/* 80-87 */
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,/* 88-8f */
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,/* 90-97 */
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,/* 98-9f */
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,/* a0-a7 */
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,/* a8-af */
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,/* b0-b7 */
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,/* b8-bf */
+AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, /* c0-c7 */
+AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, /* c8-cf */
+AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, /* d0-d7 */
+AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, AC2W, /* d8-df */
+AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, /* e0-e7 */
+AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, AC3W, /* e8-ef */
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,/* f0-f7 */
+AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,AWDWX,/* f8-ff */
+};
+uchar statewd[256]={ /* looking for the next character in a word */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 00-07 */
+AWD, ASP, ASPN, AWD, AWD, AWD, AWD, AWD, /* 08-0f */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 10-17 */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 18-1f */
+ASP, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 20-27 */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 28-2f */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 30-37 */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 38-3f */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 40-47 */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 48-4f */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 50-57 */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 58-5f */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 60-67 */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 68-6f */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 70-77 */
+AWD, AWD, AWD, AWD, AWD, AWD, AWD, AWD, /* 78-7f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 80-87 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 88-8f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 90-97 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 98-9f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* a0-a7 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* a8-af */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* b0-b7 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* b8-bf */
+AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, /* c0-c7 */
+AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, /* c8-cf */
+AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, /* d0-d7 */
+AC2, AC2, AC2, AC2, AC2, AC2, AC2, AC2, /* d8-df */
+AC3, AC3, AC3, AC3, AC3, AC3, AC3, AC3, /* e0-e7 */
+AC3, AC3, AC3, AC3, AC3, AC3, AC3, AC3, /* e8-ef */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* f0-f7 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* f8-ff */
+};
+uchar statec2[256]={ /* looking for 10xxxxxx to complete a rune */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 00-07 */
+AWDX, ASPX, ASPNX,AWDX, AWDX, AWDX, AWDX, AWDX, /* 08-0f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 10-17 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 18-1f */
+ASPX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 20-27 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 28-2f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 30-37 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 38-3f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 40-47 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 48-4f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 50-57 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 58-5f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 60-67 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 68-6f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 70-77 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 78-7f */
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, /* 80-87 */
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, /* 88-8f */
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, /* 90-97 */
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, /* 98-9f */
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, /* a0-a7 */
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, /* a8-af */
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, /* b0-b7 */
+AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, AWDR, /* b8-bf */
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, /* c0-c7 */
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, /* c8-cf */
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, /* d0-d7 */
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, /* d8-df */
+AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, /* e0-e7 */
+AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, /* e8-ef */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* f0-f7 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* f8-ff */
+};
+uchar statec3[256]={ /* looking for 10xxxxxx,10xxxxxx to complete a rune */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 00-07 */
+AWDX, ASPX, ASPNX,AWDX, AWDX, AWDX, AWDX, AWDX, /* 08-0f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 10-17 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 18-1f */
+ASPX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 20-27 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 28-2f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 30-37 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 38-3f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 40-47 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 48-4f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 50-57 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 58-5f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 60-67 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 68-6f */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 70-77 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* 78-7f */
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, /* 80-87 */
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, /* 88-8f */
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, /* 90-97 */
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, /* 98-9f */
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, /* a0-a7 */
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, /* a8-af */
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, /* b0-b7 */
+AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, AC2R, /* b8-bf */
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, /* c0-c7 */
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, /* c8-cf */
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, /* d0-d7 */
+AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, AC2X, /* d8-df */
+AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, /* e0-e7 */
+AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, AC3X, /* e8-ef */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* f0-f7 */
+AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, AWDX, /* f8-ff */
+};
+void
+count(int f, char *name)
+{
+ int n;
+ uchar buf[NBUF];
+ uchar *bufp, *ebuf;
+ uchar *state=statesp;
+
+ nline = 0;
+ nword = 0;
+ nrune = 0;
+ nbadr = 0;
+ nchar = 0;
+
+ for(;;){
+ n=read(f, buf, NBUF);
+ if(n<=0)
+ break;
+ nchar+=n;
+ nrune+=n; /* might be too large, gets decreased later */
+ bufp=buf;
+ ebuf=buf+n;
+ do{
+ switch(state[*bufp]){
+ case AC2: state=statec2; break;
+ case AC2R: state=statec2; --nrune; break;
+ case AC2W: state=statec2; nword++; break;
+ case AC2X: state=statec2; nbadr++; break;
+ case AC3: state=statec3; break;
+ case AC3W: state=statec3; nword++; break;
+ case AC3X: state=statec3; nbadr++; break;
+ case ASP: state=statesp; break;
+ case ASPN: state=statesp; nline++; break;
+ case ASPNX: state=statesp; nline++; nbadr++; break;
+ case ASPX: state=statesp; nbadr++; break;
+ case AWD: state=statewd; break;
+ case AWDR: state=statewd; --nrune; break;
+ case AWDW: state=statewd; nword++; break;
+ case AWDWX: state=statewd; nword++; nbadr++; break;
+ case AWDX: state=statewd; nbadr++; break;
+ }
+ }while(++bufp!=ebuf);
+ }
+ if(state!=statesp && state!=statewd)
+ nbadr++;
+ if(n<0)
+ perror(name);
+ report(nline, nword, nrune, nbadr, nchar, name);
+} |
| diff --git a/src/cmd/xd.c b/src/cmd/xd.c |
| t@@ -0,0 +1,355 @@
+#include
+#include
+#include
+
+unsigned char odata[16];
+unsigned char data[16];
+int ndata;
+unsigned long addr;
+int repeats;
+int swizzle;
+int flush;
+int abase=2;
+int xd(char *, int);
+void xprint(char *, long);
+void initarg(void), swizz(void);
+enum{
+ Narg=10
+};
+typedef struct Arg Arg;
+typedef void fmtfn(char *);
+struct Arg
+{
+ int ascii; /* 0==none, 1==ascii */
+ int loglen; /* 0==1, 1==2, 2==4, 3==8 */
+ int base; /* 0==8, 1==10, 2==16 */
+ fmtfn *fn; /* function to call with data */
+ char *afmt; /* format to use to print address */
+ char *fmt; /* format to use to print data */
+}arg[Narg];
+int narg;
+
+fmtfn fmt0, fmt1, fmt2, fmt3, fmtc;
+fmtfn *fmt[4] = {
+ fmt0,
+ fmt1,
+ fmt2,
+ fmt3
+};
+
+char *dfmt[4][3] = {
+ " %.3uo", " %.3ud", " %.2ux",
+ " %.6uo", " %.5ud", " %.4ux",
+ " %.11luo", " %.10lud", " %.8lux",
+ " %.22lluo", " %.20llud", " %.16llux",
+};
+
+char *cfmt[3][3] = {
+ " %c", " %c", " %c",
+ " %.3s", " %.3s", " %.2s",
+ " %.3uo", " %.3ud", " %.2ux",
+};
+
+char *afmt[2][3] = {
+ "%.7luo ", "%.7lud ", "%.7lux ",
+ "%7luo ", "%7lud ", "%7lux ",
+};
+
+Biobuf bin;
+Biobuf bout;
+
+void
+main(int argc, char *argv[])
+{
+ int i, err;
+ Arg *ap;
+
+ Binit(&bout, 1, OWRITE);
+ err = 0;
+ ap = 0;
+ while(argc>1 && argv[1][0]=='-' && argv[1][1]){
+ --argc;
+ argv++;
+ argv[0]++;
+ if(argv[0][0] == 'r'){
+ repeats = 1;
+ if(argv[0][1])
+ goto Usage;
+ continue;
+ }
+ if(argv[0][0] == 's'){
+ swizzle = 1;
+ if(argv[0][1])
+ goto Usage;
+ continue;
+ }
+ if(argv[0][0] == 'u'){
+ flush = 1;
+ if(argv[0][1])
+ goto Usage;
+ continue;
+ }
+ if(argv[0][0] == 'a'){
+ argv[0]++;
+ switch(argv[0][0]){
+ case 'o':
+ abase = 0;
+ break;
+ case 'd':
+ abase = 1;
+ break;
+ case 'x':
+ abase = 2;
+ break;
+ default:
+ goto Usage;
+ }
+ if(argv[0][1])
+ goto Usage;
+ continue;
+ }
+ ap = &arg[narg];
+ initarg();
+ while(argv[0][0]){
+ switch(argv[0][0]){
+ case 'c':
+ ap->ascii = 1;
+ ap->loglen = 0;
+ if(argv[0][1] || argv[0][-1]!='-')
+ goto Usage;
+ break;
+ case 'o':
+ ap->base = 0;
+ break;
+ case 'd':
+ ap->base = 1;
+ break;
+ case 'x':
+ ap->base = 2;
+ break;
+ case 'b':
+ case '1':
+ ap->loglen = 0;
+ break;
+ case 'w':
+ case '2':
+ ap->loglen = 1;
+ break;
+ case 'l':
+ case '4':
+ ap->loglen = 2;
+ break;
+ case 'v':
+ case '8':
+ ap->loglen = 3;
+ break;
+ default:
+ Usage:
+ fprint(2, "usage: xd [-u] [-r] [-s] [-a{odx}] [-c|{b1w2l4v8}{odx}] ... file ...\n");
+ exits("usage");
+ }
+ argv[0]++;
+ }
+ if(ap->ascii)
+ ap->fn = fmtc;
+ else
+ ap->fn = fmt[ap->loglen];
+ ap->fmt = dfmt[ap->loglen][ap->base];
+ ap->afmt = afmt[ap>arg][abase];
+ }
+ if(narg == 0)
+ initarg();
+ if(argc == 1)
+ err = xd(0, 0);
+ else if(argc == 2)
+ err = xd(argv[1], 0);
+ else for(i=1; i= Narg){
+ fprint(2, "xd: too many formats (max %d)\n", Narg);
+ exits("usage");
+ }
+ ap->ascii = 0;
+ ap->loglen = 2;
+ ap->base = 2;
+ ap->fn = fmt2;
+ ap->fmt = dfmt[ap->loglen][ap->base];
+ ap->afmt = afmt[narg>1][abase];
+}
+
+int
+xd(char *name, int title)
+{
+ int fd;
+ int i, star;
+ Arg *ap;
+ Biobuf *bp;
+
+ fd = 0;
+ if(name){
+ bp = Bopen(name, OREAD);
+ if(bp == 0){
+ fprint(2, "xd: can't open %s\n", name);
+ return 1;
+ }
+ }else{
+ bp = &bin;
+ Binit(bp, fd, OREAD);
+ }
+ if(title)
+ xprint("%s\n", (long)name);
+ addr = 0;
+ star = 0;
+ while((ndata=Bread(bp, data, 16)) >= 0){
+ if(ndata < 16)
+ for(i=ndata; i<16; i++)
+ data[i] = 0;
+ if(swizzle)
+ swizz();
+ if(ndata==16 && repeats){
+ if(addr>0 && data[0]==odata[0]){
+ for(i=1; i<16; i++)
+ if(data[i] != odata[i])
+ break;
+ if(i == 16){
+ addr += 16;
+ if(star == 0){
+ star++;
+ xprint("*\n", 0);
+ }
+ continue;
+ }
+ }
+ for(i=0; i<16; i++)
+ odata[i] = data[i];
+ star = 0;
+ }
+ for(ap=arg; ap<&arg[narg]; ap++){
+ xprint(ap->afmt, addr);
+ (*ap->fn)(ap->fmt);
+ xprint("\n", 0);
+ if(flush)
+ Bflush(&bout);
+ }
+ addr += ndata;
+ if(ndata<16){
+ xprint(afmt[0][abase], addr);
+ xprint("\n", 0);
+ if(flush)
+ Bflush(&bout);
+ break;
+ }
+ }
+ Bterm(bp);
+ return 0;
+}
+
+void
+swizz(void)
+{
+ uchar *p, *q;
+ int i;
+ uchar swdata[16];
+
+ p = data;
+ q = swdata;
+ for(i=0; i<16; i++)
+ *q++ = *p++;
+ p = data;
+ q = swdata;
+ for(i=0; i<4; i++){
+ p[0] = q[3];
+ p[1] = q[2];
+ p[2] = q[1];
+ p[3] = q[0];
+ p += 4;
+ q += 4;
+ }
+}
+
+void
+fmt0(char *f)
+{
+ int i;
+ for(i=0; i=0x7F || ' '>data[i])
+ xprint(cfmt[2][2], data[i]);
+ else
+ xprint(cfmt[0][2], data[i]);
+ break;
+ }
+}
+
+void
+xprint(char *fmt, long d)
+{
+ if(Bprint(&bout, fmt, d)<0){
+ fprint(2, "xd: i/o error\n");
+ exits("i/o error");
+ }
+} |
| diff --git a/src/cmd/yacc.c b/src/cmd/yacc.c |
| t@@ -0,0 +1,2939 @@
+#include
+#include
+#include
+#include
+
+#define Bungetrune Bungetc /* ok for now. */
+
+/*
+ * all these are 32 bit
+ */
+#define TBITSET ((32+NTERMS)/32) /* BOTCH?? +31 */
+#define BIT(a,i) ((a)[(i)>>5] & (1<<((i)&037)))
+#define SETBIT(a,i) ((a)[(i)>>5] |= (1<<((i)&037)))
+#define NWORDS(n) (((n)+32)/32)
+
+#define PARSER "/sys/lib/yaccpar"
+#define PARSERS "/sys/lib/yaccpars"
+#define TEMPNAME "y.tmp.XXXXXX"
+#define ACTNAME "y.acts.XXXXXX"
+#define OFILE "tab.c"
+#define FILEU "output"
+#define FILED "tab.h"
+#define FILEDEBUG "debug"
+
+enum
+{
+/*
+ * the following are adjustable
+ * according to memory size
+ */
+ ACTSIZE = 40000,
+ MEMSIZE = 40000,
+ NSTATES = 2000,
+ NTERMS = 511,
+ NPROD = 1600,
+ NNONTERM = 600,
+ TEMPSIZE = 2000,
+ CNAMSZ = 10000,
+ LSETSIZE = 2400,
+ WSETSIZE = 350,
+
+ NAMESIZE = 50,
+ NTYPES = 63,
+ ISIZE = 400,
+
+ PRIVATE = 0xE000, /* unicode private use */
+
+ /* relationships which must hold:
+ TBITSET ints must hold NTERMS+1 bits...
+ WSETSIZE >= NNONTERM
+ LSETSIZE >= NNONTERM
+ TEMPSIZE >= NTERMS + NNONTERM + 1
+ TEMPSIZE >= NSTATES
+ */
+
+ NTBASE = 010000,
+ ERRCODE = 8190,
+ ACCEPTCODE = 8191,
+
+ NOASC = 0, /* no assoc. */
+ LASC = 1, /* left assoc. */
+ RASC = 2, /* right assoc. */
+ BASC = 3, /* binary assoc. */
+
+ /* flags for state generation */
+
+ DONE = 0,
+ MUSTDO = 1,
+ MUSTLOOKAHEAD = 2,
+
+ /* flags for a rule having an action, and being reduced */
+
+ ACTFLAG = 04,
+ REDFLAG = 010,
+
+ /* output parser flags */
+ YYFLAG1 = -1000,
+
+ /* parse tokens */
+ IDENTIFIER = PRIVATE,
+ MARK,
+ TERM,
+ LEFT,
+ RIGHT,
+ BINARY,
+ PREC,
+ LCURLY,
+ IDENTCOLON,
+ NUMBER,
+ START,
+ TYPEDEF,
+ TYPENAME,
+ UNION,
+
+ ENDFILE = 0,
+
+ EMPTY = 1,
+ WHOKNOWS = 0,
+ OK = 1,
+ NOMORE = -1000,
+};
+
+ /* macros for getting associativity and precedence levels */
+
+#define ASSOC(i) ((i)&03)
+#define PLEVEL(i) (((i)>>4)&077)
+#define TYPE(i) (((i)>>10)&077)
+
+ /* macros for setting associativity and precedence levels */
+
+#define SETASC(i,j) i |= j
+#define SETPLEV(i,j) i |= (j<<4)
+#define SETTYPE(i,j) i |= (j<<10)
+
+ /* looping macros */
+
+#define TLOOP(i) for(i=1; i<=ntokens; i++)
+#define NTLOOP(i) for(i=0; i<=nnonter; i++)
+#define PLOOP(s,i) for(i=s; i= 0 && j < 256) {
+ if(temp1[j]) {
+ print("yacc bug -- cant have 2 different Ts with same value\n");
+ print(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name);
+ nerrors++;
+ }
+ temp1[j] = i;
+ if(j > c)
+ c = j;
+ }
+ }
+ warray("yytok1", temp1, c+1);
+
+ /* table 2 has PRIVATE-PRIVATE+256 */
+ aryfil(temp1, 256, 0);
+ c = 0;
+ TLOOP(i) {
+ j = tokset[i].value - PRIVATE;
+ if(j >= 0 && j < 256) {
+ if(temp1[j]) {
+ print("yacc bug -- cant have 2 different Ts with same value\n");
+ print(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name);
+ nerrors++;
+ }
+ temp1[j] = i;
+ if(j > c)
+ c = j;
+ }
+ }
+ warray("yytok2", temp1, c+1);
+
+ /* table 3 has everything else */
+ Bprint(ftable, "long yytok3[] =\n{\n");
+ c = 0;
+ TLOOP(i) {
+ j = tokset[i].value;
+ if(j >= 0 && j < 256)
+ continue;
+ if(j >= PRIVATE && j < 256+PRIVATE)
+ continue;
+
+ Bprint(ftable, "%4d,%4d,", j, i);
+ c++;
+ if(c%5 == 0)
+ Bprint(ftable, "\n");
+ }
+ Bprint(ftable, "%4d\n};\n", 0);
+
+ /* copy parser text */
+ while((c=Bgetrune(finput)) != Beof) {
+ if(c == '$') {
+ if((c = Bgetrune(finput)) != 'A')
+ Bputrune(ftable, '$');
+ else { /* copy actions */
+ faction = Bopen(actname, OREAD);
+ if(faction == 0)
+ error("cannot reopen action tempfile");
+ while((c=Bgetrune(faction)) != Beof)
+ Bputrune(ftable, c);
+ Bterm(faction);
+ ZAPFILE(actname);
+ c = Bgetrune(finput);
+ }
+ }
+ Bputrune(ftable, c);
+ }
+ Bterm(ftable);
+}
+
+/*
+ * copies string q into p, returning next free char ptr
+ */
+char*
+chcopy(char* p, char* q)
+{
+ int c;
+
+ while(c = *q) {
+ if(c == '"')
+ *p++ = '\\';
+ *p++ = c;
+ q++;
+ }
+ *p = 0;
+ return p;
+}
+
+/*
+ * creates output string for item pointed to by pp
+ */
+char*
+writem(int *pp)
+{
+ int i,*p;
+ static char sarr[ISIZE];
+ char* q;
+
+ for(p=pp; *p>0; p++)
+ ;
+ p = prdptr[-*p];
+ q = chcopy(sarr, nontrst[*p-NTBASE].name);
+ q = chcopy(q, ": ");
+ for(;;) {
+ *q = ' ';
+ p++;
+ if(p == pp)
+ *q = '.';
+ q++;
+ *q = '\0';
+ i = *p;
+ if(i <= 0)
+ break;
+ q = chcopy(q, symnam(i));
+ if(q > &sarr[ISIZE-30])
+ error("item too big");
+ }
+
+ /* an item calling for a reduction */
+ i = *pp;
+ if(i < 0 ) {
+ q = chcopy(q, " (");
+ sprint(q, "%d)", -i);
+ }
+ return sarr;
+}
+
+/*
+ * return a pointer to the name of symbol i
+ */
+char*
+symnam(int i)
+{
+ char* cp;
+
+ cp = (i >= NTBASE)? nontrst[i-NTBASE].name: tokset[i].name;
+ if(*cp == ' ')
+ cp++;
+ return cp;
+}
+
+/*
+ * output the summary on y.output
+ */
+void
+summary(void)
+{
+
+ if(foutput != 0) {
+ Bprint(foutput, "\n%d/%d terminals, %d/%d nonterminals\n",
+ ntokens, NTERMS, nnonter, NNONTERM);
+ Bprint(foutput, "%d/%d grammar rules, %d/%d states\n",
+ nprod, NPROD, nstate, NSTATES);
+ Bprint(foutput, "%d shift/reduce, %d reduce/reduce conflicts reported\n",
+ zzsrconf, zzrrconf);
+ Bprint(foutput, "%d/%d working sets used\n",
+ (int)(zzcwp-wsets), WSETSIZE);
+ Bprint(foutput, "memory: states,etc. %d/%d, parser %d/%d\n",
+ (int)(zzmemsz-mem0), MEMSIZE, (int)(memp-amem), ACTSIZE);
+ Bprint(foutput, "%d/%d distinct lookahead sets\n", nlset, LSETSIZE);
+ Bprint(foutput, "%d extra closures\n", zzclose - 2*nstate);
+ Bprint(foutput, "%d shift entries, %d exceptions\n", zzacent, zzexcp);
+ Bprint(foutput, "%d goto entries\n", zzgoent);
+ Bprint(foutput, "%d entries saved by goto default\n", zzgobest);
+ }
+ if(zzsrconf != 0 || zzrrconf != 0) {
+ print("\nconflicts: ");
+ if(zzsrconf)
+ print("%d shift/reduce", zzsrconf);
+ if(zzsrconf && zzrrconf)
+ print(", ");
+ if(zzrrconf)
+ print("%d reduce/reduce", zzrrconf);
+ print("\n");
+ }
+ if(ftemp != 0) {
+ Bterm(ftemp);
+ ftemp = 0;
+ }
+ if(fdefine != 0) {
+ Bterm(fdefine);
+ fdefine = 0;
+ }
+}
+
+/*
+ * write out error comment -- NEEDS WORK
+ */
+void
+error(char *s, ...)
+{
+
+ nerrors++;
+ fprint(2, "\n fatal error:");
+ fprint(2, s, (&s)[1]);
+ fprint(2, ", %s:%d\n", infile, lineno);
+ if(!fatfl)
+ return;
+ summary();
+ cleantmp();
+ exits("error");
+}
+
+/*
+ * set elements 0 through n-1 to c
+ */
+void
+aryfil(int *v, int n, int c)
+{
+ int i;
+
+ for(i=0; ilset;
+ if(pp == 0)
+ Bprint(foutput, "\tNULL");
+ else {
+ Bprint(foutput, " { ");
+ TLOOP(j)
+ if(BIT(pp,j))
+ Bprint(foutput, "%s ", symnam(j));
+ Bprint(foutput, "}");
+ }
+}
+
+/*
+ * compute an array with the beginnings of productions yielding given nonterminals
+ * The array pres points to these lists
+ * the array pyield has the lists: the total size is only NPROD+1
+ */
+void
+cpres(void)
+{
+ int c, j, i, **pmem;
+ static int *pyield[NPROD];
+
+ pmem = pyield;
+ NTLOOP(i) {
+ c = i+NTBASE;
+ pres[i] = pmem;
+ fatfl = 0; /* make undefined symbols nonfatal */
+ PLOOP(0, j)
+ if(*prdptr[j] == c)
+ *pmem++ = prdptr[j]+1;
+ if(pres[i] == pmem)
+ error("nonterminal %s not defined!", nontrst[i].name);
+ }
+ pres[i] = pmem;
+ fatfl = 1;
+ if(nerrors) {
+ summary();
+ cleantmp();
+ exits("error");
+ }
+ if(pmem != &pyield[nprod])
+ error("internal Yacc error: pyield %d", pmem-&pyield[nprod]);
+}
+
+/*
+ * compute an array with the first of nonterminals
+ */
+void
+cpfir(void)
+{
+ int *p, **s, i, **t, ch, changes;
+
+ zzcwp = &wsets[nnonter];
+ NTLOOP(i) {
+ aryfil(wsets[i].ws.lset, tbitset, 0);
+ t = pres[i+1];
+ /* initially fill the sets */
+ for(s=pres[i]; s 0; ++p) {
+ if(ch < NTBASE) {
+ SETBIT(wsets[i].ws.lset, ch);
+ break;
+ }
+ if(!pempty[ch-NTBASE])
+ break;
+ }
+ }
+
+ /* now, reflect transitivity */
+ changes = 1;
+ while(changes) {
+ changes = 0;
+ NTLOOP(i) {
+ t = pres[i+1];
+ for(s = pres[i]; s < t; ++s)
+ for(p = *s; (ch = (*p-NTBASE)) >= 0; ++p) {
+ changes |= setunion(wsets[i].ws.lset, wsets[ch].ws.lset);
+ if(!pempty[ch])
+ break;
+ }
+ }
+ }
+
+ NTLOOP(i)
+ pfirst[i] = flset(&wsets[i].ws);
+ if(!indebug)
+ return;
+ if(foutput != 0)
+ NTLOOP(i) {
+ Bprint(foutput, "\n%s: ", nontrst[i].name);
+ prlook(pfirst[i]);
+ Bprint(foutput, " %d\n", pempty[i]);
+ }
+}
+
+/*
+ * sorts last state,and sees if it equals earlier ones. returns state number
+ */
+int
+state(int c)
+{
+ Item *p1, *p2, *k, *l, *q1, *q2;
+ int size1, size2, i;
+
+ p1 = pstate[nstate];
+ p2 = pstate[nstate+1];
+ if(p1 == p2)
+ return 0; /* null state */
+ /* sort the items */
+ for(k = p2-1; k > p1; k--) /* make k the biggest */
+ for(l = k-1; l >= p1; --l)
+ if(l->pitem > k->pitem) {
+ int *s;
+ Lkset *ss;
+
+ s = k->pitem;
+ k->pitem = l->pitem;
+ l->pitem = s;
+ ss = k->look;
+ k->look = l->look;
+ l->look = ss;
+ }
+ size1 = p2 - p1; /* size of state */
+
+ for(i = (c>=NTBASE)? ntstates[c-NTBASE]: tstates[c]; i != 0; i = mstates[i]) {
+ /* get ith state */
+ q1 = pstate[i];
+ q2 = pstate[i+1];
+ size2 = q2 - q1;
+ if(size1 != size2)
+ continue;
+ k = p1;
+ for(l = q1; l < q2; l++) {
+ if(l->pitem != k->pitem)
+ break;
+ k++;
+ }
+ if(l != q2)
+ continue;
+ /* found it */
+ pstate[nstate+1] = pstate[nstate]; /* delete last state */
+ /* fix up lookaheads */
+ if(nolook)
+ return i;
+ for(l = q1, k = p1; l < q2; ++l, ++k ) {
+ int s;
+
+ SETLOOP(s)
+ clset.lset[s] = l->look->lset[s];
+ if(setunion(clset.lset, k->look->lset)) {
+ tystate[i] = MUSTDO;
+ /* register the new set */
+ l->look = flset( &clset );
+ }
+ }
+ return i;
+ }
+ /* state is new */
+ if(nolook)
+ error("yacc state/nolook error");
+ pstate[nstate+2] = p2;
+ if(nstate+1 >= NSTATES)
+ error("too many states");
+ if(c >= NTBASE) {
+ mstates[nstate] = ntstates[c-NTBASE];
+ ntstates[c-NTBASE] = nstate;
+ } else {
+ mstates[nstate] = tstates[c];
+ tstates[c] = nstate;
+ }
+ tystate[nstate] = MUSTDO;
+ return nstate++;
+}
+
+void
+putitem(int *ptr, Lkset *lptr)
+{
+ Item *j;
+
+ if(pidebug && foutput != 0)
+ Bprint(foutput, "putitem(%s), state %d\n", writem(ptr), nstate);
+ j = pstate[nstate+1];
+ j->pitem = ptr;
+ if(!nolook)
+ j->look = flset(lptr);
+ pstate[nstate+1] = ++j;
+ if((int*)j > zzmemsz) {
+ zzmemsz = (int*)j;
+ if(zzmemsz >= &mem0[MEMSIZE])
+ error("out of state space");
+ }
+}
+
+/*
+ * mark nonterminals which derive the empty string
+ * also, look for nonterminals which don't derive any token strings
+ */
+void
+cempty(void)
+{
+
+ int i, *p;
+
+ /* first, use the array pempty to detect productions that can never be reduced */
+ /* set pempty to WHONOWS */
+ aryfil(pempty, nnonter+1, WHOKNOWS);
+
+ /* now, look at productions, marking nonterminals which derive something */
+more:
+ PLOOP(0, i) {
+ if(pempty[*prdptr[i] - NTBASE])
+ continue;
+ for(p = prdptr[i]+1; *p >= 0; ++p)
+ if(*p >= NTBASE && pempty[*p-NTBASE] == WHOKNOWS)
+ break;
+ /* production can be derived */
+ if(*p < 0) {
+ pempty[*prdptr[i]-NTBASE] = OK;
+ goto more;
+ }
+ }
+
+ /* now, look at the nonterminals, to see if they are all OK */
+ NTLOOP(i) {
+ /* the added production rises or falls as the start symbol ... */
+ if(i == 0)
+ continue;
+ if(pempty[i] != OK) {
+ fatfl = 0;
+ error("nonterminal %s never derives any token string", nontrst[i].name);
+ }
+ }
+
+ if(nerrors) {
+ summary();
+ cleantmp();
+ exits("error");
+ }
+
+ /* now, compute the pempty array, to see which nonterminals derive the empty string */
+ /* set pempty to WHOKNOWS */
+ aryfil( pempty, nnonter+1, WHOKNOWS);
+
+ /* loop as long as we keep finding empty nonterminals */
+
+again:
+ PLOOP(1, i) {
+ /* not known to be empty */
+ if(pempty[*prdptr[i]-NTBASE] == WHOKNOWS) {
+ for(p = prdptr[i]+1; *p >= NTBASE && pempty[*p-NTBASE] == EMPTY ; ++p)
+ ;
+ /* we have a nontrivially empty nonterminal */
+ if(*p < 0) {
+ pempty[*prdptr[i]-NTBASE] = EMPTY;
+ /* got one ... try for another */
+ goto again;
+ }
+ }
+ }
+}
+
+/*
+ * generate the states
+ */
+void
+stagen(void)
+{
+
+ int c, i, j, more;
+ Wset *p, *q;
+
+ /* initialize */
+ nstate = 0;
+
+ /* THIS IS FUNNY from the standpoint of portability
+ * it represents the magic moment when the mem0 array, which has
+ * been holding the productions, starts to hold item pointers, of a
+ * different type...
+ * someday, alloc should be used to allocate all this stuff... for now, we
+ * accept that if pointers don't fit in integers, there is a problem...
+ */
+
+ pstate[0] = pstate[1] = (Item*)mem;
+ aryfil(clset.lset, tbitset, 0);
+ putitem(prdptr[0]+1, &clset);
+ tystate[0] = MUSTDO;
+ nstate = 1;
+ pstate[2] = pstate[1];
+
+ aryfil(amem, ACTSIZE, 0);
+
+ /* now, the main state generation loop */
+ for(more=1; more;) {
+ more = 0;
+ SLOOP(i) {
+ if(tystate[i] != MUSTDO)
+ continue;
+ tystate[i] = DONE;
+ aryfil(temp1, nnonter+1, 0);
+ /* take state i, close it, and do gotos */
+ closure(i);
+ /* generate goto's */
+ WSLOOP(wsets, p) {
+ if(p->flag)
+ continue;
+ p->flag = 1;
+ c = *(p->pitem);
+ if(c <= 1) {
+ if(pstate[i+1]-pstate[i] <= p-wsets)
+ tystate[i] = MUSTLOOKAHEAD;
+ continue;
+ }
+ /* do a goto on c */
+ WSLOOP(p, q)
+ /* this item contributes to the goto */
+ if(c == *(q->pitem)) {
+ putitem(q->pitem+1, &q->ws);
+ q->flag = 1;
+ }
+ if(c < NTBASE)
+ state(c); /* register new state */
+ else
+ temp1[c-NTBASE] = state(c);
+ }
+ if(gsdebug && foutput != 0) {
+ Bprint(foutput, "%d: ", i);
+ NTLOOP(j)
+ if(temp1[j])
+ Bprint(foutput, "%s %d, ",
+ nontrst[j].name, temp1[j]);
+ Bprint(foutput, "\n");
+ }
+ indgo[i] = apack(&temp1[1], nnonter-1) - 1;
+ /* do some more */
+ more = 1;
+ }
+ }
+}
+
+/*
+ * generate the closure of state i
+ */
+void
+closure(int i)
+{
+
+ Wset *u, *v;
+ Item *p, *q;
+ int c, ch, work, k, *pi, **s, **t;
+
+ zzclose++;
+
+ /* first, copy kernel of state i to wsets */
+ cwp = wsets;
+ ITMLOOP(i, p, q) {
+ cwp->pitem = p->pitem;
+ cwp->flag = 1; /* this item must get closed */
+ SETLOOP(k)
+ cwp->ws.lset[k] = p->look->lset[k];
+ WSBUMP(cwp);
+ }
+
+ /* now, go through the loop, closing each item */
+ work = 1;
+ while(work) {
+ work = 0;
+ WSLOOP(wsets, u) {
+ if(u->flag == 0)
+ continue;
+ /* dot is before c */
+ c = *(u->pitem);
+ if(c < NTBASE) {
+ u->flag = 0;
+ /* only interesting case is where . is before nonterminal */
+ continue;
+ }
+
+ /* compute the lookahead */
+ aryfil(clset.lset, tbitset, 0);
+
+ /* find items involving c */
+ WSLOOP(u, v)
+ if(v->flag == 1 && *(pi=v->pitem) == c) {
+ v->flag = 0;
+ if(nolook)
+ continue;
+ while((ch = *++pi) > 0) {
+ /* terminal symbol */
+ if(ch < NTBASE) {
+ SETBIT(clset.lset, ch);
+ break;
+ }
+ /* nonterminal symbol */
+ setunion(clset.lset, pfirst[ch-NTBASE]->lset);
+ if(!pempty[ch-NTBASE])
+ break;
+ }
+ if(ch <= 0)
+ setunion(clset.lset, v->ws.lset);
+ }
+
+ /*
+ * now loop over productions derived from c
+ * c is now nonterminal number
+ */
+ c -= NTBASE;
+ t = pres[c+1];
+ for(s = pres[c]; s < t; ++s) {
+ /*
+ * put these items into the closure
+ * is the item there
+ */
+ WSLOOP(wsets, v)
+ /* yes, it is there */
+ if(v->pitem == *s) {
+ if(nolook)
+ goto nexts;
+ if(setunion(v->ws.lset, clset.lset))
+ v->flag = work = 1;
+ goto nexts;
+ }
+
+ /* not there; make a new entry */
+ if(cwp-wsets+1 >= WSETSIZE)
+ error( "working set overflow");
+ cwp->pitem = *s;
+ cwp->flag = 1;
+ if(!nolook) {
+ work = 1;
+ SETLOOP(k) cwp->ws.lset[k] = clset.lset[k];
+ }
+ WSBUMP(cwp);
+
+ nexts:;
+ }
+ }
+ }
+
+ /* have computed closure; flags are reset; return */
+ if(cwp > zzcwp)
+ zzcwp = cwp;
+ if(cldebug && foutput != 0) {
+ Bprint(foutput, "\nState %d, nolook = %d\n", i, nolook);
+ WSLOOP(wsets, u) {
+ if(u->flag)
+ Bprint(foutput, "flag set!\n");
+ u->flag = 0;
+ Bprint(foutput, "\t%s", writem(u->pitem));
+ prlook(&u->ws);
+ Bprint(foutput, "\n");
+ }
+ }
+}
+
+/*
+ * decide if the lookahead set pointed to by p is known
+ * return pointer to a perminent location for the set
+ */
+Lkset*
+flset(Lkset *p)
+{
+ Lkset *q;
+ int *u, *v, *w, j;
+
+ for(q = &lkst[nlset]; q-- > lkst;) {
+ u = p->lset;
+ v = q->lset;
+ w = &v[tbitset];
+ while(v < w)
+ if(*u++ != *v++)
+ goto more;
+ /* we have matched */
+ return q;
+ more:;
+ }
+ /* add a new one */
+ q = &lkst[nlset++];
+ if(nlset >= LSETSIZE)
+ error("too many lookahead sets");
+ SETLOOP(j)
+ q->lset[j] = p->lset[j];
+ return q;
+}
+
+void
+cleantmp(void)
+{
+ ZAPFILE(actname);
+ ZAPFILE(tempname);
+}
+
+void
+intr(void)
+{
+ cleantmp();
+ exits("interrupted");
+}
+
+void
+setup(int argc, char *argv[])
+{
+ long c, t;
+ int i, j, fd, lev, ty, ytab, *p;
+ int vflag, dflag, stem;
+ char actnm[8], *stemc, *s, dirbuf[128];
+
+ ytab = 0;
+ vflag = 0;
+ dflag = 0;
+ stem = 0;
+ stemc = "y";
+ foutput = 0;
+ fdefine = 0;
+ fdebug = 0;
+ ARGBEGIN{
+ case 'v':
+ case 'V':
+ vflag++;
+ break;
+ case 'D':
+ yydebug = ARGF();
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'o':
+ ytab++;
+ ytabc = ARGF();
+ break;
+ case 's':
+ stem++;
+ stemc = ARGF();
+ break;
+ case 'S':
+ parser = PARSERS;
+ break;
+ default:
+ error("illegal option: %c", ARGC());
+ }ARGEND
+ openup(stemc, dflag, vflag, ytab, ytabc);
+
+ if((fd = mkstemp(ttempname)) >= 0){
+ tempname = ttempname;
+ ftemp = Bfdopen(fd, OWRITE);
+ }
+ if((fd = mkstemp(tactname)) >= 0){
+ actname = tactname;
+ faction = Bfdopen(fd, OWRITE);
+ }
+ if(ftemp == 0 || faction == 0)
+ error("cannot open temp file");
+ if(argc < 1)
+ error("no input file");
+ infile = argv[0];
+ if(infile[0] != '/' && getwd(dirbuf, sizeof dirbuf)!=nil){
+ i = strlen(infile)+1+strlen(dirbuf)+1+10;
+ s = malloc(i);
+ if(s != nil){
+ snprint(s, i, "%s/%s", dirbuf, infile);
+ cleanname(s);
+ infile = s;
+ }
+ }
+ finput = Bopen(infile, OREAD);
+ if(finput == 0)
+ error("cannot open '%s'", argv[0]);
+ cnamp = cnames;
+
+ defin(0, "$end");
+ extval = PRIVATE; /* tokens start in unicode 'private use' */
+ defin(0, "error");
+ defin(1, "$accept");
+ defin(0, "$unk");
+ mem = mem0;
+ i = 0;
+
+ for(t = gettok(); t != MARK && t != ENDFILE;)
+ switch(t) {
+ case ';':
+ t = gettok();
+ break;
+
+ case START:
+ if(gettok() != IDENTIFIER)
+ error("bad %%start construction");
+ start = chfind(1, tokname);
+ t = gettok();
+ continue;
+
+ case TYPEDEF:
+ if(gettok() != TYPENAME)
+ error("bad syntax in %%type");
+ ty = numbval;
+ for(;;) {
+ t = gettok();
+ switch(t) {
+ case IDENTIFIER:
+ if((t=chfind(1, tokname)) < NTBASE) {
+ j = TYPE(toklev[t]);
+ if(j != 0 && j != ty)
+ error("type redeclaration of token %s",
+ tokset[t].name);
+ else
+ SETTYPE(toklev[t], ty);
+ } else {
+ j = nontrst[t-NTBASE].value;
+ if(j != 0 && j != ty)
+ error("type redeclaration of nonterminal %s",
+ nontrst[t-NTBASE].name );
+ else
+ nontrst[t-NTBASE].value = ty;
+ }
+ case ',':
+ continue;
+ case ';':
+ t = gettok();
+ default:
+ break;
+ }
+ break;
+ }
+ continue;
+
+ case UNION:
+ /* copy the union declaration to the output */
+ cpyunion();
+ t = gettok();
+ continue;
+
+ case LEFT:
+ case BINARY:
+ case RIGHT:
+ i++;
+
+ case TERM:
+ /* nonzero means new prec. and assoc. */
+ lev = t-TERM;
+ ty = 0;
+
+ /* get identifiers so defined */
+ t = gettok();
+
+ /* there is a type defined */
+ if(t == TYPENAME) {
+ ty = numbval;
+ t = gettok();
+ }
+ for(;;) {
+ switch(t) {
+ case ',':
+ t = gettok();
+ continue;
+
+ case ';':
+ break;
+
+ case IDENTIFIER:
+ j = chfind(0, tokname);
+ if(j >= NTBASE)
+ error("%s defined earlier as nonterminal", tokname);
+ if(lev) {
+ if(ASSOC(toklev[j]))
+ error("redeclaration of precedence of %s", tokname);
+ SETASC(toklev[j], lev);
+ SETPLEV(toklev[j], i);
+ }
+ if(ty) {
+ if(TYPE(toklev[j]))
+ error("redeclaration of type of %s", tokname);
+ SETTYPE(toklev[j],ty);
+ }
+ t = gettok();
+ if(t == NUMBER) {
+ tokset[j].value = numbval;
+ if(j < ndefout && j > 3)
+ error("please define type number of %s earlier",
+ tokset[j].name);
+ t = gettok();
+ }
+ continue;
+ }
+ break;
+ }
+ continue;
+
+ case LCURLY:
+ defout(0);
+ cpycode();
+ t = gettok();
+ continue;
+
+ default:
+ error("syntax error");
+ }
+ if(t == ENDFILE)
+ error("unexpected EOF before %%");
+
+ /* t is MARK */
+ Bprint(ftable, "extern int yyerrflag;\n");
+ Bprint(ftable, "#ifndef YYMAXDEPTH\n");
+ Bprint(ftable, "#define YYMAXDEPTH 150\n");
+ Bprint(ftable, "#endif\n" );
+ if(!ntypes) {
+ Bprint(ftable, "#ifndef YYSTYPE\n");
+ Bprint(ftable, "#define YYSTYPE int\n");
+ Bprint(ftable, "#endif\n");
+ }
+ Bprint(ftable, "YYSTYPE yylval;\n");
+ Bprint(ftable, "YYSTYPE yyval;\n");
+
+ prdptr[0] = mem;
+
+ /* added production */
+ *mem++ = NTBASE;
+
+ /* if start is 0, we will overwrite with the lhs of the first rule */
+ *mem++ = start;
+ *mem++ = 1;
+ *mem++ = 0;
+ prdptr[1] = mem;
+ while((t=gettok()) == LCURLY)
+ cpycode();
+ if(t != IDENTCOLON)
+ error("bad syntax on first rule");
+
+ if(!start)
+ prdptr[0][1] = chfind(1, tokname);
+
+ /* read rules */
+ while(t != MARK && t != ENDFILE) {
+ /* process a rule */
+ rlines[nprod] = lineno;
+ if(t == '|')
+ *mem++ = *prdptr[nprod-1];
+ else
+ if(t == IDENTCOLON) {
+ *mem = chfind(1, tokname);
+ if(*mem < NTBASE)
+ error("token illegal on LHS of grammar rule");
+ mem++;
+ } else
+ error("illegal rule: missing semicolon or | ?");
+ /* read rule body */
+ t = gettok();
+
+ more_rule:
+ while(t == IDENTIFIER) {
+ *mem = chfind(1, tokname);
+ if(*mem < NTBASE)
+ levprd[nprod] = toklev[*mem];
+ mem++;
+ t = gettok();
+ }
+ if(t == PREC) {
+ if(gettok() != IDENTIFIER)
+ error("illegal %%prec syntax");
+ j = chfind(2, tokname);
+ if(j >= NTBASE)
+ error("nonterminal %s illegal after %%prec",
+ nontrst[j-NTBASE].name);
+ levprd[nprod] = toklev[j];
+ t = gettok();
+ }
+ if(t == '=') {
+ levprd[nprod] |= ACTFLAG;
+ Bprint(faction, "\ncase %d:", nprod);
+ cpyact(mem-prdptr[nprod]-1);
+ Bprint(faction, " break;");
+ if((t=gettok()) == IDENTIFIER) {
+
+ /* action within rule... */
+ sprint(actnm, "$$%d", nprod);
+
+ /* make it a nonterminal */
+ j = chfind(1, actnm);
+
+ /*
+ * the current rule will become rule number nprod+1
+ * move the contents down, and make room for the null
+ */
+ for(p = mem; p >= prdptr[nprod]; --p)
+ p[2] = *p;
+ mem += 2;
+
+ /* enter null production for action */
+ p = prdptr[nprod];
+ *p++ = j;
+ *p++ = -nprod;
+
+ /* update the production information */
+ levprd[nprod+1] = levprd[nprod] & ~ACTFLAG;
+ levprd[nprod] = ACTFLAG;
+ if(++nprod >= NPROD)
+ error("more than %d rules", NPROD);
+ prdptr[nprod] = p;
+
+ /* make the action appear in the original rule */
+ *mem++ = j;
+
+ /* get some more of the rule */
+ goto more_rule;
+ }
+ }
+
+ while(t == ';')
+ t = gettok();
+ *mem++ = -nprod;
+
+ /* check that default action is reasonable */
+ if(ntypes && !(levprd[nprod]&ACTFLAG) && nontrst[*prdptr[nprod]-NTBASE].value) {
+
+ /* no explicit action, LHS has value */
+ int tempty;
+
+ tempty = prdptr[nprod][1];
+ if(tempty < 0)
+ error("must return a value, since LHS has a type");
+ else
+ if(tempty >= NTBASE)
+ tempty = nontrst[tempty-NTBASE].value;
+ else
+ tempty = TYPE(toklev[tempty]);
+ if(tempty != nontrst[*prdptr[nprod]-NTBASE].value)
+ error("default action causes potential type clash");
+ }
+ nprod++;
+ if(nprod >= NPROD)
+ error("more than %d rules", NPROD);
+ prdptr[nprod] = mem;
+ levprd[nprod] = 0;
+ }
+
+ /* end of all rules */
+ defout(1);
+
+ finact();
+ if(t == MARK) {
+ Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile);
+ while((c=Bgetrune(finput)) != Beof)
+ Bputrune(ftable, c);
+ }
+ Bterm(finput);
+}
+
+/*
+ * finish action routine
+ */
+void
+finact(void)
+{
+
+ Bterm(faction);
+ Bprint(ftable, "#define YYEOFCODE %d\n", 1);
+ Bprint(ftable, "#define YYERRCODE %d\n", 2);
+}
+
+/*
+ * define s to be a terminal if t=0
+ * or a nonterminal if t=1
+ */
+int
+defin(int nt, char *s)
+{
+ int val;
+ Rune rune;
+
+ val = 0;
+ if(nt) {
+ nnonter++;
+ if(nnonter >= NNONTERM)
+ error("too many nonterminals, limit %d",NNONTERM);
+ nontrst[nnonter].name = cstash(s);
+ return NTBASE + nnonter;
+ }
+
+ /* must be a token */
+ ntokens++;
+ if(ntokens >= NTERMS)
+ error("too many terminals, limit %d", NTERMS);
+ tokset[ntokens].name = cstash(s);
+
+ /* establish value for token */
+ /* single character literal */
+ if(s[0] == ' ') {
+ val = chartorune(&rune, &s[1]);
+ if(s[val+1] == 0) {
+ val = rune;
+ goto out;
+ }
+ }
+
+ /* escape sequence */
+ if(s[0] == ' ' && s[1] == '\\') {
+ if(s[3] == 0) {
+ /* single character escape sequence */
+ switch(s[2]) {
+ case 'n': val = '\n'; break;
+ case 'r': val = '\r'; break;
+ case 'b': val = '\b'; break;
+ case 't': val = '\t'; break;
+ case 'f': val = '\f'; break;
+ case '\'': val = '\''; break;
+ case '"': val = '"'; break;
+ case '\\': val = '\\'; break;
+ default: error("invalid escape");
+ }
+ goto out;
+ }
+
+ /* \nnn sequence */
+ if(s[2] >= '0' && s[2] <= '7') {
+ if(s[3] < '0' ||
+ s[3] > '7' ||
+ s[4] < '0' ||
+ s[4] > '7' ||
+ s[5] != 0)
+ error("illegal \\nnn construction");
+ val = 64*s[2] + 8*s[3] + s[4] - 73*'0';
+ if(val == 0)
+ error("'\\000' is illegal");
+ goto out;
+ }
+ error("unknown escape");
+ }
+ val = extval++;
+
+out:
+ tokset[ntokens].value = val;
+ toklev[ntokens] = 0;
+ return ntokens;
+}
+
+/*
+ * write out the defines (at the end of the declaration section)
+ */
+void
+defout(int last)
+{
+ int i, c;
+ char sar[NAMESIZE+10];
+
+ for(i=ndefout; i<=ntokens; i++) {
+ /* non-literals */
+ c = tokset[i].name[0];
+ if(c != ' ' && c != '$') {
+ Bprint(ftable, "#define %s %d\n",
+ tokset[i].name, tokset[i].value);
+ if(fdefine)
+ Bprint(fdefine, "#define\t%s\t%d\n",
+ tokset[i].name, tokset[i].value);
+ }
+ }
+ ndefout = ntokens+1;
+ if(last && fdebug) {
+ Bprint(fdebug, "char* yytoknames[] =\n{\n");
+ TLOOP(i) {
+ if(tokset[i].name) {
+ chcopy(sar, tokset[i].name);
+ Bprint(fdebug, "\t\"%s\",\n", sar);
+ continue;
+ }
+ Bprint(fdebug, "\t0,\n");
+ }
+ Bprint(fdebug, "};\n");
+ }
+}
+
+char*
+cstash(char *s)
+{
+ char *temp;
+
+ temp = cnamp;
+ do {
+ if(cnamp >= &cnames[cnamsz])
+ error("too many characters in id's and literals");
+ else
+ *cnamp++ = *s;
+ } while(*s++);
+ return temp;
+}
+
+long
+gettok(void)
+{
+ long c;
+ Rune rune;
+ int i, base, match, reserve;
+ static int peekline;
+
+begin:
+ reserve = 0;
+ lineno += peekline;
+ peekline = 0;
+ c = Bgetrune(finput);
+ while(c == ' ' || c == '\n' || c == '\t' || c == '\f') {
+ if(c == '\n')
+ lineno++;
+ c = Bgetrune(finput);
+ }
+
+ /* skip comment */
+ if(c == '/') {
+ lineno += skipcom();
+ goto begin;
+ }
+ switch(c) {
+ case Beof:
+ return ENDFILE;
+
+ case '{':
+ Bungetrune(finput);
+ return '=';
+
+ case '<':
+ /* get, and look up, a type name (union member name) */
+ i = 0;
+ while((c=Bgetrune(finput)) != '>' && c >= 0 && c != '\n') {
+ rune = c;
+ c = runetochar(&tokname[i], &rune);
+ if(i < NAMESIZE)
+ i += c;
+ }
+ if(c != '>')
+ error("unterminated < ... > clause");
+ tokname[i] = 0;
+ for(i=1; i<=ntypes; i++)
+ if(!strcmp(typeset[i], tokname)) {
+ numbval = i;
+ return TYPENAME;
+ }
+ ntypes++;
+ numbval = ntypes;
+ typeset[numbval] = cstash(tokname);
+ return TYPENAME;
+
+ case '"':
+ case '\'':
+ match = c;
+ tokname[0] = ' ';
+ i = 1;
+ for(;;) {
+ c = Bgetrune(finput);
+ if(c == '\n' || c <= 0)
+ error("illegal or missing ' or \"" );
+ if(c == '\\') {
+ tokname[i] = '\\';
+ if(i < NAMESIZE)
+ i++;
+ c = Bgetrune(finput);
+ } else
+ if(c == match)
+ break;
+ rune = c;
+ c = runetochar(&tokname[i], &rune);
+ if(i < NAMESIZE)
+ i += c;
+ }
+ break;
+
+ case '%':
+ case '\\':
+ switch(c = Bgetrune(finput)) {
+ case '0': return TERM;
+ case '<': return LEFT;
+ case '2': return BINARY;
+ case '>': return RIGHT;
+ case '%':
+ case '\\': return MARK;
+ case '=': return PREC;
+ case '{': return LCURLY;
+ default: reserve = 1;
+ }
+
+ default:
+ /* number */
+ if(isdigit(c)) {
+ numbval = c-'0';
+ base = (c=='0')? 8: 10;
+ for(c = Bgetrune(finput); isdigit(c); c = Bgetrune(finput))
+ numbval = numbval*base + (c-'0');
+ Bungetrune(finput);
+ return NUMBER;
+ }
+ if(islower(c) || isupper(c) || c=='_' || c=='.' || c=='$') {
+ i = 0;
+ while(islower(c) || isupper(c) || isdigit(c) ||
+ c == '-' || c=='_' || c=='.' || c=='$') {
+ if(reserve && isupper(c))
+ c += 'a'-'A';
+ rune = c;
+ c = runetochar(&tokname[i], &rune);
+ if(i < NAMESIZE)
+ i += c;
+ c = Bgetrune(finput);
+ }
+ } else
+ return c;
+ Bungetrune(finput);
+ }
+ tokname[i] = 0;
+
+ /* find a reserved word */
+ if(reserve) {
+ for(c=0; resrv[c].name; c++)
+ if(strcmp(tokname, resrv[c].name) == 0)
+ return resrv[c].value;
+ error("invalid escape, or illegal reserved word: %s", tokname);
+ }
+
+ /* look ahead to distinguish IDENTIFIER from IDENTCOLON */
+ c = Bgetrune(finput);
+ while(c == ' ' || c == '\t'|| c == '\n' || c == '\f' || c == '/') {
+ if(c == '\n')
+ peekline++;
+ /* look for comments */
+ if(c == '/')
+ peekline += skipcom();
+ c = Bgetrune(finput);
+ }
+ if(c == ':')
+ return IDENTCOLON;
+ Bungetrune(finput);
+ return IDENTIFIER;
+}
+
+/*
+ * determine the type of a symbol
+ */
+int
+fdtype(int t)
+{
+ int v;
+
+ if(t >= NTBASE)
+ v = nontrst[t-NTBASE].value;
+ else
+ v = TYPE(toklev[t]);
+ if(v <= 0)
+ error("must specify type for %s", (t>=NTBASE)?
+ nontrst[t-NTBASE].name: tokset[t].name);
+ return v;
+}
+
+int
+chfind(int t, char *s)
+{
+ int i;
+
+ if(s[0] == ' ')
+ t = 0;
+ TLOOP(i)
+ if(!strcmp(s, tokset[i].name))
+ return i;
+ NTLOOP(i)
+ if(!strcmp(s, nontrst[i].name))
+ return NTBASE+i;
+
+ /* cannot find name */
+ if(t > 1)
+ error("%s should have been defined earlier", s);
+ return defin(t, s);
+}
+
+/*
+ * copy the union declaration to the output, and the define file if present
+ */
+void
+cpyunion(void)
+{
+ long c;
+ int level;
+
+ Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile);
+ Bprint(ftable, "typedef union ");
+ if(fdefine != 0)
+ Bprint(fdefine, "\ntypedef union ");
+
+ level = 0;
+ for(;;) {
+ if((c=Bgetrune(finput)) == Beof)
+ error("EOF encountered while processing %%union");
+ Bputrune(ftable, c);
+ if(fdefine != 0)
+ Bputrune(fdefine, c);
+ switch(c) {
+ case '\n':
+ lineno++;
+ break;
+ case '{':
+ level++;
+ break;
+ case '}':
+ level--;
+
+ /* we are finished copying */
+ if(level == 0) {
+ Bprint(ftable, " YYSTYPE;\n");
+ if(fdefine != 0)
+ Bprint(fdefine, "\tYYSTYPE;\nextern\tYYSTYPE\tyylval;\n");
+ return;
+ }
+ }
+ }
+}
+
+/*
+ * copies code between \{ and \}
+ */
+void
+cpycode(void)
+{
+
+ long c;
+
+ c = Bgetrune(finput);
+ if(c == '\n') {
+ c = Bgetrune(finput);
+ lineno++;
+ }
+ Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile);
+ while(c != Beof) {
+ if(c == '\\') {
+ if((c=Bgetrune(finput)) == '}')
+ return;
+ Bputc(ftable, '\\');
+ }
+ if(c == '%') {
+ if((c=Bgetrune(finput)) == '}')
+ return;
+ Bputc(ftable, '%');
+ }
+ Bputrune(ftable, c);
+ if(c == '\n')
+ lineno++;
+ c = Bgetrune(finput);
+ }
+ error("eof before %%}");
+}
+
+/*
+ * skip over comments
+ * skipcom is called after reading a '/'
+ */
+int
+skipcom(void)
+{
+ long c;
+ int i;
+
+ /* i is the number of lines skipped */
+ i = 0;
+ if(Bgetrune(finput) != '*')
+ error("illegal comment");
+ c = Bgetrune(finput);
+ while(c != Beof) {
+ while(c == '*')
+ if((c=Bgetrune(finput)) == '/')
+ return i;
+ if(c == '\n')
+ i++;
+ c = Bgetrune(finput);
+ }
+ error("EOF inside comment");
+ return 0;
+}
+
+/*
+ * copy C action to the next ; or closing }
+ */
+void
+cpyact(int offset)
+{
+ long c;
+ int brac, match, j, s, fnd, tok;
+
+ Bprint(faction, "\n#line\t%d\t\"%s\"\n", lineno, infile);
+ brac = 0;
+
+loop:
+ c = Bgetrune(finput);
+swt:
+ switch(c) {
+ case ';':
+ if(brac == 0) {
+ Bputrune(faction, c);
+ return;
+ }
+ goto lcopy;
+
+ case '{':
+ brac++;
+ goto lcopy;
+
+ case '$':
+ s = 1;
+ tok = -1;
+ c = Bgetrune(finput);
+
+ /* type description */
+ if(c == '<') {
+ Bungetrune(finput);
+ if(gettok() != TYPENAME)
+ error("bad syntax on $ clause");
+ tok = numbval;
+ c = Bgetrune(finput);
+ }
+ if(c == '$') {
+ Bprint(faction, "yyval");
+
+ /* put out the proper tag... */
+ if(ntypes) {
+ if(tok < 0)
+ tok = fdtype(*prdptr[nprod]);
+ Bprint(faction, ".%s", typeset[tok]);
+ }
+ goto loop;
+ }
+ if(c == '-') {
+ s = -s;
+ c = Bgetrune(finput);
+ }
+ if(isdigit(c)) {
+ j = 0;
+ while(isdigit(c)) {
+ j = j*10 + (c-'0');
+ c = Bgetrune(finput);
+ }
+ Bungetrune(finput);
+ j = j*s - offset;
+ if(j > 0)
+ error("Illegal use of $%d", j+offset);
+
+ dollar:
+ Bprint(faction, "yypt[-%d].yyv", -j);
+
+ /* put out the proper tag */
+ if(ntypes) {
+ if(j+offset <= 0 && tok < 0)
+ error("must specify type of $%d", j+offset);
+ if(tok < 0)
+ tok = fdtype(prdptr[nprod][j+offset]);
+ Bprint(faction, ".%s", typeset[tok]);
+ }
+ goto loop;
+ }
+ if(isupper(c) || islower(c) || c == '_' || c == '.') {
+ int tok; /* tok used oustide for type info */
+
+ /* look for $name */
+ Bungetrune(finput);
+ if(gettok() != IDENTIFIER)
+ error("$ must be followed by an identifier");
+ tok = chfind(2, tokname);
+ if((c = Bgetrune(finput)) != '#') {
+ Bungetrune(finput);
+ fnd = -1;
+ } else
+ if(gettok() != NUMBER) {
+ error("# must be followed by number");
+ fnd = -1;
+ } else
+ fnd = numbval;
+ for(j=1; j<=offset; ++j)
+ if(tok == prdptr[nprod][j]) {
+ if(--fnd <= 0) {
+ j -= offset;
+ goto dollar;
+ }
+ }
+ error("$name or $name#number not found");
+ }
+ Bputc(faction, '$');
+ if(s < 0 )
+ Bputc(faction, '-');
+ goto swt;
+
+ case '}':
+ brac--;
+ if(brac)
+ goto lcopy;
+ Bputrune(faction, c);
+ return;
+
+ case '/':
+ /* look for comments */
+ Bputrune(faction, c);
+ c = Bgetrune(finput);
+ if(c != '*')
+ goto swt;
+
+ /* it really is a comment */
+ Bputrune(faction, c);
+ c = Bgetrune(finput);
+ while(c >= 0) {
+ while(c == '*') {
+ Bputrune(faction, c);
+ if((c=Bgetrune(finput)) == '/')
+ goto lcopy;
+ }
+ Bputrune(faction, c);
+ if(c == '\n')
+ lineno++;
+ c = Bgetrune(finput);
+ }
+ error("EOF inside comment");
+
+ case '\'':
+ /* character constant */
+ match = '\'';
+ goto string;
+
+ case '"':
+ /* character string */
+ match = '"';
+
+ string:
+ Bputrune(faction, c);
+ while(c = Bgetrune(finput)) {
+ if(c == '\\') {
+ Bputrune(faction, c);
+ c = Bgetrune(finput);
+ if(c == '\n')
+ lineno++;
+ } else
+ if(c == match)
+ goto lcopy;
+ if(c == '\n')
+ error("newline in string or char. const.");
+ Bputrune(faction, c);
+ }
+ error("EOF in string or character constant");
+
+ case Beof:
+ error("action does not terminate");
+
+ case '\n':
+ lineno++;
+ goto lcopy;
+ }
+
+lcopy:
+ Bputrune(faction, c);
+ goto loop;
+}
+
+void
+openup(char *stem, int dflag, int vflag, int ytab, char *ytabc)
+{
+ char buf[256];
+
+ if(vflag) {
+ sprint(buf, "%s.%s", stem, FILEU);
+ foutput = Bopen(buf, OWRITE);
+ if(foutput == 0)
+ error("cannot open %s", buf);
+ }
+ if(yydebug) {
+ sprint(buf, "%s.%s", stem, FILEDEBUG);
+ if((fdebug = Bopen(buf, OWRITE)) == 0)
+ error("can't open %s", buf);
+ }
+ if(dflag) {
+ sprint(buf, "%s.%s", stem, FILED);
+ fdefine = Bopen(buf, OWRITE);
+ if(fdefine == 0)
+ error("can't create %s", buf);
+ }
+ if(ytab == 0)
+ sprint(buf, "%s.%s", stem, OFILE);
+ else
+ strcpy(buf, ytabc);
+ ftable = Bopen(buf, OWRITE);
+ if(ftable == 0)
+ error("cannot open table file %s", buf);
+}
+
+/*
+ * print the output for the states
+ */
+void
+output(void)
+{
+ int i, k, c;
+ Wset *u, *v;
+
+ Bprint(ftable, "short yyexca[] =\n{");
+ if(fdebug)
+ Bprint(fdebug, "char* yystates[] =\n{\n");
+
+ /* output the stuff for state i */
+ SLOOP(i) {
+ nolook = tystate[i]!=MUSTLOOKAHEAD;
+ closure(i);
+
+ /* output actions */
+ nolook = 1;
+ aryfil(temp1, ntokens+nnonter+1, 0);
+ WSLOOP(wsets, u) {
+ c = *(u->pitem);
+ if(c > 1 && c < NTBASE && temp1[c] == 0) {
+ WSLOOP(u, v)
+ if(c == *(v->pitem))
+ putitem(v->pitem+1, (Lkset*)0);
+ temp1[c] = state(c);
+ } else
+ if(c > NTBASE && temp1[(c -= NTBASE) + ntokens] == 0)
+ temp1[c+ntokens] = amem[indgo[i]+c];
+ }
+ if(i == 1)
+ temp1[1] = ACCEPTCODE;
+
+ /* now, we have the shifts; look at the reductions */
+ lastred = 0;
+ WSLOOP(wsets, u) {
+ c = *u->pitem;
+
+ /* reduction */
+ if(c <= 0) {
+ lastred = -c;
+ TLOOP(k)
+ if(BIT(u->ws.lset, k)) {
+ if(temp1[k] == 0)
+ temp1[k] = c;
+ else
+ if(temp1[k] < 0) { /* reduce/reduce conflict */
+ if(foutput)
+ Bprint(foutput,
+ "\n%d: reduce/reduce conflict"
+ " (red'ns %d and %d ) on %s",
+ i, -temp1[k], lastred,
+ symnam(k));
+ if(-temp1[k] > lastred)
+ temp1[k] = -lastred;
+ zzrrconf++;
+ } else
+ /* potential shift/reduce conflict */
+ precftn( lastred, k, i );
+ }
+ }
+ }
+ wract(i);
+ }
+
+ if(fdebug)
+ Bprint(fdebug, "};\n");
+ Bprint(ftable, "};\n");
+ Bprint(ftable, "#define YYNPROD %d\n", nprod);
+ Bprint(ftable, "#define YYPRIVATE %d\n", PRIVATE);
+ if(yydebug)
+ Bprint(ftable, "#define yydebug %s\n", yydebug);
+}
+
+/*
+ * pack state i from temp1 into amem
+ */
+int
+apack(int *p, int n)
+{
+ int *pp, *qq, *rr, off, *q, *r;
+
+ /* we don't need to worry about checking because
+ * we will only look at entries known to be there...
+ * eliminate leading and trailing 0's
+ */
+
+ q = p+n;
+ for(pp = p, off = 0; *pp == 0 && pp <= q; ++pp, --off)
+ ;
+ /* no actions */
+ if(pp > q)
+ return 0;
+ p = pp;
+
+ /* now, find a place for the elements from p to q, inclusive */
+ r = &amem[ACTSIZE-1];
+ for(rr = amem; rr <= r; rr++, off++) {
+ for(qq = rr, pp = p; pp <= q; pp++, qq++)
+ if(*pp != 0)
+ if(*pp != *qq && *qq != 0)
+ goto nextk;
+
+ /* we have found an acceptable k */
+ if(pkdebug && foutput != 0)
+ Bprint(foutput, "off = %d, k = %d\n", off, (int)(rr-amem));
+ for(qq = rr, pp = p; pp <= q; pp++, qq++)
+ if(*pp) {
+ if(qq > r)
+ error("action table overflow");
+ if(qq > memp)
+ memp = qq;
+ *qq = *pp;
+ }
+ if(pkdebug && foutput != 0)
+ for(pp = amem; pp <= memp; pp += 10) {
+ Bprint(foutput, "\t");
+ for(qq = pp; qq <= pp+9; qq++)
+ Bprint(foutput, "%d ", *qq);
+ Bprint(foutput, "\n");
+ }
+ return(off);
+ nextk:;
+ }
+ error("no space in action table");
+ return 0;
+}
+
+/*
+ * output the gotos for the nontermninals
+ */
+void
+go2out(void)
+{
+ int i, j, k, best, count, cbest, times;
+
+ /* mark begining of gotos */
+ Bprint(ftemp, "$\n");
+ for(i = 1; i <= nnonter; i++) {
+ go2gen(i);
+
+ /* find the best one to make default */
+ best = -1;
+ times = 0;
+
+ /* is j the most frequent */
+ for(j = 0; j <= nstate; j++) {
+ if(tystate[j] == 0)
+ continue;
+ if(tystate[j] == best)
+ continue;
+
+ /* is tystate[j] the most frequent */
+ count = 0;
+ cbest = tystate[j];
+ for(k = j; k <= nstate; k++)
+ if(tystate[k] == cbest)
+ count++;
+ if(count > times) {
+ best = cbest;
+ times = count;
+ }
+ }
+
+ /* best is now the default entry */
+ zzgobest += times-1;
+ for(j = 0; j <= nstate; j++)
+ if(tystate[j] != 0 && tystate[j] != best) {
+ Bprint(ftemp, "%d,%d,", j, tystate[j]);
+ zzgoent++;
+ }
+
+ /* now, the default */
+ if(best == -1)
+ best = 0;
+ zzgoent++;
+ Bprint(ftemp, "%d\n", best);
+ }
+}
+
+/*
+ * output the gotos for nonterminal c
+ */
+void
+go2gen(int c)
+{
+ int i, work, cc;
+ Item *p, *q;
+
+
+ /* first, find nonterminals with gotos on c */
+ aryfil(temp1, nnonter+1, 0);
+ temp1[c] = 1;
+ work = 1;
+ while(work) {
+ work = 0;
+ PLOOP(0, i)
+
+ /* cc is a nonterminal */
+ if((cc=prdptr[i][1]-NTBASE) >= 0)
+ /* cc has a goto on c */
+ if(temp1[cc] != 0) {
+
+ /* thus, the left side of production i does too */
+ cc = *prdptr[i]-NTBASE;
+ if(temp1[cc] == 0) {
+ work = 1;
+ temp1[cc] = 1;
+ }
+ }
+ }
+
+ /* now, we have temp1[c] = 1 if a goto on c in closure of cc */
+ if(g2debug && foutput != 0) {
+ Bprint(foutput, "%s: gotos on ", nontrst[c].name);
+ NTLOOP(i)
+ if(temp1[i])
+ Bprint(foutput, "%s ", nontrst[i].name);
+ Bprint(foutput, "\n");
+ }
+
+ /* now, go through and put gotos into tystate */
+ aryfil(tystate, nstate, 0);
+ SLOOP(i)
+ ITMLOOP(i, p, q)
+ if((cc = *p->pitem) >= NTBASE)
+ /* goto on c is possible */
+ if(temp1[cc-NTBASE]) {
+ tystate[i] = amem[indgo[i]+c];
+ break;
+ }
+}
+
+/*
+ * decide a shift/reduce conflict by precedence.
+ * r is a rule number, t a token number
+ * the conflict is in state s
+ * temp1[t] is changed to reflect the action
+ */
+void
+precftn(int r, int t, int s)
+{
+ int lp, lt, action;
+
+ lp = levprd[r];
+ lt = toklev[t];
+ if(PLEVEL(lt) == 0 || PLEVEL(lp) == 0) {
+
+ /* conflict */
+ if(foutput != 0)
+ Bprint(foutput,
+ "\n%d: shift/reduce conflict (shift %d(%d), red'n %d(%d)) on %s",
+ s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t));
+ zzsrconf++;
+ return;
+ }
+ if(PLEVEL(lt) == PLEVEL(lp))
+ action = ASSOC(lt);
+ else
+ if(PLEVEL(lt) > PLEVEL(lp))
+ action = RASC; /* shift */
+ else
+ action = LASC; /* reduce */
+ switch(action) {
+ case BASC: /* error action */
+ temp1[t] = ERRCODE;
+ break;
+ case LASC: /* reduce */
+ temp1[t] = -r;
+ break;
+ }
+}
+
+/*
+ * output state i
+ * temp1 has the actions, lastred the default
+ */
+void
+wract(int i)
+{
+ int p, p0, p1, ntimes, tred, count, j, flag;
+
+ /* find the best choice for lastred */
+ lastred = 0;
+ ntimes = 0;
+ TLOOP(j) {
+ if(temp1[j] >= 0)
+ continue;
+ if(temp1[j]+lastred == 0)
+ continue;
+ /* count the number of appearances of temp1[j] */
+ count = 0;
+ tred = -temp1[j];
+ levprd[tred] |= REDFLAG;
+ TLOOP(p)
+ if(temp1[p]+tred == 0)
+ count++;
+ if(count > ntimes) {
+ lastred = tred;
+ ntimes = count;
+ }
+ }
+
+ /*
+ * for error recovery, arrange that, if there is a shift on the
+ * error recovery token, `error', that the default be the error action
+ */
+ if(temp1[2] > 0)
+ lastred = 0;
+
+ /* clear out entries in temp1 which equal lastred */
+ TLOOP(p)
+ if(temp1[p]+lastred == 0)
+ temp1[p] = 0;
+
+ wrstate(i);
+ defact[i] = lastred;
+ flag = 0;
+ TLOOP(p0)
+ if((p1=temp1[p0]) != 0) {
+ if(p1 < 0) {
+ p1 = -p1;
+ goto exc;
+ }
+ if(p1 == ACCEPTCODE) {
+ p1 = -1;
+ goto exc;
+ }
+ if(p1 == ERRCODE) {
+ p1 = 0;
+ exc:
+ if(flag++ == 0)
+ Bprint(ftable, "-1, %d,\n", i);
+ Bprint(ftable, "\t%d, %d,\n", p0, p1);
+ zzexcp++;
+ continue;
+ }
+ Bprint(ftemp, "%d,%d,", p0, p1);
+ zzacent++;
+ }
+ if(flag) {
+ defact[i] = -2;
+ Bprint(ftable, "\t-2, %d,\n", lastred);
+ }
+ Bprint(ftemp, "\n");
+}
+
+/*
+ * writes state i
+ */
+void
+wrstate(int i)
+{
+ int j0, j1;
+ Item *pp, *qq;
+ Wset *u;
+
+ if(fdebug) {
+ if(lastred) {
+ Bprint(fdebug, " 0, /*%d*/\n", i);
+ } else {
+ Bprint(fdebug, " \"");
+ ITMLOOP(i, pp, qq)
+ Bprint(fdebug, "%s\\n", writem(pp->pitem));
+ if(tystate[i] == MUSTLOOKAHEAD)
+ WSLOOP(wsets + (pstate[i+1] - pstate[i]), u)
+ if(*u->pitem < 0)
+ Bprint(fdebug, "%s\\n", writem(u->pitem));
+ Bprint(fdebug, "\", /*%d*/\n", i);
+ }
+ }
+ if(foutput == 0)
+ return;
+ Bprint(foutput, "\nstate %d\n", i);
+ ITMLOOP(i, pp, qq)
+ Bprint(foutput, "\t%s\n", writem(pp->pitem));
+ if(tystate[i] == MUSTLOOKAHEAD)
+ /* print out empty productions in closure */
+ WSLOOP(wsets+(pstate[i+1]-pstate[i]), u)
+ if(*u->pitem < 0)
+ Bprint(foutput, "\t%s\n", writem(u->pitem));
+
+ /* check for state equal to another */
+ TLOOP(j0)
+ if((j1=temp1[j0]) != 0) {
+ Bprint(foutput, "\n\t%s ", symnam(j0));
+ /* shift, error, or accept */
+ if(j1 > 0) {
+ if(j1 == ACCEPTCODE)
+ Bprint(foutput, "accept");
+ else
+ if(j1 == ERRCODE)
+ Bprint(foutput, "error");
+ else
+ Bprint(foutput, "shift %d", j1);
+ } else
+ Bprint(foutput, "reduce %d (src line %d)", -j1, rlines[-j1]);
+ }
+
+ /* output the final production */
+ if(lastred)
+ Bprint(foutput, "\n\t. reduce %d (src line %d)\n\n",
+ lastred, rlines[lastred]);
+ else
+ Bprint(foutput, "\n\t. error\n\n");
+
+ /* now, output nonterminal actions */
+ j1 = ntokens;
+ for(j0 = 1; j0 <= nnonter; j0++) {
+ j1++;
+ if(temp1[j1])
+ Bprint(foutput, "\t%s goto %d\n", symnam(j0+NTBASE), temp1[j1]);
+ }
+}
+
+void
+warray(char *s, int *v, int n)
+{
+ int i;
+
+ Bprint(ftable, "short %s[] =\n{", s);
+ for(i=0;;) {
+ if(i%10 == 0)
+ Bprint(ftable, "\n");
+ Bprint(ftable, "%4d", v[i]);
+ i++;
+ if(i >= n) {
+ Bprint(ftable, "\n};\n");
+ break;
+ }
+ Bprint(ftable, ",");
+ }
+}
+
+/*
+ * in order to free up the mem and amem arrays for the optimizer,
+ * and still be able to output yyr1, etc., after the sizes of
+ * the action array is known, we hide the nonterminals
+ * derived by productions in levprd.
+ */
+
+void
+hideprod(void)
+{
+ int i, j;
+
+ j = 0;
+ levprd[0] = 0;
+ PLOOP(1, i) {
+ if(!(levprd[i] & REDFLAG)) {
+ j++;
+ if(foutput != 0)
+ Bprint(foutput, "Rule not reduced: %s\n", writem(prdptr[i]));
+ }
+ levprd[i] = *prdptr[i] - NTBASE;
+ }
+ if(j)
+ print("%d rules never reduced\n", j);
+}
+
+void
+callopt(void)
+{
+ int i, *p, j, k, *q;
+
+ /* read the arrays from tempfile and set parameters */
+ finput = Bopen(tempname, OREAD);
+ if(finput == 0)
+ error("optimizer cannot open tempfile");
+
+ pgo[0] = 0;
+ temp1[0] = 0;
+ nstate = 0;
+ nnonter = 0;
+ for(;;) {
+ switch(gtnm()) {
+ case '\n':
+ nstate++;
+ pmem--;
+ temp1[nstate] = pmem - mem0;
+ case ',':
+ continue;
+ case '$':
+ break;
+ default:
+ error("bad tempfile");
+ }
+ break;
+ }
+
+ pmem--;
+ temp1[nstate] = yypgo[0] = pmem - mem0;
+ for(;;) {
+ switch(gtnm()) {
+ case '\n':
+ nnonter++;
+ yypgo[nnonter] = pmem-mem0;
+ case ',':
+ continue;
+ case -1:
+ break;
+ default:
+ error("bad tempfile");
+ }
+ break;
+ }
+ pmem--;
+ yypgo[nnonter--] = pmem - mem0;
+ for(i = 0; i < nstate; i++) {
+ k = 32000;
+ j = 0;
+ q = mem0 + temp1[i+1];
+ for(p = mem0 + temp1[i]; p < q ; p += 2) {
+ if(*p > j)
+ j = *p;
+ if(*p < k)
+ k = *p;
+ }
+ /* nontrivial situation */
+ if(k <= j) {
+ /* j is now the range */
+/* j -= k; *//* call scj */
+ if(k > maxoff)
+ maxoff = k;
+ }
+ tystate[i] = (temp1[i+1]-temp1[i]) + 2*j;
+ if(j > maxspr)
+ maxspr = j;
+ }
+
+ /* initialize ggreed table */
+ for(i = 1; i <= nnonter; i++) {
+ ggreed[i] = 1;
+ j = 0;
+
+ /* minimum entry index is always 0 */
+ q = mem0 + yypgo[i+1] - 1;
+ for(p = mem0+yypgo[i]; p < q ; p += 2) {
+ ggreed[i] += 2;
+ if(*p > j)
+ j = *p;
+ }
+ ggreed[i] = ggreed[i] + 2*j;
+ if(j > maxoff)
+ maxoff = j;
+ }
+
+ /* now, prepare to put the shift actions into the amem array */
+ for(i = 0; i < ACTSIZE; i++)
+ amem[i] = 0;
+ maxa = amem;
+ for(i = 0; i < nstate; i++) {
+ if(tystate[i] == 0 && adb > 1)
+ Bprint(ftable, "State %d: null\n", i);
+ indgo[i] = YYFLAG1;
+ }
+ while((i = nxti()) != NOMORE)
+ if(i >= 0)
+ stin(i);
+ else
+ gin(-i);
+
+ /* print amem array */
+ if(adb > 2 )
+ for(p = amem; p <= maxa; p += 10) {
+ Bprint(ftable, "%4d ", (int)(p-amem));
+ for(i = 0; i < 10; ++i)
+ Bprint(ftable, "%4d ", p[i]);
+ Bprint(ftable, "\n");
+ }
+
+ /* write out the output appropriate to the language */
+ aoutput();
+ osummary();
+ ZAPFILE(tempname);
+}
+
+void
+gin(int i)
+{
+ int *p, *r, *s, *q1, *q2;
+
+ /* enter gotos on nonterminal i into array amem */
+ ggreed[i] = 0;
+
+ q2 = mem0+ yypgo[i+1] - 1;
+ q1 = mem0 + yypgo[i];
+
+ /* now, find amem place for it */
+ for(p = amem; p < &amem[ACTSIZE]; p++) {
+ if(*p)
+ continue;
+ for(r = q1; r < q2; r += 2) {
+ s = p + *r + 1;
+ if(*s)
+ goto nextgp;
+ if(s > maxa)
+ if((maxa = s) > &amem[ACTSIZE])
+ error("a array overflow");
+ }
+ /* we have found amem spot */
+ *p = *q2;
+ if(p > maxa)
+ if((maxa = p) > &amem[ACTSIZE])
+ error("a array overflow");
+ for(r = q1; r < q2; r += 2) {
+ s = p + *r + 1;
+ *s = r[1];
+ }
+ pgo[i] = p-amem;
+ if(adb > 1)
+ Bprint(ftable, "Nonterminal %d, entry at %d\n", i, pgo[i]);
+ return;
+
+ nextgp:;
+ }
+ error("cannot place goto %d\n", i);
+}
+
+void
+stin(int i)
+{
+ int *r, *s, n, flag, j, *q1, *q2;
+
+ tystate[i] = 0;
+
+ /* enter state i into the amem array */
+ q2 = mem0+temp1[i+1];
+ q1 = mem0+temp1[i];
+ /* find an acceptable place */
+ for(n = -maxoff; n < ACTSIZE; n++) {
+ flag = 0;
+ for(r = q1; r < q2; r += 2) {
+ if((s = *r + n + amem) < amem)
+ goto nextn;
+ if(*s == 0)
+ flag++;
+ else
+ if(*s != r[1])
+ goto nextn;
+ }
+
+ /* check that the position equals another only if the states are identical */
+ for(j=0; j 1)
+ Bprint(ftable,
+ "State %d: entry at %d equals state %d\n",
+ i, n, j);
+ return;
+ }
+
+ /* we have some disagreement */
+ goto nextn;
+ }
+ }
+
+ for(r = q1; r < q2; r += 2) {
+ if((s = *r+n+amem) >= &amem[ACTSIZE])
+ error("out of space in optimizer a array");
+ if(s > maxa)
+ maxa = s;
+ if(*s != 0 && *s != r[1])
+ error("clobber of a array, pos'n %d, by %d", s-amem, r[1]);
+ *s = r[1];
+ }
+ indgo[i] = n;
+ if(adb > 1)
+ Bprint(ftable, "State %d: entry at %d\n", i, indgo[i]);
+ return;
+ nextn:;
+ }
+ error("Error; failure to place state %d\n", i);
+}
+
+/*
+ * finds the next i
+ */
+int
+nxti(void)
+{
+ int i, max, maxi;
+
+ max = 0;
+ maxi = 0;
+ for(i = 1; i <= nnonter; i++)
+ if(ggreed[i] >= max) {
+ max = ggreed[i];
+ maxi = -i;
+ }
+ for(i = 0; i < nstate; ++i)
+ if(tystate[i] >= max) {
+ max = tystate[i];
+ maxi = i;
+ }
+ if(nxdb)
+ Bprint(ftable, "nxti = %d, max = %d\n", maxi, max);
+ if(max == 0)
+ return NOMORE;
+ return maxi;
+}
+
+/*
+ * write summary
+ */
+void
+osummary(void)
+{
+
+ int i, *p;
+
+ if(foutput == 0)
+ return;
+ i = 0;
+ for(p = maxa; p >= amem; p--)
+ if(*p == 0)
+ i++;
+
+ Bprint(foutput, "Optimizer space used: input %d/%d, output %d/%d\n",
+ (int)(pmem-mem0+1), MEMSIZE, (int)(maxa-amem+1), ACTSIZE);
+ Bprint(foutput, "%d table entries, %d zero\n", (int)(maxa-amem+1), i);
+ Bprint(foutput, "maximum spread: %d, maximum offset: %d\n", maxspr, maxoff);
+}
+
+/*
+ * this version is for C
+ * write out the optimized parser
+ */
+void
+aoutput(void)
+{
+ Bprint(ftable, "#define\tYYLAST\t%d\n", (int)(maxa-amem+1));
+ arout("yyact", amem, (maxa-amem)+1);
+ arout("yypact", indgo, nstate);
+ arout("yypgo", pgo, nnonter+1);
+}
+
+void
+arout(char *s, int *v, int n)
+{
+ int i;
+
+ Bprint(ftable, "short %s[] =\n{", s);
+ for(i = 0; i < n;) {
+ if(i%10 == 0)
+ Bprint(ftable, "\n");
+ Bprint(ftable, "%4d", v[i]);
+ i++;
+ if(i == n)
+ Bprint(ftable, "\n};\n");
+ else
+ Bprint(ftable, ",");
+ }
+}
+
+/*
+ * read and convert an integer from the standard input
+ * return the terminating character
+ * blanks, tabs, and newlines are ignored
+ */
+int
+gtnm(void)
+{
+ int sign, val, c;
+
+ sign = 0;
+ val = 0;
+ while((c=Bgetrune(finput)) != Beof) {
+ if(isdigit(c)) {
+ val = val*10 + c-'0';
+ continue;
+ }
+ if(c == '-') {
+ sign = 1;
+ continue;
+ }
+ break;
+ }
+ if(sign)
+ val = -val;
+ *pmem++ = val;
+ if(pmem >= &mem0[MEMSIZE])
+ error("out of space");
+ return c;
+} |