9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

commit e70375948b9e9afebde07fb294abf5f039f19d44
parent 7dce804fe658181cb8cbb102a525ca34b4fb0006
Author: anselm@garbe.us <unknown>
Date:   Thu, 27 May 2010 10:26:43 +0100

added sha1sum and ed, enabled factor and primes, increases version to 6, remaining work is syncing with most recent code and applying some patches to rc
Diffstat:
MMakefile | 8+++-----
Mconfig.mk | 2+-
Aed/Makefile | 10++++++++++
Aed/ed.1 | 683+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aed/ed.c | 1616+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib9/Makefile | 9++++++++-
Alib9/sec/libsec.h | 366+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib9/sec/os.h | 2++
Alib9/sec/sha1.c | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib9/sec/sha1block.c | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib9/sec/sha1pickle.c | 38++++++++++++++++++++++++++++++++++++++
Asha1sum/Makefile | 10++++++++++
Asha1sum/sha1sum.1 | 0
Asha1sum/sha1sum.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mstd.mk | 4++--
15 files changed, 3114 insertions(+), 9 deletions(-)

diff --git a/Makefile b/Makefile @@ -2,11 +2,9 @@ include config.mk -SUBDIRS = lib9 yacc awk basename bc cal cat cleanname date dc du echo \ - fortune freq getflags grep hoc ls mk mkdir mtime rc read \ - sed seq sleep sort tail tee test touch tr troff uniq - -# factor primes +SUBDIRS = lib9 yacc awk basename bc cal cat cleanname date dc du echo ed \ + factor fortune freq getflags grep hoc ls mk mkdir mtime primes rc read \ + sha1sum sed seq sleep sort tail tee test touch tr troff uniq all: @echo 9base build options: diff --git a/config.mk b/config.mk @@ -4,7 +4,7 @@ PREFIX = /usr/local/plan9 MANPREFIX = ${PREFIX}/share/man -VERSION = 5 +VERSION = 6 OBJTYPE = 386 #OBJTYPE = arm #OBJTYPE = x86_64 diff --git a/ed/Makefile b/ed/Makefile @@ -0,0 +1,10 @@ +# ed - ed unix port from plan9 +# Depends on ../lib9 + +TARG = ed + +include ../std.mk + +pre-uninstall: + +post-install: diff --git a/ed/ed.1 b/ed/ed.1 @@ -0,0 +1,683 @@ +.TH ED 1 +.SH NAME +ed \- text editor +.SH SYNOPSIS +.B ed +[ +.B - +] +[ +.B -o +] +[ +.I file +] +.SH DESCRIPTION +.I Ed +is a venerable text editor. +.PP +If a +.I file +argument is given, +.I ed +simulates an +.L e +command (see below) on that file: +it is read into +.I ed's +buffer so that it can be edited. +The options are +.TP +.B - +Suppress the printing +of character counts by +.LR e , +.LR r , +and +.L w +commands and of the confirming +.L ! +by +.L ! +commands. +.TP +.B -o +(for output piping) +Write all output to the standard error file except writing by +.L w +commands. +If no +.I file +is given, make +.B /dev/stdout +the remembered file; see the +.L e +command below. +.PP +.I Ed +operates on a `buffer', a copy of the file it is editing; +changes made +in the buffer have no effect on the file until a +.L w +(write) +command is given. +The copy of the text being edited resides +in a temporary file called the +.IR buffer . +.PP +Commands to +.I ed +have a simple and regular structure: zero, one, or +two +.I addresses +followed by a single character +.IR command , +possibly +followed by parameters to the command. +These addresses specify one or more lines in the buffer. +Missing addresses are supplied by default. +.PP +In general, only one command may appear on a line. +Certain commands allow the +addition of text to the buffer. +While +.I ed +is accepting text, it is said +to be in +.I "input mode." +In this mode, no commands are recognized; +all input is merely collected. +Input mode is left by typing a period +.L . +alone at the +beginning of a line. +.PP +.I Ed +supports the +.I "regular expression" +notation described in +.IR regexp (7). +Regular expressions are used in addresses to specify +lines and in one command +(see +.I s +below) +to specify a portion of a line which is to be replaced. +If it is desired to use one of +the regular expression metacharacters as an ordinary +character, that character may be preceded by +.RB ` \e '. +This also applies to the character bounding the regular +expression (often +.LR / ) +and to +.L \e +itself. +.PP +To understand addressing in +.I ed +it is necessary to know that at any time there is a +.I "current line." +Generally, the current line is +the last line affected by a command; however, +the exact effect on the current line +is discussed under the description of +each command. +Addresses are constructed as follows. +.TP +1. +The character +.LR . , +customarily called `dot', +addresses the current line. +.TP +2. +The character +.L $ +addresses the last line of the buffer. +.TP +3. +A decimal number +.I n +addresses the +.IR n -th +line of the buffer. +.TP +4. +.BI \'x +addresses the line marked with the name +.IR x , +which must be a lower-case letter. +Lines are marked with the +.L k +command. +.TP +5. +A regular expression enclosed in slashes ( +.LR / ) +addresses +the line found by searching forward from the current line +and stopping at the first line containing a +string that matches the regular expression. +If necessary the search wraps around to the beginning of the +buffer. +.TP +6. +A regular expression enclosed in queries +.L ? +addresses +the line found by searching backward from the current line +and stopping at the first line containing +a string that matches the regular expression. +If necessary +the search wraps around to the end of the buffer. +.TP +7. +An address followed by a plus sign +.L + +or a minus sign +.L - +followed by a decimal number specifies that address plus +(resp. minus) the indicated number of lines. +The plus sign may be omitted. +.TP +8. +An address followed by +.L + +(or +.LR - ) +followed by a +regular expression enclosed in slashes specifies the first +matching line following (or preceding) that address. +The search wraps around if necessary. +The +.L + +may be omitted, so +.L 0/x/ +addresses the +.I first +line in the buffer with an +.LR x . +Enclosing the regular expression in +.L ? +reverses the search direction. +.TP +9. +If an address begins with +.L + +or +.L - +the addition or subtraction is taken with respect to the current line; +e.g.\& +.L -5 +is understood to mean +.LR .-5 . +.TP +10. +If an address ends with +.L + +or +.LR - , +then 1 is added (resp. subtracted). +As a consequence of this rule and rule 9, +the address +.L - +refers to the line before the current line. +Moreover, +trailing +.L + +and +.L - +characters +have cumulative effect, so +.L -- +refers to the current +line less 2. +.TP +11. +To maintain compatibility with earlier versions of the editor, +the character +.L ^ +in addresses is +equivalent to +.LR - . +.PP +Commands may require zero, one, or two addresses. +Commands which require no addresses regard the presence +of an address as an error. +Commands which accept one or two addresses +assume default addresses when insufficient are given. +If more addresses are given than a command requires, +the last one or two (depending on what is accepted) are used. +.PP +Addresses are separated from each other typically by a comma +.LR , . +They may also be separated by a semicolon +.LR ; . +In this case the current line +is set to +the previous address before the next address is interpreted. +If no address precedes a comma or semicolon, line 1 is assumed; +if no address follows, the last line of the buffer is assumed. +The second address of any two-address sequence +must correspond to a line following the line corresponding to the first address. +.PP +In the following list of +.I ed +commands, the default addresses +are shown in parentheses. +The parentheses are not part of +the address, but are used to show that the given addresses are +the default. +`Dot' means the current line. +.TP +.RB (\|\fL.\fP\|) \|a +.br +.ns +.TP +<text> +.br +.ns +.TP +.B . +Read the given text +and append it after the addressed line. +Dot is left +on the last line input, if there +were any, otherwise at the addressed line. +Address +.L 0 +is legal for this command; text is placed +at the beginning of the buffer. +.TP +.RB (\|\fL.,.\fP\|) \|b [ +- ][\fIpagesize\fP][ pln\fR] +Browse. +Print a `page', normally 20 lines. +The optional +.L + +(default) or +.L - +specifies whether the next or previous +page is to be printed. +The optional +.I pagesize +is the number of lines in a page. +The optional +.LR p , +.LR n , +or +.L l +causes printing in the specified format, initially +.LR p . +Pagesize and format are remembered between +.L b +commands. +Dot is left at the last line displayed. +.TP +.RB (\|\fL.,.\fP\|) \|c +.br +.ns +.TP +<text> +.br +.ns +.TP +.B . +Change. +Delete the addressed lines, then accept input +text to replace these lines. +Dot is left at the last line input; if there were none, +it is left at the line preceding the deleted lines. +.TP +.RB (\|\fL.,.\fP\|) \|d +Delete the addressed lines from the buffer. +Dot is set to the line following the last line deleted, or to +the last line of the buffer if the deleted lines had no successor. +.TP +.BI e " filename" +Edit. +Delete the entire contents of the buffer; +then read the named file into the buffer. +Dot is set to the last line of the buffer. +The number of characters read is typed. +The file name is remembered for possible use in later +.LR e , +.LR r , +or +.L w +commands. +If +.I filename +is missing, the remembered name is used. +.TP +.BI E " filename" +Unconditional +.LR e ; +see +.RL ` q ' +below. +.TP +.BI f " filename" +Print the currently remembered file name. +If +.I filename +is given, +the currently remembered file name is first changed to +.IR filename . +.TP +.RB (\|\fL1,$\fP\|) \|g/\fIregular\ expression\fP/\fIcommand\ list\fP +.PD 0 +.TP +.RB (\|\fL1,$\fP\|) \|g/\fIregular\ expression\fP/ +.TP +.RB (\|\fL1,$\fP\|) \|g/\fIregular\ expression\fP +.PD +Global. +First mark every line which matches +the given +.IR regular expression . +Then for every such line, execute the +.I command list +with dot initially set to that line. +A single command or the first of multiple commands +appears on the same line with the global command. +All lines of a multi-line list except the last line must end with +.LR \e . +The +.RB \&` \&. \&' +terminating input mode for an +.LR a , +.LR i , +.L c +command may be omitted if it would be on the +last line of the command list. +The commands +.L g +and +.L v +are not permitted in the command list. +Any character other than space or newline may +be used instead of +.L / +to delimit the regular expression. +The second and third forms mean +.BI g/ regular\ expression /p \f1. +.TP +.RB (\| .\| ) \|i +.PD 0 +.TP +<text> +.TP +.B . +Insert the given text before the addressed line. +Dot is left at the last line input, or, if there were none, +at the line before the addressed line. +This command differs from the +.I a +command only in the placement of the +text. +.PD +.TP +.RB (\| .,.+1 \|) \|j +Join the addressed lines into a single line; +intermediate newlines are deleted. +Dot is left at the resulting line. +.TP +.RB (\|\fL.\fP\|) \|k\fIx\fP +Mark the addressed line with name +.IR x , +which must be a lower-case letter. +The address form +.BI \' x +then addresses this line. +.ne 2.5 +.TP +.RB (\|\fL.,.\fP\|) \|l +List. +Print the addressed lines in an unambiguous way: +a tab is printed as +.LR \et , +a backspace as +.LR \eb , +backslashes as +.LR \e\e , +and non-printing characters as +a backslash, an +.LR x , +and four hexadecimal digits. +Long lines are folded, +with the second and subsequent sub-lines indented one tab stop. +If the last character in the line is a blank, +it is followed by +.LR \en . +An +.L l +may be appended, like +.LR p , +to any non-I/O command. +.TP +.RB (\|\fL.,.\fP\|) \|m\fIa +Move. +Reposition the addressed lines after the line +addressed by +.IR a . +Dot is left at the last moved line. +.TP +.RB (\|\fL.,.\fP\|) \|n +Number. +Perform +.LR p , +prefixing each line with its line number and a tab. +An +.L n +may be appended, like +.LR p , +to any non-I/O command. +.TP +.RB (\|\fL.,.\fP\|) \|p +Print the addressed lines. +Dot is left at the last line printed. +A +.L p +appended to any non-I/O command causes the then current line +to be printed after the command is executed. +.TP +.RB (\|\fL.,.\fP\|) \|P +This command is a synonym for +.LR p . +.TP +.B q +Quit the editor. +No automatic write +of a file is done. +A +.L q +or +.L e +command is considered to be in error if the buffer has +been modified since the last +.LR w , +.LR q , +or +.L e +command. +.TP +.B Q +Quit unconditionally. +.TP +.RB ( $ )\|r\ \fIfilename\fP +Read in the given file after the addressed line. +If no +.I filename +is given, the remembered file name is used. +The file name is remembered if there were no +remembered file name already. +If the read is successful, the number of characters +read is printed. +Dot is left at the last line read from the file. +.TP +.RB (\|\fL.,.\fP\|) \|s\fIn\fP/\fIregular\ expression\fP/\fIreplacement\fP/ +.PD 0 +.TP +.RB (\|\fL.,.\fP\|) \|s\fIn\fP/\fIregular\ expression\fP/\fIreplacement\fP/g +.TP +.RB (\|\fL.,.\fP\|) \|s\fIn\fP/\fIregular\ expression\fP/\fIreplacement\fP +.PD +Substitute. +Search each addressed +line for an occurrence of the specified regular expression. +On each line in which +.I n +matches are found +.RI ( n +defaults to 1 if missing), +the +.IR n th +matched string is replaced by the replacement specified. +If the global replacement indicator +.L g +appears after the command, +all subsequent matches on the line are also replaced. +It is an error for the substitution to fail on all addressed lines. +Any character other than space or newline +may be used instead of +.L / +to delimit the regular expression +and the replacement. +Dot is left at the last line substituted. +The third form means +.BI s n / regular\ expression / replacement\fP/p\f1. +The second +.L / +may be omitted if the replacement is +empty. +.IP +An ampersand +.L & +appearing in the replacement +is replaced by the string matching the regular expression. +The characters +.BI \e n\f1, +where +.I n +is a digit, +are replaced by the text matched by the +.IR n -th +regular subexpression +enclosed between +.L ( +and +.LR ) . +When +nested parenthesized subexpressions +are present, +.I n +is determined by counting occurrences of +.L ( +starting from the left. +.IP +A literal +.LR & , +.LR / , +.L \e +or newline may be included in a replacement +by prefixing it with +.LR \e . +.TP +.RB (\|\fL.,.\fP\|) \|t\|\fIa +Transfer. +Copy the addressed lines +after the line addressed by +.IR a . +Dot is left at the last line of the copy. +.TP +.RB (\|\fL.,.\fP\|) \|u +Undo. +Restore the preceding contents +of the first addressed line (sic), which must be the last line +in which a substitution was made (double sic). +.TP +.RB (\|\fL1,$\fP\|) \|v/\fIregular\ expression\fP/\fIcommand\ list\fP +This command is the same as the global command +.L g +except that the command list is executed with +dot initially set to every line +.I except +those +matching the regular expression. +.TP +.RB (\|\fL1,$\fP\|) \|w " \fIfilename\fP" +Write the addressed lines to +the given file. +If the file does not exist, +it is created with mode 666 (readable and writable by everyone). +If no +.I filename +is given, the remembered file name, if any, is used. +The file name is remembered if there were no +remembered file name already. +Dot is unchanged. +If the write is successful, the number of characters written is +printed. +.TP +.RB (\|\fL1,$\fP\|) \|W " \fIfilename\fP" +Perform +.LR w , +but append to, instead of overwriting, any existing file contents. +.TP +.RB ( $ ) \|= +Print the line number of the addressed line. +Dot is unchanged. +.TP +.BI ! shell\ command +Send the remainder of the line after the +.L ! +to +.IR rc (1) +to be interpreted as a command. +Dot is unchanged. +.TP +.RB (\| .+1 )\|<newline> +An address without a command is taken as a +.L p +command. +A terminal +.L / +may be omitted from the address. +A blank line alone is equivalent to +.LR .+1p ; +it is useful +for stepping through text. +.PP +If an interrupt signal +.SM (DEL) +is sent, +.I ed +prints a +.L ? +and returns to its command level. +.PP +When reading a file, +.I ed +discards +.SM NUL +characters +and all characters after the last newline. +.SH FILES +.B /tmp/e* +.br +.B ed.hup +\ \ work is saved here if terminal hangs up +.SH SOURCE +.B \*9/src/cmd/ed.c +.SH "SEE ALSO" +.IR sam (1), +.IR sed (1), +.IR regexp (7) +.SH DIAGNOSTICS +.BI ? name +for inaccessible file; +.L ?TMP +for temporary file overflow; +.L ? +for errors in commands or other overflows. diff --git a/ed/ed.c b/ed/ed.c @@ -0,0 +1,1616 @@ +/* + * Editor + */ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <regexp.h> + +#undef EOF /* stdio? */ + +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/sizeof(Rune)]; +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[] = "/var/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 = "/dev/stdout"; + 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('\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('\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('\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('?'); + 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('\n'); + lastc = '\n'; + error1(Q); + notejmp(a, savej, 0); + } + if(strcmp(s, "hangup") == 0 || strcmp(s, "kill") == 0){ + if(rescuing) + noted(NDFLT); + rescue(); + } + if(strstr(s, "child")) + noted(NCONT); + 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); + } +} + +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, d; + + nline = 0; + dot = a; + while((*f)() == 0) { + if((dol-zero) >= nlall) { + nlall += 512; + a1 = realloc(zero, (nlall+50)*sizeof(int*)); + if(a1 == 0) { + error("MEM?"); + rescue(); + } + /* relocate pointers; avoid wraparound if sizeof(int) < sizeof(int*) */ + d = addr1 - zero; + addr1 = a1 + d; + d = addr2 - zero; + addr2 = a1 + d; + d = dol - zero; + dol = a1 + d; + d = dot - zero; + dot = a1 + d; + zero = a1; + } + d = putline(); + nline++; + a1 = ++dol; + a2 = a1+1; + rdot = ++dot; + while(a1 > rdot) + *--a2 = *--a1; + *rdot = d; + } + 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) { + execlp("rc", "rc", "-c", buf, (char*)0); + sysfatal("exec failed: %r"); + 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/sizeof(Rune)) - 1); + while(*lp++ = *bp++) { + nl -= sizeof(Rune); + if(nl == 0) { + bp = getblock(tl += BLKSIZE/sizeof(Rune), 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/sizeof(Rune))-1); + while(*bp = *lp++) { + if(*bp++ == '\n') { + bp[-1] = 0; + linebp = lp; + break; + } + nl -= sizeof(Rune); + if(nl == 0) { + tl += BLKSIZE/sizeof(Rune); + 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/sizeof(Rune)); + off = (atl*sizeof(Rune)) & (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/sizeof(Rune)]) + error(Q); + } else + if(c == '\n' && (!globp || !globp[0])) { + peekc = c; + pflag++; + break; + } else + if(c == seof) + break; + *p++ = c; + if(p >= &rhsbuf[LBSIZE/sizeof(Rune)]) + 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<ad1) { + dot = adt + (ad2-ad1); + if((++adt)==ad1) + return; + reverse(adt, ad1); + reverse(ad1, ad2); + reverse(adt, ad2); + } else + 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 + '0'); +} + +void +putst(char *sp) +{ + Rune r; + + col = 0; + for(;;) { + sp += chartorune(&r, sp); + if(r == 0) + break; + putchr(r); + } + putchr('\n'); +} + +void +putshst(Rune *sp) +{ + col = 0; + while(*sp) + putchr(*sp++); + putchr('\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/lib9/Makefile b/lib9/Makefile @@ -13,10 +13,16 @@ TARG=lib9 # convM2S.o # convS2M.o +SECFILES=\ + sec/sha1block.o\ + sec/sha1.o\ + sec/sha1pickle.o\ + NUM=\ fmt/charstod.o\ fmt/pow10.o\ + FMTOFILES=\ fmt/dofmt.o\ fmt/fltfmt.o\ @@ -193,6 +199,7 @@ LIB9OFILES=\ zoneinfo.o\ OFILES=\ + $(SECFILES)\ $(FMTOFILES)\ $(UTFOFILES)\ $(BIOFILES)\ @@ -212,7 +219,7 @@ ${LIB}: ${OFILES} .c.o: @echo CC $*.c - @${CC} -o $*.o ${CFLAGS} -I${PREFIX}/include $*.c + @${CC} -o $*.o ${CFLAGS} -Isec -I${PREFIX}/include $*.c clean: rm -f ${OFILES} ${LIB} diff --git a/lib9/sec/libsec.h b/lib9/sec/libsec.h @@ -0,0 +1,366 @@ +#ifndef _LIBSEC_H_ +#define _LIBSEC_H_ 1 +#if defined(__cplusplus) +extern "C" { +#endif +/* +#pragma lib "libsec.a" +#pragma src "/sys/src/libsec" +*/ + +AUTOLIB(sec) + +#ifndef _MPINT +typedef struct mpint mpint; +#endif + +/*******************************************************/ +/* AES definitions */ +/*******************************************************/ + +enum +{ + AESbsize= 16, + AESmaxkey= 32, + AESmaxrounds= 14 +}; + +typedef struct AESstate AESstate; +struct AESstate +{ + ulong setup; + int rounds; + int keybytes; + uchar key[AESmaxkey]; /* unexpanded key */ + u32int ekey[4*(AESmaxrounds + 1)]; /* encryption key */ + u32int dkey[4*(AESmaxrounds + 1)]; /* decryption key */ + uchar ivec[AESbsize]; /* initialization vector */ +}; + +void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec); +void aesCBCencrypt(uchar *p, int len, AESstate *s); +void aesCBCdecrypt(uchar *p, int len, AESstate *s); + +/*******************************************************/ +/* Blowfish Definitions */ +/*******************************************************/ + +enum +{ + BFbsize = 8, + BFrounds = 16 +}; + +/* 16-round Blowfish */ +typedef struct BFstate BFstate; +struct BFstate +{ + ulong setup; + + uchar key[56]; + uchar ivec[8]; + + u32int pbox[BFrounds+2]; + u32int sbox[1024]; +}; + +void setupBFstate(BFstate *s, uchar key[], int keybytes, uchar *ivec); +void bfCBCencrypt(uchar*, int, BFstate*); +void bfCBCdecrypt(uchar*, int, BFstate*); +void bfECBencrypt(uchar*, int, BFstate*); +void bfECBdecrypt(uchar*, int, BFstate*); + +/*******************************************************/ +/* DES definitions */ +/*******************************************************/ + +enum +{ + DESbsize= 8 +}; + +/* single des */ +typedef struct DESstate DESstate; +struct DESstate +{ + ulong setup; + uchar key[8]; /* unexpanded key */ + ulong expanded[32]; /* expanded key */ + uchar ivec[8]; /* initialization vector */ +}; + +void setupDESstate(DESstate *s, uchar key[8], uchar *ivec); +void des_key_setup(uchar[8], ulong[32]); +void block_cipher(ulong*, uchar*, int); +void desCBCencrypt(uchar*, int, DESstate*); +void desCBCdecrypt(uchar*, int, DESstate*); +void desECBencrypt(uchar*, int, DESstate*); +void desECBdecrypt(uchar*, int, DESstate*); + +/* for backward compatibility with 7 byte DES key format */ +void des56to64(uchar *k56, uchar *k64); +void des64to56(uchar *k64, uchar *k56); +void key_setup(uchar[7], ulong[32]); + +/* triple des encrypt/decrypt orderings */ +enum { + DES3E= 0, + DES3D= 1, + DES3EEE= 0, + DES3EDE= 2, + DES3DED= 5, + DES3DDD= 7 +}; + +typedef struct DES3state DES3state; +struct DES3state +{ + ulong setup; + uchar key[3][8]; /* unexpanded key */ + ulong expanded[3][32]; /* expanded key */ + uchar ivec[8]; /* initialization vector */ +}; + +void setupDES3state(DES3state *s, uchar key[3][8], uchar *ivec); +void triple_block_cipher(ulong keys[3][32], uchar*, int); +void des3CBCencrypt(uchar*, int, DES3state*); +void des3CBCdecrypt(uchar*, int, DES3state*); +void des3ECBencrypt(uchar*, int, DES3state*); +void des3ECBdecrypt(uchar*, int, DES3state*); + +/*******************************************************/ +/* digests */ +/*******************************************************/ + +enum +{ + SHA1dlen= 20, /* SHA digest length */ + MD4dlen= 16, /* MD4 digest length */ + MD5dlen= 16 /* MD5 digest length */ +}; + +typedef struct DigestState DigestState; +struct DigestState +{ + ulong len; + u32int state[5]; + uchar buf[128]; + int blen; + char malloced; + char seeded; +}; +typedef struct DigestState SHAstate; /* obsolete name */ +typedef struct DigestState SHA1state; +typedef struct DigestState MD5state; +typedef struct DigestState MD4state; + +DigestState* md4(uchar*, ulong, uchar*, DigestState*); +DigestState* md5(uchar*, ulong, uchar*, DigestState*); +DigestState* sha1(uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_md5(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha1(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +char* sha1pickle(SHA1state*); +SHA1state* sha1unpickle(char*); + +/*******************************************************/ +/* random number generation */ +/*******************************************************/ +void genrandom(uchar *buf, int nbytes); +void prng(uchar *buf, int nbytes); +ulong fastrand(void); +ulong nfastrand(ulong); + +/*******************************************************/ +/* primes */ +/*******************************************************/ +void genprime(mpint *p, int n, int accuracy); /* generate an n bit probable prime */ +void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy); /* prime and generator */ +void genstrongprime(mpint *p, int n, int accuracy); /* generate an n bit strong prime */ +void DSAprimes(mpint *q, mpint *p, uchar seed[SHA1dlen]); +int probably_prime(mpint *n, int nrep); /* miller-rabin test */ +int smallprimetest(mpint *p); /* returns -1 if not prime, 0 otherwise */ + +/*******************************************************/ +/* rc4 */ +/*******************************************************/ +typedef struct RC4state RC4state; +struct RC4state +{ + uchar state[256]; + uchar x; + uchar y; +}; + +void setupRC4state(RC4state*, uchar*, int); +void rc4(RC4state*, uchar*, int); +void rc4skip(RC4state*, int); +void rc4back(RC4state*, int); + +/*******************************************************/ +/* rsa */ +/*******************************************************/ +typedef struct RSApub RSApub; +typedef struct RSApriv RSApriv; +typedef struct PEMChain PEMChain; + +/* public/encryption key */ +struct RSApub +{ + mpint *n; /* modulus */ + mpint *ek; /* exp (encryption key) */ +}; + +/* private/decryption key */ +struct RSApriv +{ + RSApub pub; + + mpint *dk; /* exp (decryption key) */ + + /* precomputed values to help with chinese remainder theorem calc */ + mpint *p; + mpint *q; + mpint *kp; /* dk mod p-1 */ + mpint *kq; /* dk mod q-1 */ + mpint *c2; /* (inv p) mod q */ +}; + +struct PEMChain +{ + PEMChain *next; + uchar *pem; + int pemlen; +}; + +RSApriv* rsagen(int nlen, int elen, int rounds); +mpint* rsaencrypt(RSApub *k, mpint *in, mpint *out); +mpint* rsadecrypt(RSApriv *k, mpint *in, mpint *out); +RSApub* rsapuballoc(void); +void rsapubfree(RSApub*); +RSApriv* rsaprivalloc(void); +void rsaprivfree(RSApriv*); +RSApub* rsaprivtopub(RSApriv*); +RSApub* X509toRSApub(uchar*, int, char*, int); +RSApriv* asn1toRSApriv(uchar*, int); +uchar* decodepem(char *s, char *type, int *len, char**); +PEMChain* decodepemchain(char *s, char *type); +uchar* X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen); +RSApriv* rsafill(mpint *n, mpint *ek, mpint *dk, mpint *p, mpint *q); +uchar* X509req(RSApriv *priv, char *subj, int *certlen); + +/*******************************************************/ +/* elgamal */ +/*******************************************************/ +typedef struct EGpub EGpub; +typedef struct EGpriv EGpriv; +typedef struct EGsig EGsig; + +/* public/encryption key */ +struct EGpub +{ + mpint *p; /* modulus */ + mpint *alpha; /* generator */ + mpint *key; /* (encryption key) alpha**secret mod p */ +}; + +/* private/decryption key */ +struct EGpriv +{ + EGpub pub; + mpint *secret; /* (decryption key) */ +}; + +/* signature */ +struct EGsig +{ + mpint *r, *s; +}; + +EGpriv* eggen(int nlen, int rounds); +mpint* egencrypt(EGpub *k, mpint *in, mpint *out); +mpint* egdecrypt(EGpriv *k, mpint *in, mpint *out); +EGsig* egsign(EGpriv *k, mpint *m); +int egverify(EGpub *k, EGsig *sig, mpint *m); +EGpub* egpuballoc(void); +void egpubfree(EGpub*); +EGpriv* egprivalloc(void); +void egprivfree(EGpriv*); +EGsig* egsigalloc(void); +void egsigfree(EGsig*); +EGpub* egprivtopub(EGpriv*); + +/*******************************************************/ +/* dsa */ +/*******************************************************/ +typedef struct DSApub DSApub; +typedef struct DSApriv DSApriv; +typedef struct DSAsig DSAsig; + +/* public/encryption key */ +struct DSApub +{ + mpint *p; /* modulus */ + mpint *q; /* group order, q divides p-1 */ + mpint *alpha; /* group generator */ + mpint *key; /* (encryption key) alpha**secret mod p */ +}; + +/* private/decryption key */ +struct DSApriv +{ + DSApub pub; + mpint *secret; /* (decryption key) */ +}; + +/* signature */ +struct DSAsig +{ + mpint *r, *s; +}; + +DSApriv* dsagen(DSApub *opub); +DSAsig* dsasign(DSApriv *k, mpint *m); +int dsaverify(DSApub *k, DSAsig *sig, mpint *m); +DSApub* dsapuballoc(void); +void dsapubfree(DSApub*); +DSApriv* dsaprivalloc(void); +void dsaprivfree(DSApriv*); +DSAsig* dsasigalloc(void); +void dsasigfree(DSAsig*); +DSApub* dsaprivtopub(DSApriv*); +DSApriv* asn1toDSApriv(uchar*, int); + +/*******************************************************/ +/* TLS */ +/*******************************************************/ +typedef struct Thumbprint{ + struct Thumbprint *next; + uchar sha1[SHA1dlen]; +} Thumbprint; + +typedef struct TLSconn{ + char dir[40]; /* connection directory */ + uchar *cert; /* certificate (local on input, remote on output) */ + uchar *sessionID; + int certlen, sessionIDlen; + int (*trace)(char*fmt, ...); + PEMChain *chain; +} TLSconn; + +/* tlshand.c */ +extern int tlsClient(int fd, TLSconn *c); +extern int tlsServer(int fd, TLSconn *c); + +/* thumb.c */ +extern Thumbprint* initThumbprints(char *ok, char *crl); +extern void freeThumbprints(Thumbprint *ok); +extern int okThumbprint(uchar *sha1, Thumbprint *ok); + +/* readcert.c */ +extern uchar *readcert(char *filename, int *pcertlen); +PEMChain *readcertchain(char *filename); + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/lib9/sec/os.h b/lib9/sec/os.h @@ -0,0 +1,2 @@ +#include <u.h> +#include <libc.h> diff --git a/lib9/sec/sha1.c b/lib9/sec/sha1.c @@ -0,0 +1,127 @@ +#include "os.h" +#include <libsec.h> + +static void encode(uchar*, u32int*, ulong); + +extern void _sha1block(uchar*, ulong, u32int*); + +/* + * we require len to be a multiple of 64 for all but + * the last call. There must be room in the input buffer + * to pad. + */ +SHA1state* +sha1(uchar *p, ulong len, uchar *digest, SHA1state *s) +{ + uchar buf[128]; + u32int x[16]; + int i; + uchar *e; + + if(s == nil){ + s = malloc(sizeof(*s)); + if(s == nil) + return nil; + memset(s, 0, sizeof(*s)); + s->malloced = 1; + } + + if(s->seeded == 0){ + /* seed the state, these constants would look nicer big-endian */ + s->state[0] = 0x67452301; + s->state[1] = 0xefcdab89; + s->state[2] = 0x98badcfe; + s->state[3] = 0x10325476; + s->state[4] = 0xc3d2e1f0; + s->seeded = 1; + } + + /* fill out the partial 64 byte block from previous calls */ + if(s->blen){ + i = 64 - s->blen; + if(len < i) + i = len; + memmove(s->buf + s->blen, p, i); + len -= i; + s->blen += i; + p += i; + if(s->blen == 64){ + _sha1block(s->buf, s->blen, s->state); + s->len += s->blen; + s->blen = 0; + } + } + + /* do 64 byte blocks */ + i = len & ~0x3f; + if(i){ + _sha1block(p, i, s->state); + s->len += i; + len -= i; + p += i; + } + + /* save the left overs if not last call */ + if(digest == 0){ + if(len){ + memmove(s->buf, p, len); + s->blen += len; + } + return s; + } + + /* + * this is the last time through, pad what's left with 0x80, + * 0's, and the input count to create a multiple of 64 bytes + */ + if(s->blen){ + p = s->buf; + len = s->blen; + } else { + memmove(buf, p, len); + p = buf; + } + s->len += len; + e = p + len; + if(len < 56) + i = 56 - len; + else + i = 120 - len; + memset(e, 0, i); + *e = 0x80; + len += i; + + /* append the count */ + x[0] = s->len>>29; + x[1] = s->len<<3; + encode(p+len, x, 8); + + /* digest the last part */ + _sha1block(p, len+8, s->state); + s->len += len+8; + + /* return result and free state */ + encode(digest, s->state, SHA1dlen); + if(s->malloced == 1) + free(s); + return nil; +} + +/* + * encodes input (ulong) into output (uchar). Assumes len is + * a multiple of 4. + */ +static void +encode(uchar *output, u32int *input, ulong len) +{ + u32int x; + uchar *e; + + for(e = output + len; output < e;) { + x = *input++; + *output++ = x >> 24; + *output++ = x >> 16; + *output++ = x >> 8; + *output++ = x; + } +} diff --git a/lib9/sec/sha1block.c b/lib9/sec/sha1block.c @@ -0,0 +1,187 @@ +#include "os.h" + +void +_sha1block(uchar *p, ulong len, u32int *s) +{ + u32int a, b, c, d, e, x; + uchar *end; + u32int *wp, *wend; + u32int w[80]; + + /* at this point, we have a multiple of 64 bytes */ + for(end = p+len; p < end;){ + a = s[0]; + b = s[1]; + c = s[2]; + d = s[3]; + e = s[4]; + + wend = w + 15; + for(wp = w; wp < wend; wp += 5){ + wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; + e += ((a<<5) | (a>>27)) + wp[0]; + e += 0x5a827999 + (((c^d)&b)^d); + b = (b<<30)|(b>>2); + + wp[1] = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7]; + d += ((e<<5) | (e>>27)) + wp[1]; + d += 0x5a827999 + (((b^c)&a)^c); + a = (a<<30)|(a>>2); + + wp[2] = (p[8]<<24) | (p[9]<<16) | (p[10]<<8) | p[11]; + c += ((d<<5) | (d>>27)) + wp[2]; + c += 0x5a827999 + (((a^b)&e)^b); + e = (e<<30)|(e>>2); + + wp[3] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15]; + b += ((c<<5) | (c>>27)) + wp[3]; + b += 0x5a827999 + (((e^a)&d)^a); + d = (d<<30)|(d>>2); + + wp[4] = (p[16]<<24) | (p[17]<<16) | (p[18]<<8) | p[19]; + a += ((b<<5) | (b>>27)) + wp[4]; + a += 0x5a827999 + (((d^e)&c)^e); + c = (c<<30)|(c>>2); + + p += 20; + } + + wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; + e += ((a<<5) | (a>>27)) + wp[0]; + e += 0x5a827999 + (((c^d)&b)^d); + b = (b<<30)|(b>>2); + + x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; + wp[1] = (x<<1) | (x>>31); + d += ((e<<5) | (e>>27)) + wp[1]; + d += 0x5a827999 + (((b^c)&a)^c); + a = (a<<30)|(a>>2); + + x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; + wp[2] = (x<<1) | (x>>31); + c += ((d<<5) | (d>>27)) + wp[2]; + c += 0x5a827999 + (((a^b)&e)^b); + e = (e<<30)|(e>>2); + + x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; + wp[3] = (x<<1) | (x>>31); + b += ((c<<5) | (c>>27)) + wp[3]; + b += 0x5a827999 + (((e^a)&d)^a); + d = (d<<30)|(d>>2); + + x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; + wp[4] = (x<<1) | (x>>31); + a += ((b<<5) | (b>>27)) + wp[4]; + a += 0x5a827999 + (((d^e)&c)^e); + c = (c<<30)|(c>>2); + + wp += 5; + p += 4; + + wend = w + 40; + for(; wp < wend; wp += 5){ + x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; + wp[0] = (x<<1) | (x>>31); + e += ((a<<5) | (a>>27)) + wp[0]; + e += 0x6ed9eba1 + (b^c^d); + b = (b<<30)|(b>>2); + + x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; + wp[1] = (x<<1) | (x>>31); + d += ((e<<5) | (e>>27)) + wp[1]; + d += 0x6ed9eba1 + (a^b^c); + a = (a<<30)|(a>>2); + + x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; + wp[2] = (x<<1) | (x>>31); + c += ((d<<5) | (d>>27)) + wp[2]; + c += 0x6ed9eba1 + (e^a^b); + e = (e<<30)|(e>>2); + + x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; + wp[3] = (x<<1) | (x>>31); + b += ((c<<5) | (c>>27)) + wp[3]; + b += 0x6ed9eba1 + (d^e^a); + d = (d<<30)|(d>>2); + + x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; + wp[4] = (x<<1) | (x>>31); + a += ((b<<5) | (b>>27)) + wp[4]; + a += 0x6ed9eba1 + (c^d^e); + c = (c<<30)|(c>>2); + } + + wend = w + 60; + for(; wp < wend; wp += 5){ + x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; + wp[0] = (x<<1) | (x>>31); + e += ((a<<5) | (a>>27)) + wp[0]; + e += 0x8f1bbcdc + ((b&c)|((b|c)&d)); + b = (b<<30)|(b>>2); + + x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; + wp[1] = (x<<1) | (x>>31); + d += ((e<<5) | (e>>27)) + wp[1]; + d += 0x8f1bbcdc + ((a&b)|((a|b)&c)); + a = (a<<30)|(a>>2); + + x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; + wp[2] = (x<<1) | (x>>31); + c += ((d<<5) | (d>>27)) + wp[2]; + c += 0x8f1bbcdc + ((e&a)|((e|a)&b)); + e = (e<<30)|(e>>2); + + x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; + wp[3] = (x<<1) | (x>>31); + b += ((c<<5) | (c>>27)) + wp[3]; + b += 0x8f1bbcdc + ((d&e)|((d|e)&a)); + d = (d<<30)|(d>>2); + + x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; + wp[4] = (x<<1) | (x>>31); + a += ((b<<5) | (b>>27)) + wp[4]; + a += 0x8f1bbcdc + ((c&d)|((c|d)&e)); + c = (c<<30)|(c>>2); + } + + wend = w + 80; + for(; wp < wend; wp += 5){ + x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; + wp[0] = (x<<1) | (x>>31); + e += ((a<<5) | (a>>27)) + wp[0]; + e += 0xca62c1d6 + (b^c^d); + b = (b<<30)|(b>>2); + + x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; + wp[1] = (x<<1) | (x>>31); + d += ((e<<5) | (e>>27)) + wp[1]; + d += 0xca62c1d6 + (a^b^c); + a = (a<<30)|(a>>2); + + x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; + wp[2] = (x<<1) | (x>>31); + c += ((d<<5) | (d>>27)) + wp[2]; + c += 0xca62c1d6 + (e^a^b); + e = (e<<30)|(e>>2); + + x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; + wp[3] = (x<<1) | (x>>31); + b += ((c<<5) | (c>>27)) + wp[3]; + b += 0xca62c1d6 + (d^e^a); + d = (d<<30)|(d>>2); + + x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; + wp[4] = (x<<1) | (x>>31); + a += ((b<<5) | (b>>27)) + wp[4]; + a += 0xca62c1d6 + (c^d^e); + c = (c<<30)|(c>>2); + } + + /* save state */ + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + } +} diff --git a/lib9/sec/sha1pickle.c b/lib9/sec/sha1pickle.c @@ -0,0 +1,38 @@ +#include "os.h" +#include <libsec.h> + +char* +sha1pickle(SHA1state *s) +{ + char *p; + int m, n; + + m = 5*9+4*((s->blen+3)/3); + p = malloc(m); + if(p == nil) + return p; + n = sprint(p, "%8.8ux %8.8ux %8.8ux %8.8ux %8.8ux ", + s->state[0], s->state[1], s->state[2], + s->state[3], s->state[4]); + enc64(p+n, m-n, s->buf, s->blen); + return p; +} + +SHA1state* +sha1unpickle(char *p) +{ + SHA1state *s; + + s = malloc(sizeof(*s)); + if(s == nil) + return nil; + s->state[0] = strtoul(p, &p, 16); + s->state[1] = strtoul(p, &p, 16); + s->state[2] = strtoul(p, &p, 16); + s->state[3] = strtoul(p, &p, 16); + s->state[4] = strtoul(p, &p, 16); + s->blen = dec64(s->buf, sizeof(s->buf), p, strlen(p)); + s->malloced = 1; + s->seeded = 1; + return s; +} diff --git a/sha1sum/Makefile b/sha1sum/Makefile @@ -0,0 +1,10 @@ +# sha1sum - sha1sum unix port from plan9 +# Depends on ../lib9 + +TARG = sha1sum + +include ../std.mk + +pre-uninstall: + +post-install: diff --git a/sha1sum/sha1sum.1 b/sha1sum/sha1sum.1 diff --git a/sha1sum/sha1sum.c b/sha1sum/sha1sum.c @@ -0,0 +1,61 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <libsec.h> + +static int +digestfmt(Fmt *fmt) +{ + char buf[SHA1dlen*2+1]; + uchar *p; + int i; + + p = va_arg(fmt->args, uchar*); + for(i=0; i<SHA1dlen; i++) + sprint(buf+2*i, "%.2ux", p[i]); + return fmtstrcpy(fmt, buf); +} + +static void +sum(int fd, char *name) +{ + int n; + uchar buf[8192], digest[SHA1dlen]; + DigestState *s; + + s = sha1(nil, 0, nil, nil); + while((n = read(fd, buf, sizeof buf)) > 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/std.mk b/std.mk @@ -25,11 +25,11 @@ uninstall: pre-uninstall .c.o: @echo CC $*.c - @${CC} ${CFLAGS} -I../lib9 -I../lib9 $*.c + @${CC} ${CFLAGS} -I../lib9 -I../lib9/sec $*.c clean: rm -f ${OFILES} ${TARG} ${TARG}: ${OFILES} @echo LD ${TARG} - @${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L../lib9 -l9 + @${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L../lib9 -l9 -lm