added sha1sum and ed, enabled factor and primes, increases version to 6, remain… | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit e70375948b9e9afebde07fb294abf5f039f19d44 | |
parent 7dce804fe658181cb8cbb102a525ca34b4fb0006 | |
Author: [email protected] <unknown> | |
Date: Thu, 27 May 2010 10:26:43 +0100 | |
added sha1sum and ed, enabled factor and primes, increases version to 6, remain… | |
Diffstat: | |
M Makefile | 8 +++----- | |
M config.mk | 2 +- | |
A ed/Makefile | 10 ++++++++++ | |
A ed/ed.1 | 683 +++++++++++++++++++++++++++++… | |
A ed/ed.c | 1616 +++++++++++++++++++++++++++++… | |
M lib9/Makefile | 9 ++++++++- | |
A lib9/sec/libsec.h | 366 +++++++++++++++++++++++++++++… | |
A lib9/sec/os.h | 2 ++ | |
A lib9/sec/sha1.c | 127 +++++++++++++++++++++++++++++… | |
A lib9/sec/sha1block.c | 187 +++++++++++++++++++++++++++++… | |
A lib9/sec/sha1pickle.c | 38 +++++++++++++++++++++++++++++… | |
A sha1sum/Makefile | 10 ++++++++++ | |
A sha1sum/sha1sum.1 | 0 | |
A sha1sum/sha1sum.c | 61 +++++++++++++++++++++++++++++… | |
M std.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 r… | |
+ 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 addres… | |
+.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", … | |
+ 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) … | |
+ 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 matc… | |
+ 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.re… | |
+ 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 ran… | |
+ 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 prob… | |
+void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy); … | |
+void genstrongprime(mpint *p, int n, int accuracy); /* generate … | |
+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… | |
+ | |
+/*******************************************************/ | |
+/* 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 *… | |
+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 |