mirror of
https://git.suckless.org/9base
synced 2025-08-07 15:42:00 -07:00
initial import
This commit is contained in:
287
LICENSE
Normal file
287
LICENSE
Normal file
@@ -0,0 +1,287 @@
|
||||
The rare bits touched by Anselm R. Garbe are under following LICENSE:
|
||||
|
||||
MIT/X Consortium License
|
||||
|
||||
(C)opyright MMV Anselm R. Garbe <garbeam at gmail dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
===================================================================
|
||||
|
||||
The Plan 9 software is provided under the terms of the
|
||||
Lucent Public License, Version 1.02, reproduced below,
|
||||
with the following notable exceptions:
|
||||
|
||||
1. No right is granted to create derivative works of or
|
||||
to redistribute (other than with the Plan 9 Operating System)
|
||||
the screen imprinter fonts identified in subdirectory
|
||||
/lib/font/bit/lucida and printer fonts (Lucida Sans Unicode, Lucida
|
||||
Sans Italic, Lucida Sans Demibold, Lucida Typewriter, Lucida Sans
|
||||
Typewriter83), identified in subdirectory /sys/lib/postscript/font.
|
||||
These directories contain material copyrights by B&H Inc. and Y&Y Inc.
|
||||
|
||||
2. The printer fonts identified in subdirectory /sys/lib/ghostscript/font
|
||||
are subject to the GNU GPL, reproduced in the file /LICENSE.gpl.
|
||||
|
||||
3. The ghostscript program in the subdirectory /sys/src/cmd/gs is
|
||||
covered by the Aladdin Free Public License, reproduced in the file
|
||||
/LICENSE.afpl.
|
||||
|
||||
Other, less notable exceptions are marked in the file tree with
|
||||
COPYING, COPYRIGHT, or LICENSE files.
|
||||
|
||||
===================================================================
|
||||
|
||||
Lucent Public License Version 1.02
|
||||
|
||||
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC
|
||||
LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
|
||||
PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
|
||||
|
||||
1. DEFINITIONS
|
||||
|
||||
"Contribution" means:
|
||||
|
||||
a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original
|
||||
Program, and
|
||||
b. in the case of each Contributor,
|
||||
|
||||
i. changes to the Program, and
|
||||
ii. additions to the Program;
|
||||
|
||||
where such changes and/or additions to the Program were added to the
|
||||
Program by such Contributor itself or anyone acting on such
|
||||
Contributor's behalf, and the Contributor explicitly consents, in
|
||||
accordance with Section 3C, to characterization of the changes and/or
|
||||
additions as Contributions.
|
||||
|
||||
"Contributor" means LUCENT and any other entity that has Contributed a
|
||||
Contribution to the Program.
|
||||
|
||||
"Distributor" means a Recipient that distributes the Program,
|
||||
modifications to the Program, or any part thereof.
|
||||
|
||||
"Licensed Patents" mean patent claims licensable by a Contributor
|
||||
which are necessarily infringed by the use or sale of its Contribution
|
||||
alone or when combined with the Program.
|
||||
|
||||
"Original Program" means the original version of the software
|
||||
accompanying this Agreement as released by LUCENT, including source
|
||||
code, object code and documentation, if any.
|
||||
|
||||
"Program" means the Original Program and Contributions or any part
|
||||
thereof
|
||||
|
||||
"Recipient" means anyone who receives the Program under this
|
||||
Agreement, including all Contributors.
|
||||
|
||||
2. GRANT OF RIGHTS
|
||||
|
||||
a. Subject to the terms of this Agreement, each Contributor hereby
|
||||
grants Recipient a non-exclusive, worldwide, royalty-free copyright
|
||||
license to reproduce, prepare derivative works of, publicly display,
|
||||
publicly perform, distribute and sublicense the Contribution of such
|
||||
Contributor, if any, and such derivative works, in source code and
|
||||
object code form.
|
||||
|
||||
b. Subject to the terms of this Agreement, each Contributor hereby
|
||||
grants Recipient a non-exclusive, worldwide, royalty-free patent
|
||||
license under Licensed Patents to make, use, sell, offer to sell,
|
||||
import and otherwise transfer the Contribution of such Contributor, if
|
||||
any, in source code and object code form. The patent license granted
|
||||
by a Contributor shall also apply to the combination of the
|
||||
Contribution of that Contributor and the Program if, at the time the
|
||||
Contribution is added by the Contributor, such addition of the
|
||||
Contribution causes such combination to be covered by the Licensed
|
||||
Patents. The patent license granted by a Contributor shall not apply
|
||||
to (i) any other combinations which include the Contribution, nor to
|
||||
(ii) Contributions of other Contributors. No hardware per se is
|
||||
licensed hereunder.
|
||||
|
||||
c. Recipient understands that although each Contributor grants the
|
||||
licenses to its Contributions set forth herein, no assurances are
|
||||
provided by any Contributor that the Program does not infringe the
|
||||
patent or other intellectual property rights of any other entity. Each
|
||||
Contributor disclaims any liability to Recipient for claims brought by
|
||||
any other entity based on infringement of intellectual property rights
|
||||
or otherwise. As a condition to exercising the rights and licenses
|
||||
granted hereunder, each Recipient hereby assumes sole responsibility
|
||||
to secure any other intellectual property rights needed, if any. For
|
||||
example, if a third party patent license is required to allow
|
||||
Recipient to distribute the Program, it is Recipient's responsibility
|
||||
to acquire that license before distributing the Program.
|
||||
|
||||
d. Each Contributor represents that to its knowledge it has sufficient
|
||||
copyright rights in its Contribution, if any, to grant the copyright
|
||||
license set forth in this Agreement.
|
||||
|
||||
3. REQUIREMENTS
|
||||
|
||||
A. Distributor may choose to distribute the Program in any form under
|
||||
this Agreement or under its own license agreement, provided that:
|
||||
|
||||
a. it complies with the terms and conditions of this Agreement;
|
||||
|
||||
b. if the Program is distributed in source code or other tangible
|
||||
form, a copy of this Agreement or Distributor's own license agreement
|
||||
is included with each copy of the Program; and
|
||||
|
||||
c. if distributed under Distributor's own license agreement, such
|
||||
license agreement:
|
||||
|
||||
i. effectively disclaims on behalf of all Contributors all warranties
|
||||
and conditions, express and implied, including warranties or
|
||||
conditions of title and non-infringement, and implied warranties or
|
||||
conditions of merchantability and fitness for a particular purpose;
|
||||
ii. effectively excludes on behalf of all Contributors all liability
|
||||
for damages, including direct, indirect, special, incidental and
|
||||
consequential damages, such as lost profits; and
|
||||
iii. states that any provisions which differ from this Agreement are
|
||||
offered by that Contributor alone and not by any other party.
|
||||
|
||||
B. Each Distributor must include the following in a conspicuous
|
||||
location in the Program:
|
||||
|
||||
Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights
|
||||
Reserved.
|
||||
|
||||
C. In addition, each Contributor must identify itself as the
|
||||
originator of its Contribution in a manner that reasonably allows
|
||||
subsequent Recipients to identify the originator of the Contribution.
|
||||
Also, each Contributor must agree that the additions and/or changes
|
||||
are intended to be a Contribution. Once a Contribution is contributed,
|
||||
it may not thereafter be revoked.
|
||||
|
||||
4. COMMERCIAL DISTRIBUTION
|
||||
|
||||
Commercial distributors of software may accept certain
|
||||
responsibilities with respect to end users, business partners and the
|
||||
like. While this license is intended to facilitate the commercial use
|
||||
of the Program, the Distributor who includes the Program in a
|
||||
commercial product offering should do so in a manner which does not
|
||||
create potential liability for Contributors. Therefore, if a
|
||||
Distributor includes the Program in a commercial product offering,
|
||||
such Distributor ("Commercial Distributor") hereby agrees to defend
|
||||
and indemnify every Contributor ("Indemnified Contributor") against
|
||||
any losses, damages and costs (collectively"Losses") arising from
|
||||
claims, lawsuits and other legal actions brought by a third party
|
||||
against the Indemnified Contributor to the extent caused by the acts
|
||||
or omissions of such Commercial Distributor in connection with its
|
||||
distribution of the Program in a commercial product offering. The
|
||||
obligations in this section do not apply to any claims or Losses
|
||||
relating to any actual or alleged intellectual property infringement.
|
||||
In order to qualify, an Indemnified Contributor must: a) promptly
|
||||
notify the Commercial Distributor in writing of such claim, and b)
|
||||
allow the Commercial Distributor to control, and cooperate with the
|
||||
Commercial Distributor in, the defense and any related settlement
|
||||
negotiations. The Indemnified Contributor may participate in any such
|
||||
claim at its own expense.
|
||||
|
||||
For example, a Distributor might include the Program in a commercial
|
||||
product offering, Product X. That Distributor is then a Commercial
|
||||
Distributor. If that Commercial Distributor then makes performance
|
||||
claims, or offers warranties related to Product X, those performance
|
||||
claims and warranties are such Commercial Distributor's responsibility
|
||||
alone. Under this section, the Commercial Distributor would have to
|
||||
defend claims against the Contributors related to those performance
|
||||
claims and warranties, and if a court requires any Contributor to pay
|
||||
any damages as a result, the Commercial Distributor must pay those
|
||||
damages.
|
||||
|
||||
5. NO WARRANTY
|
||||
|
||||
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
|
||||
PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||
WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
|
||||
OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
|
||||
responsible for determining the appropriateness of using and
|
||||
distributing the Program and assumes all risks associated with its
|
||||
exercise of rights under this Agreement, including but not limited to
|
||||
the risks and costs of program errors, compliance with applicable
|
||||
laws, damage to or loss of data, programs or equipment, and
|
||||
unavailability or interruption of operations.
|
||||
|
||||
6. DISCLAIMER OF LIABILITY
|
||||
|
||||
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
|
||||
ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
|
||||
WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
|
||||
DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
|
||||
HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
7. EXPORT CONTROL
|
||||
|
||||
Recipient agrees that Recipient alone is responsible for compliance
|
||||
with the United States export administration regulations (and the
|
||||
export control laws and regulation of any other countries).
|
||||
|
||||
8. GENERAL
|
||||
|
||||
If any provision of this Agreement is invalid or unenforceable under
|
||||
applicable law, it shall not affect the validity or enforceability of
|
||||
the remainder of the terms of this Agreement, and without further
|
||||
action by the parties hereto, such provision shall be reformed to the
|
||||
minimum extent necessary to make such provision valid and enforceable.
|
||||
|
||||
If Recipient institutes patent litigation against a Contributor with
|
||||
respect to a patent applicable to software (including a cross-claim or
|
||||
counterclaim in a lawsuit), then any patent licenses granted by that
|
||||
Contributor to such Recipient under this Agreement shall terminate as
|
||||
of the date such litigation is filed. In addition, if Recipient
|
||||
institutes patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Program
|
||||
itself (excluding combinations of the Program with other software or
|
||||
hardware) infringes such Recipient's patent(s), then such Recipient's
|
||||
rights granted under Section 2(b) shall terminate as of the date such
|
||||
litigation is filed.
|
||||
|
||||
All Recipient's rights under this Agreement shall terminate if it
|
||||
fails to comply with any of the material terms or conditions of this
|
||||
Agreement and does not cure such failure in a reasonable period of
|
||||
time after becoming aware of such noncompliance. If all Recipient's
|
||||
rights under this Agreement terminate, Recipient agrees to cease use
|
||||
and distribution of the Program as soon as reasonably practicable.
|
||||
However, Recipient's obligations under this Agreement and any licenses
|
||||
granted by Recipient relating to the Program shall continue and
|
||||
survive.
|
||||
|
||||
LUCENT may publish new versions (including revisions) of this
|
||||
Agreement from time to time. Each new version of the Agreement will be
|
||||
given a distinguishing version number. The Program (including
|
||||
Contributions) may always be distributed subject to the version of the
|
||||
Agreement under which it was received. In addition, after a new
|
||||
version of the Agreement is published, Contributor may elect to
|
||||
distribute the Program (including its Contributions) under the new
|
||||
version. No one other than LUCENT has the right to modify this
|
||||
Agreement. Except as expressly stated in Sections 2(a) and 2(b) above,
|
||||
Recipient receives no rights or licenses to the intellectual property
|
||||
of any Contributor under this Agreement, whether expressly, by
|
||||
implication, estoppel or otherwise. All rights in the Program not
|
||||
expressly granted under this Agreement are reserved.
|
||||
|
||||
This Agreement is governed by the laws of the State of New York and
|
||||
the intellectual property laws of the United States of America. No
|
||||
party to this Agreement will bring a legal action under this Agreement
|
||||
more than one year after the cause of action arose. Each party waives
|
||||
its rights to a jury trial in any resulting litigation.
|
||||
|
35
Makefile
Normal file
35
Makefile
Normal file
@@ -0,0 +1,35 @@
|
||||
# 9base - awk basename cat cleanname echo grep rc sed seq sleep sort tee
|
||||
# test touch tr uniq from Plan 9
|
||||
|
||||
include config.mk
|
||||
|
||||
SUBDIRS = lib9 yacc awk basename bc cat cleanname date echo grep rc \
|
||||
sed seq sleep sort tee test touch tr uniq
|
||||
|
||||
all:
|
||||
@echo 9base build options:
|
||||
@echo "CFLAGS = ${CFLAGS}"
|
||||
@echo "LDFLAGS = ${LDFLAGS}"
|
||||
@echo "CC = ${CC}"
|
||||
@chmod 755 yacc/9yacc
|
||||
@for i in ${SUBDIRS}; do cd $$i; ${MAKE} || exit; cd ..; done;
|
||||
|
||||
clean:
|
||||
@for i in ${SUBDIRS}; do cd $$i; ${MAKE} clean || exit; cd ..; done
|
||||
@echo cleaned 9base
|
||||
|
||||
install: all
|
||||
@for i in ${SUBDIRS}; do cd $$i; ${MAKE} install || exit; cd ..; done
|
||||
@echo installed 9base to ${DESTDIR}${PREFIX}
|
||||
|
||||
uninstall:
|
||||
@for i in ${SUBDIRS}; do cd $$i; ${MAKE} uninstall || exit; cd ..; done
|
||||
@echo uninstalled 9base
|
||||
|
||||
dist: clean
|
||||
@mkdir -p 9base-${VERSION}
|
||||
@cp -R Makefile README LICENSE config.mk ${SUBDIRS} 9base-${VERSION}
|
||||
@tar -cf 9base-${VERSION}.tar 9base-${VERSION}
|
||||
@gzip 9base-${VERSION}.tar
|
||||
@rm -rf 9base-${VERSION}
|
||||
@echo created distribution 9base-${VERSION}.tar.gz
|
30
README
Normal file
30
README
Normal file
@@ -0,0 +1,30 @@
|
||||
Abstract
|
||||
--------
|
||||
This is a port of various original Plan 9 tools for Unix, based on
|
||||
plan9port [1], mk-with-libs.tgz [2], and wmii [3]. See the LICENSE
|
||||
file for license details.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
In order to build 9base you need yacc or bison.
|
||||
|
||||
Installation
|
||||
------------
|
||||
Edit config.mk to match your local setup and execute 'make install'
|
||||
(if necessary as root). By default, 9rc is installed into its own
|
||||
hierarchy, /usr/local/9. This is done to avoid conflicts with the
|
||||
standard tools of your system. You can then put /usr/local/9/bin at
|
||||
the end of your PATH.
|
||||
|
||||
Credits
|
||||
-------
|
||||
Many thanks go to Lucent, the Bell Labs which developed this fine
|
||||
stuff and to Russ Cox for his plan9port.
|
||||
|
||||
References
|
||||
----------
|
||||
[1] http://swtch.com/plan9port/
|
||||
[2] http://swtch.com/plan9port/unix/
|
||||
[3] http://wmii.de
|
||||
|
||||
--Anselm R. Garbe
|
47
awk/Makefile
Normal file
47
awk/Makefile
Normal file
@@ -0,0 +1,47 @@
|
||||
# awk - awk unix port from plan9
|
||||
# Depends on ../lib9
|
||||
|
||||
include ../config.mk
|
||||
|
||||
TARG = awk
|
||||
|
||||
OFILES = re.o lex.o main.o parse.o proctab.o tran.o lib.o run.o y.tab.o
|
||||
|
||||
YFILES = awkgram.y
|
||||
|
||||
MANFILES = awk.1
|
||||
|
||||
all:
|
||||
@if [ ! -f y.tab.c ]; then \
|
||||
${MAKE} -f Makefile depend;\
|
||||
fi
|
||||
@${MAKE} -f Makefile ${TARG}
|
||||
@echo built ${TARG}
|
||||
|
||||
|
||||
depend:
|
||||
@echo YACC ${YFILES}
|
||||
@${YACC} -d ${YFILES}
|
||||
|
||||
install: ${TARG}
|
||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
@cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
|
||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
@cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
|
||||
@chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
|
||||
|
||||
uninstall:
|
||||
rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
|
||||
|
||||
.c.o:
|
||||
@echo CC $*.c
|
||||
@${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
|
||||
|
||||
clean:
|
||||
rm -f ${OFILES} ${TARG} y.tab.c y.tab.h
|
||||
|
||||
${TARG}: ${OFILES}
|
||||
@echo LD ${TARG}
|
||||
@${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -lm -L${PREFIX}/lib -L../lib9 -l9
|
527
awk/awk.1
Normal file
527
awk/awk.1
Normal file
@@ -0,0 +1,527 @@
|
||||
.TH AWK 1
|
||||
.SH NAME
|
||||
awk \- pattern-directed scanning and processing language
|
||||
.SH SYNOPSIS
|
||||
.B awk
|
||||
[
|
||||
.BI -F fs
|
||||
]
|
||||
[
|
||||
.BI -v
|
||||
.I var=value
|
||||
]
|
||||
[
|
||||
.BI -mr n
|
||||
]
|
||||
[
|
||||
.BI -mf n
|
||||
]
|
||||
[
|
||||
.B -f
|
||||
.I prog
|
||||
[
|
||||
.I prog
|
||||
]
|
||||
[
|
||||
.I file ...
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Awk
|
||||
scans each input
|
||||
.I file
|
||||
for lines that match any of a set of patterns specified literally in
|
||||
.IR prog
|
||||
or in one or more files
|
||||
specified as
|
||||
.B -f
|
||||
.IR file .
|
||||
With each pattern
|
||||
there can be an associated action that will be performed
|
||||
when a line of a
|
||||
.I file
|
||||
matches the pattern.
|
||||
Each line is matched against the
|
||||
pattern portion of every pattern-action statement;
|
||||
the associated action is performed for each matched pattern.
|
||||
The file name
|
||||
.L -
|
||||
means the standard input.
|
||||
Any
|
||||
.IR file
|
||||
of the form
|
||||
.I var=value
|
||||
is treated as an assignment, not a file name,
|
||||
and is executed at the time it would have been opened if it were a file name.
|
||||
The option
|
||||
.B -v
|
||||
followed by
|
||||
.I var=value
|
||||
is an assignment to be done before
|
||||
.I prog
|
||||
is executed;
|
||||
any number of
|
||||
.B -v
|
||||
options may be present.
|
||||
.B \-F
|
||||
.IR fs
|
||||
option defines the input field separator to be the regular expression
|
||||
.IR fs .
|
||||
.PP
|
||||
An input line is normally made up of fields separated by white space,
|
||||
or by regular expression
|
||||
.BR FS .
|
||||
The fields are denoted
|
||||
.BR $1 ,
|
||||
.BR $2 ,
|
||||
\&..., while
|
||||
.B $0
|
||||
refers to the entire line.
|
||||
If
|
||||
.BR FS
|
||||
is null, the input line is split into one field per character.
|
||||
.PP
|
||||
To compensate for inadequate implementation of storage management,
|
||||
the
|
||||
.B \-mr
|
||||
option can be used to set the maximum size of the input record,
|
||||
and the
|
||||
.B \-mf
|
||||
option to set the maximum number of fields.
|
||||
.PP
|
||||
A pattern-action statement has the form
|
||||
.IP
|
||||
.IB pattern " { " action " }
|
||||
.PP
|
||||
A missing
|
||||
.BI { " action " }
|
||||
means print the line;
|
||||
a missing pattern always matches.
|
||||
Pattern-action statements are separated by newlines or semicolons.
|
||||
.PP
|
||||
An action is a sequence of statements.
|
||||
A statement can be one of the following:
|
||||
.PP
|
||||
.EX
|
||||
.ta \w'\fLdelete array[expression]'u
|
||||
if(\fI expression \fP)\fI statement \fP\fR[ \fPelse\fI statement \fP\fR]\fP
|
||||
while(\fI expression \fP)\fI statement\fP
|
||||
for(\fI expression \fP;\fI expression \fP;\fI expression \fP)\fI statement\fP
|
||||
for(\fI var \fPin\fI array \fP)\fI statement\fP
|
||||
do\fI statement \fPwhile(\fI expression \fP)
|
||||
break
|
||||
continue
|
||||
{\fR [\fP\fI statement ... \fP\fR] \fP}
|
||||
\fIexpression\fP #\fR commonly\fP\fI var = expression\fP
|
||||
print\fR [ \fP\fIexpression-list \fP\fR] \fP\fR[ \fP>\fI expression \fP\fR]\fP
|
||||
printf\fI format \fP\fR[ \fP,\fI expression-list \fP\fR] \fP\fR[ \fP>\fI expression \fP\fR]\fP
|
||||
return\fR [ \fP\fIexpression \fP\fR]\fP
|
||||
next #\fR skip remaining patterns on this input line\fP
|
||||
nextfile #\fR skip rest of this file, open next, start at top\fP
|
||||
delete\fI array\fP[\fI expression \fP] #\fR delete an array element\fP
|
||||
delete\fI array\fP #\fR delete all elements of array\fP
|
||||
exit\fR [ \fP\fIexpression \fP\fR]\fP #\fR exit immediately; status is \fP\fIexpression\fP
|
||||
.EE
|
||||
.DT
|
||||
.PP
|
||||
Statements are terminated by
|
||||
semicolons, newlines or right braces.
|
||||
An empty
|
||||
.I expression-list
|
||||
stands for
|
||||
.BR $0 .
|
||||
String constants are quoted \&\fL"\ "\fR,
|
||||
with the usual C escapes recognized within.
|
||||
Expressions take on string or numeric values as appropriate,
|
||||
and are built using the operators
|
||||
.B + \- * / % ^
|
||||
(exponentiation), and concatenation (indicated by white space).
|
||||
The operators
|
||||
.B
|
||||
! ++ \-\- += \-= *= /= %= ^= > >= < <= == != ?:
|
||||
are also available in expressions.
|
||||
Variables may be scalars, array elements
|
||||
(denoted
|
||||
.IB x [ i ] )
|
||||
or fields.
|
||||
Variables are initialized to the null string.
|
||||
Array subscripts may be any string,
|
||||
not necessarily numeric;
|
||||
this allows for a form of associative memory.
|
||||
Multiple subscripts such as
|
||||
.B [i,j,k]
|
||||
are permitted; the constituents are concatenated,
|
||||
separated by the value of
|
||||
.BR SUBSEP .
|
||||
.PP
|
||||
The
|
||||
.B print
|
||||
statement prints its arguments on the standard output
|
||||
(or on a file if
|
||||
.BI > file
|
||||
or
|
||||
.BI >> file
|
||||
is present or on a pipe if
|
||||
.BI | cmd
|
||||
is present), separated by the current output field separator,
|
||||
and terminated by the output record separator.
|
||||
.I file
|
||||
and
|
||||
.I cmd
|
||||
may be literal names or parenthesized expressions;
|
||||
identical string values in different statements denote
|
||||
the same open file.
|
||||
The
|
||||
.B printf
|
||||
statement formats its expression list according to the format
|
||||
(see
|
||||
.IR fprintf (2)) .
|
||||
The built-in function
|
||||
.BI close( expr )
|
||||
closes the file or pipe
|
||||
.IR expr .
|
||||
The built-in function
|
||||
.BI fflush( expr )
|
||||
flushes any buffered output for the file or pipe
|
||||
.IR expr .
|
||||
.PP
|
||||
The mathematical functions
|
||||
.BR exp ,
|
||||
.BR log ,
|
||||
.BR sqrt ,
|
||||
.BR sin ,
|
||||
.BR cos ,
|
||||
and
|
||||
.BR atan2
|
||||
are built in.
|
||||
Other built-in functions:
|
||||
.TF length
|
||||
.TP
|
||||
.B length
|
||||
the length of its argument
|
||||
taken as a string,
|
||||
or of
|
||||
.B $0
|
||||
if no argument.
|
||||
.TP
|
||||
.B rand
|
||||
random number on (0,1)
|
||||
.TP
|
||||
.B srand
|
||||
sets seed for
|
||||
.B rand
|
||||
and returns the previous seed.
|
||||
.TP
|
||||
.B int
|
||||
truncates to an integer value
|
||||
.TP
|
||||
.B utf
|
||||
converts its numerical argument, a character number, to a
|
||||
.SM UTF
|
||||
string
|
||||
.TP
|
||||
.BI substr( s , " m" , " n\fL)
|
||||
the
|
||||
.IR n -character
|
||||
substring of
|
||||
.I s
|
||||
that begins at position
|
||||
.IR m
|
||||
counted from 1.
|
||||
.TP
|
||||
.BI index( s , " t" )
|
||||
the position in
|
||||
.I s
|
||||
where the string
|
||||
.I t
|
||||
occurs, or 0 if it does not.
|
||||
.TP
|
||||
.BI match( s , " r" )
|
||||
the position in
|
||||
.I s
|
||||
where the regular expression
|
||||
.I r
|
||||
occurs, or 0 if it does not.
|
||||
The variables
|
||||
.B RSTART
|
||||
and
|
||||
.B RLENGTH
|
||||
are set to the position and length of the matched string.
|
||||
.TP
|
||||
.BI split( s , " a" , " fs\fL)
|
||||
splits the string
|
||||
.I s
|
||||
into array elements
|
||||
.IB a [1]\f1,
|
||||
.IB a [2]\f1,
|
||||
\&...,
|
||||
.IB a [ n ]\f1,
|
||||
and returns
|
||||
.IR n .
|
||||
The separation is done with the regular expression
|
||||
.I fs
|
||||
or with the field separator
|
||||
.B FS
|
||||
if
|
||||
.I fs
|
||||
is not given.
|
||||
An empty string as field separator splits the string
|
||||
into one array element per character.
|
||||
.TP
|
||||
.BI sub( r , " t" , " s\fL)
|
||||
substitutes
|
||||
.I t
|
||||
for the first occurrence of the regular expression
|
||||
.I r
|
||||
in the string
|
||||
.IR s .
|
||||
If
|
||||
.I s
|
||||
is not given,
|
||||
.B $0
|
||||
is used.
|
||||
.TP
|
||||
.B gsub
|
||||
same as
|
||||
.B sub
|
||||
except that all occurrences of the regular expression
|
||||
are replaced;
|
||||
.B sub
|
||||
and
|
||||
.B gsub
|
||||
return the number of replacements.
|
||||
.TP
|
||||
.BI sprintf( fmt , " expr" , " ...\fL)
|
||||
the string resulting from formatting
|
||||
.I expr ...
|
||||
according to the
|
||||
.I printf
|
||||
format
|
||||
.I fmt
|
||||
.TP
|
||||
.BI system( cmd )
|
||||
executes
|
||||
.I cmd
|
||||
and returns its exit status
|
||||
.TP
|
||||
.BI tolower( str )
|
||||
returns a copy of
|
||||
.I str
|
||||
with all upper-case characters translated to their
|
||||
corresponding lower-case equivalents.
|
||||
.TP
|
||||
.BI toupper( str )
|
||||
returns a copy of
|
||||
.I str
|
||||
with all lower-case characters translated to their
|
||||
corresponding upper-case equivalents.
|
||||
.PD
|
||||
.PP
|
||||
The ``function''
|
||||
.B getline
|
||||
sets
|
||||
.B $0
|
||||
to the next input record from the current input file;
|
||||
.B getline
|
||||
.BI < file
|
||||
sets
|
||||
.B $0
|
||||
to the next record from
|
||||
.IR file .
|
||||
.B getline
|
||||
.I x
|
||||
sets variable
|
||||
.I x
|
||||
instead.
|
||||
Finally,
|
||||
.IB cmd " | getline
|
||||
pipes the output of
|
||||
.I cmd
|
||||
into
|
||||
.BR getline ;
|
||||
each call of
|
||||
.B getline
|
||||
returns the next line of output from
|
||||
.IR cmd .
|
||||
In all cases,
|
||||
.B getline
|
||||
returns 1 for a successful input,
|
||||
0 for end of file, and \-1 for an error.
|
||||
.PP
|
||||
Patterns are arbitrary Boolean combinations
|
||||
(with
|
||||
.BR "! || &&" )
|
||||
of regular expressions and
|
||||
relational expressions.
|
||||
Regular expressions are as in
|
||||
.IR regexp (6).
|
||||
Isolated regular expressions
|
||||
in a pattern apply to the entire line.
|
||||
Regular expressions may also occur in
|
||||
relational expressions, using the operators
|
||||
.BR ~
|
||||
and
|
||||
.BR !~ .
|
||||
.BI / re /
|
||||
is a constant regular expression;
|
||||
any string (constant or variable) may be used
|
||||
as a regular expression, except in the position of an isolated regular expression
|
||||
in a pattern.
|
||||
.PP
|
||||
A pattern may consist of two patterns separated by a comma;
|
||||
in this case, the action is performed for all lines
|
||||
from an occurrence of the first pattern
|
||||
though an occurrence of the second.
|
||||
.PP
|
||||
A relational expression is one of the following:
|
||||
.IP
|
||||
.I expression matchop regular-expression
|
||||
.br
|
||||
.I expression relop expression
|
||||
.br
|
||||
.IB expression " in " array-name
|
||||
.br
|
||||
.BI ( expr , expr,... ") in " array-name
|
||||
.PP
|
||||
where a
|
||||
.I relop
|
||||
is any of the six relational operators in C,
|
||||
and a
|
||||
.I matchop
|
||||
is either
|
||||
.B ~
|
||||
(matches)
|
||||
or
|
||||
.B !~
|
||||
(does not match).
|
||||
A conditional is an arithmetic expression,
|
||||
a relational expression,
|
||||
or a Boolean combination
|
||||
of these.
|
||||
.PP
|
||||
The special patterns
|
||||
.B BEGIN
|
||||
and
|
||||
.B END
|
||||
may be used to capture control before the first input line is read
|
||||
and after the last.
|
||||
.B BEGIN
|
||||
and
|
||||
.B END
|
||||
do not combine with other patterns.
|
||||
.PP
|
||||
Variable names with special meanings:
|
||||
.TF FILENAME
|
||||
.TP
|
||||
.B CONVFMT
|
||||
conversion format used when converting numbers
|
||||
(default
|
||||
.BR "%.6g" )
|
||||
.TP
|
||||
.B FS
|
||||
regular expression used to separate fields; also settable
|
||||
by option
|
||||
.BI \-F fs\f1.
|
||||
.TP
|
||||
.BR NF
|
||||
number of fields in the current record
|
||||
.TP
|
||||
.B NR
|
||||
ordinal number of the current record
|
||||
.TP
|
||||
.B FNR
|
||||
ordinal number of the current record in the current file
|
||||
.TP
|
||||
.B FILENAME
|
||||
the name of the current input file
|
||||
.TP
|
||||
.B RS
|
||||
input record separator (default newline)
|
||||
.TP
|
||||
.B OFS
|
||||
output field separator (default blank)
|
||||
.TP
|
||||
.B ORS
|
||||
output record separator (default newline)
|
||||
.TP
|
||||
.B OFMT
|
||||
output format for numbers (default
|
||||
.BR "%.6g" )
|
||||
.TP
|
||||
.B SUBSEP
|
||||
separates multiple subscripts (default 034)
|
||||
.TP
|
||||
.B ARGC
|
||||
argument count, assignable
|
||||
.TP
|
||||
.B ARGV
|
||||
argument array, assignable;
|
||||
non-null members are taken as file names
|
||||
.TP
|
||||
.B ENVIRON
|
||||
array of environment variables; subscripts are names.
|
||||
.PD
|
||||
.PP
|
||||
Functions may be defined (at the position of a pattern-action statement) thus:
|
||||
.IP
|
||||
.L
|
||||
function foo(a, b, c) { ...; return x }
|
||||
.PP
|
||||
Parameters are passed by value if scalar and by reference if array name;
|
||||
functions may be called recursively.
|
||||
Parameters are local to the function; all other variables are global.
|
||||
Thus local variables may be created by providing excess parameters in
|
||||
the function definition.
|
||||
.SH EXAMPLES
|
||||
.TP
|
||||
.L
|
||||
length($0) > 72
|
||||
Print lines longer than 72 characters.
|
||||
.TP
|
||||
.L
|
||||
{ print $2, $1 }
|
||||
Print first two fields in opposite order.
|
||||
.PP
|
||||
.EX
|
||||
BEGIN { FS = ",[ \et]*|[ \et]+" }
|
||||
{ print $2, $1 }
|
||||
.EE
|
||||
.ns
|
||||
.IP
|
||||
Same, with input fields separated by comma and/or blanks and tabs.
|
||||
.PP
|
||||
.EX
|
||||
{ s += $1 }
|
||||
END { print "sum is", s, " average is", s/NR }
|
||||
.EE
|
||||
.ns
|
||||
.IP
|
||||
Add up first column, print sum and average.
|
||||
.TP
|
||||
.L
|
||||
/start/, /stop/
|
||||
Print all lines between start/stop pairs.
|
||||
.PP
|
||||
.EX
|
||||
BEGIN { # Simulate echo(1)
|
||||
for (i = 1; i < ARGC; i++) printf "%s ", ARGV[i]
|
||||
printf "\en"
|
||||
exit }
|
||||
.EE
|
||||
.SH SOURCE
|
||||
.B /sys/src/cmd/awk
|
||||
.SH SEE ALSO
|
||||
.IR sed (1),
|
||||
.IR regexp (6),
|
||||
.br
|
||||
A. V. Aho, B. W. Kernighan, P. J. Weinberger,
|
||||
.I
|
||||
The AWK Programming Language,
|
||||
Addison-Wesley, 1988. ISBN 0-201-07981-X
|
||||
.SH BUGS
|
||||
There are no explicit conversions between numbers and strings.
|
||||
To force an expression to be treated as a number add 0 to it;
|
||||
to force it to be treated as a string concatenate
|
||||
\&\fL""\fP to it.
|
||||
.br
|
||||
The scope rules for variables in functions are a botch;
|
||||
the syntax is worse.
|
184
awk/awk.h
Normal file
184
awk/awk.h
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
Copyright (c) Lucent Technologies 1997
|
||||
All Rights Reserved
|
||||
|
||||
*/
|
||||
|
||||
typedef double Awkfloat;
|
||||
|
||||
/* unsigned char is more trouble than it's worth */
|
||||
|
||||
typedef unsigned char uschar;
|
||||
|
||||
#define xfree(a) { if ((a) != NULL) { free((char *) a); a = NULL; } }
|
||||
|
||||
#define DEBUG
|
||||
#ifdef DEBUG
|
||||
/* uses have to be doubly parenthesized */
|
||||
# define dprintf(x) if (dbg) printf x
|
||||
#else
|
||||
# define dprintf(x)
|
||||
#endif
|
||||
|
||||
extern char errbuf[];
|
||||
|
||||
extern int compile_time; /* 1 if compiling, 0 if running */
|
||||
extern int safe; /* 0 => unsafe, 1 => safe */
|
||||
|
||||
#define RECSIZE (8 * 1024) /* sets limit on records, fields, etc., etc. */
|
||||
extern int recsize; /* size of current record, orig RECSIZE */
|
||||
|
||||
extern char **FS;
|
||||
extern char **RS;
|
||||
extern char **ORS;
|
||||
extern char **OFS;
|
||||
extern char **OFMT;
|
||||
extern Awkfloat *NR;
|
||||
extern Awkfloat *FNR;
|
||||
extern Awkfloat *NF;
|
||||
extern char **FILENAME;
|
||||
extern char **SUBSEP;
|
||||
extern Awkfloat *RSTART;
|
||||
extern Awkfloat *RLENGTH;
|
||||
|
||||
extern char *record; /* points to $0 */
|
||||
extern int lineno; /* line number in awk program */
|
||||
extern int errorflag; /* 1 if error has occurred */
|
||||
extern int donefld; /* 1 if record broken into fields */
|
||||
extern int donerec; /* 1 if record is valid (no fld has changed */
|
||||
extern char inputFS[]; /* FS at time of input, for field splitting */
|
||||
|
||||
extern int dbg;
|
||||
|
||||
extern char *patbeg; /* beginning of pattern matched */
|
||||
extern int patlen; /* length of pattern matched. set in b.c */
|
||||
|
||||
/* Cell: all information about a variable or constant */
|
||||
|
||||
typedef struct Cell {
|
||||
uschar ctype; /* OCELL, OBOOL, OJUMP, etc. */
|
||||
uschar csub; /* CCON, CTEMP, CFLD, etc. */
|
||||
char *nval; /* name, for variables only */
|
||||
char *sval; /* string value */
|
||||
Awkfloat fval; /* value as number */
|
||||
int tval; /* type info: STR|NUM|ARR|FCN|FLD|CON|DONTFREE */
|
||||
struct Cell *cnext; /* ptr to next if chained */
|
||||
} Cell;
|
||||
|
||||
typedef struct Array { /* symbol table array */
|
||||
int nelem; /* elements in table right now */
|
||||
int size; /* size of tab */
|
||||
Cell **tab; /* hash table pointers */
|
||||
} Array;
|
||||
|
||||
#define NSYMTAB 50 /* initial size of a symbol table */
|
||||
extern Array *symtab;
|
||||
|
||||
extern Cell *nrloc; /* NR */
|
||||
extern Cell *fnrloc; /* FNR */
|
||||
extern Cell *nfloc; /* NF */
|
||||
extern Cell *rstartloc; /* RSTART */
|
||||
extern Cell *rlengthloc; /* RLENGTH */
|
||||
|
||||
/* Cell.tval values: */
|
||||
#define NUM 01 /* number value is valid */
|
||||
#define STR 02 /* string value is valid */
|
||||
#define DONTFREE 04 /* string space is not freeable */
|
||||
#define CON 010 /* this is a constant */
|
||||
#define ARR 020 /* this is an array */
|
||||
#define FCN 040 /* this is a function name */
|
||||
#define FLD 0100 /* this is a field $1, $2, ... */
|
||||
#define REC 0200 /* this is $0 */
|
||||
|
||||
|
||||
/* function types */
|
||||
#define FLENGTH 1
|
||||
#define FSQRT 2
|
||||
#define FEXP 3
|
||||
#define FLOG 4
|
||||
#define FINT 5
|
||||
#define FSYSTEM 6
|
||||
#define FRAND 7
|
||||
#define FSRAND 8
|
||||
#define FSIN 9
|
||||
#define FCOS 10
|
||||
#define FATAN 11
|
||||
#define FTOUPPER 12
|
||||
#define FTOLOWER 13
|
||||
#define FFLUSH 14
|
||||
#define FUTF 15
|
||||
|
||||
/* Node: parse tree is made of nodes, with Cell's at bottom */
|
||||
|
||||
typedef struct Node {
|
||||
int ntype;
|
||||
struct Node *nnext;
|
||||
int lineno;
|
||||
int nobj;
|
||||
struct Node *narg[1]; /* variable: actual size set by calling malloc */
|
||||
} Node;
|
||||
|
||||
#define NIL ((Node *) 0)
|
||||
|
||||
extern Node *winner;
|
||||
extern Node *nullstat;
|
||||
extern Node *nullnode;
|
||||
|
||||
/* ctypes */
|
||||
#define OCELL 1
|
||||
#define OBOOL 2
|
||||
#define OJUMP 3
|
||||
|
||||
/* Cell subtypes: csub */
|
||||
#define CFREE 7
|
||||
#define CCOPY 6
|
||||
#define CCON 5
|
||||
#define CTEMP 4
|
||||
#define CNAME 3
|
||||
#define CVAR 2
|
||||
#define CFLD 1
|
||||
#define CUNK 0
|
||||
|
||||
/* bool subtypes */
|
||||
#define BTRUE 11
|
||||
#define BFALSE 12
|
||||
|
||||
/* jump subtypes */
|
||||
#define JEXIT 21
|
||||
#define JNEXT 22
|
||||
#define JBREAK 23
|
||||
#define JCONT 24
|
||||
#define JRET 25
|
||||
#define JNEXTFILE 26
|
||||
|
||||
/* node types */
|
||||
#define NVALUE 1
|
||||
#define NSTAT 2
|
||||
#define NEXPR 3
|
||||
|
||||
|
||||
extern int pairstack[], paircnt;
|
||||
|
||||
#define notlegal(n) (n <= FIRSTTOKEN || n >= LASTTOKEN || proctab[n-FIRSTTOKEN] == nullproc)
|
||||
#define isvalue(n) ((n)->ntype == NVALUE)
|
||||
#define isexpr(n) ((n)->ntype == NEXPR)
|
||||
#define isjump(n) ((n)->ctype == OJUMP)
|
||||
#define isexit(n) ((n)->csub == JEXIT)
|
||||
#define isbreak(n) ((n)->csub == JBREAK)
|
||||
#define iscont(n) ((n)->csub == JCONT)
|
||||
#define isnext(n) ((n)->csub == JNEXT)
|
||||
#define isnextfile(n) ((n)->csub == JNEXTFILE)
|
||||
#define isret(n) ((n)->csub == JRET)
|
||||
#define isrec(n) ((n)->tval & REC)
|
||||
#define isfld(n) ((n)->tval & FLD)
|
||||
#define isstr(n) ((n)->tval & STR)
|
||||
#define isnum(n) ((n)->tval & NUM)
|
||||
#define isarr(n) ((n)->tval & ARR)
|
||||
#define isfcn(n) ((n)->tval & FCN)
|
||||
#define istrue(n) ((n)->csub == BTRUE)
|
||||
#define istemp(n) ((n)->csub == CTEMP)
|
||||
#define isargument(n) ((n)->nobj == ARG)
|
||||
/* #define freeable(p) (!((p)->tval & DONTFREE)) */
|
||||
#define freeable(p) ( ((p)->tval & (STR|DONTFREE)) == STR )
|
||||
|
||||
#include "proto.h"
|
488
awk/awkgram.y
Normal file
488
awk/awkgram.y
Normal file
@@ -0,0 +1,488 @@
|
||||
/****************************************************************
|
||||
Copyright (C) Lucent Technologies 1997
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name Lucent Technologies or any of
|
||||
its entities not be used in advertising or publicity pertaining
|
||||
to distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
****************************************************************/
|
||||
|
||||
%{
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "awk.h"
|
||||
|
||||
#define makedfa(a,b) compre(a)
|
||||
|
||||
void checkdup(Node *list, Cell *item);
|
||||
int yywrap(void) { return(1); }
|
||||
|
||||
Node *beginloc = 0;
|
||||
Node *endloc = 0;
|
||||
int infunc = 0; /* = 1 if in arglist or body of func */
|
||||
int inloop = 0; /* = 1 if in while, for, do */
|
||||
char *curfname = 0; /* current function name */
|
||||
Node *arglist = 0; /* list of args for current function */
|
||||
%}
|
||||
|
||||
%union {
|
||||
Node *p;
|
||||
Cell *cp;
|
||||
int i;
|
||||
char *s;
|
||||
}
|
||||
|
||||
%token <i> FIRSTTOKEN /* must be first */
|
||||
%token <p> PROGRAM PASTAT PASTAT2 XBEGIN XEND
|
||||
%token <i> NL ',' '{' '(' '|' ';' '/' ')' '}' '[' ']'
|
||||
%token <i> ARRAY
|
||||
%token <i> MATCH NOTMATCH MATCHOP
|
||||
%token <i> FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS
|
||||
%token <i> AND BOR APPEND EQ GE GT LE LT NE IN
|
||||
%token <i> ARG BLTIN BREAK CLOSE CONTINUE DELETE DO EXIT FOR FUNC
|
||||
%token <i> SUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NEXTFILE
|
||||
%token <i> ADD MINUS MULT DIVIDE MOD
|
||||
%token <i> ASSIGN ASGNOP ADDEQ SUBEQ MULTEQ DIVEQ MODEQ POWEQ
|
||||
%token <i> PRINT PRINTF SPRINTF
|
||||
%token <p> ELSE INTEST CONDEXPR
|
||||
%token <i> POSTINCR PREINCR POSTDECR PREDECR
|
||||
%token <cp> VAR IVAR VARNF CALL NUMBER STRING
|
||||
%token <s> REGEXPR
|
||||
|
||||
%type <p> pas pattern ppattern plist pplist patlist prarg term re
|
||||
%type <p> pa_pat pa_stat pa_stats
|
||||
%type <s> reg_expr
|
||||
%type <p> simple_stmt opt_simple_stmt stmt stmtlist
|
||||
%type <p> var varname funcname varlist
|
||||
%type <p> for if else while
|
||||
%type <i> do st
|
||||
%type <i> pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor
|
||||
%type <i> subop print
|
||||
|
||||
%right ASGNOP
|
||||
%right '?'
|
||||
%right ':'
|
||||
%left BOR
|
||||
%left AND
|
||||
%left GETLINE
|
||||
%nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|'
|
||||
%left ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC
|
||||
%left GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER
|
||||
%left PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR
|
||||
%left REGEXPR VAR VARNF IVAR WHILE '('
|
||||
%left CAT
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%left NOT UMINUS
|
||||
%right POWER
|
||||
%right DECR INCR
|
||||
%left INDIRECT
|
||||
%token LASTTOKEN /* must be last */
|
||||
|
||||
%%
|
||||
|
||||
program:
|
||||
pas { if (errorflag==0)
|
||||
winner = (Node *)stat3(PROGRAM, beginloc, $1, endloc); }
|
||||
| error { yyclearin; bracecheck(); SYNTAX("bailing out"); }
|
||||
;
|
||||
|
||||
and:
|
||||
AND | and NL
|
||||
;
|
||||
|
||||
bor:
|
||||
BOR | bor NL
|
||||
;
|
||||
|
||||
comma:
|
||||
',' | comma NL
|
||||
;
|
||||
|
||||
do:
|
||||
DO | do NL
|
||||
;
|
||||
|
||||
else:
|
||||
ELSE | else NL
|
||||
;
|
||||
|
||||
for:
|
||||
FOR '(' opt_simple_stmt ';' opt_nl pattern ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt
|
||||
{ --inloop; $$ = stat4(FOR, $3, notnull($6), $9, $12); }
|
||||
| FOR '(' opt_simple_stmt ';' ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt
|
||||
{ --inloop; $$ = stat4(FOR, $3, NIL, $7, $10); }
|
||||
| FOR '(' varname IN varname rparen {inloop++;} stmt
|
||||
{ --inloop; $$ = stat3(IN, $3, makearr($5), $8); }
|
||||
;
|
||||
|
||||
funcname:
|
||||
VAR { setfname($1); }
|
||||
| CALL { setfname($1); }
|
||||
;
|
||||
|
||||
if:
|
||||
IF '(' pattern rparen { $$ = notnull($3); }
|
||||
;
|
||||
|
||||
lbrace:
|
||||
'{' | lbrace NL
|
||||
;
|
||||
|
||||
nl:
|
||||
NL | nl NL
|
||||
;
|
||||
|
||||
opt_nl:
|
||||
/* empty */ { $$ = 0; }
|
||||
| nl
|
||||
;
|
||||
|
||||
opt_pst:
|
||||
/* empty */ { $$ = 0; }
|
||||
| pst
|
||||
;
|
||||
|
||||
|
||||
opt_simple_stmt:
|
||||
/* empty */ { $$ = 0; }
|
||||
| simple_stmt
|
||||
;
|
||||
|
||||
pas:
|
||||
opt_pst { $$ = 0; }
|
||||
| opt_pst pa_stats opt_pst { $$ = $2; }
|
||||
;
|
||||
|
||||
pa_pat:
|
||||
pattern { $$ = notnull($1); }
|
||||
;
|
||||
|
||||
pa_stat:
|
||||
pa_pat { $$ = stat2(PASTAT, $1, stat2(PRINT, rectonode(), NIL)); }
|
||||
| pa_pat lbrace stmtlist '}' { $$ = stat2(PASTAT, $1, $3); }
|
||||
| pa_pat ',' pa_pat { $$ = pa2stat($1, $3, stat2(PRINT, rectonode(), NIL)); }
|
||||
| pa_pat ',' pa_pat lbrace stmtlist '}' { $$ = pa2stat($1, $3, $5); }
|
||||
| lbrace stmtlist '}' { $$ = stat2(PASTAT, NIL, $2); }
|
||||
| XBEGIN lbrace stmtlist '}'
|
||||
{ beginloc = linkum(beginloc, $3); $$ = 0; }
|
||||
| XEND lbrace stmtlist '}'
|
||||
{ endloc = linkum(endloc, $3); $$ = 0; }
|
||||
| FUNC funcname '(' varlist rparen {infunc++;} lbrace stmtlist '}'
|
||||
{ infunc--; curfname=0; defn((Cell *)$2, $4, $8); $$ = 0; }
|
||||
;
|
||||
|
||||
pa_stats:
|
||||
pa_stat
|
||||
| pa_stats opt_pst pa_stat { $$ = linkum($1, $3); }
|
||||
;
|
||||
|
||||
patlist:
|
||||
pattern
|
||||
| patlist comma pattern { $$ = linkum($1, $3); }
|
||||
;
|
||||
|
||||
ppattern:
|
||||
var ASGNOP ppattern { $$ = op2($2, $1, $3); }
|
||||
| ppattern '?' ppattern ':' ppattern %prec '?'
|
||||
{ $$ = op3(CONDEXPR, notnull($1), $3, $5); }
|
||||
| ppattern bor ppattern %prec BOR
|
||||
{ $$ = op2(BOR, notnull($1), notnull($3)); }
|
||||
| ppattern and ppattern %prec AND
|
||||
{ $$ = op2(AND, notnull($1), notnull($3)); }
|
||||
| ppattern MATCHOP reg_expr { $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
|
||||
| ppattern MATCHOP ppattern
|
||||
{ if (constnode($3))
|
||||
$$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0));
|
||||
else
|
||||
$$ = op3($2, (Node *)1, $1, $3); }
|
||||
| ppattern IN varname { $$ = op2(INTEST, $1, makearr($3)); }
|
||||
| '(' plist ')' IN varname { $$ = op2(INTEST, $2, makearr($5)); }
|
||||
| ppattern term %prec CAT { $$ = op2(CAT, $1, $2); }
|
||||
| re
|
||||
| term
|
||||
;
|
||||
|
||||
pattern:
|
||||
var ASGNOP pattern { $$ = op2($2, $1, $3); }
|
||||
| pattern '?' pattern ':' pattern %prec '?'
|
||||
{ $$ = op3(CONDEXPR, notnull($1), $3, $5); }
|
||||
| pattern bor pattern %prec BOR
|
||||
{ $$ = op2(BOR, notnull($1), notnull($3)); }
|
||||
| pattern and pattern %prec AND
|
||||
{ $$ = op2(AND, notnull($1), notnull($3)); }
|
||||
| pattern EQ pattern { $$ = op2($2, $1, $3); }
|
||||
| pattern GE pattern { $$ = op2($2, $1, $3); }
|
||||
| pattern GT pattern { $$ = op2($2, $1, $3); }
|
||||
| pattern LE pattern { $$ = op2($2, $1, $3); }
|
||||
| pattern LT pattern { $$ = op2($2, $1, $3); }
|
||||
| pattern NE pattern { $$ = op2($2, $1, $3); }
|
||||
| pattern MATCHOP reg_expr { $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
|
||||
| pattern MATCHOP pattern
|
||||
{ if (constnode($3))
|
||||
$$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0));
|
||||
else
|
||||
$$ = op3($2, (Node *)1, $1, $3); }
|
||||
| pattern IN varname { $$ = op2(INTEST, $1, makearr($3)); }
|
||||
| '(' plist ')' IN varname { $$ = op2(INTEST, $2, makearr($5)); }
|
||||
| pattern '|' GETLINE var {
|
||||
if (safe) SYNTAX("cmd | getline is unsafe");
|
||||
else $$ = op3(GETLINE, $4, itonp($2), $1); }
|
||||
| pattern '|' GETLINE {
|
||||
if (safe) SYNTAX("cmd | getline is unsafe");
|
||||
else $$ = op3(GETLINE, (Node*)0, itonp($2), $1); }
|
||||
| pattern term %prec CAT { $$ = op2(CAT, $1, $2); }
|
||||
| re
|
||||
| term
|
||||
;
|
||||
|
||||
plist:
|
||||
pattern comma pattern { $$ = linkum($1, $3); }
|
||||
| plist comma pattern { $$ = linkum($1, $3); }
|
||||
;
|
||||
|
||||
pplist:
|
||||
ppattern
|
||||
| pplist comma ppattern { $$ = linkum($1, $3); }
|
||||
;
|
||||
|
||||
prarg:
|
||||
/* empty */ { $$ = rectonode(); }
|
||||
| pplist
|
||||
| '(' plist ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
print:
|
||||
PRINT | PRINTF
|
||||
;
|
||||
|
||||
pst:
|
||||
NL | ';' | pst NL | pst ';'
|
||||
;
|
||||
|
||||
rbrace:
|
||||
'}' | rbrace NL
|
||||
;
|
||||
|
||||
re:
|
||||
reg_expr
|
||||
{ $$ = op3(MATCH, NIL, rectonode(), (Node*)makedfa($1, 0)); }
|
||||
| NOT re { $$ = op1(NOT, notnull($2)); }
|
||||
;
|
||||
|
||||
reg_expr:
|
||||
'/' {startreg();} REGEXPR '/' { $$ = $3; }
|
||||
;
|
||||
|
||||
rparen:
|
||||
')' | rparen NL
|
||||
;
|
||||
|
||||
simple_stmt:
|
||||
print prarg '|' term {
|
||||
if (safe) SYNTAX("print | is unsafe");
|
||||
else $$ = stat3($1, $2, itonp($3), $4); }
|
||||
| print prarg APPEND term {
|
||||
if (safe) SYNTAX("print >> is unsafe");
|
||||
else $$ = stat3($1, $2, itonp($3), $4); }
|
||||
| print prarg GT term {
|
||||
if (safe) SYNTAX("print > is unsafe");
|
||||
else $$ = stat3($1, $2, itonp($3), $4); }
|
||||
| print prarg { $$ = stat3($1, $2, NIL, NIL); }
|
||||
| DELETE varname '[' patlist ']' { $$ = stat2(DELETE, makearr($2), $4); }
|
||||
| DELETE varname { $$ = stat2(DELETE, makearr($2), 0); }
|
||||
| pattern { $$ = exptostat($1); }
|
||||
| error { yyclearin; SYNTAX("illegal statement"); }
|
||||
;
|
||||
|
||||
st:
|
||||
nl
|
||||
| ';' opt_nl
|
||||
;
|
||||
|
||||
stmt:
|
||||
BREAK st { if (!inloop) SYNTAX("break illegal outside of loops");
|
||||
$$ = stat1(BREAK, NIL); }
|
||||
| CLOSE pattern st { $$ = stat1(CLOSE, $2); }
|
||||
| CONTINUE st { if (!inloop) SYNTAX("continue illegal outside of loops");
|
||||
$$ = stat1(CONTINUE, NIL); }
|
||||
| do {inloop++;} stmt {--inloop;} WHILE '(' pattern ')' st
|
||||
{ $$ = stat2(DO, $3, notnull($7)); }
|
||||
| EXIT pattern st { $$ = stat1(EXIT, $2); }
|
||||
| EXIT st { $$ = stat1(EXIT, NIL); }
|
||||
| for
|
||||
| if stmt else stmt { $$ = stat3(IF, $1, $2, $4); }
|
||||
| if stmt { $$ = stat3(IF, $1, $2, NIL); }
|
||||
| lbrace stmtlist rbrace { $$ = $2; }
|
||||
| NEXT st { if (infunc)
|
||||
SYNTAX("next is illegal inside a function");
|
||||
$$ = stat1(NEXT, NIL); }
|
||||
| NEXTFILE st { if (infunc)
|
||||
SYNTAX("nextfile is illegal inside a function");
|
||||
$$ = stat1(NEXTFILE, NIL); }
|
||||
| RETURN pattern st { $$ = stat1(RETURN, $2); }
|
||||
| RETURN st { $$ = stat1(RETURN, NIL); }
|
||||
| simple_stmt st
|
||||
| while {inloop++;} stmt { --inloop; $$ = stat2(WHILE, $1, $3); }
|
||||
| ';' opt_nl { $$ = 0; }
|
||||
;
|
||||
|
||||
stmtlist:
|
||||
stmt
|
||||
| stmtlist stmt { $$ = linkum($1, $2); }
|
||||
;
|
||||
|
||||
subop:
|
||||
SUB | GSUB
|
||||
;
|
||||
|
||||
term:
|
||||
term '/' ASGNOP term { $$ = op2(DIVEQ, $1, $4); }
|
||||
| term '+' term { $$ = op2(ADD, $1, $3); }
|
||||
| term '-' term { $$ = op2(MINUS, $1, $3); }
|
||||
| term '*' term { $$ = op2(MULT, $1, $3); }
|
||||
| term '/' term { $$ = op2(DIVIDE, $1, $3); }
|
||||
| term '%' term { $$ = op2(MOD, $1, $3); }
|
||||
| term POWER term { $$ = op2(POWER, $1, $3); }
|
||||
| '-' term %prec UMINUS { $$ = op1(UMINUS, $2); }
|
||||
| '+' term %prec UMINUS { $$ = $2; }
|
||||
| NOT term %prec UMINUS { $$ = op1(NOT, notnull($2)); }
|
||||
| BLTIN '(' ')' { $$ = op2(BLTIN, itonp($1), rectonode()); }
|
||||
| BLTIN '(' patlist ')' { $$ = op2(BLTIN, itonp($1), $3); }
|
||||
| BLTIN { $$ = op2(BLTIN, itonp($1), rectonode()); }
|
||||
| CALL '(' ')' { $$ = op2(CALL, celltonode($1,CVAR), NIL); }
|
||||
| CALL '(' patlist ')' { $$ = op2(CALL, celltonode($1,CVAR), $3); }
|
||||
| DECR var { $$ = op1(PREDECR, $2); }
|
||||
| INCR var { $$ = op1(PREINCR, $2); }
|
||||
| var DECR { $$ = op1(POSTDECR, $1); }
|
||||
| var INCR { $$ = op1(POSTINCR, $1); }
|
||||
| GETLINE var LT term { $$ = op3(GETLINE, $2, itonp($3), $4); }
|
||||
| GETLINE LT term { $$ = op3(GETLINE, NIL, itonp($2), $3); }
|
||||
| GETLINE var { $$ = op3(GETLINE, $2, NIL, NIL); }
|
||||
| GETLINE { $$ = op3(GETLINE, NIL, NIL, NIL); }
|
||||
| INDEX '(' pattern comma pattern ')'
|
||||
{ $$ = op2(INDEX, $3, $5); }
|
||||
| INDEX '(' pattern comma reg_expr ')'
|
||||
{ SYNTAX("index() doesn't permit regular expressions");
|
||||
$$ = op2(INDEX, $3, (Node*)$5); }
|
||||
| '(' pattern ')' { $$ = $2; }
|
||||
| MATCHFCN '(' pattern comma reg_expr ')'
|
||||
{ $$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa($5, 1)); }
|
||||
| MATCHFCN '(' pattern comma pattern ')'
|
||||
{ if (constnode($5))
|
||||
$$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa(strnode($5), 1));
|
||||
else
|
||||
$$ = op3(MATCHFCN, (Node *)1, $3, $5); }
|
||||
| NUMBER { $$ = celltonode($1, CCON); }
|
||||
| SPLIT '(' pattern comma varname comma pattern ')' /* string */
|
||||
{ $$ = op4(SPLIT, $3, makearr($5), $7, (Node*)STRING); }
|
||||
| SPLIT '(' pattern comma varname comma reg_expr ')' /* const /regexp/ */
|
||||
{ $$ = op4(SPLIT, $3, makearr($5), (Node*)makedfa($7, 1), (Node *)REGEXPR); }
|
||||
| SPLIT '(' pattern comma varname ')'
|
||||
{ $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); } /* default */
|
||||
| SPRINTF '(' patlist ')' { $$ = op1($1, $3); }
|
||||
| STRING { $$ = celltonode($1, CCON); }
|
||||
| subop '(' reg_expr comma pattern ')'
|
||||
{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); }
|
||||
| subop '(' pattern comma pattern ')'
|
||||
{ if (constnode($3))
|
||||
$$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, rectonode());
|
||||
else
|
||||
$$ = op4($1, (Node *)1, $3, $5, rectonode()); }
|
||||
| subop '(' reg_expr comma pattern comma var ')'
|
||||
{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, $7); }
|
||||
| subop '(' pattern comma pattern comma var ')'
|
||||
{ if (constnode($3))
|
||||
$$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, $7);
|
||||
else
|
||||
$$ = op4($1, (Node *)1, $3, $5, $7); }
|
||||
| SUBSTR '(' pattern comma pattern comma pattern ')'
|
||||
{ $$ = op3(SUBSTR, $3, $5, $7); }
|
||||
| SUBSTR '(' pattern comma pattern ')'
|
||||
{ $$ = op3(SUBSTR, $3, $5, NIL); }
|
||||
| var
|
||||
;
|
||||
|
||||
var:
|
||||
varname
|
||||
| varname '[' patlist ']' { $$ = op2(ARRAY, makearr($1), $3); }
|
||||
| IVAR { $$ = op1(INDIRECT, celltonode($1, CVAR)); }
|
||||
| INDIRECT term { $$ = op1(INDIRECT, $2); }
|
||||
;
|
||||
|
||||
varlist:
|
||||
/* nothing */ { arglist = $$ = 0; }
|
||||
| VAR { arglist = $$ = celltonode($1,CVAR); }
|
||||
| varlist comma VAR {
|
||||
checkdup($1, $3);
|
||||
arglist = $$ = linkum($1,celltonode($3,CVAR)); }
|
||||
;
|
||||
|
||||
varname:
|
||||
VAR { $$ = celltonode($1, CVAR); }
|
||||
| ARG { $$ = op1(ARG, itonp($1)); }
|
||||
| VARNF { $$ = op1(VARNF, (Node *) $1); }
|
||||
;
|
||||
|
||||
|
||||
while:
|
||||
WHILE '(' pattern rparen { $$ = notnull($3); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void setfname(Cell *p)
|
||||
{
|
||||
if (isarr(p))
|
||||
SYNTAX("%s is an array, not a function", p->nval);
|
||||
else if (isfcn(p))
|
||||
SYNTAX("you can't define function %s more than once", p->nval);
|
||||
curfname = p->nval;
|
||||
}
|
||||
|
||||
int constnode(Node *p)
|
||||
{
|
||||
return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON;
|
||||
}
|
||||
|
||||
char *strnode(Node *p)
|
||||
{
|
||||
return ((Cell *)(p->narg[0]))->sval;
|
||||
}
|
||||
|
||||
Node *notnull(Node *n)
|
||||
{
|
||||
switch (n->nobj) {
|
||||
case LE: case LT: case EQ: case NE: case GT: case GE:
|
||||
case BOR: case AND: case NOT:
|
||||
return n;
|
||||
default:
|
||||
return op2(NE, n, nullnode);
|
||||
}
|
||||
}
|
||||
|
||||
void checkdup(Node *vl, Cell *cp) /* check if name already in list */
|
||||
{
|
||||
char *s = cp->nval;
|
||||
for ( ; vl; vl = vl->nnext) {
|
||||
if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) {
|
||||
SYNTAX("duplicate argument %s", s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
569
awk/lex.c
Normal file
569
awk/lex.c
Normal file
@@ -0,0 +1,569 @@
|
||||
/****************************************************************
|
||||
Copyright (C) Lucent Technologies 1997
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name Lucent Technologies or any of
|
||||
its entities not be used in advertising or publicity pertaining
|
||||
to distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
****************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "awk.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
extern int infunc;
|
||||
|
||||
int lineno = 1;
|
||||
int bracecnt = 0;
|
||||
int brackcnt = 0;
|
||||
int parencnt = 0;
|
||||
|
||||
typedef struct Keyword {
|
||||
char *word;
|
||||
int sub;
|
||||
int type;
|
||||
} Keyword;
|
||||
|
||||
Keyword keywords[] ={ /* keep sorted: binary searched */
|
||||
{ "BEGIN", XBEGIN, XBEGIN },
|
||||
{ "END", XEND, XEND },
|
||||
{ "NF", VARNF, VARNF },
|
||||
{ "atan2", FATAN, BLTIN },
|
||||
{ "break", BREAK, BREAK },
|
||||
{ "close", CLOSE, CLOSE },
|
||||
{ "continue", CONTINUE, CONTINUE },
|
||||
{ "cos", FCOS, BLTIN },
|
||||
{ "delete", DELETE, DELETE },
|
||||
{ "do", DO, DO },
|
||||
{ "else", ELSE, ELSE },
|
||||
{ "exit", EXIT, EXIT },
|
||||
{ "exp", FEXP, BLTIN },
|
||||
{ "fflush", FFLUSH, BLTIN },
|
||||
{ "for", FOR, FOR },
|
||||
{ "func", FUNC, FUNC },
|
||||
{ "function", FUNC, FUNC },
|
||||
{ "getline", GETLINE, GETLINE },
|
||||
{ "gsub", GSUB, GSUB },
|
||||
{ "if", IF, IF },
|
||||
{ "in", IN, IN },
|
||||
{ "index", INDEX, INDEX },
|
||||
{ "int", FINT, BLTIN },
|
||||
{ "length", FLENGTH, BLTIN },
|
||||
{ "log", FLOG, BLTIN },
|
||||
{ "match", MATCHFCN, MATCHFCN },
|
||||
{ "next", NEXT, NEXT },
|
||||
{ "nextfile", NEXTFILE, NEXTFILE },
|
||||
{ "print", PRINT, PRINT },
|
||||
{ "printf", PRINTF, PRINTF },
|
||||
{ "rand", FRAND, BLTIN },
|
||||
{ "return", RETURN, RETURN },
|
||||
{ "sin", FSIN, BLTIN },
|
||||
{ "split", SPLIT, SPLIT },
|
||||
{ "sprintf", SPRINTF, SPRINTF },
|
||||
{ "sqrt", FSQRT, BLTIN },
|
||||
{ "srand", FSRAND, BLTIN },
|
||||
{ "sub", SUB, SUB },
|
||||
{ "substr", SUBSTR, SUBSTR },
|
||||
{ "system", FSYSTEM, BLTIN },
|
||||
{ "tolower", FTOLOWER, BLTIN },
|
||||
{ "toupper", FTOUPPER, BLTIN },
|
||||
{ "while", WHILE, WHILE },
|
||||
{ "utf", FUTF, BLTIN },
|
||||
};
|
||||
|
||||
#define DEBUG
|
||||
#ifdef DEBUG
|
||||
#define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
|
||||
#else
|
||||
#define RET(x) return(x)
|
||||
#endif
|
||||
|
||||
int peek(void)
|
||||
{
|
||||
int c = input();
|
||||
unput(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
int gettok(char **pbuf, int *psz) /* get next input token */
|
||||
{
|
||||
int c;
|
||||
char *buf = *pbuf;
|
||||
int sz = *psz;
|
||||
char *bp = buf;
|
||||
|
||||
c = input();
|
||||
if (c == 0)
|
||||
return 0;
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
if (!isalnum(c) && c != '.' && c != '_')
|
||||
return c;
|
||||
|
||||
*bp++ = c;
|
||||
if (isalpha(c) || c == '_') { /* it's a varname */
|
||||
for ( ; (c = input()) != 0; ) {
|
||||
if (bp-buf >= sz)
|
||||
if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0))
|
||||
FATAL( "out of space for name %.10s...", buf );
|
||||
if (isalnum(c) || c == '_')
|
||||
*bp++ = c;
|
||||
else {
|
||||
*bp = 0;
|
||||
unput(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else { /* it's a number */
|
||||
char *rem;
|
||||
/* read input until can't be a number */
|
||||
for ( ; (c = input()) != 0; ) {
|
||||
if (bp-buf >= sz)
|
||||
if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0))
|
||||
FATAL( "out of space for number %.10s...", buf );
|
||||
if (isdigit(c) || c == 'e' || c == 'E'
|
||||
|| c == '.' || c == '+' || c == '-')
|
||||
*bp++ = c;
|
||||
else {
|
||||
unput(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*bp = 0;
|
||||
strtod(buf, &rem); /* parse the number */
|
||||
unputstr(rem); /* put rest back for later */
|
||||
rem[0] = 0;
|
||||
}
|
||||
*pbuf = buf;
|
||||
*psz = sz;
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
int word(char *);
|
||||
int string(void);
|
||||
int regexpr(void);
|
||||
int sc = 0; /* 1 => return a } right now */
|
||||
int reg = 0; /* 1 => return a REGEXPR now */
|
||||
|
||||
int yylex(void)
|
||||
{
|
||||
int c;
|
||||
static char *buf = 0;
|
||||
static int bufsize = 500;
|
||||
|
||||
if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL)
|
||||
FATAL( "out of space in yylex" );
|
||||
if (sc) {
|
||||
sc = 0;
|
||||
RET('}');
|
||||
}
|
||||
if (reg) {
|
||||
reg = 0;
|
||||
return regexpr();
|
||||
}
|
||||
for (;;) {
|
||||
c = gettok(&buf, &bufsize);
|
||||
if (c == 0)
|
||||
return 0;
|
||||
if (isalpha(c) || c == '_')
|
||||
return word(buf);
|
||||
if (isdigit(c) || c == '.') {
|
||||
yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab);
|
||||
/* should this also have STR set? */
|
||||
RET(NUMBER);
|
||||
}
|
||||
|
||||
yylval.i = c;
|
||||
switch (c) {
|
||||
case '\n': /* {EOL} */
|
||||
RET(NL);
|
||||
case '\r': /* assume \n is coming */
|
||||
case ' ': /* {WS}+ */
|
||||
case '\t':
|
||||
break;
|
||||
case '#': /* #.* strip comments */
|
||||
while ((c = input()) != '\n' && c != 0)
|
||||
;
|
||||
unput(c);
|
||||
break;
|
||||
case ';':
|
||||
RET(';');
|
||||
case '\\':
|
||||
if (peek() == '\n') {
|
||||
input();
|
||||
} else if (peek() == '\r') {
|
||||
input(); input(); /* \n */
|
||||
lineno++;
|
||||
} else {
|
||||
RET(c);
|
||||
}
|
||||
break;
|
||||
case '&':
|
||||
if (peek() == '&') {
|
||||
input(); RET(AND);
|
||||
} else
|
||||
RET('&');
|
||||
case '|':
|
||||
if (peek() == '|') {
|
||||
input(); RET(BOR);
|
||||
} else
|
||||
RET('|');
|
||||
case '!':
|
||||
if (peek() == '=') {
|
||||
input(); yylval.i = NE; RET(NE);
|
||||
} else if (peek() == '~') {
|
||||
input(); yylval.i = NOTMATCH; RET(MATCHOP);
|
||||
} else
|
||||
RET(NOT);
|
||||
case '~':
|
||||
yylval.i = MATCH;
|
||||
RET(MATCHOP);
|
||||
case '<':
|
||||
if (peek() == '=') {
|
||||
input(); yylval.i = LE; RET(LE);
|
||||
} else {
|
||||
yylval.i = LT; RET(LT);
|
||||
}
|
||||
case '=':
|
||||
if (peek() == '=') {
|
||||
input(); yylval.i = EQ; RET(EQ);
|
||||
} else {
|
||||
yylval.i = ASSIGN; RET(ASGNOP);
|
||||
}
|
||||
case '>':
|
||||
if (peek() == '=') {
|
||||
input(); yylval.i = GE; RET(GE);
|
||||
} else if (peek() == '>') {
|
||||
input(); yylval.i = APPEND; RET(APPEND);
|
||||
} else {
|
||||
yylval.i = GT; RET(GT);
|
||||
}
|
||||
case '+':
|
||||
if (peek() == '+') {
|
||||
input(); yylval.i = INCR; RET(INCR);
|
||||
} else if (peek() == '=') {
|
||||
input(); yylval.i = ADDEQ; RET(ASGNOP);
|
||||
} else
|
||||
RET('+');
|
||||
case '-':
|
||||
if (peek() == '-') {
|
||||
input(); yylval.i = DECR; RET(DECR);
|
||||
} else if (peek() == '=') {
|
||||
input(); yylval.i = SUBEQ; RET(ASGNOP);
|
||||
} else
|
||||
RET('-');
|
||||
case '*':
|
||||
if (peek() == '=') { /* *= */
|
||||
input(); yylval.i = MULTEQ; RET(ASGNOP);
|
||||
} else if (peek() == '*') { /* ** or **= */
|
||||
input(); /* eat 2nd * */
|
||||
if (peek() == '=') {
|
||||
input(); yylval.i = POWEQ; RET(ASGNOP);
|
||||
} else {
|
||||
RET(POWER);
|
||||
}
|
||||
} else
|
||||
RET('*');
|
||||
case '/':
|
||||
RET('/');
|
||||
case '%':
|
||||
if (peek() == '=') {
|
||||
input(); yylval.i = MODEQ; RET(ASGNOP);
|
||||
} else
|
||||
RET('%');
|
||||
case '^':
|
||||
if (peek() == '=') {
|
||||
input(); yylval.i = POWEQ; RET(ASGNOP);
|
||||
} else
|
||||
RET(POWER);
|
||||
|
||||
case '$':
|
||||
/* BUG: awkward, if not wrong */
|
||||
c = gettok(&buf, &bufsize);
|
||||
if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
|
||||
unputstr(buf);
|
||||
RET(INDIRECT);
|
||||
} else if (isalpha(c)) {
|
||||
if (strcmp(buf, "NF") == 0) { /* very special */
|
||||
unputstr("(NF)");
|
||||
RET(INDIRECT);
|
||||
}
|
||||
yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
|
||||
RET(IVAR);
|
||||
} else {
|
||||
unputstr(buf);
|
||||
RET(INDIRECT);
|
||||
}
|
||||
|
||||
case '}':
|
||||
if (--bracecnt < 0)
|
||||
SYNTAX( "extra }" );
|
||||
sc = 1;
|
||||
RET(';');
|
||||
case ']':
|
||||
if (--brackcnt < 0)
|
||||
SYNTAX( "extra ]" );
|
||||
RET(']');
|
||||
case ')':
|
||||
if (--parencnt < 0)
|
||||
SYNTAX( "extra )" );
|
||||
RET(')');
|
||||
case '{':
|
||||
bracecnt++;
|
||||
RET('{');
|
||||
case '[':
|
||||
brackcnt++;
|
||||
RET('[');
|
||||
case '(':
|
||||
parencnt++;
|
||||
RET('(');
|
||||
|
||||
case '"':
|
||||
return string(); /* BUG: should be like tran.c ? */
|
||||
|
||||
default:
|
||||
RET(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int string(void)
|
||||
{
|
||||
int c, n;
|
||||
char *s, *bp;
|
||||
static char *buf = 0;
|
||||
static int bufsz = 500;
|
||||
|
||||
if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
|
||||
FATAL("out of space for strings");
|
||||
for (bp = buf; (c = input()) != '"'; ) {
|
||||
if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, 0))
|
||||
FATAL("out of space for string %.10s...", buf);
|
||||
switch (c) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
case 0:
|
||||
SYNTAX( "non-terminated string %.10s...", buf );
|
||||
lineno++;
|
||||
break;
|
||||
case '\\':
|
||||
c = input();
|
||||
switch (c) {
|
||||
case '"': *bp++ = '"'; break;
|
||||
case 'n': *bp++ = '\n'; break;
|
||||
case 't': *bp++ = '\t'; break;
|
||||
case 'f': *bp++ = '\f'; break;
|
||||
case 'r': *bp++ = '\r'; break;
|
||||
case 'b': *bp++ = '\b'; break;
|
||||
case 'v': *bp++ = '\v'; break;
|
||||
case 'a': *bp++ = '\007'; break;
|
||||
case '\\': *bp++ = '\\'; break;
|
||||
|
||||
case '0': case '1': case '2': /* octal: \d \dd \ddd */
|
||||
case '3': case '4': case '5': case '6': case '7':
|
||||
n = c - '0';
|
||||
if ((c = peek()) >= '0' && c < '8') {
|
||||
n = 8 * n + input() - '0';
|
||||
if ((c = peek()) >= '0' && c < '8')
|
||||
n = 8 * n + input() - '0';
|
||||
}
|
||||
*bp++ = n;
|
||||
break;
|
||||
|
||||
case 'x': /* hex \x0-9a-fA-F + */
|
||||
{ char xbuf[100], *px;
|
||||
for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
|
||||
if (isdigit(c)
|
||||
|| (c >= 'a' && c <= 'f')
|
||||
|| (c >= 'A' && c <= 'F'))
|
||||
*px++ = c;
|
||||
else
|
||||
break;
|
||||
}
|
||||
*px = 0;
|
||||
unput(c);
|
||||
sscanf(xbuf, "%x", &n);
|
||||
*bp++ = n;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
*bp++ = c;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*bp++ = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*bp = 0;
|
||||
s = tostring(buf);
|
||||
*bp++ = ' '; *bp++ = 0;
|
||||
yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
|
||||
RET(STRING);
|
||||
}
|
||||
|
||||
|
||||
int binsearch(char *w, Keyword *kp, int n)
|
||||
{
|
||||
int cond, low, mid, high;
|
||||
|
||||
low = 0;
|
||||
high = n - 1;
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
if ((cond = strcmp(w, kp[mid].word)) < 0)
|
||||
high = mid - 1;
|
||||
else if (cond > 0)
|
||||
low = mid + 1;
|
||||
else
|
||||
return mid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int word(char *w)
|
||||
{
|
||||
Keyword *kp;
|
||||
int c, n;
|
||||
|
||||
n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
|
||||
kp = keywords + n;
|
||||
if (n != -1) { /* found in table */
|
||||
yylval.i = kp->sub;
|
||||
switch (kp->type) { /* special handling */
|
||||
case FSYSTEM:
|
||||
if (safe)
|
||||
SYNTAX( "system is unsafe" );
|
||||
RET(kp->type);
|
||||
case FUNC:
|
||||
if (infunc)
|
||||
SYNTAX( "illegal nested function" );
|
||||
RET(kp->type);
|
||||
case RETURN:
|
||||
if (!infunc)
|
||||
SYNTAX( "return not in function" );
|
||||
RET(kp->type);
|
||||
case VARNF:
|
||||
yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
|
||||
RET(VARNF);
|
||||
default:
|
||||
RET(kp->type);
|
||||
}
|
||||
}
|
||||
c = peek(); /* look for '(' */
|
||||
if (c != '(' && infunc && (n=isarg(w)) >= 0) {
|
||||
yylval.i = n;
|
||||
RET(ARG);
|
||||
} else {
|
||||
yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
|
||||
if (c == '(') {
|
||||
RET(CALL);
|
||||
} else {
|
||||
RET(VAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startreg(void) /* next call to yyles will return a regular expression */
|
||||
{
|
||||
reg = 1;
|
||||
}
|
||||
|
||||
int regexpr(void)
|
||||
{
|
||||
int c;
|
||||
static char *buf = 0;
|
||||
static int bufsz = 500;
|
||||
char *bp;
|
||||
|
||||
if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
|
||||
FATAL("out of space for rex expr");
|
||||
bp = buf;
|
||||
for ( ; (c = input()) != '/' && c != 0; ) {
|
||||
if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, 0))
|
||||
FATAL("out of space for reg expr %.10s...", buf);
|
||||
if (c == '\n') {
|
||||
SYNTAX( "newline in regular expression %.10s...", buf );
|
||||
unput('\n');
|
||||
break;
|
||||
} else if (c == '\\') {
|
||||
*bp++ = '\\';
|
||||
*bp++ = input();
|
||||
} else {
|
||||
*bp++ = c;
|
||||
}
|
||||
}
|
||||
*bp = 0;
|
||||
yylval.s = tostring(buf);
|
||||
unput('/');
|
||||
RET(REGEXPR);
|
||||
}
|
||||
|
||||
/* low-level lexical stuff, sort of inherited from lex */
|
||||
|
||||
char ebuf[300];
|
||||
char *ep = ebuf;
|
||||
char yysbuf[100]; /* pushback buffer */
|
||||
char *yysptr = yysbuf;
|
||||
FILE *yyin = 0;
|
||||
|
||||
int input(void) /* get next lexical input character */
|
||||
{
|
||||
int c;
|
||||
extern char *lexprog;
|
||||
|
||||
if (yysptr > yysbuf)
|
||||
c = *--yysptr;
|
||||
else if (lexprog != NULL) { /* awk '...' */
|
||||
if ((c = *lexprog) != 0)
|
||||
lexprog++;
|
||||
} else /* awk -f ... */
|
||||
c = pgetc();
|
||||
if (c == '\n')
|
||||
lineno++;
|
||||
else if (c == EOF)
|
||||
c = 0;
|
||||
if (ep >= ebuf + sizeof ebuf)
|
||||
ep = ebuf;
|
||||
return *ep++ = c;
|
||||
}
|
||||
|
||||
void unput(int c) /* put lexical character back on input */
|
||||
{
|
||||
if (c == '\n')
|
||||
lineno--;
|
||||
if (yysptr >= yysbuf + sizeof(yysbuf))
|
||||
FATAL("pushed back too much: %.20s...", yysbuf);
|
||||
*yysptr++ = c;
|
||||
if (--ep < ebuf)
|
||||
ep = ebuf + sizeof(ebuf) - 1;
|
||||
}
|
||||
|
||||
void unputstr(char *s) /* put a string back on input */
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = strlen(s)-1; i >= 0; i--)
|
||||
unput(s[i]);
|
||||
}
|
686
awk/lib.c
Normal file
686
awk/lib.c
Normal file
@@ -0,0 +1,686 @@
|
||||
/****************************************************************
|
||||
Copyright (C) Lucent Technologies 1997
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name Lucent Technologies or any of
|
||||
its entities not be used in advertising or publicity pertaining
|
||||
to distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
****************************************************************/
|
||||
|
||||
#define DEBUG
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "awk.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
FILE *infile = NULL;
|
||||
char *file = "";
|
||||
char *record;
|
||||
int recsize = RECSIZE;
|
||||
char *fields;
|
||||
int fieldssize = RECSIZE;
|
||||
|
||||
Cell **fldtab; /* pointers to Cells */
|
||||
char inputFS[100] = " ";
|
||||
|
||||
#define MAXFLD 200
|
||||
int nfields = MAXFLD; /* last allocated slot for $i */
|
||||
|
||||
int donefld; /* 1 = implies rec broken into fields */
|
||||
int donerec; /* 1 = record is valid (no flds have changed) */
|
||||
|
||||
int lastfld = 0; /* last used field */
|
||||
int argno = 1; /* current input argument number */
|
||||
extern Awkfloat *ARGC;
|
||||
|
||||
static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
|
||||
static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
|
||||
|
||||
void recinit(unsigned int n)
|
||||
{
|
||||
record = (char *) malloc(n);
|
||||
fields = (char *) malloc(n);
|
||||
fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *));
|
||||
if (record == NULL || fields == NULL || fldtab == NULL)
|
||||
FATAL("out of space for $0 and fields");
|
||||
fldtab[0] = (Cell *) malloc(sizeof (Cell));
|
||||
*fldtab[0] = dollar0;
|
||||
fldtab[0]->sval = record;
|
||||
fldtab[0]->nval = tostring("0");
|
||||
makefields(1, nfields);
|
||||
}
|
||||
|
||||
void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
|
||||
{
|
||||
char temp[50];
|
||||
int i;
|
||||
|
||||
for (i = n1; i <= n2; i++) {
|
||||
fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
|
||||
if (fldtab[i] == NULL)
|
||||
FATAL("out of space in makefields %d", i);
|
||||
*fldtab[i] = dollar1;
|
||||
sprintf(temp, "%d", i);
|
||||
fldtab[i]->nval = tostring(temp);
|
||||
}
|
||||
}
|
||||
|
||||
void initgetrec(void)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
for (i = 1; i < *ARGC; i++) {
|
||||
if (!isclvar(p = getargv(i))) { /* find 1st real filename */
|
||||
setsval(lookup("FILENAME", symtab), getargv(i));
|
||||
return;
|
||||
}
|
||||
setclvar(p); /* a commandline assignment before filename */
|
||||
argno++;
|
||||
}
|
||||
infile = stdin; /* no filenames, so use stdin */
|
||||
}
|
||||
|
||||
int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
|
||||
{ /* note: cares whether buf == record */
|
||||
int c;
|
||||
static int firsttime = 1;
|
||||
char *buf = *pbuf;
|
||||
int bufsize = *pbufsize;
|
||||
|
||||
if (firsttime) {
|
||||
firsttime = 0;
|
||||
initgetrec();
|
||||
}
|
||||
dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
|
||||
*RS, *FS, *ARGC, *FILENAME) );
|
||||
if (isrecord) {
|
||||
donefld = 0;
|
||||
donerec = 1;
|
||||
}
|
||||
buf[0] = 0;
|
||||
while (argno < *ARGC || infile == stdin) {
|
||||
dprintf( ("argno=%d, file=|%s|\n", argno, file) );
|
||||
if (infile == NULL) { /* have to open a new file */
|
||||
file = getargv(argno);
|
||||
if (*file == '\0') { /* it's been zapped */
|
||||
argno++;
|
||||
continue;
|
||||
}
|
||||
if (isclvar(file)) { /* a var=value arg */
|
||||
setclvar(file);
|
||||
argno++;
|
||||
continue;
|
||||
}
|
||||
*FILENAME = file;
|
||||
dprintf( ("opening file %s\n", file) );
|
||||
if (*file == '-' && *(file+1) == '\0')
|
||||
infile = stdin;
|
||||
else if ((infile = fopen(file, "r")) == NULL)
|
||||
FATAL("can't open file %s", file);
|
||||
setfval(fnrloc, 0.0);
|
||||
}
|
||||
c = readrec(&buf, &bufsize, infile);
|
||||
if (c != 0 || buf[0] != '\0') { /* normal record */
|
||||
if (isrecord) {
|
||||
if (freeable(fldtab[0]))
|
||||
xfree(fldtab[0]->sval);
|
||||
fldtab[0]->sval = buf; /* buf == record */
|
||||
fldtab[0]->tval = REC | STR | DONTFREE;
|
||||
if (is_number(fldtab[0]->sval)) {
|
||||
fldtab[0]->fval = atof(fldtab[0]->sval);
|
||||
fldtab[0]->tval |= NUM;
|
||||
}
|
||||
}
|
||||
setfval(nrloc, nrloc->fval+1);
|
||||
setfval(fnrloc, fnrloc->fval+1);
|
||||
*pbuf = buf;
|
||||
*pbufsize = bufsize;
|
||||
return 1;
|
||||
}
|
||||
/* EOF arrived on this file; set up next */
|
||||
if (infile != stdin)
|
||||
fclose(infile);
|
||||
infile = NULL;
|
||||
argno++;
|
||||
}
|
||||
*pbuf = buf;
|
||||
*pbufsize = bufsize;
|
||||
return 0; /* true end of file */
|
||||
}
|
||||
|
||||
void nextfile(void)
|
||||
{
|
||||
if (infile != stdin)
|
||||
fclose(infile);
|
||||
infile = NULL;
|
||||
argno++;
|
||||
}
|
||||
|
||||
int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */
|
||||
{
|
||||
int sep, c;
|
||||
char *rr, *buf = *pbuf;
|
||||
int bufsize = *pbufsize;
|
||||
|
||||
if (strlen(*FS) >= sizeof(inputFS))
|
||||
FATAL("field separator %.10s... is too long", *FS);
|
||||
strcpy(inputFS, *FS); /* for subsequent field splitting */
|
||||
if ((sep = **RS) == 0) {
|
||||
sep = '\n';
|
||||
while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
|
||||
;
|
||||
if (c != EOF)
|
||||
ungetc(c, inf);
|
||||
}
|
||||
for (rr = buf; ; ) {
|
||||
for (; (c=getc(inf)) != sep && c != EOF; ) {
|
||||
if (rr-buf+1 > bufsize)
|
||||
if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
|
||||
FATAL("input record `%.30s...' too long", buf);
|
||||
*rr++ = c;
|
||||
}
|
||||
if (**RS == sep || c == EOF)
|
||||
break;
|
||||
if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
|
||||
break;
|
||||
if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
|
||||
FATAL("input record `%.30s...' too long", buf);
|
||||
*rr++ = '\n';
|
||||
*rr++ = c;
|
||||
}
|
||||
if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
|
||||
FATAL("input record `%.30s...' too long", buf);
|
||||
*rr = 0;
|
||||
dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
|
||||
*pbuf = buf;
|
||||
*pbufsize = bufsize;
|
||||
return c == EOF && rr == buf ? 0 : 1;
|
||||
}
|
||||
|
||||
char *getargv(int n) /* get ARGV[n] */
|
||||
{
|
||||
Cell *x;
|
||||
char *s, temp[50];
|
||||
extern Array *ARGVtab;
|
||||
|
||||
sprintf(temp, "%d", n);
|
||||
x = setsymtab(temp, "", 0.0, STR, ARGVtab);
|
||||
s = getsval(x);
|
||||
dprintf( ("getargv(%d) returns |%s|\n", n, s) );
|
||||
return s;
|
||||
}
|
||||
|
||||
void setclvar(char *s) /* set var=value from s */
|
||||
{
|
||||
char *p;
|
||||
Cell *q;
|
||||
|
||||
for (p=s; *p != '='; p++)
|
||||
;
|
||||
*p++ = 0;
|
||||
p = qstring(p, '\0');
|
||||
q = setsymtab(s, p, 0.0, STR, symtab);
|
||||
setsval(q, p);
|
||||
if (is_number(q->sval)) {
|
||||
q->fval = atof(q->sval);
|
||||
q->tval |= NUM;
|
||||
}
|
||||
dprintf( ("command line set %s to |%s|\n", s, p) );
|
||||
}
|
||||
|
||||
|
||||
void fldbld(void) /* create fields from current record */
|
||||
{
|
||||
/* this relies on having fields[] the same length as $0 */
|
||||
/* the fields are all stored in this one array with \0's */
|
||||
char *r, *fr, sep;
|
||||
Cell *p;
|
||||
int i, j, n;
|
||||
|
||||
if (donefld)
|
||||
return;
|
||||
if (!isstr(fldtab[0]))
|
||||
getsval(fldtab[0]);
|
||||
r = fldtab[0]->sval;
|
||||
n = strlen(r);
|
||||
if (n > fieldssize) {
|
||||
xfree(fields);
|
||||
if ((fields = (char *) malloc(n+1)) == NULL)
|
||||
FATAL("out of space for fields in fldbld %d", n);
|
||||
fieldssize = n;
|
||||
}
|
||||
fr = fields;
|
||||
i = 0; /* number of fields accumulated here */
|
||||
if (strlen(inputFS) > 1) { /* it's a regular expression */
|
||||
i = refldbld(r, inputFS);
|
||||
} else if ((sep = *inputFS) == ' ') { /* default whitespace */
|
||||
for (i = 0; ; ) {
|
||||
while (*r == ' ' || *r == '\t' || *r == '\n')
|
||||
r++;
|
||||
if (*r == 0)
|
||||
break;
|
||||
i++;
|
||||
if (i > nfields)
|
||||
growfldtab(i);
|
||||
if (freeable(fldtab[i]))
|
||||
xfree(fldtab[i]->sval);
|
||||
fldtab[i]->sval = fr;
|
||||
fldtab[i]->tval = FLD | STR | DONTFREE;
|
||||
do
|
||||
*fr++ = *r++;
|
||||
while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
|
||||
*fr++ = 0;
|
||||
}
|
||||
*fr = 0;
|
||||
} else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
|
||||
for (i = 0; *r != 0; r++) {
|
||||
char buf[2];
|
||||
i++;
|
||||
if (i > nfields)
|
||||
growfldtab(i);
|
||||
if (freeable(fldtab[i]))
|
||||
xfree(fldtab[i]->sval);
|
||||
buf[0] = *r;
|
||||
buf[1] = 0;
|
||||
fldtab[i]->sval = tostring(buf);
|
||||
fldtab[i]->tval = FLD | STR;
|
||||
}
|
||||
*fr = 0;
|
||||
} else if (*r != 0) { /* if 0, it's a null field */
|
||||
for (;;) {
|
||||
i++;
|
||||
if (i > nfields)
|
||||
growfldtab(i);
|
||||
if (freeable(fldtab[i]))
|
||||
xfree(fldtab[i]->sval);
|
||||
fldtab[i]->sval = fr;
|
||||
fldtab[i]->tval = FLD | STR | DONTFREE;
|
||||
while (*r != sep && *r != '\n' && *r != '\0') /* \n is always a separator */
|
||||
*fr++ = *r++;
|
||||
*fr++ = 0;
|
||||
if (*r++ == 0)
|
||||
break;
|
||||
}
|
||||
*fr = 0;
|
||||
}
|
||||
if (i > nfields)
|
||||
FATAL("record `%.30s...' has too many fields; can't happen", r);
|
||||
cleanfld(i+1, lastfld); /* clean out junk from previous record */
|
||||
lastfld = i;
|
||||
donefld = 1;
|
||||
for (j = 1; j <= lastfld; j++) {
|
||||
p = fldtab[j];
|
||||
if(is_number(p->sval)) {
|
||||
p->fval = atof(p->sval);
|
||||
p->tval |= NUM;
|
||||
}
|
||||
}
|
||||
setfval(nfloc, (Awkfloat) lastfld);
|
||||
if (dbg) {
|
||||
for (j = 0; j <= lastfld; j++) {
|
||||
p = fldtab[j];
|
||||
printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
|
||||
{ /* nvals remain intact */
|
||||
Cell *p;
|
||||
int i;
|
||||
|
||||
for (i = n1; i <= n2; i++) {
|
||||
p = fldtab[i];
|
||||
if (freeable(p))
|
||||
xfree(p->sval);
|
||||
p->sval = "";
|
||||
p->tval = FLD | STR | DONTFREE;
|
||||
}
|
||||
}
|
||||
|
||||
void newfld(int n) /* add field n after end of existing lastfld */
|
||||
{
|
||||
if (n > nfields)
|
||||
growfldtab(n);
|
||||
cleanfld(lastfld+1, n);
|
||||
lastfld = n;
|
||||
setfval(nfloc, (Awkfloat) n);
|
||||
}
|
||||
|
||||
Cell *fieldadr(int n) /* get nth field */
|
||||
{
|
||||
if (n < 0)
|
||||
FATAL("trying to access field %d", n);
|
||||
if (n > nfields) /* fields after NF are empty */
|
||||
growfldtab(n); /* but does not increase NF */
|
||||
return(fldtab[n]);
|
||||
}
|
||||
|
||||
void growfldtab(int n) /* make new fields up to at least $n */
|
||||
{
|
||||
int nf = 2 * nfields;
|
||||
|
||||
if (n > nf)
|
||||
nf = n;
|
||||
fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
|
||||
if (fldtab == NULL)
|
||||
FATAL("out of space creating %d fields", nf);
|
||||
makefields(nfields+1, nf);
|
||||
nfields = nf;
|
||||
}
|
||||
|
||||
int refldbld(char *rec, char *fs) /* build fields from reg expr in FS */
|
||||
{
|
||||
/* this relies on having fields[] the same length as $0 */
|
||||
/* the fields are all stored in this one array with \0's */
|
||||
char *fr;
|
||||
void *p;
|
||||
int i, n;
|
||||
|
||||
n = strlen(rec);
|
||||
if (n > fieldssize) {
|
||||
xfree(fields);
|
||||
if ((fields = (char *) malloc(n+1)) == NULL)
|
||||
FATAL("out of space for fields in refldbld %d", n);
|
||||
fieldssize = n;
|
||||
}
|
||||
fr = fields;
|
||||
*fr = '\0';
|
||||
if (*rec == '\0')
|
||||
return 0;
|
||||
p = compre(fs);
|
||||
dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
|
||||
for (i = 1; ; i++) {
|
||||
if (i > nfields)
|
||||
growfldtab(i);
|
||||
if (freeable(fldtab[i]))
|
||||
xfree(fldtab[i]->sval);
|
||||
fldtab[i]->tval = FLD | STR | DONTFREE;
|
||||
fldtab[i]->sval = fr;
|
||||
dprintf( ("refldbld: i=%d\n", i) );
|
||||
if (nematch(p, rec, rec)) {
|
||||
dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
|
||||
strncpy(fr, rec, patbeg-rec);
|
||||
fr += patbeg - rec + 1;
|
||||
*(fr-1) = '\0';
|
||||
rec = patbeg + patlen;
|
||||
} else {
|
||||
dprintf( ("no match %s\n", rec) );
|
||||
strcpy(fr, rec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void recbld(void) /* create $0 from $1..$NF if necessary */
|
||||
{
|
||||
int i;
|
||||
char *r, *p;
|
||||
|
||||
if (donerec == 1)
|
||||
return;
|
||||
r = record;
|
||||
for (i = 1; i <= *NF; i++) {
|
||||
p = getsval(fldtab[i]);
|
||||
if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
|
||||
FATAL("created $0 `%.30s...' too long", record);
|
||||
while ((*r = *p++) != 0)
|
||||
r++;
|
||||
if (i < *NF) {
|
||||
if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
|
||||
FATAL("created $0 `%.30s...' too long", record);
|
||||
for (p = *OFS; (*r = *p++) != 0; )
|
||||
r++;
|
||||
}
|
||||
}
|
||||
if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
|
||||
FATAL("built giant record `%.30s...'", record);
|
||||
*r = '\0';
|
||||
dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
|
||||
|
||||
if (freeable(fldtab[0]))
|
||||
xfree(fldtab[0]->sval);
|
||||
fldtab[0]->tval = REC | STR | DONTFREE;
|
||||
fldtab[0]->sval = record;
|
||||
|
||||
dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
|
||||
dprintf( ("recbld = |%s|\n", record) );
|
||||
donerec = 1;
|
||||
}
|
||||
|
||||
int errorflag = 0;
|
||||
|
||||
void yyerror(char *s)
|
||||
{
|
||||
SYNTAX(s);
|
||||
}
|
||||
|
||||
void SYNTAX(char *fmt, ...)
|
||||
{
|
||||
extern char *cmdname, *curfname;
|
||||
static int been_here = 0;
|
||||
va_list varg;
|
||||
|
||||
if (been_here++ > 2)
|
||||
return;
|
||||
fprintf(stderr, "%s: ", cmdname);
|
||||
va_start(varg, fmt);
|
||||
vfprintf(stderr, fmt, varg);
|
||||
va_end(varg);
|
||||
if(compile_time == 1 && cursource() != NULL)
|
||||
fprintf(stderr, " at %s:%d", cursource(), lineno);
|
||||
else
|
||||
fprintf(stderr, " at line %d", lineno);
|
||||
if (curfname != NULL)
|
||||
fprintf(stderr, " in function %s", curfname);
|
||||
fprintf(stderr, "\n");
|
||||
errorflag = 2;
|
||||
eprint();
|
||||
}
|
||||
|
||||
void fpecatch(int n)
|
||||
{
|
||||
FATAL("floating point exception %d", n);
|
||||
}
|
||||
|
||||
extern int bracecnt, brackcnt, parencnt;
|
||||
|
||||
void bracecheck(void)
|
||||
{
|
||||
int c;
|
||||
static int beenhere = 0;
|
||||
|
||||
if (beenhere++)
|
||||
return;
|
||||
while ((c = input()) != EOF && c != '\0')
|
||||
bclass(c);
|
||||
bcheck2(bracecnt, '{', '}');
|
||||
bcheck2(brackcnt, '[', ']');
|
||||
bcheck2(parencnt, '(', ')');
|
||||
}
|
||||
|
||||
void bcheck2(int n, int c1, int c2)
|
||||
{
|
||||
if (n == 1)
|
||||
fprintf(stderr, "\tmissing %c\n", c2);
|
||||
else if (n > 1)
|
||||
fprintf(stderr, "\t%d missing %c's\n", n, c2);
|
||||
else if (n == -1)
|
||||
fprintf(stderr, "\textra %c\n", c2);
|
||||
else if (n < -1)
|
||||
fprintf(stderr, "\t%d extra %c's\n", -n, c2);
|
||||
}
|
||||
|
||||
void FATAL(char *fmt, ...)
|
||||
{
|
||||
extern char *cmdname;
|
||||
va_list varg;
|
||||
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "%s: ", cmdname);
|
||||
va_start(varg, fmt);
|
||||
vfprintf(stderr, fmt, varg);
|
||||
va_end(varg);
|
||||
error();
|
||||
if (dbg > 1) /* core dump if serious debugging on */
|
||||
abort();
|
||||
exit(2);
|
||||
}
|
||||
|
||||
void WARNING(char *fmt, ...)
|
||||
{
|
||||
extern char *cmdname;
|
||||
va_list varg;
|
||||
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "%s: ", cmdname);
|
||||
va_start(varg, fmt);
|
||||
vfprintf(stderr, fmt, varg);
|
||||
va_end(varg);
|
||||
error();
|
||||
}
|
||||
|
||||
void error()
|
||||
{
|
||||
extern Node *curnode;
|
||||
int line;
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
if (compile_time != 2 && NR && *NR > 0) {
|
||||
if (strcmp(*FILENAME, "-") != 0)
|
||||
fprintf(stderr, " input record %s:%d", *FILENAME, (int) (*FNR));
|
||||
else
|
||||
fprintf(stderr, " input record number %d", (int) (*FNR));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
if (compile_time != 2 && curnode)
|
||||
line = curnode->lineno;
|
||||
else if (compile_time != 2 && lineno)
|
||||
line = lineno;
|
||||
else
|
||||
line = -1;
|
||||
if (compile_time == 1 && cursource() != NULL){
|
||||
if(line >= 0)
|
||||
fprintf(stderr, " source %s:%d", cursource(), line);
|
||||
else
|
||||
fprintf(stderr, " source file %s", cursource());
|
||||
}else if(line >= 0)
|
||||
fprintf(stderr, " source line %d", line);
|
||||
fprintf(stderr, "\n");
|
||||
eprint();
|
||||
}
|
||||
|
||||
void eprint(void) /* try to print context around error */
|
||||
{
|
||||
char *p, *q;
|
||||
int c;
|
||||
static int been_here = 0;
|
||||
extern char ebuf[], *ep;
|
||||
|
||||
if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
|
||||
return;
|
||||
p = ep - 1;
|
||||
if (p > ebuf && *p == '\n')
|
||||
p--;
|
||||
for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
|
||||
;
|
||||
while (*p == '\n')
|
||||
p++;
|
||||
fprintf(stderr, " context is\n\t");
|
||||
for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
|
||||
;
|
||||
for ( ; p < q; p++)
|
||||
if (*p)
|
||||
putc(*p, stderr);
|
||||
fprintf(stderr, " >>> ");
|
||||
for ( ; p < ep; p++)
|
||||
if (*p)
|
||||
putc(*p, stderr);
|
||||
fprintf(stderr, " <<< ");
|
||||
if (*ep)
|
||||
while ((c = input()) != '\n' && c != '\0' && c != EOF) {
|
||||
putc(c, stderr);
|
||||
bclass(c);
|
||||
}
|
||||
putc('\n', stderr);
|
||||
ep = ebuf;
|
||||
}
|
||||
|
||||
void bclass(int c)
|
||||
{
|
||||
switch (c) {
|
||||
case '{': bracecnt++; break;
|
||||
case '}': bracecnt--; break;
|
||||
case '[': brackcnt++; break;
|
||||
case ']': brackcnt--; break;
|
||||
case '(': parencnt++; break;
|
||||
case ')': parencnt--; break;
|
||||
}
|
||||
}
|
||||
|
||||
double errcheck(double x, char *s)
|
||||
{
|
||||
|
||||
if (errno == EDOM) {
|
||||
errno = 0;
|
||||
WARNING("%s argument out of domain", s);
|
||||
x = 1;
|
||||
} else if (errno == ERANGE) {
|
||||
errno = 0;
|
||||
WARNING("%s result out of range", s);
|
||||
x = 1;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int isclvar(char *s) /* is s of form var=something ? */
|
||||
{
|
||||
char *os = s;
|
||||
|
||||
if (!isalpha(*s) && *s != '_')
|
||||
return 0;
|
||||
for ( ; *s; s++)
|
||||
if (!(isalnum(*s) || *s == '_'))
|
||||
break;
|
||||
return *s == '=' && s > os && *(s+1) != '=';
|
||||
}
|
||||
|
||||
/* strtod is supposed to be a proper test of what's a valid number */
|
||||
|
||||
#include <math.h>
|
||||
int is_number(char *s)
|
||||
{
|
||||
double r;
|
||||
char *ep;
|
||||
errno = 0;
|
||||
r = strtod(s, &ep);
|
||||
if (ep == s || r == HUGE_VAL || errno == ERANGE)
|
||||
return 0;
|
||||
while (*ep == ' ' || *ep == '\t' || *ep == '\n')
|
||||
ep++;
|
||||
if (*ep == '\0')
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
197
awk/main.c
Normal file
197
awk/main.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/****************************************************************
|
||||
Copyright (C) Lucent Technologies 1997
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name Lucent Technologies or any of
|
||||
its entities not be used in advertising or publicity pertaining
|
||||
to distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
****************************************************************/
|
||||
|
||||
char *version = "version 19990602";
|
||||
|
||||
#define DEBUG
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include "awk.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
extern char **environ;
|
||||
extern int nfields;
|
||||
|
||||
int dbg = 0;
|
||||
char *cmdname; /* gets argv[0] for error messages */
|
||||
extern FILE *yyin; /* lex input file */
|
||||
char *lexprog; /* points to program argument if it exists */
|
||||
extern int errorflag; /* non-zero if any syntax errors; set by yyerror */
|
||||
int compile_time = 2; /* for error printing: */
|
||||
/* 2 = cmdline, 1 = compile, 0 = running */
|
||||
|
||||
char *pfile[20]; /* program filenames from -f's */
|
||||
int npfile = 0; /* number of filenames */
|
||||
int curpfile = 0; /* current filename */
|
||||
|
||||
int safe = 0; /* 1 => "safe" mode */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *fs = NULL, *marg;
|
||||
int temp;
|
||||
|
||||
cmdname = argv[0];
|
||||
if (argc == 1) {
|
||||
fprintf(stderr, "Usage: %s [-f programfile | 'program'] [-Ffieldsep] [-v var=value] [files]\n", cmdname);
|
||||
exit(1);
|
||||
}
|
||||
signal(SIGFPE, fpecatch);
|
||||
yyin = NULL;
|
||||
symtab = makesymtab(NSYMTAB);
|
||||
while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
|
||||
if (strcmp(argv[1], "--") == 0) { /* explicit end of args */
|
||||
argc--;
|
||||
argv++;
|
||||
break;
|
||||
}
|
||||
switch (argv[1][1]) {
|
||||
case 's':
|
||||
if (strcmp(argv[1], "-safe") == 0)
|
||||
safe = 1;
|
||||
break;
|
||||
case 'f': /* next argument is program filename */
|
||||
argc--;
|
||||
argv++;
|
||||
if (argc <= 1)
|
||||
FATAL("no program filename");
|
||||
pfile[npfile++] = argv[1];
|
||||
break;
|
||||
case 'F': /* set field separator */
|
||||
if (argv[1][2] != 0) { /* arg is -Fsomething */
|
||||
if (argv[1][2] == 't' && argv[1][3] == 0) /* wart: t=>\t */
|
||||
fs = "\t";
|
||||
else if (argv[1][2] != 0)
|
||||
fs = &argv[1][2];
|
||||
} else { /* arg is -F something */
|
||||
argc--; argv++;
|
||||
if (argc > 1 && argv[1][0] == 't' && argv[1][1] == 0) /* wart: t=>\t */
|
||||
fs = "\t";
|
||||
else if (argc > 1 && argv[1][0] != 0)
|
||||
fs = &argv[1][0];
|
||||
}
|
||||
if (fs == NULL || *fs == '\0')
|
||||
WARNING("field separator FS is empty");
|
||||
break;
|
||||
case 'v': /* -v a=1 to be done NOW. one -v for each */
|
||||
if (argv[1][2] == '\0' && --argc > 1 && isclvar((++argv)[1]))
|
||||
setclvar(argv[1]);
|
||||
break;
|
||||
case 'm': /* more memory: -mr=record, -mf=fields */
|
||||
/* no longer needed */
|
||||
marg = argv[1];
|
||||
if (argv[1][3])
|
||||
temp = atoi(&argv[1][3]);
|
||||
else {
|
||||
argv++; argc--;
|
||||
temp = atoi(&argv[1][0]);
|
||||
}
|
||||
switch (marg[2]) {
|
||||
case 'r': recsize = temp; break;
|
||||
case 'f': nfields = temp; break;
|
||||
default: FATAL("unknown option %s\n", marg);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
dbg = atoi(&argv[1][2]);
|
||||
if (dbg == 0)
|
||||
dbg = 1;
|
||||
printf("awk %s\n", version);
|
||||
break;
|
||||
case 'V': /* added for exptools "standard" */
|
||||
printf("awk %s\n", version);
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
WARNING("unknown option %s ignored", argv[1]);
|
||||
break;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
/* argv[1] is now the first argument */
|
||||
if (npfile == 0) { /* no -f; first argument is program */
|
||||
if (argc <= 1) {
|
||||
if (dbg)
|
||||
exit(0);
|
||||
FATAL("no program given");
|
||||
}
|
||||
dprintf( ("program = |%s|\n", argv[1]) );
|
||||
lexprog = argv[1];
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
recinit(recsize);
|
||||
syminit();
|
||||
compile_time = 1;
|
||||
argv[0] = cmdname; /* put prog name at front of arglist */
|
||||
dprintf( ("argc=%d, argv[0]=%s\n", argc, argv[0]) );
|
||||
arginit(argc, argv);
|
||||
if (!safe)
|
||||
envinit(environ);
|
||||
yyparse();
|
||||
if (fs)
|
||||
*FS = qstring(fs, '\0');
|
||||
dprintf( ("errorflag=%d\n", errorflag) );
|
||||
if (errorflag == 0) {
|
||||
compile_time = 0;
|
||||
run(winner);
|
||||
} else
|
||||
bracecheck();
|
||||
return(errorflag);
|
||||
}
|
||||
|
||||
int pgetc(void) /* get 1 character from awk program */
|
||||
{
|
||||
int c;
|
||||
|
||||
for (;;) {
|
||||
if (yyin == NULL) {
|
||||
if (curpfile >= npfile)
|
||||
return EOF;
|
||||
if (strcmp(pfile[curpfile], "-") == 0)
|
||||
yyin = stdin;
|
||||
else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
|
||||
FATAL("can't open file %s", pfile[curpfile]);
|
||||
lineno = 1;
|
||||
}
|
||||
if ((c = getc(yyin)) != EOF)
|
||||
return c;
|
||||
if (yyin != stdin)
|
||||
fclose(yyin);
|
||||
yyin = NULL;
|
||||
curpfile++;
|
||||
}
|
||||
}
|
||||
|
||||
char *cursource(void) /* current source file name */
|
||||
{
|
||||
if (npfile > 0)
|
||||
return pfile[curpfile];
|
||||
else
|
||||
return NULL;
|
||||
}
|
168
awk/maketab.c
Normal file
168
awk/maketab.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/****************************************************************
|
||||
Copyright (C) Lucent Technologies 1997
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name Lucent Technologies or any of
|
||||
its entities not be used in advertising or publicity pertaining
|
||||
to distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
****************************************************************/
|
||||
|
||||
/*
|
||||
* this program makes the table to link function names
|
||||
* and type indices that is used by execute() in run.c.
|
||||
* it finds the indices in y.tab.h, produced by yacc.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "awk.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
struct xx
|
||||
{ int token;
|
||||
char *name;
|
||||
char *pname;
|
||||
} proc[] = {
|
||||
{ PROGRAM, "program", NULL },
|
||||
{ BOR, "boolop", " || " },
|
||||
{ AND, "boolop", " && " },
|
||||
{ NOT, "boolop", " !" },
|
||||
{ NE, "relop", " != " },
|
||||
{ EQ, "relop", " == " },
|
||||
{ LE, "relop", " <= " },
|
||||
{ LT, "relop", " < " },
|
||||
{ GE, "relop", " >= " },
|
||||
{ GT, "relop", " > " },
|
||||
{ ARRAY, "array", NULL },
|
||||
{ INDIRECT, "indirect", "$(" },
|
||||
{ SUBSTR, "substr", "substr" },
|
||||
{ SUB, "sub", "sub" },
|
||||
{ GSUB, "gsub", "gsub" },
|
||||
{ INDEX, "sindex", "sindex" },
|
||||
{ SPRINTF, "awksprintf", "sprintf " },
|
||||
{ ADD, "arith", " + " },
|
||||
{ MINUS, "arith", " - " },
|
||||
{ MULT, "arith", " * " },
|
||||
{ DIVIDE, "arith", " / " },
|
||||
{ MOD, "arith", " % " },
|
||||
{ UMINUS, "arith", " -" },
|
||||
{ POWER, "arith", " **" },
|
||||
{ PREINCR, "incrdecr", "++" },
|
||||
{ POSTINCR, "incrdecr", "++" },
|
||||
{ PREDECR, "incrdecr", "--" },
|
||||
{ POSTDECR, "incrdecr", "--" },
|
||||
{ CAT, "cat", " " },
|
||||
{ PASTAT, "pastat", NULL },
|
||||
{ PASTAT2, "dopa2", NULL },
|
||||
{ MATCH, "matchop", " ~ " },
|
||||
{ NOTMATCH, "matchop", " !~ " },
|
||||
{ MATCHFCN, "matchop", "matchop" },
|
||||
{ INTEST, "intest", "intest" },
|
||||
{ PRINTF, "awkprintf", "printf" },
|
||||
{ PRINT, "printstat", "print" },
|
||||
{ CLOSE, "closefile", "closefile" },
|
||||
{ DELETE, "awkdelete", "awkdelete" },
|
||||
{ SPLIT, "split", "split" },
|
||||
{ ASSIGN, "assign", " = " },
|
||||
{ ADDEQ, "assign", " += " },
|
||||
{ SUBEQ, "assign", " -= " },
|
||||
{ MULTEQ, "assign", " *= " },
|
||||
{ DIVEQ, "assign", " /= " },
|
||||
{ MODEQ, "assign", " %= " },
|
||||
{ POWEQ, "assign", " ^= " },
|
||||
{ CONDEXPR, "condexpr", " ?: " },
|
||||
{ IF, "ifstat", "if(" },
|
||||
{ WHILE, "whilestat", "while(" },
|
||||
{ FOR, "forstat", "for(" },
|
||||
{ DO, "dostat", "do" },
|
||||
{ IN, "instat", "instat" },
|
||||
{ NEXT, "jump", "next" },
|
||||
{ NEXTFILE, "jump", "nextfile" },
|
||||
{ EXIT, "jump", "exit" },
|
||||
{ BREAK, "jump", "break" },
|
||||
{ CONTINUE, "jump", "continue" },
|
||||
{ RETURN, "jump", "ret" },
|
||||
{ BLTIN, "bltin", "bltin" },
|
||||
{ CALL, "call", "call" },
|
||||
{ ARG, "arg", "arg" },
|
||||
{ VARNF, "getnf", "NF" },
|
||||
{ GETLINE, "getline", "getline" },
|
||||
{ 0, "", "" },
|
||||
};
|
||||
|
||||
#define SIZE (LASTTOKEN - FIRSTTOKEN + 1)
|
||||
char *table[SIZE];
|
||||
char *names[SIZE];
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct xx *p;
|
||||
int i, n, tok;
|
||||
char c;
|
||||
FILE *fp;
|
||||
char buf[200], name[200], def[200];
|
||||
|
||||
printf("#include <stdio.h>\n");
|
||||
printf("#include \"awk.h\"\n");
|
||||
printf("#include \"y.tab.h\"\n\n");
|
||||
for (i = SIZE; --i >= 0; )
|
||||
names[i] = "";
|
||||
|
||||
if ((fp = fopen("y.tab.h", "r")) == NULL) {
|
||||
fprintf(stderr, "maketab can't open y.tab.h!\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("static char *printname[%d] = {\n", SIZE);
|
||||
i = 0;
|
||||
while (fgets(buf, sizeof buf, fp) != NULL) {
|
||||
n = sscanf(buf, "%1c %s %s %d", &c, def, name, &tok);
|
||||
if (c != '#' || (n != 4 && strcmp(def,"define") != 0)) /* not a valid #define */
|
||||
continue;
|
||||
if (tok < FIRSTTOKEN || tok > LASTTOKEN) {
|
||||
fprintf(stderr, "maketab funny token %d %s\n", tok, buf);
|
||||
exit(1);
|
||||
}
|
||||
names[tok-FIRSTTOKEN] = (char *) malloc(strlen(name)+1);
|
||||
strcpy(names[tok-FIRSTTOKEN], name);
|
||||
printf("\t(char *) \"%s\",\t/* %d */\n", name, tok);
|
||||
i++;
|
||||
}
|
||||
printf("};\n\n");
|
||||
|
||||
for (p=proc; p->token!=0; p++)
|
||||
table[p->token-FIRSTTOKEN] = p->name;
|
||||
printf("\nCell *(*proctab[%d])(Node **, int) = {\n", SIZE);
|
||||
for (i=0; i<SIZE; i++)
|
||||
if (table[i]==0)
|
||||
printf("\tnullproc,\t/* %s */\n", names[i]);
|
||||
else
|
||||
printf("\t%s,\t/* %s */\n", table[i], names[i]);
|
||||
printf("};\n\n");
|
||||
|
||||
printf("char *tokname(int n)\n"); /* print a tokname() function */
|
||||
printf("{\n");
|
||||
printf(" static char buf[100];\n\n");
|
||||
printf(" if (n < FIRSTTOKEN || n > LASTTOKEN) {\n");
|
||||
printf(" sprintf(buf, \"token %%d\", n);\n");
|
||||
printf(" return buf;\n");
|
||||
printf(" }\n");
|
||||
printf(" return printname[n-FIRSTTOKEN];\n");
|
||||
printf("}\n");
|
||||
return 0;
|
||||
}
|
271
awk/parse.c
Normal file
271
awk/parse.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/****************************************************************
|
||||
Copyright (C) Lucent Technologies 1997
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name Lucent Technologies or any of
|
||||
its entities not be used in advertising or publicity pertaining
|
||||
to distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
****************************************************************/
|
||||
|
||||
#define DEBUG
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "awk.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
Node *nodealloc(int n)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = (Node *) malloc(sizeof(Node) + (n-1)*sizeof(Node *));
|
||||
if (x == NULL)
|
||||
FATAL("out of space in nodealloc");
|
||||
x->nnext = NULL;
|
||||
x->lineno = lineno;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *exptostat(Node *a)
|
||||
{
|
||||
a->ntype = NSTAT;
|
||||
return(a);
|
||||
}
|
||||
|
||||
Node *node1(int a, Node *b)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = nodealloc(1);
|
||||
x->nobj = a;
|
||||
x->narg[0]=b;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *node2(int a, Node *b, Node *c)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = nodealloc(2);
|
||||
x->nobj = a;
|
||||
x->narg[0] = b;
|
||||
x->narg[1] = c;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *node3(int a, Node *b, Node *c, Node *d)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = nodealloc(3);
|
||||
x->nobj = a;
|
||||
x->narg[0] = b;
|
||||
x->narg[1] = c;
|
||||
x->narg[2] = d;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *node4(int a, Node *b, Node *c, Node *d, Node *e)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = nodealloc(4);
|
||||
x->nobj = a;
|
||||
x->narg[0] = b;
|
||||
x->narg[1] = c;
|
||||
x->narg[2] = d;
|
||||
x->narg[3] = e;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *stat1(int a, Node *b)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = node1(a,b);
|
||||
x->ntype = NSTAT;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *stat2(int a, Node *b, Node *c)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = node2(a,b,c);
|
||||
x->ntype = NSTAT;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *stat3(int a, Node *b, Node *c, Node *d)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = node3(a,b,c,d);
|
||||
x->ntype = NSTAT;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *stat4(int a, Node *b, Node *c, Node *d, Node *e)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = node4(a,b,c,d,e);
|
||||
x->ntype = NSTAT;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *op1(int a, Node *b)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = node1(a,b);
|
||||
x->ntype = NEXPR;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *op2(int a, Node *b, Node *c)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = node2(a,b,c);
|
||||
x->ntype = NEXPR;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *op3(int a, Node *b, Node *c, Node *d)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = node3(a,b,c,d);
|
||||
x->ntype = NEXPR;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *op4(int a, Node *b, Node *c, Node *d, Node *e)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = node4(a,b,c,d,e);
|
||||
x->ntype = NEXPR;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *celltonode(Cell *a, int b)
|
||||
{
|
||||
Node *x;
|
||||
|
||||
a->ctype = OCELL;
|
||||
a->csub = b;
|
||||
x = node1(0, (Node *) a);
|
||||
x->ntype = NVALUE;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *rectonode(void) /* make $0 into a Node */
|
||||
{
|
||||
extern Cell *literal0;
|
||||
return op1(INDIRECT, celltonode(literal0, CUNK));
|
||||
}
|
||||
|
||||
Node *makearr(Node *p)
|
||||
{
|
||||
Cell *cp;
|
||||
|
||||
if (isvalue(p)) {
|
||||
cp = (Cell *) (p->narg[0]);
|
||||
if (isfcn(cp))
|
||||
SYNTAX( "%s is a function, not an array", cp->nval );
|
||||
else if (!isarr(cp)) {
|
||||
xfree(cp->sval);
|
||||
cp->sval = (char *) makesymtab(NSYMTAB);
|
||||
cp->tval = ARR;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#define PA2NUM 50 /* max number of pat,pat patterns allowed */
|
||||
int paircnt; /* number of them in use */
|
||||
int pairstack[PA2NUM]; /* state of each pat,pat */
|
||||
|
||||
Node *pa2stat(Node *a, Node *b, Node *c) /* pat, pat {...} */
|
||||
{
|
||||
Node *x;
|
||||
|
||||
x = node4(PASTAT2, a, b, c, itonp(paircnt));
|
||||
if (paircnt++ >= PA2NUM)
|
||||
SYNTAX( "limited to %d pat,pat statements", PA2NUM );
|
||||
x->ntype = NSTAT;
|
||||
return(x);
|
||||
}
|
||||
|
||||
Node *linkum(Node *a, Node *b)
|
||||
{
|
||||
Node *c;
|
||||
|
||||
if (errorflag) /* don't link things that are wrong */
|
||||
return a;
|
||||
if (a == NULL)
|
||||
return(b);
|
||||
else if (b == NULL)
|
||||
return(a);
|
||||
for (c = a; c->nnext != NULL; c = c->nnext)
|
||||
;
|
||||
c->nnext = b;
|
||||
return(a);
|
||||
}
|
||||
|
||||
void defn(Cell *v, Node *vl, Node *st) /* turn on FCN bit in definition, */
|
||||
{ /* body of function, arglist */
|
||||
Node *p;
|
||||
int n;
|
||||
|
||||
if (isarr(v)) {
|
||||
SYNTAX( "`%s' is an array name and a function name", v->nval );
|
||||
return;
|
||||
}
|
||||
v->tval = FCN;
|
||||
v->sval = (char *) st;
|
||||
n = 0; /* count arguments */
|
||||
for (p = vl; p; p = p->nnext)
|
||||
n++;
|
||||
v->fval = n;
|
||||
dprintf( ("defining func %s (%d args)\n", v->nval, n) );
|
||||
}
|
||||
|
||||
int isarg(char *s) /* is s in argument list for current function? */
|
||||
{ /* return -1 if not, otherwise arg # */
|
||||
extern Node *arglist;
|
||||
Node *p = arglist;
|
||||
int n;
|
||||
|
||||
for (n = 0; p != 0; p = p->nnext, n++)
|
||||
if (strcmp(((Cell *)(p->narg[0]))->nval, s) == 0)
|
||||
return n;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ptoi(void *p) /* convert pointer to integer */
|
||||
{
|
||||
return (int) (long) p; /* swearing that p fits, of course */
|
||||
}
|
||||
|
||||
Node *itonp(int i) /* and vice versa */
|
||||
{
|
||||
return (Node *) (long) i;
|
||||
}
|
206
awk/proctab.c
Normal file
206
awk/proctab.c
Normal file
@@ -0,0 +1,206 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "awk.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
static char *printname[92] = {
|
||||
(char *) "FIRSTTOKEN", /* 57346 */
|
||||
(char *) "PROGRAM", /* 57347 */
|
||||
(char *) "PASTAT", /* 57348 */
|
||||
(char *) "PASTAT2", /* 57349 */
|
||||
(char *) "XBEGIN", /* 57350 */
|
||||
(char *) "XEND", /* 57351 */
|
||||
(char *) "NL", /* 57352 */
|
||||
(char *) "ARRAY", /* 57353 */
|
||||
(char *) "MATCH", /* 57354 */
|
||||
(char *) "NOTMATCH", /* 57355 */
|
||||
(char *) "MATCHOP", /* 57356 */
|
||||
(char *) "FINAL", /* 57357 */
|
||||
(char *) "DOT", /* 57358 */
|
||||
(char *) "ALL", /* 57359 */
|
||||
(char *) "CCL", /* 57360 */
|
||||
(char *) "NCCL", /* 57361 */
|
||||
(char *) "CHAR", /* 57362 */
|
||||
(char *) "OR", /* 57363 */
|
||||
(char *) "STAR", /* 57364 */
|
||||
(char *) "QUEST", /* 57365 */
|
||||
(char *) "PLUS", /* 57366 */
|
||||
(char *) "AND", /* 57367 */
|
||||
(char *) "BOR", /* 57368 */
|
||||
(char *) "APPEND", /* 57369 */
|
||||
(char *) "EQ", /* 57370 */
|
||||
(char *) "GE", /* 57371 */
|
||||
(char *) "GT", /* 57372 */
|
||||
(char *) "LE", /* 57373 */
|
||||
(char *) "LT", /* 57374 */
|
||||
(char *) "NE", /* 57375 */
|
||||
(char *) "IN", /* 57376 */
|
||||
(char *) "ARG", /* 57377 */
|
||||
(char *) "BLTIN", /* 57378 */
|
||||
(char *) "BREAK", /* 57379 */
|
||||
(char *) "CLOSE", /* 57380 */
|
||||
(char *) "CONTINUE", /* 57381 */
|
||||
(char *) "DELETE", /* 57382 */
|
||||
(char *) "DO", /* 57383 */
|
||||
(char *) "EXIT", /* 57384 */
|
||||
(char *) "FOR", /* 57385 */
|
||||
(char *) "FUNC", /* 57386 */
|
||||
(char *) "SUB", /* 57387 */
|
||||
(char *) "GSUB", /* 57388 */
|
||||
(char *) "IF", /* 57389 */
|
||||
(char *) "INDEX", /* 57390 */
|
||||
(char *) "LSUBSTR", /* 57391 */
|
||||
(char *) "MATCHFCN", /* 57392 */
|
||||
(char *) "NEXT", /* 57393 */
|
||||
(char *) "NEXTFILE", /* 57394 */
|
||||
(char *) "ADD", /* 57395 */
|
||||
(char *) "MINUS", /* 57396 */
|
||||
(char *) "MULT", /* 57397 */
|
||||
(char *) "DIVIDE", /* 57398 */
|
||||
(char *) "MOD", /* 57399 */
|
||||
(char *) "ASSIGN", /* 57400 */
|
||||
(char *) "ASGNOP", /* 57401 */
|
||||
(char *) "ADDEQ", /* 57402 */
|
||||
(char *) "SUBEQ", /* 57403 */
|
||||
(char *) "MULTEQ", /* 57404 */
|
||||
(char *) "DIVEQ", /* 57405 */
|
||||
(char *) "MODEQ", /* 57406 */
|
||||
(char *) "POWEQ", /* 57407 */
|
||||
(char *) "PRINT", /* 57408 */
|
||||
(char *) "PRINTF", /* 57409 */
|
||||
(char *) "SPRINTF", /* 57410 */
|
||||
(char *) "ELSE", /* 57411 */
|
||||
(char *) "INTEST", /* 57412 */
|
||||
(char *) "CONDEXPR", /* 57413 */
|
||||
(char *) "POSTINCR", /* 57414 */
|
||||
(char *) "PREINCR", /* 57415 */
|
||||
(char *) "POSTDECR", /* 57416 */
|
||||
(char *) "PREDECR", /* 57417 */
|
||||
(char *) "VAR", /* 57418 */
|
||||
(char *) "IVAR", /* 57419 */
|
||||
(char *) "VARNF", /* 57420 */
|
||||
(char *) "CALL", /* 57421 */
|
||||
(char *) "NUMBER", /* 57422 */
|
||||
(char *) "STRING", /* 57423 */
|
||||
(char *) "REGEXPR", /* 57424 */
|
||||
(char *) "GETLINE", /* 57425 */
|
||||
(char *) "RETURN", /* 57426 */
|
||||
(char *) "SPLIT", /* 57427 */
|
||||
(char *) "SUBSTR", /* 57428 */
|
||||
(char *) "WHILE", /* 57429 */
|
||||
(char *) "CAT", /* 57430 */
|
||||
(char *) "NOT", /* 57431 */
|
||||
(char *) "UMINUS", /* 57432 */
|
||||
(char *) "POWER", /* 57433 */
|
||||
(char *) "DECR", /* 57434 */
|
||||
(char *) "INCR", /* 57435 */
|
||||
(char *) "INDIRECT", /* 57436 */
|
||||
(char *) "LASTTOKEN", /* 57437 */
|
||||
};
|
||||
|
||||
|
||||
Cell *(*proctab[92])(Node **, int) = {
|
||||
nullproc, /* FIRSTTOKEN */
|
||||
program, /* PROGRAM */
|
||||
pastat, /* PASTAT */
|
||||
dopa2, /* PASTAT2 */
|
||||
nullproc, /* XBEGIN */
|
||||
nullproc, /* XEND */
|
||||
nullproc, /* NL */
|
||||
array, /* ARRAY */
|
||||
matchop, /* MATCH */
|
||||
matchop, /* NOTMATCH */
|
||||
nullproc, /* MATCHOP */
|
||||
nullproc, /* FINAL */
|
||||
nullproc, /* DOT */
|
||||
nullproc, /* ALL */
|
||||
nullproc, /* CCL */
|
||||
nullproc, /* NCCL */
|
||||
nullproc, /* CHAR */
|
||||
nullproc, /* OR */
|
||||
nullproc, /* STAR */
|
||||
nullproc, /* QUEST */
|
||||
nullproc, /* PLUS */
|
||||
boolop, /* AND */
|
||||
boolop, /* BOR */
|
||||
nullproc, /* APPEND */
|
||||
relop, /* EQ */
|
||||
relop, /* GE */
|
||||
relop, /* GT */
|
||||
relop, /* LE */
|
||||
relop, /* LT */
|
||||
relop, /* NE */
|
||||
instat, /* IN */
|
||||
arg, /* ARG */
|
||||
bltin, /* BLTIN */
|
||||
jump, /* BREAK */
|
||||
closefile, /* CLOSE */
|
||||
jump, /* CONTINUE */
|
||||
awkdelete, /* DELETE */
|
||||
dostat, /* DO */
|
||||
jump, /* EXIT */
|
||||
forstat, /* FOR */
|
||||
nullproc, /* FUNC */
|
||||
sub, /* SUB */
|
||||
gsub, /* GSUB */
|
||||
ifstat, /* IF */
|
||||
sindex, /* INDEX */
|
||||
nullproc, /* LSUBSTR */
|
||||
matchop, /* MATCHFCN */
|
||||
jump, /* NEXT */
|
||||
jump, /* NEXTFILE */
|
||||
arith, /* ADD */
|
||||
arith, /* MINUS */
|
||||
arith, /* MULT */
|
||||
arith, /* DIVIDE */
|
||||
arith, /* MOD */
|
||||
assign, /* ASSIGN */
|
||||
nullproc, /* ASGNOP */
|
||||
assign, /* ADDEQ */
|
||||
assign, /* SUBEQ */
|
||||
assign, /* MULTEQ */
|
||||
assign, /* DIVEQ */
|
||||
assign, /* MODEQ */
|
||||
assign, /* POWEQ */
|
||||
printstat, /* PRINT */
|
||||
awkprintf, /* PRINTF */
|
||||
awksprintf, /* SPRINTF */
|
||||
nullproc, /* ELSE */
|
||||
intest, /* INTEST */
|
||||
condexpr, /* CONDEXPR */
|
||||
incrdecr, /* POSTINCR */
|
||||
incrdecr, /* PREINCR */
|
||||
incrdecr, /* POSTDECR */
|
||||
incrdecr, /* PREDECR */
|
||||
nullproc, /* VAR */
|
||||
nullproc, /* IVAR */
|
||||
getnf, /* VARNF */
|
||||
call, /* CALL */
|
||||
nullproc, /* NUMBER */
|
||||
nullproc, /* STRING */
|
||||
nullproc, /* REGEXPR */
|
||||
getline, /* GETLINE */
|
||||
jump, /* RETURN */
|
||||
split, /* SPLIT */
|
||||
substr, /* SUBSTR */
|
||||
whilestat, /* WHILE */
|
||||
cat, /* CAT */
|
||||
boolop, /* NOT */
|
||||
arith, /* UMINUS */
|
||||
arith, /* POWER */
|
||||
nullproc, /* DECR */
|
||||
nullproc, /* INCR */
|
||||
indirect, /* INDIRECT */
|
||||
nullproc, /* LASTTOKEN */
|
||||
};
|
||||
|
||||
char *tokname(int n)
|
||||
{
|
||||
static char buf[100];
|
||||
|
||||
if (n < FIRSTTOKEN || n > LASTTOKEN) {
|
||||
sprintf(buf, "token %d", n);
|
||||
return buf;
|
||||
}
|
||||
return printname[n-FIRSTTOKEN];
|
||||
}
|
177
awk/proto.h
Normal file
177
awk/proto.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/****************************************************************
|
||||
Copyright (C) Lucent Technologies 1997
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name Lucent Technologies or any of
|
||||
its entities not be used in advertising or publicity pertaining
|
||||
to distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
****************************************************************/
|
||||
|
||||
extern int yywrap(void);
|
||||
extern void setfname(Cell *);
|
||||
extern int constnode(Node *);
|
||||
extern char *strnode(Node *);
|
||||
extern Node *notnull(Node *);
|
||||
extern int yyparse(void);
|
||||
|
||||
extern int yylex(void);
|
||||
extern void startreg(void);
|
||||
extern int input(void);
|
||||
extern void unput(int);
|
||||
extern void unputstr(char *);
|
||||
extern int yylook(void);
|
||||
extern int yyback(int *, int);
|
||||
extern int yyinput(void);
|
||||
|
||||
extern void *compre(char *);
|
||||
extern int hexstr(char **);
|
||||
extern void quoted(char **, char **, char *);
|
||||
extern int match(void *, char *, char *);
|
||||
extern int pmatch(void *, char *, char *);
|
||||
extern int nematch(void *, char *, char *);
|
||||
extern int countposn(char *, int);
|
||||
extern void overflow(void);
|
||||
|
||||
extern int pgetc(void);
|
||||
extern char *cursource(void);
|
||||
|
||||
extern Node *nodealloc(int);
|
||||
extern Node *exptostat(Node *);
|
||||
extern Node *node1(int, Node *);
|
||||
extern Node *node2(int, Node *, Node *);
|
||||
extern Node *node3(int, Node *, Node *, Node *);
|
||||
extern Node *node4(int, Node *, Node *, Node *, Node *);
|
||||
extern Node *stat3(int, Node *, Node *, Node *);
|
||||
extern Node *op2(int, Node *, Node *);
|
||||
extern Node *op1(int, Node *);
|
||||
extern Node *stat1(int, Node *);
|
||||
extern Node *op3(int, Node *, Node *, Node *);
|
||||
extern Node *op4(int, Node *, Node *, Node *, Node *);
|
||||
extern Node *stat2(int, Node *, Node *);
|
||||
extern Node *stat4(int, Node *, Node *, Node *, Node *);
|
||||
extern Node *celltonode(Cell *, int);
|
||||
extern Node *rectonode(void);
|
||||
extern Node *makearr(Node *);
|
||||
extern Node *pa2stat(Node *, Node *, Node *);
|
||||
extern Node *linkum(Node *, Node *);
|
||||
extern void defn(Cell *, Node *, Node *);
|
||||
extern int isarg(char *);
|
||||
extern char *tokname(int);
|
||||
extern Cell *(*proctab[])(Node **, int);
|
||||
extern int ptoi(void *);
|
||||
extern Node *itonp(int);
|
||||
|
||||
extern void syminit(void);
|
||||
extern void arginit(int, char **);
|
||||
extern void envinit(char **);
|
||||
extern Array *makesymtab(int);
|
||||
extern void freesymtab(Cell *);
|
||||
extern void freeelem(Cell *, char *);
|
||||
extern Cell *setsymtab(char *, char *, double, unsigned int, Array *);
|
||||
extern int hash(char *, int);
|
||||
extern void rehash(Array *);
|
||||
extern Cell *lookup(char *, Array *);
|
||||
extern double setfval(Cell *, double);
|
||||
extern void funnyvar(Cell *, char *);
|
||||
extern char *setsval(Cell *, char *);
|
||||
extern double getfval(Cell *);
|
||||
extern char *getsval(Cell *);
|
||||
extern char *tostring(char *);
|
||||
extern char *qstring(char *, int);
|
||||
|
||||
extern void recinit(unsigned int);
|
||||
extern void initgetrec(void);
|
||||
extern void makefields(int, int);
|
||||
extern void growfldtab(int n);
|
||||
extern int getrec(char **, int *, int);
|
||||
extern void nextfile(void);
|
||||
extern int readrec(char **buf, int *bufsize, FILE *inf);
|
||||
extern char *getargv(int);
|
||||
extern void setclvar(char *);
|
||||
extern void fldbld(void);
|
||||
extern void cleanfld(int, int);
|
||||
extern void newfld(int);
|
||||
extern int refldbld(char *, char *);
|
||||
extern void recbld(void);
|
||||
extern Cell *fieldadr(int);
|
||||
extern void yyerror(char *);
|
||||
extern void fpecatch(int);
|
||||
extern void bracecheck(void);
|
||||
extern void bcheck2(int, int, int);
|
||||
extern void SYNTAX(char *, ...);
|
||||
extern void FATAL(char *, ...);
|
||||
extern void WARNING(char *, ...);
|
||||
extern void error(void);
|
||||
extern void eprint(void);
|
||||
extern void bclass(int);
|
||||
extern double errcheck(double, char *);
|
||||
extern int isclvar(char *);
|
||||
extern int is_number(char *);
|
||||
|
||||
extern int adjbuf(char **pb, int *sz, int min, int q, char **pbp, char *what);
|
||||
extern void run(Node *);
|
||||
extern Cell *execute(Node *);
|
||||
extern Cell *program(Node **, int);
|
||||
extern Cell *call(Node **, int);
|
||||
extern Cell *copycell(Cell *);
|
||||
extern Cell *arg(Node **, int);
|
||||
extern Cell *jump(Node **, int);
|
||||
extern Cell *getline(Node **, int);
|
||||
extern Cell *getnf(Node **, int);
|
||||
extern Cell *array(Node **, int);
|
||||
extern Cell *awkdelete(Node **, int);
|
||||
extern Cell *intest(Node **, int);
|
||||
extern Cell *matchop(Node **, int);
|
||||
extern Cell *boolop(Node **, int);
|
||||
extern Cell *relop(Node **, int);
|
||||
extern void tfree(Cell *);
|
||||
extern Cell *gettemp(void);
|
||||
extern Cell *field(Node **, int);
|
||||
extern Cell *indirect(Node **, int);
|
||||
extern Cell *substr(Node **, int);
|
||||
extern Cell *sindex(Node **, int);
|
||||
extern int format(char **, int *, char *, Node *);
|
||||
extern Cell *awksprintf(Node **, int);
|
||||
extern Cell *awkprintf(Node **, int);
|
||||
extern Cell *arith(Node **, int);
|
||||
extern double ipow(double, int);
|
||||
extern Cell *incrdecr(Node **, int);
|
||||
extern Cell *assign(Node **, int);
|
||||
extern Cell *cat(Node **, int);
|
||||
extern Cell *pastat(Node **, int);
|
||||
extern Cell *dopa2(Node **, int);
|
||||
extern Cell *split(Node **, int);
|
||||
extern Cell *condexpr(Node **, int);
|
||||
extern Cell *ifstat(Node **, int);
|
||||
extern Cell *whilestat(Node **, int);
|
||||
extern Cell *dostat(Node **, int);
|
||||
extern Cell *forstat(Node **, int);
|
||||
extern Cell *instat(Node **, int);
|
||||
extern Cell *bltin(Node **, int);
|
||||
extern Cell *printstat(Node **, int);
|
||||
extern Cell *nullproc(Node **, int);
|
||||
extern FILE *redirect(int, Node *);
|
||||
extern FILE *openfile(int, char *);
|
||||
extern char *filename(FILE *);
|
||||
extern Cell *closefile(Node **, int);
|
||||
extern void closeall(void);
|
||||
extern Cell *sub(Node **, int);
|
||||
extern Cell *gsub(Node **, int);
|
||||
|
||||
extern FILE *popen(const char *, const char *);
|
||||
extern int pclose(FILE *);
|
325
awk/re.c
Normal file
325
awk/re.c
Normal file
@@ -0,0 +1,325 @@
|
||||
/****************************************************************
|
||||
Copyright (C) Lucent Technologies 1997
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name Lucent Technologies or any of
|
||||
its entities not be used in advertising or publicity pertaining
|
||||
to distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
****************************************************************/
|
||||
|
||||
|
||||
#define DEBUG
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <setjmp.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "awk.h"
|
||||
#include "y.tab.h"
|
||||
#include "regexp.h"
|
||||
|
||||
/* This file provides the interface between the main body of
|
||||
* awk and the pattern matching package. It preprocesses
|
||||
* patterns prior to compilation to provide awk-like semantics
|
||||
* to character sequences not supported by the pattern package.
|
||||
* The following conversions are performed:
|
||||
*
|
||||
* "()" -> "[]"
|
||||
* "[-" -> "[\-"
|
||||
* "[^-" -> "[^\-"
|
||||
* "-]" -> "\-]"
|
||||
* "[]" -> "[]*"
|
||||
* "\xdddd" -> "\z" where 'z' is the UTF sequence
|
||||
* for the hex value
|
||||
* "\ddd" -> "\o" where 'o' is a char octal value
|
||||
* "\b" -> "\B" where 'B' is backspace
|
||||
* "\t" -> "\T" where 'T' is tab
|
||||
* "\f" -> "\F" where 'F' is form feed
|
||||
* "\n" -> "\N" where 'N' is newline
|
||||
* "\r" -> "\r" where 'C' is cr
|
||||
*/
|
||||
|
||||
#define MAXRE 512
|
||||
|
||||
static char re[MAXRE]; /* copy buffer */
|
||||
|
||||
char *patbeg;
|
||||
int patlen; /* number of chars in pattern */
|
||||
|
||||
#define NPATS 20 /* number of slots in pattern cache */
|
||||
|
||||
static struct pat_list /* dynamic pattern cache */
|
||||
{
|
||||
char *re;
|
||||
int use;
|
||||
Reprog *program;
|
||||
} pattern[NPATS];
|
||||
|
||||
static int npats; /* cache fill level */
|
||||
|
||||
/* Compile a pattern */
|
||||
void
|
||||
*compre(char *pat)
|
||||
{
|
||||
int i, j, inclass;
|
||||
char c, *p, *s;
|
||||
Reprog *program;
|
||||
|
||||
if (!compile_time) { /* search cache for dynamic pattern */
|
||||
for (i = 0; i < npats; i++)
|
||||
if (!strcmp(pat, pattern[i].re)) {
|
||||
pattern[i].use++;
|
||||
return((void *) pattern[i].program);
|
||||
}
|
||||
}
|
||||
/* Preprocess Pattern for compilation */
|
||||
p = re;
|
||||
s = pat;
|
||||
inclass = 0;
|
||||
while (c = *s++) {
|
||||
if (c == '\\') {
|
||||
quoted(&s, &p, re+MAXRE);
|
||||
continue;
|
||||
}
|
||||
else if (!inclass && c == '(' && *s == ')') {
|
||||
if (p < re+MAXRE-2) { /* '()' -> '[]*' */
|
||||
*p++ = '[';
|
||||
*p++ = ']';
|
||||
c = '*';
|
||||
s++;
|
||||
}
|
||||
else overflow();
|
||||
}
|
||||
else if (c == '['){ /* '[-' -> '[\-' */
|
||||
inclass = 1;
|
||||
if (*s == '-') {
|
||||
if (p < re+MAXRE-2) {
|
||||
*p++ = '[';
|
||||
*p++ = '\\';
|
||||
c = *s++;
|
||||
}
|
||||
else overflow();
|
||||
} /* '[^-' -> '[^\-'*/
|
||||
else if (*s == '^' && s[1] == '-'){
|
||||
if (p < re+MAXRE-3) {
|
||||
*p++ = '[';
|
||||
*p++ = *s++;
|
||||
*p++ = '\\';
|
||||
c = *s++;
|
||||
}
|
||||
else overflow();
|
||||
}
|
||||
else if (*s == '['){ /* skip '[[' */
|
||||
if (p < re+MAXRE-1)
|
||||
*p++ = c;
|
||||
else overflow();
|
||||
c = *s++;
|
||||
}
|
||||
else if (*s == '^' && s[1] == '[') { /* skip '[^['*/
|
||||
if (p < re+MAXRE-2) {
|
||||
*p++ = c;
|
||||
*p++ = *s++;
|
||||
c = *s++;
|
||||
}
|
||||
else overflow();
|
||||
}
|
||||
else if (*s == ']') { /* '[]' -> '[]*' */
|
||||
if (p < re+MAXRE-2) {
|
||||
*p++ = c;
|
||||
*p++ = *s++;
|
||||
c = '*';
|
||||
inclass = 0;
|
||||
}
|
||||
else overflow();
|
||||
}
|
||||
}
|
||||
else if (c == '-' && *s == ']') { /* '-]' -> '\-]' */
|
||||
if (p < re+MAXRE-1)
|
||||
*p++ = '\\';
|
||||
else overflow();
|
||||
}
|
||||
else if (c == ']')
|
||||
inclass = 0;
|
||||
if (p < re+MAXRE-1)
|
||||
*p++ = c;
|
||||
else overflow();
|
||||
}
|
||||
*p = 0;
|
||||
program = regcomp(re); /* compile pattern */
|
||||
if (!compile_time) {
|
||||
if (npats < NPATS) /* Room in cache */
|
||||
i = npats++;
|
||||
else { /* Throw out least used */
|
||||
int use = pattern[0].use;
|
||||
i = 0;
|
||||
for (j = 1; j < NPATS; j++) {
|
||||
if (pattern[j].use < use) {
|
||||
use = pattern[j].use;
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
xfree(pattern[i].program);
|
||||
xfree(pattern[i].re);
|
||||
}
|
||||
pattern[i].re = tostring(pat);
|
||||
pattern[i].program = program;
|
||||
pattern[i].use = 1;
|
||||
}
|
||||
return((void *) program);
|
||||
}
|
||||
|
||||
/* T/F match indication - matched string not exported */
|
||||
int
|
||||
match(void *p, char *s, char *q)
|
||||
{
|
||||
return regexec((Reprog *) p, (char *) s, 0, 0);
|
||||
}
|
||||
|
||||
/* match and delimit the matched string */
|
||||
int
|
||||
pmatch(void *p, char *s, char *start)
|
||||
{
|
||||
Resub m;
|
||||
|
||||
m.s.sp = start;
|
||||
m.e.ep = 0;
|
||||
if (regexec((Reprog *) p, (char *) s, &m, 1)) {
|
||||
patbeg = m.s.sp;
|
||||
patlen = m.e.ep-m.s.sp;
|
||||
return 1;
|
||||
}
|
||||
patlen = -1;
|
||||
patbeg = start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* perform a non-empty match */
|
||||
int
|
||||
nematch(void *p, char *s, char *start)
|
||||
{
|
||||
if (pmatch(p, s, start) == 1 && patlen > 0)
|
||||
return 1;
|
||||
patlen = -1;
|
||||
patbeg = start;
|
||||
return 0;
|
||||
}
|
||||
/* in the parsing of regular expressions, metacharacters like . have */
|
||||
/* to be seen literally; \056 is not a metacharacter. */
|
||||
int
|
||||
hexstr(char **pp) /* find and eval hex string at pp, return new p */
|
||||
{
|
||||
int c;
|
||||
int n = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0, c = (*pp)[i]; i < 4 && isxdigit(c); i++, c = (*pp)[i]) {
|
||||
if (isdigit(c))
|
||||
n = 16 * n + c - '0';
|
||||
else if ('a' <= c && c <= 'f')
|
||||
n = 16 * n + c - 'a' + 10;
|
||||
else if ('A' <= c && c <= 'F')
|
||||
n = 16 * n + c - 'A' + 10;
|
||||
}
|
||||
*pp += i;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* look for awk-specific escape sequences */
|
||||
|
||||
#define isoctdigit(c) ((c) >= '0' && (c) <= '7') /* multiple use of arg */
|
||||
|
||||
void
|
||||
quoted(char **s, char **to, char *end) /* handle escaped sequence */
|
||||
{
|
||||
char *p = *s;
|
||||
char *t = *to;
|
||||
wchar_t c;
|
||||
|
||||
switch(c = *p++) {
|
||||
case 't':
|
||||
c = '\t';
|
||||
break;
|
||||
case 'n':
|
||||
c = '\n';
|
||||
break;
|
||||
case 'f':
|
||||
c = '\f';
|
||||
break;
|
||||
case 'r':
|
||||
c = '\r';
|
||||
break;
|
||||
case 'b':
|
||||
c = '\b';
|
||||
break;
|
||||
default:
|
||||
if (t < end-1) /* all else must be escaped */
|
||||
*t++ = '\\';
|
||||
if (c == 'x') { /* hexadecimal goo follows */
|
||||
c = hexstr(&p);
|
||||
if (t < end-MB_CUR_MAX)
|
||||
t += wctomb(t, c);
|
||||
else overflow();
|
||||
*to = t;
|
||||
*s = p;
|
||||
return;
|
||||
} else if (isoctdigit(c)) { /* \d \dd \ddd */
|
||||
c -= '0';
|
||||
if (isoctdigit(*p)) {
|
||||
c = 8 * c + *p++ - '0';
|
||||
if (isoctdigit(*p))
|
||||
c = 8 * c + *p++ - '0';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (t < end-1)
|
||||
*t++ = c;
|
||||
*s = p;
|
||||
*to = t;
|
||||
}
|
||||
/* count rune positions */
|
||||
int
|
||||
countposn(char *s, int n)
|
||||
{
|
||||
int i, j;
|
||||
char *end;
|
||||
|
||||
for (i = 0, end = s+n; *s && s < end; i++){
|
||||
j = mblen(s, n);
|
||||
if(j <= 0)
|
||||
j = 1;
|
||||
s += j;
|
||||
}
|
||||
return(i);
|
||||
}
|
||||
|
||||
/* pattern package error handler */
|
||||
|
||||
void
|
||||
regerror(char *s)
|
||||
{
|
||||
FATAL("%s", s);
|
||||
}
|
||||
|
||||
void
|
||||
overflow(void)
|
||||
{
|
||||
FATAL("%s", "regular expression too big");
|
||||
}
|
434
awk/tran.c
Normal file
434
awk/tran.c
Normal file
@@ -0,0 +1,434 @@
|
||||
/****************************************************************
|
||||
Copyright (C) Lucent Technologies 1997
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name Lucent Technologies or any of
|
||||
its entities not be used in advertising or publicity pertaining
|
||||
to distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
****************************************************************/
|
||||
|
||||
#define DEBUG
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "awk.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
#define FULLTAB 2 /* rehash when table gets this x full */
|
||||
#define GROWTAB 4 /* grow table by this factor */
|
||||
|
||||
Array *symtab; /* main symbol table */
|
||||
|
||||
char **FS; /* initial field sep */
|
||||
char **RS; /* initial record sep */
|
||||
char **OFS; /* output field sep */
|
||||
char **ORS; /* output record sep */
|
||||
char **OFMT; /* output format for numbers */
|
||||
char **CONVFMT; /* format for conversions in getsval */
|
||||
Awkfloat *NF; /* number of fields in current record */
|
||||
Awkfloat *NR; /* number of current record */
|
||||
Awkfloat *FNR; /* number of current record in current file */
|
||||
char **FILENAME; /* current filename argument */
|
||||
Awkfloat *ARGC; /* number of arguments from command line */
|
||||
char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
|
||||
Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
|
||||
Awkfloat *RLENGTH; /* length of same */
|
||||
|
||||
Cell *nrloc; /* NR */
|
||||
Cell *nfloc; /* NF */
|
||||
Cell *fnrloc; /* FNR */
|
||||
Array *ARGVtab; /* symbol table containing ARGV[...] */
|
||||
Array *ENVtab; /* symbol table containing ENVIRON[...] */
|
||||
Cell *rstartloc; /* RSTART */
|
||||
Cell *rlengthloc; /* RLENGTH */
|
||||
Cell *symtabloc; /* SYMTAB */
|
||||
|
||||
Cell *nullloc; /* a guaranteed empty cell */
|
||||
Node *nullnode; /* zero&null, converted into a node for comparisons */
|
||||
Cell *literal0;
|
||||
|
||||
extern Cell **fldtab;
|
||||
|
||||
void syminit(void) /* initialize symbol table with builtin vars */
|
||||
{
|
||||
literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
|
||||
/* this is used for if(x)... tests: */
|
||||
nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
|
||||
nullnode = celltonode(nullloc, CCON);
|
||||
|
||||
FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
|
||||
RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
|
||||
OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
|
||||
ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
|
||||
OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
|
||||
CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
|
||||
FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
|
||||
nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
|
||||
NF = &nfloc->fval;
|
||||
nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
|
||||
NR = &nrloc->fval;
|
||||
fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
|
||||
FNR = &fnrloc->fval;
|
||||
SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
|
||||
rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
|
||||
RSTART = &rstartloc->fval;
|
||||
rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
|
||||
RLENGTH = &rlengthloc->fval;
|
||||
symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
|
||||
symtabloc->sval = (char *) symtab;
|
||||
}
|
||||
|
||||
void arginit(int ac, char **av) /* set up ARGV and ARGC */
|
||||
{
|
||||
Cell *cp;
|
||||
int i;
|
||||
char temp[50];
|
||||
|
||||
ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
|
||||
cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
|
||||
ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
|
||||
cp->sval = (char *) ARGVtab;
|
||||
for (i = 0; i < ac; i++) {
|
||||
sprintf(temp, "%d", i);
|
||||
if (is_number(*av))
|
||||
setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
|
||||
else
|
||||
setsymtab(temp, *av, 0.0, STR, ARGVtab);
|
||||
av++;
|
||||
}
|
||||
}
|
||||
|
||||
void envinit(char **envp) /* set up ENVIRON variable */
|
||||
{
|
||||
Cell *cp;
|
||||
char *p;
|
||||
|
||||
cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
|
||||
ENVtab = makesymtab(NSYMTAB);
|
||||
cp->sval = (char *) ENVtab;
|
||||
for ( ; *envp; envp++) {
|
||||
if ((p = strchr(*envp, '=')) == NULL)
|
||||
continue;
|
||||
*p++ = 0; /* split into two strings at = */
|
||||
if (is_number(p))
|
||||
setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
|
||||
else
|
||||
setsymtab(*envp, p, 0.0, STR, ENVtab);
|
||||
p[-1] = '='; /* restore in case env is passed down to a shell */
|
||||
}
|
||||
}
|
||||
|
||||
Array *makesymtab(int n) /* make a new symbol table */
|
||||
{
|
||||
Array *ap;
|
||||
Cell **tp;
|
||||
|
||||
ap = (Array *) malloc(sizeof(Array));
|
||||
tp = (Cell **) calloc(n, sizeof(Cell *));
|
||||
if (ap == NULL || tp == NULL)
|
||||
FATAL("out of space in makesymtab");
|
||||
ap->nelem = 0;
|
||||
ap->size = n;
|
||||
ap->tab = tp;
|
||||
return(ap);
|
||||
}
|
||||
|
||||
void freesymtab(Cell *ap) /* free a symbol table */
|
||||
{
|
||||
Cell *cp, *temp;
|
||||
Array *tp;
|
||||
int i;
|
||||
|
||||
if (!isarr(ap))
|
||||
return;
|
||||
tp = (Array *) ap->sval;
|
||||
if (tp == NULL)
|
||||
return;
|
||||
for (i = 0; i < tp->size; i++) {
|
||||
for (cp = tp->tab[i]; cp != NULL; cp = temp) {
|
||||
xfree(cp->nval);
|
||||
if (freeable(cp))
|
||||
xfree(cp->sval);
|
||||
temp = cp->cnext; /* avoids freeing then using */
|
||||
free(cp);
|
||||
}
|
||||
tp->tab[i] = 0;
|
||||
}
|
||||
free(tp->tab);
|
||||
free(tp);
|
||||
}
|
||||
|
||||
void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */
|
||||
{
|
||||
Array *tp;
|
||||
Cell *p, *prev = NULL;
|
||||
int h;
|
||||
|
||||
tp = (Array *) ap->sval;
|
||||
h = hash(s, tp->size);
|
||||
for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
|
||||
if (strcmp(s, p->nval) == 0) {
|
||||
if (prev == NULL) /* 1st one */
|
||||
tp->tab[h] = p->cnext;
|
||||
else /* middle somewhere */
|
||||
prev->cnext = p->cnext;
|
||||
if (freeable(p))
|
||||
xfree(p->sval);
|
||||
free(p->nval);
|
||||
free(p);
|
||||
tp->nelem--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
|
||||
{
|
||||
int h;
|
||||
Cell *p;
|
||||
|
||||
if (n != NULL && (p = lookup(n, tp)) != NULL) {
|
||||
dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
|
||||
p, p->nval, p->sval, p->fval, p->tval) );
|
||||
return(p);
|
||||
}
|
||||
p = (Cell *) malloc(sizeof(Cell));
|
||||
if (p == NULL)
|
||||
FATAL("out of space for symbol table at %s", n);
|
||||
p->nval = tostring(n);
|
||||
p->sval = s ? tostring(s) : tostring("");
|
||||
p->fval = f;
|
||||
p->tval = t;
|
||||
p->csub = CUNK;
|
||||
p->ctype = OCELL;
|
||||
tp->nelem++;
|
||||
if (tp->nelem > FULLTAB * tp->size)
|
||||
rehash(tp);
|
||||
h = hash(n, tp->size);
|
||||
p->cnext = tp->tab[h];
|
||||
tp->tab[h] = p;
|
||||
dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
|
||||
p, p->nval, p->sval, p->fval, p->tval) );
|
||||
return(p);
|
||||
}
|
||||
|
||||
int hash(char *s, int n) /* form hash value for string s */
|
||||
{
|
||||
unsigned hashval;
|
||||
|
||||
for (hashval = 0; *s != '\0'; s++)
|
||||
hashval = (*s + 31 * hashval);
|
||||
return hashval % n;
|
||||
}
|
||||
|
||||
void rehash(Array *tp) /* rehash items in small table into big one */
|
||||
{
|
||||
int i, nh, nsz;
|
||||
Cell *cp, *op, **np;
|
||||
|
||||
nsz = GROWTAB * tp->size;
|
||||
np = (Cell **) calloc(nsz, sizeof(Cell *));
|
||||
if (np == NULL) /* can't do it, but can keep running. */
|
||||
return; /* someone else will run out later. */
|
||||
for (i = 0; i < tp->size; i++) {
|
||||
for (cp = tp->tab[i]; cp; cp = op) {
|
||||
op = cp->cnext;
|
||||
nh = hash(cp->nval, nsz);
|
||||
cp->cnext = np[nh];
|
||||
np[nh] = cp;
|
||||
}
|
||||
}
|
||||
free(tp->tab);
|
||||
tp->tab = np;
|
||||
tp->size = nsz;
|
||||
}
|
||||
|
||||
Cell *lookup(char *s, Array *tp) /* look for s in tp */
|
||||
{
|
||||
Cell *p;
|
||||
int h;
|
||||
|
||||
h = hash(s, tp->size);
|
||||
for (p = tp->tab[h]; p != NULL; p = p->cnext)
|
||||
if (strcmp(s, p->nval) == 0)
|
||||
return(p); /* found it */
|
||||
return(NULL); /* not found */
|
||||
}
|
||||
|
||||
Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
|
||||
{
|
||||
int fldno;
|
||||
|
||||
if ((vp->tval & (NUM | STR)) == 0)
|
||||
funnyvar(vp, "assign to");
|
||||
if (isfld(vp)) {
|
||||
donerec = 0; /* mark $0 invalid */
|
||||
fldno = atoi(vp->nval);
|
||||
if (fldno > *NF)
|
||||
newfld(fldno);
|
||||
dprintf( ("setting field %d to %g\n", fldno, f) );
|
||||
} else if (isrec(vp)) {
|
||||
donefld = 0; /* mark $1... invalid */
|
||||
donerec = 1;
|
||||
}
|
||||
if (freeable(vp))
|
||||
xfree(vp->sval); /* free any previous string */
|
||||
vp->tval &= ~STR; /* mark string invalid */
|
||||
vp->tval |= NUM; /* mark number ok */
|
||||
dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
|
||||
return vp->fval = f;
|
||||
}
|
||||
|
||||
void funnyvar(Cell *vp, char *rw)
|
||||
{
|
||||
if (isarr(vp))
|
||||
FATAL("can't %s %s; it's an array name.", rw, vp->nval);
|
||||
if (vp->tval & FCN)
|
||||
FATAL("can't %s %s; it's a function.", rw, vp->nval);
|
||||
WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
|
||||
vp, vp->nval, vp->sval, vp->fval, vp->tval);
|
||||
}
|
||||
|
||||
char *setsval(Cell *vp, char *s) /* set string val of a Cell */
|
||||
{
|
||||
char *t;
|
||||
int fldno;
|
||||
|
||||
dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
|
||||
if ((vp->tval & (NUM | STR)) == 0)
|
||||
funnyvar(vp, "assign to");
|
||||
if (isfld(vp)) {
|
||||
donerec = 0; /* mark $0 invalid */
|
||||
fldno = atoi(vp->nval);
|
||||
if (fldno > *NF)
|
||||
newfld(fldno);
|
||||
dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
|
||||
} else if (isrec(vp)) {
|
||||
donefld = 0; /* mark $1... invalid */
|
||||
donerec = 1;
|
||||
}
|
||||
t = tostring(s); /* in case it's self-assign */
|
||||
vp->tval &= ~NUM;
|
||||
vp->tval |= STR;
|
||||
if (freeable(vp))
|
||||
xfree(vp->sval);
|
||||
vp->tval &= ~DONTFREE;
|
||||
dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
|
||||
return(vp->sval = t);
|
||||
}
|
||||
|
||||
Awkfloat getfval(Cell *vp) /* get float val of a Cell */
|
||||
{
|
||||
if ((vp->tval & (NUM | STR)) == 0)
|
||||
funnyvar(vp, "read value of");
|
||||
if (isfld(vp) && donefld == 0)
|
||||
fldbld();
|
||||
else if (isrec(vp) && donerec == 0)
|
||||
recbld();
|
||||
if (!isnum(vp)) { /* not a number */
|
||||
vp->fval = atof(vp->sval); /* best guess */
|
||||
if (is_number(vp->sval) && !(vp->tval&CON))
|
||||
vp->tval |= NUM; /* make NUM only sparingly */
|
||||
}
|
||||
dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
|
||||
return(vp->fval);
|
||||
}
|
||||
|
||||
char *getsval(Cell *vp) /* get string val of a Cell */
|
||||
{
|
||||
char s[100]; /* BUG: unchecked */
|
||||
double dtemp;
|
||||
|
||||
if ((vp->tval & (NUM | STR)) == 0)
|
||||
funnyvar(vp, "read value of");
|
||||
if (isfld(vp) && donefld == 0)
|
||||
fldbld();
|
||||
else if (isrec(vp) && donerec == 0)
|
||||
recbld();
|
||||
if (isstr(vp) == 0) {
|
||||
if (freeable(vp))
|
||||
xfree(vp->sval);
|
||||
if (modf(vp->fval, &dtemp) == 0) /* it's integral */
|
||||
sprintf(s, "%.30g", vp->fval);
|
||||
else
|
||||
sprintf(s, *CONVFMT, vp->fval);
|
||||
vp->sval = tostring(s);
|
||||
vp->tval &= ~DONTFREE;
|
||||
vp->tval |= STR;
|
||||
}
|
||||
dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
|
||||
return(vp->sval);
|
||||
}
|
||||
|
||||
char *tostring(char *s) /* make a copy of string s */
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = (char *) malloc(strlen(s)+1);
|
||||
if (p == NULL)
|
||||
FATAL("out of space in tostring on %s", s);
|
||||
strcpy(p, s);
|
||||
return(p);
|
||||
}
|
||||
|
||||
char *qstring(char *s, int delim) /* collect string up to next delim */
|
||||
{
|
||||
char *os = s;
|
||||
int c, n;
|
||||
char *buf, *bp;
|
||||
|
||||
if ((buf = (char *) malloc(strlen(s)+3)) == NULL)
|
||||
FATAL( "out of space in qstring(%s)", s);
|
||||
for (bp = buf; (c = *s) != delim; s++) {
|
||||
if (c == '\n')
|
||||
SYNTAX( "newline in string %.20s...", os );
|
||||
else if (c != '\\')
|
||||
*bp++ = c;
|
||||
else { /* \something */
|
||||
c = *++s;
|
||||
if (c == 0) { /* \ at end */
|
||||
*bp++ = '\\';
|
||||
break; /* for loop */
|
||||
}
|
||||
switch (c) {
|
||||
case '\\': *bp++ = '\\'; break;
|
||||
case 'n': *bp++ = '\n'; break;
|
||||
case 't': *bp++ = '\t'; break;
|
||||
case 'b': *bp++ = '\b'; break;
|
||||
case 'f': *bp++ = '\f'; break;
|
||||
case 'r': *bp++ = '\r'; break;
|
||||
default:
|
||||
if (!isdigit(c)) {
|
||||
*bp++ = c;
|
||||
break;
|
||||
}
|
||||
n = c - '0';
|
||||
if (isdigit(s[1])) {
|
||||
n = 8 * n + *++s - '0';
|
||||
if (isdigit(s[1]))
|
||||
n = 8 * n + *++s - '0';
|
||||
}
|
||||
*bp++ = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*bp++ = 0;
|
||||
return buf;
|
||||
}
|
36
basename/Makefile
Normal file
36
basename/Makefile
Normal file
@@ -0,0 +1,36 @@
|
||||
# basename - basename unix port from plan9
|
||||
# Depends on ../lib9
|
||||
|
||||
include ../config.mk
|
||||
|
||||
TARG = basename
|
||||
|
||||
OFILES = basename.o
|
||||
|
||||
MANFILES = basename.1
|
||||
|
||||
all: ${TARG}
|
||||
@echo built ${TARG}
|
||||
|
||||
install: ${TARG}
|
||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
@cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
|
||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
@cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
|
||||
@chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
|
||||
|
||||
uninstall:
|
||||
rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
|
||||
|
||||
.c.o:
|
||||
@echo CC $*.c
|
||||
@${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
|
||||
|
||||
clean:
|
||||
rm -f ${OFILES} ${TARG}
|
||||
|
||||
${TARG}: ${OFILES}
|
||||
@echo LD ${TARG}
|
||||
@${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9
|
35
basename/basename.1
Normal file
35
basename/basename.1
Normal file
@@ -0,0 +1,35 @@
|
||||
.TH BASENAME 1
|
||||
.SH NAME
|
||||
basename \- strip file name affixes
|
||||
.SH SYNOPSIS
|
||||
.B basename
|
||||
[
|
||||
.B -d
|
||||
]
|
||||
.I string
|
||||
[
|
||||
.I suffix
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
.I Basename
|
||||
deletes any prefix ending in slash
|
||||
.RB ( / )
|
||||
and the
|
||||
.IR suffix ,
|
||||
if present in
|
||||
.IR string ,
|
||||
from
|
||||
.IR string ,
|
||||
and prints the result on the standard output.
|
||||
.PP
|
||||
The
|
||||
.B -d
|
||||
option instead prints the directory component,
|
||||
that is,
|
||||
.I string
|
||||
up to but not including the final slash.
|
||||
If the string contains no slash,
|
||||
a period and newline are printed.
|
||||
.SH SOURCE
|
||||
.B \*9/src/cmd/basename.c
|
41
basename/basename.c
Normal file
41
basename/basename.c
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *pr;
|
||||
int n, dflag;
|
||||
|
||||
dflag = 0;
|
||||
if(argc>1 && strcmp(argv[1], "-d") == 0){
|
||||
--argc;
|
||||
++argv;
|
||||
dflag = 1;
|
||||
}
|
||||
if(argc < 2 || argc > 3){
|
||||
fprint(2, "usage: basename [-d] string [suffix]\n");
|
||||
exits("usage");
|
||||
}
|
||||
pr = utfrrune(argv[1], '/');
|
||||
if(dflag){
|
||||
if(pr){
|
||||
*pr = 0;
|
||||
print("%s\n", argv[1]);
|
||||
exits(0);
|
||||
}
|
||||
print(".\n");
|
||||
exits(0);
|
||||
}
|
||||
if(pr)
|
||||
pr++;
|
||||
else
|
||||
pr = argv[1];
|
||||
if(argc==3){
|
||||
n = strlen(pr)-strlen(argv[2]);
|
||||
if(n >= 0 && !strcmp(pr+n, argv[2]))
|
||||
pr[n] = 0;
|
||||
}
|
||||
print("%s\n", pr);
|
||||
exits(0);
|
||||
}
|
46
bc/Makefile
Normal file
46
bc/Makefile
Normal file
@@ -0,0 +1,46 @@
|
||||
# bc - bc unix port from plan9
|
||||
# Depends on ../lib9
|
||||
|
||||
include ../config.mk
|
||||
|
||||
TARG = bc
|
||||
|
||||
OFILES = y.tab.o
|
||||
|
||||
YFILES = bc.y
|
||||
|
||||
MANFILES = bc.1
|
||||
|
||||
all:
|
||||
@if [ ! -f y.tab.c ]; then \
|
||||
${MAKE} -f Makefile depend;\
|
||||
fi
|
||||
@${MAKE} -f Makefile ${TARG}
|
||||
@echo built ${TARG}
|
||||
|
||||
depend:
|
||||
@echo YACC ${YFILES}
|
||||
@${YACC} -d ${YFILES}
|
||||
|
||||
install: ${TARG}
|
||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
@cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
|
||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
@cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
|
||||
@chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
|
||||
|
||||
uninstall:
|
||||
rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
|
||||
|
||||
.c.o:
|
||||
@echo CC $*.c
|
||||
@${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
|
||||
|
||||
clean:
|
||||
rm -f ${OFILES} ${TARG} y.tab.c y.tab.h
|
||||
|
||||
${TARG}: ${OFILES}
|
||||
@echo LD ${TARG}
|
||||
@${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -lm -L${PREFIX}/lib -L../lib9 -l9
|
292
bc/bc.1
Normal file
292
bc/bc.1
Normal file
@@ -0,0 +1,292 @@
|
||||
.TH BC 1
|
||||
.SH NAME
|
||||
bc \- arbitrary-precision arithmetic language
|
||||
.SH SYNOPSIS
|
||||
.B bc
|
||||
[
|
||||
.B -c
|
||||
]
|
||||
[
|
||||
.B -l
|
||||
]
|
||||
[
|
||||
.B -s
|
||||
]
|
||||
[
|
||||
.I file ...
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Bc
|
||||
is an interactive processor for a language that resembles
|
||||
C but provides arithmetic on numbers of arbitrary length with up
|
||||
to 100 digits right of the decimal point.
|
||||
It takes input from any files given, then reads
|
||||
the standard input.
|
||||
The
|
||||
.B -l
|
||||
argument stands for the name
|
||||
of an arbitrary precision math library.
|
||||
The
|
||||
.B -s
|
||||
argument suppresses the automatic display
|
||||
of calculation results; all output is via the
|
||||
.B print
|
||||
command.
|
||||
.PP
|
||||
The following syntax for
|
||||
.I bc
|
||||
programs is like that of C;
|
||||
.I L
|
||||
means letter
|
||||
.BR a - z ,
|
||||
.I E
|
||||
means expression,
|
||||
.I S
|
||||
means statement.
|
||||
.TF length(E)
|
||||
.TP
|
||||
Lexical
|
||||
.RS
|
||||
.HP
|
||||
comments are enclosed in
|
||||
.B /* */
|
||||
.HP
|
||||
newlines end statements
|
||||
.RE
|
||||
.TP
|
||||
Names
|
||||
.IP
|
||||
simple variables:
|
||||
.I L
|
||||
.br
|
||||
array elements:
|
||||
.IB L [ E ]
|
||||
.br
|
||||
The words
|
||||
.BR ibase ,
|
||||
.BR obase ,
|
||||
and
|
||||
.B scale
|
||||
.TP
|
||||
Other operands
|
||||
.IP
|
||||
arbitrarily long numbers with optional sign and decimal point.
|
||||
.RS
|
||||
.TP
|
||||
.BI ( E )
|
||||
.TP
|
||||
.BI sqrt( E )
|
||||
.TP
|
||||
.BI length( E )
|
||||
number of significant decimal digits
|
||||
.TP
|
||||
.BI scale( E )
|
||||
number of digits right of decimal point
|
||||
.TP
|
||||
.IB L ( E , ... ,\fIE\fP)
|
||||
function call
|
||||
.RE
|
||||
.TP
|
||||
Operators
|
||||
.RS
|
||||
.HP
|
||||
.B "+ - * / % ^\ "
|
||||
.RB ( %
|
||||
is remainder;
|
||||
.B ^
|
||||
is power)
|
||||
.HP
|
||||
.B "++ --\ "
|
||||
.TP
|
||||
.B "== <= >= != < >"
|
||||
.TP
|
||||
.B "= += -= *= /= %= ^="
|
||||
.RE
|
||||
.TP
|
||||
Statements
|
||||
.RS
|
||||
.br
|
||||
.I E
|
||||
.br
|
||||
.B {
|
||||
.I S
|
||||
.B ;
|
||||
\&...
|
||||
.B ;
|
||||
.I S
|
||||
.B }
|
||||
.br
|
||||
.B "print"
|
||||
.I E
|
||||
.br
|
||||
.B "if ("
|
||||
.I E
|
||||
.B )
|
||||
.I S
|
||||
.br
|
||||
.B "while ("
|
||||
.I E
|
||||
.B )
|
||||
.I S
|
||||
.br
|
||||
.B "for ("
|
||||
.I E
|
||||
.B ;
|
||||
.I E
|
||||
.B ;
|
||||
.I E
|
||||
.B ")"
|
||||
.I S
|
||||
.br
|
||||
null statement
|
||||
.br
|
||||
.B break
|
||||
.br
|
||||
.B quit
|
||||
.br
|
||||
\fL"\fRtext\fL"\fR
|
||||
.RE
|
||||
.TP
|
||||
Function definitions
|
||||
.RS
|
||||
.br
|
||||
.B define
|
||||
.I L
|
||||
.B (
|
||||
.I L
|
||||
.B ,
|
||||
\&...
|
||||
.B ,
|
||||
.I L
|
||||
.B ){
|
||||
.PD0
|
||||
.br
|
||||
.B auto
|
||||
.I L
|
||||
.B ,
|
||||
\&...
|
||||
.B ,
|
||||
.I L
|
||||
.br
|
||||
.I S
|
||||
.B ;
|
||||
\&...
|
||||
.B ;
|
||||
.I S
|
||||
.br
|
||||
.B return
|
||||
.I E
|
||||
.LP
|
||||
.B }
|
||||
.RE
|
||||
.TP
|
||||
Functions in
|
||||
.B -l
|
||||
math library
|
||||
.RS
|
||||
.TP
|
||||
.BI s( x )
|
||||
sine
|
||||
.TP
|
||||
.BI c( x )
|
||||
cosine
|
||||
.TP
|
||||
.BI e( x )
|
||||
exponential
|
||||
.TP
|
||||
.BI l( x )
|
||||
log
|
||||
.TP
|
||||
.BI a( x )
|
||||
arctangent
|
||||
.TP
|
||||
.BI j( "n, x" )
|
||||
Bessel function
|
||||
.RE
|
||||
.PP
|
||||
.DT
|
||||
All function arguments are passed by value.
|
||||
.PD
|
||||
.PP
|
||||
The value of an expression at the top level is printed
|
||||
unless the main operator is an assignment or the
|
||||
.B -s
|
||||
command line argument is given.
|
||||
Text in quotes, which may include newlines, is always printed.
|
||||
Either semicolons or newlines may separate statements.
|
||||
Assignment to
|
||||
.B scale
|
||||
influences the number of digits to be retained on arithmetic
|
||||
operations in the manner of
|
||||
.IR dc (1).
|
||||
Assignments to
|
||||
.B ibase
|
||||
or
|
||||
.B obase
|
||||
set the input and output number radix respectively.
|
||||
.PP
|
||||
The same letter may be used as an array, a function,
|
||||
and a simple variable simultaneously.
|
||||
All variables are global to the program.
|
||||
Automatic variables are pushed down during function calls.
|
||||
In a declaration of an array as a function argument
|
||||
or automatic variable
|
||||
empty square brackets must follow the array name.
|
||||
.PP
|
||||
.I Bc
|
||||
is actually a preprocessor for
|
||||
.IR dc (1),
|
||||
which it invokes automatically, unless the
|
||||
.B -c
|
||||
(compile only)
|
||||
option is present.
|
||||
In this case the
|
||||
.I dc
|
||||
input is sent to the standard output instead.
|
||||
.SH EXAMPLE
|
||||
Define a function to compute an approximate value of
|
||||
the exponential.
|
||||
Use it to print 10 values.
|
||||
(The exponential function in the library gives better answers.)
|
||||
.PP
|
||||
.EX
|
||||
scale = 20
|
||||
define e(x) {
|
||||
auto a, b, c, i, s
|
||||
a = 1
|
||||
b = 1
|
||||
s = 1
|
||||
for(i=1; 1; i++) {
|
||||
a *= x
|
||||
b *= i
|
||||
c = a/b
|
||||
if(c == 0) return s
|
||||
s += c
|
||||
}
|
||||
}
|
||||
for(i=1; i<=10; i++) print e(i)
|
||||
.EE
|
||||
.SH FILES
|
||||
.B \*9/lib/bclib
|
||||
mathematical library
|
||||
.SH SOURCE
|
||||
.B \*9/src/cmd/bc.y
|
||||
.SH "SEE ALSO"
|
||||
.IR dc (1),
|
||||
.IR hoc (1)
|
||||
.SH BUGS
|
||||
No
|
||||
.LR && ,
|
||||
.LR || ,
|
||||
or
|
||||
.L !
|
||||
operators.
|
||||
.PP
|
||||
A
|
||||
.L for
|
||||
statement must have all three
|
||||
.LR E s.
|
||||
.PP
|
||||
A
|
||||
.L quit
|
||||
is interpreted when read, not when executed.
|
985
bc/bc.y
Normal file
985
bc/bc.y
Normal file
@@ -0,0 +1,985 @@
|
||||
%{
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
|
||||
#define bsp_max 5000
|
||||
|
||||
Biobuf *in;
|
||||
#define stdin bstdin
|
||||
#define stdout bstdout
|
||||
Biobuf stdin;
|
||||
Biobuf stdout;
|
||||
char cary[1000];
|
||||
char* cp = { cary };
|
||||
char string[1000];
|
||||
char* str = { string };
|
||||
int crs = 128;
|
||||
int rcrs = 128; /* reset crs */
|
||||
int bindx = 0;
|
||||
int lev = 0;
|
||||
int ln;
|
||||
int* ttp;
|
||||
char* ss = "";
|
||||
int bstack[10] = { 0 };
|
||||
char* numb[15] =
|
||||
{
|
||||
" 0", " 1", " 2", " 3", " 4", " 5",
|
||||
" 6", " 7", " 8", " 9", " 10", " 11",
|
||||
" 12", " 13", " 14"
|
||||
};
|
||||
int* pre;
|
||||
int* post;
|
||||
|
||||
long peekc = -1;
|
||||
int sargc;
|
||||
int ifile;
|
||||
char** sargv;
|
||||
|
||||
char *funtab[] =
|
||||
{
|
||||
"<1>","<2>","<3>","<4>","<5>",
|
||||
"<6>","<7>","<8>","<9>","<10>",
|
||||
"<11>","<12>","<13>","<14>","<15>",
|
||||
"<16>","<17>","<18>","<19>","<20>",
|
||||
"<21>","<22>","<23>","<24>","<25>",
|
||||
"<26>"
|
||||
};
|
||||
char *atab[] =
|
||||
{
|
||||
"<221>","<222>","<223>","<224>","<225>",
|
||||
"<226>","<227>","<228>","<229>","<230>",
|
||||
"<231>","<232>","<233>","<234>","<235>",
|
||||
"<236>","<237>","<238>","<239>","<240>",
|
||||
"<241>","<242>","<243>","<244>","<245>",
|
||||
"<246>"
|
||||
};
|
||||
char* letr[26] =
|
||||
{
|
||||
"a","b","c","d","e","f","g","h","i","j",
|
||||
"k","l","m","n","o","p","q","r","s","t",
|
||||
"u","v","w","x","y","z"
|
||||
};
|
||||
char* dot = { "." };
|
||||
int bspace[bsp_max];
|
||||
int* bsp_nxt = { bspace };
|
||||
int bdebug = 0;
|
||||
int lflag;
|
||||
int cflag;
|
||||
int sflag;
|
||||
|
||||
int* bundle(int, ...);
|
||||
void conout(int*, char*);
|
||||
int cpeek(int, int, int);
|
||||
int getch(void);
|
||||
int* geta(char*);
|
||||
int* getf(char*);
|
||||
void getout(void);
|
||||
void output(int*);
|
||||
void pp(char*);
|
||||
void routput(int*);
|
||||
void tp(char*);
|
||||
void yyerror(char*, ...);
|
||||
int yyparse(void);
|
||||
|
||||
typedef void* pointer;
|
||||
/* #pragma varargck type "lx" pointer */
|
||||
|
||||
%}
|
||||
%union
|
||||
{
|
||||
int* iptr;
|
||||
char* cptr;
|
||||
int cc;
|
||||
}
|
||||
|
||||
%type <iptr> pstat stat stat1 def slist dlets e ase nase
|
||||
%type <iptr> slist re fprefix cargs eora cons constant lora
|
||||
%type <cptr> crs
|
||||
|
||||
%token <cptr> LETTER EQOP _AUTO DOT
|
||||
%token <cc> DIGIT SQRT LENGTH _IF FFF EQ
|
||||
%token <cc> _PRINT _WHILE _FOR NE LE GE INCR DECR
|
||||
%token <cc> _RETURN _BREAK _DEFINE BASE OBASE SCALE
|
||||
%token <cc> QSTR ERROR
|
||||
|
||||
%right '=' EQOP
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%right '^'
|
||||
%left UMINUS
|
||||
|
||||
%%
|
||||
start:
|
||||
start stuff
|
||||
| stuff
|
||||
|
||||
stuff:
|
||||
pstat tail
|
||||
{
|
||||
output($1);
|
||||
}
|
||||
| def dargs ')' '{' dlist slist '}'
|
||||
{
|
||||
ttp = bundle(6, pre, $6, post , "0", numb[lev], "Q");
|
||||
conout(ttp, (char*)$1);
|
||||
rcrs = crs;
|
||||
output((int*)""); /* this is horse puk!! */
|
||||
lev = bindx = 0;
|
||||
}
|
||||
|
||||
dlist:
|
||||
tail
|
||||
| dlist _AUTO dlets tail
|
||||
|
||||
stat:
|
||||
stat1
|
||||
| nase
|
||||
{
|
||||
if(sflag)
|
||||
bundle(2, $1, "s.");
|
||||
}
|
||||
|
||||
pstat:
|
||||
stat1
|
||||
{
|
||||
if(sflag)
|
||||
bundle(2, $1, "0");
|
||||
}
|
||||
| nase
|
||||
{
|
||||
if(!sflag)
|
||||
bundle(2, $1, "ps.");
|
||||
}
|
||||
|
||||
stat1:
|
||||
{
|
||||
bundle(1, "");
|
||||
}
|
||||
| ase
|
||||
{
|
||||
bundle(2, $1, "s.");
|
||||
}
|
||||
| SCALE '=' e
|
||||
{
|
||||
bundle(2, $3, "k");
|
||||
}
|
||||
| SCALE EQOP e
|
||||
{
|
||||
bundle(4, "K", $3, $2, "k");
|
||||
}
|
||||
| BASE '=' e
|
||||
{
|
||||
bundle(2, $3, "i");
|
||||
}
|
||||
| BASE EQOP e
|
||||
{
|
||||
bundle(4, "I", $3, $2, "i");
|
||||
}
|
||||
| OBASE '=' e
|
||||
{
|
||||
bundle(2, $3, "o");
|
||||
}
|
||||
| OBASE EQOP e
|
||||
{
|
||||
bundle(4, "O", $3, $2, "o");
|
||||
}
|
||||
| QSTR
|
||||
{
|
||||
bundle(3, "[", $1, "]P");
|
||||
}
|
||||
| _BREAK
|
||||
{
|
||||
bundle(2, numb[lev-bstack[bindx-1]], "Q");
|
||||
}
|
||||
| _PRINT e
|
||||
{
|
||||
bundle(2, $2, "ps.");
|
||||
}
|
||||
| _RETURN e
|
||||
{
|
||||
bundle(4, $2, post, numb[lev], "Q");
|
||||
}
|
||||
| _RETURN
|
||||
{
|
||||
bundle(4, "0", post, numb[lev], "Q");
|
||||
}
|
||||
| '{' slist '}'
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
| FFF
|
||||
{
|
||||
bundle(1, "fY");
|
||||
}
|
||||
| _IF crs BLEV '(' re ')' stat
|
||||
{
|
||||
conout($7, $2);
|
||||
bundle(3, $5, $2, " ");
|
||||
}
|
||||
| _WHILE crs '(' re ')' stat BLEV
|
||||
{
|
||||
bundle(3, $6, $4, $2);
|
||||
conout($$, $2);
|
||||
bundle(3, $4, $2, " ");
|
||||
}
|
||||
| fprefix crs re ';' e ')' stat BLEV
|
||||
{
|
||||
bundle(5, $7, $5, "s.", $3, $2);
|
||||
conout($$, $2);
|
||||
bundle(5, $1, "s.", $3, $2, " ");
|
||||
}
|
||||
| '~' LETTER '=' e
|
||||
{
|
||||
bundle(3, $4, "S", $2);
|
||||
}
|
||||
|
||||
fprefix:
|
||||
_FOR '(' e ';'
|
||||
{
|
||||
$$ = $3;
|
||||
}
|
||||
|
||||
BLEV:
|
||||
=
|
||||
{
|
||||
--bindx;
|
||||
}
|
||||
|
||||
slist:
|
||||
stat
|
||||
| slist tail stat
|
||||
{
|
||||
bundle(2, $1, $3);
|
||||
}
|
||||
|
||||
tail:
|
||||
'\n'
|
||||
{
|
||||
ln++;
|
||||
}
|
||||
| ';'
|
||||
|
||||
re:
|
||||
e EQ e
|
||||
{
|
||||
$$ = bundle(3, $1, $3, "=");
|
||||
}
|
||||
| e '<' e
|
||||
{
|
||||
bundle(3, $1, $3, ">");
|
||||
}
|
||||
| e '>' e
|
||||
{
|
||||
bundle(3, $1, $3, "<");
|
||||
}
|
||||
| e NE e
|
||||
{
|
||||
bundle(3, $1, $3, "!=");
|
||||
}
|
||||
| e GE e
|
||||
{
|
||||
bundle(3, $1, $3, "!>");
|
||||
}
|
||||
| e LE e
|
||||
{
|
||||
bundle(3, $1, $3, "!<");
|
||||
}
|
||||
| e
|
||||
{
|
||||
bundle(2, $1, " 0!=");
|
||||
}
|
||||
|
||||
nase:
|
||||
'(' e ')'
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
| cons
|
||||
{
|
||||
bundle(3, " ", $1, " ");
|
||||
}
|
||||
| DOT cons
|
||||
{
|
||||
bundle(3, " .", $2, " ");
|
||||
}
|
||||
| cons DOT cons
|
||||
{
|
||||
bundle(5, " ", $1, ".", $3, " ");
|
||||
}
|
||||
| cons DOT
|
||||
{
|
||||
bundle(4, " ", $1, ".", " ");
|
||||
}
|
||||
| DOT
|
||||
{
|
||||
$<cptr>$ = "l.";
|
||||
}
|
||||
| LETTER '[' e ']'
|
||||
{
|
||||
bundle(3, $3, ";", geta($1));
|
||||
}
|
||||
| LETTER INCR
|
||||
{
|
||||
bundle(4, "l", $1, "d1+s", $1);
|
||||
}
|
||||
| INCR LETTER
|
||||
{
|
||||
bundle(4, "l", $2, "1+ds", $2);
|
||||
}
|
||||
| DECR LETTER
|
||||
{
|
||||
bundle(4, "l", $2, "1-ds", $2);
|
||||
}
|
||||
| LETTER DECR
|
||||
{
|
||||
bundle(4, "l", $1, "d1-s", $1);
|
||||
}
|
||||
| LETTER '[' e ']' INCR
|
||||
{
|
||||
bundle(7, $3, ";", geta($1), "d1+" ,$3, ":" ,geta($1));
|
||||
}
|
||||
| INCR LETTER '[' e ']'
|
||||
{
|
||||
bundle(7, $4, ";", geta($2), "1+d", $4, ":", geta($2));
|
||||
}
|
||||
| LETTER '[' e ']' DECR
|
||||
{
|
||||
bundle(7, $3, ";", geta($1), "d1-", $3, ":", geta($1));
|
||||
}
|
||||
| DECR LETTER '[' e ']'
|
||||
{
|
||||
bundle(7, $4, ";", geta($2), "1-d", $4, ":" ,geta($2));
|
||||
}
|
||||
| SCALE INCR
|
||||
{
|
||||
bundle(1, "Kd1+k");
|
||||
}
|
||||
| INCR SCALE
|
||||
{
|
||||
bundle(1, "K1+dk");
|
||||
}
|
||||
| SCALE DECR
|
||||
{
|
||||
bundle(1, "Kd1-k");
|
||||
}
|
||||
| DECR SCALE
|
||||
{
|
||||
bundle(1, "K1-dk");
|
||||
}
|
||||
| BASE INCR
|
||||
{
|
||||
bundle(1, "Id1+i");
|
||||
}
|
||||
| INCR BASE
|
||||
{
|
||||
bundle(1, "I1+di");
|
||||
}
|
||||
| BASE DECR
|
||||
{
|
||||
bundle(1, "Id1-i");
|
||||
}
|
||||
| DECR BASE
|
||||
{
|
||||
bundle(1, "I1-di");
|
||||
}
|
||||
| OBASE INCR
|
||||
{
|
||||
bundle(1, "Od1+o");
|
||||
}
|
||||
| INCR OBASE
|
||||
{
|
||||
bundle(1, "O1+do");
|
||||
}
|
||||
| OBASE DECR
|
||||
{
|
||||
bundle(1, "Od1-o");
|
||||
}
|
||||
| DECR OBASE
|
||||
{
|
||||
bundle(1, "O1-do");
|
||||
}
|
||||
| LETTER '(' cargs ')'
|
||||
{
|
||||
bundle(4, $3, "l", getf($1), "x");
|
||||
}
|
||||
| LETTER '(' ')'
|
||||
{
|
||||
bundle(3, "l", getf($1), "x");
|
||||
}
|
||||
| LETTER = {
|
||||
bundle(2, "l", $1);
|
||||
}
|
||||
| LENGTH '(' e ')'
|
||||
{
|
||||
bundle(2, $3, "Z");
|
||||
}
|
||||
| SCALE '(' e ')'
|
||||
{
|
||||
bundle(2, $3, "X");
|
||||
}
|
||||
| '?'
|
||||
{
|
||||
bundle(1, "?");
|
||||
}
|
||||
| SQRT '(' e ')'
|
||||
{
|
||||
bundle(2, $3, "v");
|
||||
}
|
||||
| '~' LETTER
|
||||
{
|
||||
bundle(2, "L", $2);
|
||||
}
|
||||
| SCALE
|
||||
{
|
||||
bundle(1, "K");
|
||||
}
|
||||
| BASE
|
||||
{
|
||||
bundle(1, "I");
|
||||
}
|
||||
| OBASE
|
||||
{
|
||||
bundle(1, "O");
|
||||
}
|
||||
| '-' e
|
||||
{
|
||||
bundle(3, " 0", $2, "-");
|
||||
}
|
||||
| e '+' e
|
||||
{
|
||||
bundle(3, $1, $3, "+");
|
||||
}
|
||||
| e '-' e
|
||||
{
|
||||
bundle(3, $1, $3, "-");
|
||||
}
|
||||
| e '*' e
|
||||
{
|
||||
bundle(3, $1, $3, "*");
|
||||
}
|
||||
| e '/' e
|
||||
{
|
||||
bundle(3, $1, $3, "/");
|
||||
}
|
||||
| e '%' e
|
||||
{
|
||||
bundle(3, $1, $3, "%%");
|
||||
}
|
||||
| e '^' e
|
||||
{
|
||||
bundle(3, $1, $3, "^");
|
||||
}
|
||||
|
||||
ase:
|
||||
LETTER '=' e
|
||||
{
|
||||
bundle(3, $3, "ds", $1);
|
||||
}
|
||||
| LETTER '[' e ']' '=' e
|
||||
{
|
||||
bundle(5, $6, "d", $3, ":", geta($1));
|
||||
}
|
||||
| LETTER EQOP e
|
||||
{
|
||||
bundle(6, "l", $1, $3, $2, "ds", $1);
|
||||
}
|
||||
| LETTER '[' e ']' EQOP e
|
||||
{
|
||||
bundle(9, $3, ";", geta($1), $6, $5, "d", $3, ":", geta($1));
|
||||
}
|
||||
|
||||
e:
|
||||
ase
|
||||
| nase
|
||||
|
||||
cargs:
|
||||
eora
|
||||
| cargs ',' eora
|
||||
{
|
||||
bundle(2, $1, $3);
|
||||
}
|
||||
|
||||
eora:
|
||||
e
|
||||
| LETTER '[' ']'
|
||||
{
|
||||
bundle(2, "l", geta($1));
|
||||
}
|
||||
|
||||
cons:
|
||||
constant
|
||||
{
|
||||
*cp++ = 0;
|
||||
}
|
||||
|
||||
constant:
|
||||
'_'
|
||||
{
|
||||
$<cptr>$ = cp;
|
||||
*cp++ = '_';
|
||||
}
|
||||
| DIGIT
|
||||
{
|
||||
$<cptr>$ = cp;
|
||||
*cp++ = $1;
|
||||
}
|
||||
| constant DIGIT
|
||||
{
|
||||
*cp++ = $2;
|
||||
}
|
||||
|
||||
crs:
|
||||
=
|
||||
{
|
||||
$$ = cp;
|
||||
*cp++ = '<';
|
||||
*cp++ = crs/100+'0';
|
||||
*cp++ = (crs%100)/10+'0';
|
||||
*cp++ = crs%10+'0';
|
||||
*cp++ = '>';
|
||||
*cp++ = '\0';
|
||||
if(crs++ >= 220) {
|
||||
yyerror("program too big");
|
||||
getout();
|
||||
}
|
||||
bstack[bindx++] = lev++;
|
||||
}
|
||||
|
||||
def:
|
||||
_DEFINE LETTER '('
|
||||
{
|
||||
$$ = getf($2);
|
||||
pre = (int*)"";
|
||||
post = (int*)"";
|
||||
lev = 1;
|
||||
bindx = 0;
|
||||
bstack[bindx] = 0;
|
||||
}
|
||||
|
||||
dargs:
|
||||
| lora
|
||||
{
|
||||
pp((char*)$1);
|
||||
}
|
||||
| dargs ',' lora
|
||||
{
|
||||
pp((char*)$3);
|
||||
}
|
||||
|
||||
dlets:
|
||||
lora
|
||||
{
|
||||
tp((char*)$1);
|
||||
}
|
||||
| dlets ',' lora
|
||||
{
|
||||
tp((char*)$3);
|
||||
}
|
||||
|
||||
lora:
|
||||
LETTER
|
||||
{
|
||||
$<cptr>$=$1;
|
||||
}
|
||||
| LETTER '[' ']'
|
||||
{
|
||||
$$ = geta($1);
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
int
|
||||
yylex(void)
|
||||
{
|
||||
int c, ch;
|
||||
|
||||
restart:
|
||||
c = getch();
|
||||
peekc = -1;
|
||||
while(c == ' ' || c == '\t')
|
||||
c = getch();
|
||||
if(c == '\\') {
|
||||
getch();
|
||||
goto restart;
|
||||
}
|
||||
if(c >= 'a' && c <= 'z') {
|
||||
/* look ahead to look for reserved words */
|
||||
peekc = getch();
|
||||
if(peekc >= 'a' && peekc <= 'z') { /* must be reserved word */
|
||||
if(c=='p' && peekc=='r') {
|
||||
c = _PRINT;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='i' && peekc=='f') {
|
||||
c = _IF;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='w' && peekc=='h') {
|
||||
c = _WHILE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='f' && peekc=='o') {
|
||||
c = _FOR;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='s' && peekc=='q') {
|
||||
c = SQRT;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='r' && peekc=='e') {
|
||||
c = _RETURN;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='b' && peekc=='r') {
|
||||
c = _BREAK;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='d' && peekc=='e') {
|
||||
c = _DEFINE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='s' && peekc=='c') {
|
||||
c = SCALE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='b' && peekc=='a') {
|
||||
c = BASE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='i' && peekc=='b') {
|
||||
c = BASE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='o' && peekc=='b') {
|
||||
c = OBASE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='d' && peekc=='i') {
|
||||
c = FFF;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='a' && peekc=='u') {
|
||||
c = _AUTO;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='l' && peekc=='e') {
|
||||
c = LENGTH;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='q' && peekc=='u')
|
||||
getout();
|
||||
/* could not be found */
|
||||
return ERROR;
|
||||
|
||||
skip: /* skip over rest of word */
|
||||
peekc = -1;
|
||||
for(;;) {
|
||||
ch = getch();
|
||||
if(ch < 'a' || ch > 'z')
|
||||
break;
|
||||
}
|
||||
peekc = ch;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* usual case; just one single letter */
|
||||
yylval.cptr = letr[c-'a'];
|
||||
return LETTER;
|
||||
}
|
||||
if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
|
||||
yylval.cc = c;
|
||||
return DIGIT;
|
||||
}
|
||||
switch(c) {
|
||||
case '.':
|
||||
return DOT;
|
||||
case '*':
|
||||
yylval.cptr = "*";
|
||||
return cpeek('=', EQOP, c);
|
||||
case '%':
|
||||
yylval.cptr = "%%";
|
||||
return cpeek('=', EQOP, c);
|
||||
case '^':
|
||||
yylval.cptr = "^";
|
||||
return cpeek('=', EQOP, c);
|
||||
case '+':
|
||||
ch = cpeek('=', EQOP, c);
|
||||
if(ch == EQOP) {
|
||||
yylval.cptr = "+";
|
||||
return ch;
|
||||
}
|
||||
return cpeek('+', INCR, c);
|
||||
case '-':
|
||||
ch = cpeek('=', EQOP, c);
|
||||
if(ch == EQOP) {
|
||||
yylval.cptr = "-";
|
||||
return ch;
|
||||
}
|
||||
return cpeek('-', DECR, c);
|
||||
case '=':
|
||||
return cpeek('=', EQ, '=');
|
||||
case '<':
|
||||
return cpeek('=', LE, '<');
|
||||
case '>':
|
||||
return cpeek('=', GE, '>');
|
||||
case '!':
|
||||
return cpeek('=', NE, '!');
|
||||
case '/':
|
||||
ch = cpeek('=', EQOP, c);
|
||||
if(ch == EQOP) {
|
||||
yylval.cptr = "/";
|
||||
return ch;
|
||||
}
|
||||
if(peekc == '*') {
|
||||
peekc = -1;
|
||||
for(;;) {
|
||||
ch = getch();
|
||||
if(ch == '*') {
|
||||
peekc = getch();
|
||||
if(peekc == '/') {
|
||||
peekc = -1;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
case '"':
|
||||
yylval.cptr = str;
|
||||
while((c=getch()) != '"'){
|
||||
*str++ = c;
|
||||
if(str >= &string[999]){
|
||||
yyerror("string space exceeded");
|
||||
getout();
|
||||
}
|
||||
}
|
||||
*str++ = 0;
|
||||
return QSTR;
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
cpeek(int c, int yes, int no)
|
||||
{
|
||||
|
||||
peekc = getch();
|
||||
if(peekc == c) {
|
||||
peekc = -1;
|
||||
return yes;
|
||||
}
|
||||
return no;
|
||||
}
|
||||
|
||||
int
|
||||
getch(void)
|
||||
{
|
||||
long ch;
|
||||
|
||||
loop:
|
||||
ch = peekc;
|
||||
if(ch < 0){
|
||||
if(in == 0)
|
||||
ch = -1;
|
||||
else
|
||||
ch = Bgetc(in);
|
||||
}
|
||||
peekc = -1;
|
||||
if(ch >= 0)
|
||||
return ch;
|
||||
ifile++;
|
||||
if(ifile > sargc) {
|
||||
if(ifile >= sargc+2)
|
||||
getout();
|
||||
in = &stdin;
|
||||
Binit(in, 0, OREAD);
|
||||
ln = 0;
|
||||
goto loop;
|
||||
}
|
||||
Bterm(in);
|
||||
if((in = Bopen(sargv[ifile], OREAD)) != 0){
|
||||
ln = 0;
|
||||
ss = sargv[ifile];
|
||||
goto loop;
|
||||
}
|
||||
yyerror("cannot open input file");
|
||||
return 0; /* shut up ken */
|
||||
}
|
||||
|
||||
int*
|
||||
bundle(int a, ...)
|
||||
{
|
||||
int i, *p, *q;
|
||||
|
||||
p = &a;
|
||||
i = *p++;
|
||||
q = bsp_nxt;
|
||||
if(bdebug)
|
||||
fprint(2, "bundle %d elements at %lx\n", i, q);
|
||||
while(i-- > 0) {
|
||||
if(bsp_nxt >= &bspace[bsp_max])
|
||||
yyerror("bundling space exceeded");
|
||||
*bsp_nxt++ = *p++;
|
||||
}
|
||||
*bsp_nxt++ = 0;
|
||||
yyval.iptr = q;
|
||||
return q;
|
||||
}
|
||||
|
||||
void
|
||||
routput(int *p)
|
||||
{
|
||||
if(bdebug)
|
||||
fprint(2, "routput(%lx)\n", p);
|
||||
if(p >= &bspace[0] && p < &bspace[bsp_max]) {
|
||||
/* part of a bundle */
|
||||
while(*p != 0)
|
||||
routput((int*)(*p++));
|
||||
} else
|
||||
Bprint(&stdout, (char*)p); /* character string */
|
||||
}
|
||||
|
||||
void
|
||||
output(int *p)
|
||||
{
|
||||
routput(p);
|
||||
bsp_nxt = &bspace[0];
|
||||
Bprint(&stdout, "\n");
|
||||
Bflush(&stdout);
|
||||
cp = cary;
|
||||
crs = rcrs;
|
||||
}
|
||||
|
||||
void
|
||||
conout(int *p, char *s)
|
||||
{
|
||||
Bprint(&stdout, "[");
|
||||
routput(p);
|
||||
Bprint(&stdout, "]s%s\n", s);
|
||||
Bflush(&stdout);
|
||||
lev--;
|
||||
}
|
||||
|
||||
void
|
||||
yyerror(char *s, ...)
|
||||
{
|
||||
if(ifile > sargc)
|
||||
ss = "teletype";
|
||||
Bprint(&stdout, "c[%s on line %d, %s]pc\n", s, ln+1, ss);
|
||||
Bflush(&stdout);
|
||||
cp = cary;
|
||||
crs = rcrs;
|
||||
bindx = 0;
|
||||
lev = 0;
|
||||
bsp_nxt = &bspace[0];
|
||||
}
|
||||
|
||||
void
|
||||
pp(char *s)
|
||||
{
|
||||
/* puts the relevant stuff on pre and post for the letter s */
|
||||
bundle(3, "S", s, pre);
|
||||
pre = yyval.iptr;
|
||||
bundle(4, post, "L", s, "s.");
|
||||
post = yyval.iptr;
|
||||
}
|
||||
|
||||
void
|
||||
tp(char *s)
|
||||
{
|
||||
/* same as pp, but for temps */
|
||||
bundle(3, "0S", s, pre);
|
||||
pre = yyval.iptr;
|
||||
bundle(4, post, "L", s, "s.");
|
||||
post = yyval.iptr;
|
||||
}
|
||||
|
||||
void
|
||||
yyinit(int argc, char **argv)
|
||||
{
|
||||
Binit(&stdout, 1, OWRITE);
|
||||
sargv = argv;
|
||||
sargc = argc - 1;
|
||||
if(sargc == 0) {
|
||||
in = &stdin;
|
||||
Binit(in, 0, OREAD);
|
||||
} else if((in = Bopen(sargv[1], OREAD)) == 0)
|
||||
yyerror("cannot open input file");
|
||||
ifile = 1;
|
||||
ln = 0;
|
||||
ss = sargv[1];
|
||||
}
|
||||
|
||||
void
|
||||
getout(void)
|
||||
{
|
||||
Bprint(&stdout, "q");
|
||||
Bflush(&stdout);
|
||||
exits(0);
|
||||
}
|
||||
|
||||
int*
|
||||
getf(char *p)
|
||||
{
|
||||
return (int*)funtab[*p - 'a'];
|
||||
}
|
||||
|
||||
int*
|
||||
geta(char *p)
|
||||
{
|
||||
return (int*)atab[*p - 'a'];
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int p[2];
|
||||
|
||||
while(argc > 1 && *argv[1] == '-') {
|
||||
switch(argv[1][1]) {
|
||||
case 'd':
|
||||
bdebug++;
|
||||
break;
|
||||
case 'c':
|
||||
cflag++;
|
||||
break;
|
||||
case 'l':
|
||||
lflag++;
|
||||
break;
|
||||
case 's':
|
||||
sflag++;
|
||||
break;
|
||||
default:
|
||||
fprint(2, "Usage: bc [-l] [-c] [file ...]\n");
|
||||
exits("usage");
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
if(lflag) {
|
||||
argv--;
|
||||
argc++;
|
||||
argv[1] = unsharp("#9/lib/bclib");
|
||||
}
|
||||
if(cflag) {
|
||||
yyinit(argc, argv);
|
||||
for(;;)
|
||||
yyparse();
|
||||
/* exits(0); */
|
||||
}
|
||||
pipe(p);
|
||||
if(fork() == 0) {
|
||||
dup(p[1], 1);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
yyinit(argc, argv);
|
||||
for(;;)
|
||||
yyparse();
|
||||
}
|
||||
dup(p[0], 0);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
execlp("dc", "dc", (char*)0);
|
||||
}
|
36
cat/Makefile
Normal file
36
cat/Makefile
Normal file
@@ -0,0 +1,36 @@
|
||||
# cat - cat unix port from plan9
|
||||
# Depends on ../lib9
|
||||
|
||||
include ../config.mk
|
||||
|
||||
TARG = cat
|
||||
|
||||
OFILES = cat.o
|
||||
|
||||
MANFILES = cat.1
|
||||
|
||||
all: ${TARG}
|
||||
@echo built ${TARG}
|
||||
|
||||
install: ${TARG}
|
||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
@cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
|
||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
@cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
|
||||
@chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
|
||||
|
||||
uninstall:
|
||||
rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
|
||||
|
||||
.c.o:
|
||||
@echo CC $*.c
|
||||
@${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
|
||||
|
||||
clean:
|
||||
rm -f ${OFILES} ${TARG}
|
||||
|
||||
${TARG}: ${OFILES}
|
||||
@echo LD ${TARG}
|
||||
@${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9
|
108
cat/cat.1
Normal file
108
cat/cat.1
Normal file
@@ -0,0 +1,108 @@
|
||||
.TH CAT 1
|
||||
.SH NAME
|
||||
cat, read, nobs \- catenate files
|
||||
.SH SYNOPSIS
|
||||
.B cat
|
||||
[
|
||||
.I file ...
|
||||
]
|
||||
.br
|
||||
.B read
|
||||
[
|
||||
.B -m
|
||||
] [
|
||||
.B -n
|
||||
.I nline
|
||||
] [
|
||||
.I file ...
|
||||
]
|
||||
.br
|
||||
.B nobs
|
||||
[
|
||||
.I file ...
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Cat
|
||||
reads each
|
||||
.I file
|
||||
in sequence and writes it on the standard output.
|
||||
Thus
|
||||
.IP
|
||||
.L
|
||||
cat file
|
||||
.LP
|
||||
prints a file and
|
||||
.IP
|
||||
.L
|
||||
cat file1 file2 >file3
|
||||
.LP
|
||||
concatenates the first two files and places the result
|
||||
on the third.
|
||||
.PP
|
||||
If no
|
||||
.I file
|
||||
is given,
|
||||
.I cat
|
||||
reads from the standard input.
|
||||
Output is buffered in blocks matching the input.
|
||||
.PP
|
||||
.I Read
|
||||
copies to standard output exactly one line from the named
|
||||
.IR file ,
|
||||
default standard input.
|
||||
It is useful in interactive
|
||||
.IR rc (1)
|
||||
scripts.
|
||||
.PP
|
||||
The
|
||||
.B -m
|
||||
flag causes it to continue reading and writing multiple lines until end of file;
|
||||
.B -n
|
||||
causes it to read no more than
|
||||
.I nline
|
||||
lines.
|
||||
.PP
|
||||
.I Read
|
||||
always executes a single
|
||||
.B write
|
||||
for each line of input, which can be helpful when
|
||||
preparing input to programs that expect line-at-a-time data.
|
||||
It never reads any more data from the input than it prints to the output.
|
||||
.PP
|
||||
.I Nobs
|
||||
copies the named files to
|
||||
standard output except that it removes all backspace
|
||||
characters and the characters that precede them.
|
||||
It is useful to use as
|
||||
.B $PAGER
|
||||
with the Unix version of
|
||||
.IR man (1)
|
||||
when run inside a
|
||||
.I win
|
||||
(see
|
||||
.IR acme (1))
|
||||
window.
|
||||
.SH SOURCE
|
||||
.B \*9/src/cmd/cat.c
|
||||
.br
|
||||
.B \*9/src/cmd/read.c
|
||||
.br
|
||||
.B \*9/bin/nobs
|
||||
.SH SEE ALSO
|
||||
.IR cp (1)
|
||||
.SH DIAGNOSTICS
|
||||
.I Read
|
||||
exits with status
|
||||
.B eof
|
||||
on end of file or, in the
|
||||
.B -n
|
||||
case, if it doesn't read
|
||||
.I nlines
|
||||
lines.
|
||||
.SH BUGS
|
||||
Beware of
|
||||
.L "cat a b >a"
|
||||
and
|
||||
.LR "cat a b >b" ,
|
||||
which
|
||||
destroy input files before reading them.
|
36
cat/cat.c
Normal file
36
cat/cat.c
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
cat(int f, char *s)
|
||||
{
|
||||
char buf[8192];
|
||||
long n;
|
||||
|
||||
while((n=read(f, buf, (long)sizeof buf))>0)
|
||||
if(write(1, buf, n)!=n)
|
||||
sysfatal("write error copying %s: %r", s);
|
||||
if(n < 0)
|
||||
sysfatal("error reading %s: %r", s);
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int f, i;
|
||||
|
||||
argv0 = "cat";
|
||||
if(argc == 1)
|
||||
cat(0, "<stdin>");
|
||||
else for(i=1; i<argc; i++){
|
||||
f = open(argv[i], OREAD);
|
||||
if(f < 0)
|
||||
sysfatal("can't open %s: %r", argv[i]);
|
||||
else{
|
||||
cat(f, argv[i]);
|
||||
close(f);
|
||||
}
|
||||
}
|
||||
exits(0);
|
||||
}
|
||||
|
36
cleanname/Makefile
Normal file
36
cleanname/Makefile
Normal file
@@ -0,0 +1,36 @@
|
||||
# cleanname - cleanname unix port from plan9
|
||||
# Depends on ../lib9
|
||||
|
||||
include ../config.mk
|
||||
|
||||
TARG = cleanname
|
||||
|
||||
OFILES = cleanname.o
|
||||
|
||||
MANFILES = cleanname.1
|
||||
|
||||
all: ${TARG}
|
||||
@echo built ${TARG}
|
||||
|
||||
install: ${TARG}
|
||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
@cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
|
||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
@cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
|
||||
@chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
|
||||
|
||||
uninstall:
|
||||
rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
|
||||
|
||||
.c.o:
|
||||
@echo CC $*.c
|
||||
@${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
|
||||
|
||||
clean:
|
||||
rm -f ${OFILES} ${TARG}
|
||||
|
||||
${TARG}: ${OFILES}
|
||||
@echo LD ${TARG}
|
||||
@${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9
|
32
cleanname/cleanname.1
Normal file
32
cleanname/cleanname.1
Normal file
@@ -0,0 +1,32 @@
|
||||
.TH CLEANNAME 1
|
||||
.SH NAME
|
||||
cleanname \- clean a path name
|
||||
.SH SYNOPSIS
|
||||
.B cleanname
|
||||
[
|
||||
.B -d
|
||||
.I pwd
|
||||
]
|
||||
.I names ...
|
||||
.SH DESCRIPTION
|
||||
For each file name argument,
|
||||
.IR cleanname ,
|
||||
by lexical processing only,
|
||||
prints the shortest equivalent string that names the same
|
||||
(possibly hypothetical) file.
|
||||
It eliminates multiple and trailing slashes, and it lexically
|
||||
interprets
|
||||
.B .
|
||||
and
|
||||
.B ..
|
||||
directory components in the name.
|
||||
If the
|
||||
.B -d
|
||||
option is present,
|
||||
unrooted names are prefixed with
|
||||
.IB pwd /
|
||||
before processing.
|
||||
.SH SOURCE
|
||||
.B \*9/src/cmd/cleanname.c
|
||||
.SH SEE ALSO
|
||||
.IR cleanname (3).
|
44
cleanname/cleanname.c
Normal file
44
cleanname/cleanname.c
Normal file
@@ -0,0 +1,44 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *dir;
|
||||
char *name;
|
||||
int i;
|
||||
|
||||
dir = nil;
|
||||
ARGBEGIN{
|
||||
case 'd':
|
||||
if((dir=ARGF()) == nil)
|
||||
goto Usage;
|
||||
break;
|
||||
default:
|
||||
goto Usage;
|
||||
}ARGEND;
|
||||
|
||||
if(argc < 1) {
|
||||
Usage:
|
||||
fprint(2, "usage: cleanname [-d pwd] name...\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
for(i=0; i<argc; i++) {
|
||||
if(dir == nil || argv[i][0] == '/') {
|
||||
cleanname(argv[i]);
|
||||
print("%s\n", argv[i]);
|
||||
} else {
|
||||
name = malloc(strlen(argv[i])+1+strlen(dir)+1);
|
||||
if(name == nil) {
|
||||
fprint(2, "cleanname: out of memory\n");
|
||||
exits("out of memory");
|
||||
}
|
||||
sprint(name, "%s/%s", dir, argv[i]);
|
||||
cleanname(name);
|
||||
print("%s\n", name);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
exits(0);
|
||||
}
|
15
config.mk
Normal file
15
config.mk
Normal file
@@ -0,0 +1,15 @@
|
||||
# Customize to fit your system
|
||||
|
||||
# paths
|
||||
PREFIX = /usr/local/9
|
||||
MANPREFIX = ${PREFIX}/share/man
|
||||
|
||||
# flags
|
||||
VERSION = 20051114
|
||||
CFLAGS = -Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -Os -c -I. -DPREFIX="\"${PREFIX}\""
|
||||
LDFLAGS = -static
|
||||
|
||||
# compiler
|
||||
AR = ar rc
|
||||
CC = cc
|
||||
YACC = ../yacc/9yacc
|
36
date/Makefile
Normal file
36
date/Makefile
Normal file
@@ -0,0 +1,36 @@
|
||||
# date - date unix port from plan9
|
||||
# Depends on ../lib9
|
||||
|
||||
include ../config.mk
|
||||
|
||||
TARG = date
|
||||
|
||||
OFILES = date.o
|
||||
|
||||
MANFILES = date.1
|
||||
|
||||
all: ${TARG}
|
||||
@echo built ${TARG}
|
||||
|
||||
install: ${TARG}
|
||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
@cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
|
||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
@cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
|
||||
@chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
|
||||
|
||||
uninstall:
|
||||
rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
|
||||
|
||||
.c.o:
|
||||
@echo CC $*.c
|
||||
@${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
|
||||
|
||||
clean:
|
||||
rm -f ${OFILES} ${TARG}
|
||||
|
||||
${TARG}: ${OFILES}
|
||||
@echo LD ${TARG}
|
||||
@${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9
|
58
date/date.1
Normal file
58
date/date.1
Normal file
@@ -0,0 +1,58 @@
|
||||
.TH DATE 1
|
||||
.SH NAME
|
||||
date \- date and time
|
||||
.SH SYNOPSIS
|
||||
.B date
|
||||
[
|
||||
.I option
|
||||
] [
|
||||
.I seconds
|
||||
]
|
||||
.\" .br
|
||||
.\" .B clock
|
||||
.SH DESCRIPTION
|
||||
Print the date, in the format
|
||||
.PP
|
||||
.B
|
||||
Tue Aug 16 17:03:52 CDT 1977
|
||||
.PP
|
||||
The options are
|
||||
.TP
|
||||
.B -u
|
||||
Report Greenwich Mean Time (GMT) rather than local time.
|
||||
.TP
|
||||
.B -n
|
||||
Report the date as the number of seconds since the
|
||||
epoch, 00:00:00 GMT, January 1, 1970.
|
||||
.PP
|
||||
The conversion from Greenwich Mean Time to local time depends on the
|
||||
.B $timezone
|
||||
environment variable; see
|
||||
.IR ctime (3).
|
||||
.PP
|
||||
If the optional argument
|
||||
.I seconds
|
||||
is present, it is used as the time to convert rather than
|
||||
the real time.
|
||||
.\" .SH FILES
|
||||
.\" .TF /adm/timezone/local
|
||||
.\" .TP
|
||||
.\" .B /env/timezone
|
||||
.\" Current timezone name and adjustments.
|
||||
.\" .TP
|
||||
.\" .B /adm/timezone
|
||||
.\" A directory containing timezone tables.
|
||||
.\" .TP
|
||||
.\" .B /adm/timezone/local
|
||||
.\" Default timezone file, copied by
|
||||
.\" .IR init (8)
|
||||
.\" into
|
||||
.\" .BR /env/timezone .
|
||||
.\" .PD
|
||||
.\" .PP
|
||||
.\" .I Clock
|
||||
.\" draws a simple analog clock in its window.
|
||||
.SH SOURCE
|
||||
.B \*9/src/cmd/date.c
|
||||
.\" .br
|
||||
.\" .B \*9/src/cmd/draw/clock.c
|
30
date/date.c
Normal file
30
date/date.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int uflg, nflg;
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
ulong now;
|
||||
|
||||
ARGBEGIN{
|
||||
case 'n': nflg = 1; break;
|
||||
case 'u': uflg = 1; break;
|
||||
default: fprint(2, "usage: date [-un] [seconds]\n"); exits("usage");
|
||||
}ARGEND
|
||||
|
||||
if(argc == 1)
|
||||
now = strtoul(*argv, 0, 0);
|
||||
else
|
||||
now = time(0);
|
||||
|
||||
if(nflg)
|
||||
print("%ld\n", now);
|
||||
else if(uflg)
|
||||
print("%s", asctime(gmtime(now)));
|
||||
else
|
||||
print("%s", ctime(now));
|
||||
|
||||
exits(0);
|
||||
}
|
36
echo/Makefile
Normal file
36
echo/Makefile
Normal file
@@ -0,0 +1,36 @@
|
||||
# echo - echo unix port from plan9
|
||||
# Depends on ../lib9
|
||||
|
||||
include ../config.mk
|
||||
|
||||
TARG = echo
|
||||
|
||||
OFILES = echo.o
|
||||
|
||||
MANFILES = echo.1
|
||||
|
||||
all: ${TARG}
|
||||
@echo built ${TARG}
|
||||
|
||||
install: ${TARG}
|
||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
@cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
|
||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
@cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
|
||||
@chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
|
||||
|
||||
uninstall:
|
||||
rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
|
||||
|
||||
.c.o:
|
||||
@echo CC $*.c
|
||||
@${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
|
||||
|
||||
clean:
|
||||
rm -f ${OFILES} ${TARG}
|
||||
|
||||
${TARG}: ${OFILES}
|
||||
@echo LD ${TARG}
|
||||
@${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9
|
26
echo/echo.1
Normal file
26
echo/echo.1
Normal file
@@ -0,0 +1,26 @@
|
||||
.TH ECHO 1
|
||||
.SH NAME
|
||||
echo \- print arguments
|
||||
.SH SYNOPSIS
|
||||
.B echo
|
||||
[
|
||||
.B -n
|
||||
]
|
||||
[
|
||||
.I arg ...
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Echo
|
||||
writes its arguments separated by blanks and terminated by
|
||||
a newline on the standard output.
|
||||
Option
|
||||
.B -n
|
||||
suppresses the newline.
|
||||
.SH SOURCE
|
||||
.B \*9/src/cmd/echo.c
|
||||
.SH DIAGNOSTICS
|
||||
If
|
||||
.I echo
|
||||
draws an error while writing to standard output, the exit status is
|
||||
.LR "write error" .
|
||||
Otherwise the exit status is empty.
|
38
echo/echo.c
Normal file
38
echo/echo.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int nflag;
|
||||
int i, len;
|
||||
char *buf, *p;
|
||||
|
||||
nflag = 0;
|
||||
if(argc > 1 && strcmp(argv[1], "-n") == 0)
|
||||
nflag = 1;
|
||||
|
||||
len = 1;
|
||||
for(i = 1+nflag; i < argc; i++)
|
||||
len += strlen(argv[i])+1;
|
||||
|
||||
buf = malloc(len);
|
||||
if(buf == 0)
|
||||
exits("no memory");
|
||||
|
||||
p = buf;
|
||||
for(i = 1+nflag; i < argc; i++){
|
||||
strcpy(p, argv[i]);
|
||||
p += strlen(p);
|
||||
if(i < argc-1)
|
||||
*p++ = ' ';
|
||||
}
|
||||
|
||||
if(!nflag)
|
||||
*p++ = '\n';
|
||||
|
||||
if(write(1, buf, p-buf) < 0)
|
||||
fprint(2, "echo: write error: %r\n");
|
||||
|
||||
exits((char *)0);
|
||||
}
|
46
grep/Makefile
Normal file
46
grep/Makefile
Normal file
@@ -0,0 +1,46 @@
|
||||
# grep - grep unix port from plan9
|
||||
# Depends on ../lib9
|
||||
|
||||
include ../config.mk
|
||||
|
||||
TARG = grep
|
||||
|
||||
OFILES = y.tab.o main.o comp.o sub.o
|
||||
|
||||
YFILES = grep.y
|
||||
|
||||
MANFILES = grep.1
|
||||
|
||||
all:
|
||||
@if [ ! -f y.tab.c ]; then \
|
||||
${MAKE} -f Makefile depend;\
|
||||
fi
|
||||
@${MAKE} -f Makefile ${TARG}
|
||||
@echo built ${TARG}
|
||||
|
||||
depend:
|
||||
@echo YACC ${YFILES}
|
||||
@${YACC} -d ${YFILES}
|
||||
|
||||
install: ${TARG}
|
||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||
@cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
|
||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||
@cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
|
||||
@chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
|
||||
|
||||
uninstall:
|
||||
rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
|
||||
rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
|
||||
|
||||
.c.o:
|
||||
@echo CC $*.c
|
||||
@${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
|
||||
|
||||
clean:
|
||||
rm -f ${OFILES} ${TARG} y.tab.c y.tab.h
|
||||
|
||||
${TARG}: ${OFILES}
|
||||
@echo LD ${TARG}
|
||||
@${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9
|
277
grep/comp.c
Normal file
277
grep/comp.c
Normal file
@@ -0,0 +1,277 @@
|
||||
#include "grep.h"
|
||||
|
||||
/*
|
||||
* incremental compiler.
|
||||
* add the branch c to the
|
||||
* state s.
|
||||
*/
|
||||
void
|
||||
increment(State *s, int c)
|
||||
{
|
||||
int i;
|
||||
State *t, **tt;
|
||||
Re *re1, *re2;
|
||||
|
||||
nfollow = 0;
|
||||
gen++;
|
||||
matched = 0;
|
||||
for(i=0; i<s->count; i++)
|
||||
fol1(s->re[i], c);
|
||||
qsort(follow, nfollow, sizeof(*follow), fcmp);
|
||||
for(tt=&state0; t = *tt;) {
|
||||
if(t->count > nfollow) {
|
||||
tt = &t->linkleft;
|
||||
goto cont;
|
||||
}
|
||||
if(t->count < nfollow) {
|
||||
tt = &t->linkright;
|
||||
goto cont;
|
||||
}
|
||||
for(i=0; i<nfollow; i++) {
|
||||
re1 = t->re[i];
|
||||
re2 = follow[i];
|
||||
if(re1 > re2) {
|
||||
tt = &t->linkleft;
|
||||
goto cont;
|
||||
}
|
||||
if(re1 < re2) {
|
||||
tt = &t->linkright;
|
||||
goto cont;
|
||||
}
|
||||
}
|
||||
if(!!matched && !t->match) {
|
||||
tt = &t->linkleft;
|
||||
goto cont;
|
||||
}
|
||||
if(!matched && !!t->match) {
|
||||
tt = &t->linkright;
|
||||
goto cont;
|
||||
}
|
||||
s->next[c] = t;
|
||||
return;
|
||||
cont:;
|
||||
}
|
||||
|
||||
t = sal(nfollow);
|
||||
*tt = t;
|
||||
for(i=0; i<nfollow; i++) {
|
||||
re1 = follow[i];
|
||||
t->re[i] = re1;
|
||||
}
|
||||
s->next[c] = t;
|
||||
t->match = matched;
|
||||
}
|
||||
|
||||
int
|
||||
fcmp(const void *va, const void *vb)
|
||||
{
|
||||
Re **aa, **bb;
|
||||
Re *a, *b;
|
||||
|
||||
aa = (Re**)va;
|
||||
bb = (Re**)vb;
|
||||
a = *aa;
|
||||
b = *bb;
|
||||
if(a > b)
|
||||
return 1;
|
||||
if(a < b)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
fol1(Re *r, int c)
|
||||
{
|
||||
Re *r1;
|
||||
|
||||
loop:
|
||||
if(r->gen == gen)
|
||||
return;
|
||||
if(nfollow >= maxfollow)
|
||||
error("nfollow");
|
||||
r->gen = gen;
|
||||
switch(r->type) {
|
||||
default:
|
||||
error("fol1");
|
||||
|
||||
case Tcase:
|
||||
if(c >= 0 && c < 256)
|
||||
if(r1 = r->u.cases[c])
|
||||
follow[nfollow++] = r1;
|
||||
if(r = r->next)
|
||||
goto loop;
|
||||
break;
|
||||
|
||||
case Talt:
|
||||
case Tor:
|
||||
fol1(r->u.alt, c);
|
||||
r = r->next;
|
||||
goto loop;
|
||||
|
||||
case Tbegin:
|
||||
if(c == '\n' || c == Cbegin)
|
||||
follow[nfollow++] = r->next;
|
||||
break;
|
||||
|
||||
case Tend:
|
||||
if(c == '\n')
|
||||
matched = 1;
|
||||
break;
|
||||
|
||||
case Tclass:
|
||||
if(c >= r->u.x.lo && c <= r->u.x.hi)
|
||||
follow[nfollow++] = r->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Rune tab1[] =
|
||||
{
|
||||
0x007f,
|
||||
0x07ff,
|
||||
};
|
||||
Rune tab2[] =
|
||||
{
|
||||
0x003f,
|
||||
0x0fff,
|
||||
};
|
||||
|
||||
Re2
|
||||
rclass(Rune p0, Rune p1)
|
||||
{
|
||||
char xc0[6], xc1[6];
|
||||
int i, n, m;
|
||||
Re2 x;
|
||||
|
||||
if(p0 > p1)
|
||||
return re2char(0xff, 0xff); // no match
|
||||
|
||||
/*
|
||||
* bust range into same length
|
||||
* character sequences
|
||||
*/
|
||||
for(i=0; i<nelem(tab1); i++) {
|
||||
m = tab1[i];
|
||||
if(p0 <= m && p1 > m)
|
||||
return re2or(rclass(p0, m), rclass(m+1, p1));
|
||||
}
|
||||
|
||||
/*
|
||||
* bust range into part of a single page
|
||||
* or into full pages
|
||||
*/
|
||||
for(i=0; i<nelem(tab2); i++) {
|
||||
m = tab2[i];
|
||||
if((p0 & ~m) != (p1 & ~m)) {
|
||||
if((p0 & m) != 0)
|
||||
return re2or(rclass(p0, p0|m), rclass((p0|m)+1, p1));
|
||||
if((p1 & m) != m)
|
||||
return re2or(rclass(p0, (p1&~m)-1), rclass(p1&~m, p1));
|
||||
}
|
||||
}
|
||||
|
||||
n = runetochar(xc0, &p0);
|
||||
i = runetochar(xc1, &p1);
|
||||
if(i != n)
|
||||
error("length");
|
||||
|
||||
x = re2char(xc0[0], xc1[0]);
|
||||
for(i=1; i<n; i++)
|
||||
x = re2cat(x, re2char(xc0[i], xc1[i]));
|
||||
return x;
|
||||
}
|
||||
|
||||
int
|
||||
pcmp(const void *va, const void *vb)
|
||||
{
|
||||
int n;
|
||||
Rune *a, *b;
|
||||
|
||||
a = (Rune*)va;
|
||||
b = (Rune*)vb;
|
||||
|
||||
n = a[0] - b[0];
|
||||
if(n)
|
||||
return n;
|
||||
return a[1] - b[1];
|
||||
}
|
||||
|
||||
/*
|
||||
* convert character chass into
|
||||
* run-pair ranges of matches.
|
||||
* this is 10646/utf specific and
|
||||
* needs to be changed for some
|
||||
* other input character set.
|
||||
* this is the key to a fast
|
||||
* regular search of characters
|
||||
* by looking at sequential bytes.
|
||||
*/
|
||||
Re2
|
||||
re2class(char *s)
|
||||
{
|
||||
Rune pairs[200], *p, *q, ov;
|
||||
int nc;
|
||||
Re2 x;
|
||||
|
||||
nc = 0;
|
||||
if(*s == '^') {
|
||||
nc = 1;
|
||||
s++;
|
||||
}
|
||||
|
||||
p = pairs;
|
||||
s += chartorune(p, s);
|
||||
for(;;) {
|
||||
if(*p == '\\')
|
||||
s += chartorune(p, s);
|
||||
if(*p == 0)
|
||||
break;
|
||||
p[1] = *p;
|
||||
p += 2;
|
||||
s += chartorune(p, s);
|
||||
if(*p != '-')
|
||||
continue;
|
||||
s += chartorune(p, s);
|
||||
if(*p == '\\')
|
||||
s += chartorune(p, s);
|
||||
if(*p == 0)
|
||||
break;
|
||||
p[-1] = *p;
|
||||
s += chartorune(p, s);
|
||||
}
|
||||
*p = 0;
|
||||
qsort(pairs, (p-pairs)/2, 2*sizeof(*pairs), pcmp);
|
||||
|
||||
q = pairs;
|
||||
for(p=pairs+2; *p; p+=2) {
|
||||
if(p[0] > p[1])
|
||||
continue;
|
||||
if(p[0] > q[1] || p[1] < q[0]) {
|
||||
q[2] = p[0];
|
||||
q[3] = p[1];
|
||||
q += 2;
|
||||
continue;
|
||||
}
|
||||
if(p[0] < q[0])
|
||||
q[0] = p[0];
|
||||
if(p[1] > q[1])
|
||||
q[1] = p[1];
|
||||
}
|
||||
q[2] = 0;
|
||||
|
||||
p = pairs;
|
||||
if(nc) {
|
||||
x = rclass(0, p[0]-1);
|
||||
ov = p[1]+1;
|
||||
for(p+=2; *p; p+=2) {
|
||||
x = re2or(x, rclass(ov, p[0]-1));
|
||||
ov = p[1]+1;
|
||||
}
|
||||
x = re2or(x, rclass(ov, 0xffff));
|
||||
} else {
|
||||
x = rclass(p[0], p[1]);
|
||||
for(p+=2; *p; p+=2)
|
||||
x = re2or(x, rclass(p[0], p[1]));
|
||||
}
|
||||
return x;
|
||||
}
|
124
grep/grep.1
Normal file
124
grep/grep.1
Normal file
@@ -0,0 +1,124 @@
|
||||
.TH GREP 1
|
||||
.SH NAME
|
||||
grep, g \- search a file for a pattern
|
||||
.SH SYNOPSIS
|
||||
.B grep
|
||||
[
|
||||
.I option ...
|
||||
]
|
||||
.I pattern
|
||||
[
|
||||
.I file ...
|
||||
]
|
||||
.PP
|
||||
.B g
|
||||
[
|
||||
.I option ...
|
||||
]
|
||||
.I pattern
|
||||
[
|
||||
.I file ...
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Grep\^
|
||||
searches the input
|
||||
.I files\^
|
||||
(standard input default)
|
||||
for lines that match the
|
||||
.IR pattern ,
|
||||
a regular expression as defined in
|
||||
.IR regexp (7)
|
||||
with the addition of a newline character as an alternative
|
||||
(substitute for
|
||||
.BR | )
|
||||
with lowest precedence.
|
||||
Normally, each line matching the pattern is `selected',
|
||||
and each selected line is copied to the standard output.
|
||||
The options are
|
||||
.TP
|
||||
.B -c
|
||||
Print only a count of matching lines.
|
||||
.PD 0
|
||||
.TP
|
||||
.B -h
|
||||
Do not print file name tags (headers) with output lines.
|
||||
.TP
|
||||
.B -e
|
||||
The following argument is taken as a
|
||||
.IR pattern .
|
||||
This option makes it easy to specify patterns that
|
||||
might confuse argument parsing, such as
|
||||
.BR -n .
|
||||
.TP
|
||||
.B -i
|
||||
Ignore alphabetic case distinctions. The implementation
|
||||
folds into lower case all letters in the pattern and input before
|
||||
interpretation. Matched lines are printed in their original form.
|
||||
.TP
|
||||
.B -l
|
||||
(ell) Print the names of files with selected lines; don't print the lines.
|
||||
.TP
|
||||
.B -L
|
||||
Print the names of files with no selected lines;
|
||||
the converse of
|
||||
.BR -l .
|
||||
.TP
|
||||
.B -n
|
||||
Mark each printed line with its line number counted in its file.
|
||||
.TP
|
||||
.B -s
|
||||
Produce no output, but return status.
|
||||
.TP
|
||||
.B -v
|
||||
Reverse: print lines that do not match the pattern.
|
||||
.TP
|
||||
.B -f
|
||||
The pattern argument is the name of a file containing regular
|
||||
expressions one per line.
|
||||
.TP
|
||||
.B -b
|
||||
Don't buffer the output: write each output line as soon as it is discovered.
|
||||
.PD
|
||||
.PP
|
||||
Output lines are tagged by file name when there is more than one
|
||||
input file.
|
||||
(To force this tagging, include
|
||||
.B /dev/null
|
||||
as a file name argument.)
|
||||
.PP
|
||||
Care should be taken when
|
||||
using the shell metacharacters
|
||||
.B $*[^|()=\e
|
||||
and newline
|
||||
in
|
||||
.IR pattern ;
|
||||
it is safest to enclose the
|
||||
entire expression
|
||||
in single quotes
|
||||
.BR \&\|' \|.\|.\|.\| ' .
|
||||
An expression starting with '*'
|
||||
will treat the rest of the expression
|
||||
as literal characters.
|
||||
.PP
|
||||
.I G
|
||||
invokes grep with
|
||||
.B -n
|
||||
and forces tagging of output lines by file name.
|
||||
If no files are listed, it searches all files matching
|
||||
.IP
|
||||
.EX
|
||||
*.C *.b *.c *.h *.m *.cc *.java *.cgi *.pl *.py *.tex *.ms
|
||||
.EE
|
||||
.SH SOURCE
|
||||
.B \*9/src/cmd/grep
|
||||
.br
|
||||
.B \*9/bin/g
|
||||
.SH SEE ALSO
|
||||
.IR ed (1),
|
||||
.IR awk (1),
|
||||
.IR sed (1),
|
||||
.IR sam (1),
|
||||
.IR regexp (7)
|
||||
.SH DIAGNOSTICS
|
||||
Exit status is null if any lines are selected,
|
||||
or non-null when no lines are selected or an error occurs.
|
125
grep/grep.h
Normal file
125
grep/grep.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
|
||||
#ifndef EXTERN
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
typedef struct Re Re;
|
||||
typedef struct Re2 Re2;
|
||||
typedef struct State State;
|
||||
|
||||
struct State
|
||||
{
|
||||
int count;
|
||||
int match;
|
||||
Re** re;
|
||||
State* linkleft;
|
||||
State* linkright;
|
||||
State* next[256];
|
||||
};
|
||||
struct Re2
|
||||
{
|
||||
Re* beg;
|
||||
Re* end;
|
||||
};
|
||||
struct Re
|
||||
{
|
||||
uchar type;
|
||||
ushort gen;
|
||||
union
|
||||
{
|
||||
Re* alt; /* Talt */
|
||||
Re** cases; /* case */
|
||||
struct /* class */
|
||||
{
|
||||
Rune lo;
|
||||
Rune hi;
|
||||
} x;
|
||||
Rune val; /* char */
|
||||
} u;
|
||||
Re* next;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Talt = 1,
|
||||
Tbegin,
|
||||
Tcase,
|
||||
Tclass,
|
||||
Tend,
|
||||
Tor,
|
||||
|
||||
Caselim = 7,
|
||||
Nhunk = 1<<16,
|
||||
Cbegin = 0x10000,
|
||||
Flshcnt = (1<<9)-1,
|
||||
|
||||
Cflag = 1<<0,
|
||||
Hflag = 1<<1,
|
||||
Iflag = 1<<2,
|
||||
Llflag = 1<<3,
|
||||
LLflag = 1<<4,
|
||||
Nflag = 1<<5,
|
||||
Sflag = 1<<6,
|
||||
Vflag = 1<<7,
|
||||
Bflag = 1<<8
|
||||
};
|
||||
|
||||
EXTERN union
|
||||
{
|
||||
char string[16*1024];
|
||||
struct
|
||||
{
|
||||
/*
|
||||
* if a line requires multiple reads, we keep shifting
|
||||
* buf down into pre and then do another read into
|
||||
* buf. so you'll get the last 16-32k of the matching line.
|
||||
* if h were smaller than buf you'd get a suffix of the
|
||||
* line with a hole cut out.
|
||||
*/
|
||||
uchar pre[16*1024]; /* to save to previous '\n' */
|
||||
uchar buf[16*1024]; /* input buffer */
|
||||
} u;
|
||||
} u;
|
||||
|
||||
EXTERN char *filename;
|
||||
EXTERN Biobuf bout;
|
||||
EXTERN char flags[256];
|
||||
EXTERN Re** follow;
|
||||
EXTERN ushort gen;
|
||||
EXTERN char* input;
|
||||
EXTERN long lineno;
|
||||
EXTERN int literal;
|
||||
EXTERN int matched;
|
||||
EXTERN long maxfollow;
|
||||
EXTERN long nfollow;
|
||||
EXTERN int peekc;
|
||||
EXTERN Biobuf* rein;
|
||||
EXTERN State* state0;
|
||||
EXTERN Re2 topre;
|
||||
|
||||
extern Re* addcase(Re*);
|
||||
extern void appendnext(Re*, Re*);
|
||||
extern void error(char*);
|
||||
extern int fcmp(const void*, const void*); /* (Re**, Re**) */
|
||||
extern void fol1(Re*, int);
|
||||
extern int getrec(void);
|
||||
extern void increment(State*, int);
|
||||
#define initstate grepinitstate
|
||||
extern State* initstate(Re*);
|
||||
extern void* mal(int);
|
||||
extern void patchnext(Re*, Re*);
|
||||
extern Re* ral(int);
|
||||
extern Re2 re2cat(Re2, Re2);
|
||||
extern Re2 re2class(char*);
|
||||
extern Re2 re2or(Re2, Re2);
|
||||
extern Re2 re2char(int, int);
|
||||
extern Re2 re2star(Re2);
|
||||
extern State* sal(int);
|
||||
extern int search(char*, int);
|
||||
extern void str2top(char*);
|
||||
extern int yyparse(void);
|
||||
extern void reprint(char*, Re*);
|
||||
extern void yyerror(char*, ...);
|
226
grep/grep.y
Normal file
226
grep/grep.y
Normal file
@@ -0,0 +1,226 @@
|
||||
%{
|
||||
#include "grep.h"
|
||||
%}
|
||||
|
||||
%union
|
||||
{
|
||||
int val;
|
||||
char* str;
|
||||
Re2 re;
|
||||
}
|
||||
|
||||
%type <re> expr prog
|
||||
%type <re> expr0 expr1 expr2 expr3 expr4
|
||||
%token <str> LCLASS
|
||||
%token <val> LCHAR
|
||||
%token LLPAREN LRPAREN LALT LSTAR LPLUS LQUES
|
||||
%token LBEGIN LEND LDOT LBAD LNEWLINE
|
||||
%%
|
||||
|
||||
prog:
|
||||
expr newlines
|
||||
{
|
||||
$$.beg = ral(Tend);
|
||||
$$.end = $$.beg;
|
||||
$$ = re2cat(re2star(re2or(re2char(0x00, '\n'-1), re2char('\n'+1, 0xff))), $$);
|
||||
$$ = re2cat($1, $$);
|
||||
$$ = re2cat(re2star(re2char(0x00, 0xff)), $$);
|
||||
topre = $$;
|
||||
}
|
||||
|
||||
expr:
|
||||
expr0
|
||||
| expr newlines expr0
|
||||
{
|
||||
$$ = re2or($1, $3);
|
||||
}
|
||||
|
||||
expr0:
|
||||
expr1
|
||||
| LSTAR { literal = 1; } expr1
|
||||
{
|
||||
$$ = $3;
|
||||
}
|
||||
|
||||
expr1:
|
||||
expr2
|
||||
| expr1 LALT expr2
|
||||
{
|
||||
$$ = re2or($1, $3);
|
||||
}
|
||||
|
||||
expr2:
|
||||
expr3
|
||||
| expr2 expr3
|
||||
{
|
||||
$$ = re2cat($1, $2);
|
||||
}
|
||||
|
||||
expr3:
|
||||
expr4
|
||||
| expr3 LSTAR
|
||||
{
|
||||
$$ = re2star($1);
|
||||
}
|
||||
| expr3 LPLUS
|
||||
{
|
||||
$$.beg = ral(Talt);
|
||||
patchnext($1.end, $$.beg);
|
||||
$$.beg->u.alt = $1.beg;
|
||||
$$.end = $$.beg;
|
||||
$$.beg = $1.beg;
|
||||
}
|
||||
| expr3 LQUES
|
||||
{
|
||||
$$.beg = ral(Talt);
|
||||
$$.beg->u.alt = $1.beg;
|
||||
$$.end = $1.end;
|
||||
appendnext($$.end, $$.beg);
|
||||
}
|
||||
|
||||
expr4:
|
||||
LCHAR
|
||||
{
|
||||
$$.beg = ral(Tclass);
|
||||
$$.beg->u.x.lo = $1;
|
||||
$$.beg->u.x.hi = $1;
|
||||
$$.end = $$.beg;
|
||||
}
|
||||
| LBEGIN
|
||||
{
|
||||
$$.beg = ral(Tbegin);
|
||||
$$.end = $$.beg;
|
||||
}
|
||||
| LEND
|
||||
{
|
||||
$$.beg = ral(Tend);
|
||||
$$.end = $$.beg;
|
||||
}
|
||||
| LDOT
|
||||
{
|
||||
$$ = re2class("^\n");
|
||||
}
|
||||
| LCLASS
|
||||
{
|
||||
$$ = re2class($1);
|
||||
}
|
||||
| LLPAREN expr1 LRPAREN
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
newlines:
|
||||
LNEWLINE
|
||||
| newlines LNEWLINE
|
||||
%%
|
||||
|
||||
void
|
||||
yyerror(char *e, ...)
|
||||
{
|
||||
if(filename)
|
||||
fprint(2, "grep: %s:%ld: %s\n", filename, lineno, e);
|
||||
else
|
||||
fprint(2, "grep: %s\n", e);
|
||||
exits("syntax");
|
||||
}
|
||||
|
||||
int
|
||||
yylex(void)
|
||||
{
|
||||
char *q, *eq;
|
||||
int c, s;
|
||||
|
||||
if(peekc) {
|
||||
s = peekc;
|
||||
peekc = 0;
|
||||
return s;
|
||||
}
|
||||
c = getrec();
|
||||
if(literal) {
|
||||
if(c != 0 && c != '\n') {
|
||||
yylval.val = c;
|
||||
return LCHAR;
|
||||
}
|
||||
literal = 0;
|
||||
}
|
||||
switch(c) {
|
||||
default:
|
||||
yylval.val = c;
|
||||
s = LCHAR;
|
||||
break;
|
||||
case '\\':
|
||||
c = getrec();
|
||||
yylval.val = c;
|
||||
s = LCHAR;
|
||||
if(c == '\n')
|
||||
s = LNEWLINE;
|
||||
break;
|
||||
case '[':
|
||||
goto getclass;
|
||||
case '(':
|
||||
s = LLPAREN;
|
||||
break;
|
||||
case ')':
|
||||
s = LRPAREN;
|
||||
break;
|
||||
case '|':
|
||||
s = LALT;
|
||||
break;
|
||||
case '*':
|
||||
s = LSTAR;
|
||||
break;
|
||||
case '+':
|
||||
s = LPLUS;
|
||||
break;
|
||||
case '?':
|
||||
s = LQUES;
|
||||
break;
|
||||
case '^':
|
||||
s = LBEGIN;
|
||||
break;
|
||||
case '$':
|
||||
s = LEND;
|
||||
break;
|
||||
case '.':
|
||||
s = LDOT;
|
||||
break;
|
||||
case 0:
|
||||
peekc = -1;
|
||||
case '\n':
|
||||
s = LNEWLINE;
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
|
||||
getclass:
|
||||
q = u.string;
|
||||
eq = q + nelem(u.string) - 5;
|
||||
c = getrec();
|
||||
if(c == '^') {
|
||||
q[0] = '^';
|
||||
q[1] = '\n';
|
||||
q[2] = '-';
|
||||
q[3] = '\n';
|
||||
q += 4;
|
||||
c = getrec();
|
||||
}
|
||||
for(;;) {
|
||||
if(q >= eq)
|
||||
error("class too long");
|
||||
if(c == ']' || c == 0)
|
||||
break;
|
||||
if(c == '\\') {
|
||||
*q++ = c;
|
||||
c = getrec();
|
||||
if(c == 0)
|
||||
break;
|
||||
}
|
||||
*q++ = c;
|
||||
c = getrec();
|
||||
}
|
||||
*q = 0;
|
||||
if(c == 0)
|
||||
return LBAD;
|
||||
yylval.str = u.string;
|
||||
return LCLASS;
|
||||
}
|
263
grep/main.c
Normal file
263
grep/main.c
Normal file
@@ -0,0 +1,263 @@
|
||||
#define EXTERN
|
||||
#include "grep.h"
|
||||
|
||||
char *validflags = "bchiLlnsv";
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: grep [-%s] [-f file] [-e expr] [file ...]\n", validflags);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, status;
|
||||
|
||||
ARGBEGIN {
|
||||
default:
|
||||
if(utfrune(validflags, ARGC()) == nil)
|
||||
usage();
|
||||
flags[ARGC()]++;
|
||||
break;
|
||||
|
||||
case 'E': /* ignore, turns gnu grep into egrep */
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
flags['e']++;
|
||||
lineno = 0;
|
||||
str2top(ARGF());
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
flags['f']++;
|
||||
filename = ARGF();
|
||||
rein = Bopen(filename, OREAD);
|
||||
if(rein == 0) {
|
||||
fprint(2, "grep: can't open %s: %r\n", filename);
|
||||
exits("open");
|
||||
}
|
||||
lineno = 1;
|
||||
str2top(filename);
|
||||
break;
|
||||
} ARGEND
|
||||
|
||||
if(flags['f'] == 0 && flags['e'] == 0) {
|
||||
if(argc <= 0)
|
||||
usage();
|
||||
str2top(argv[0]);
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
follow = mal(maxfollow*sizeof(*follow));
|
||||
state0 = initstate(topre.beg);
|
||||
|
||||
Binit(&bout, 1, OWRITE);
|
||||
switch(argc) {
|
||||
case 0:
|
||||
status = search(0, 0);
|
||||
break;
|
||||
case 1:
|
||||
status = search(argv[0], 0);
|
||||
break;
|
||||
default:
|
||||
status = 0;
|
||||
for(i=0; i<argc; i++)
|
||||
status |= search(argv[i], Hflag);
|
||||
break;
|
||||
}
|
||||
if(status)
|
||||
exits(0);
|
||||
exits("no matches");
|
||||
}
|
||||
|
||||
int
|
||||
search(char *file, int flag)
|
||||
{
|
||||
State *s, *ns;
|
||||
int c, fid, eof, nl, empty;
|
||||
long count, lineno, n;
|
||||
uchar *elp, *lp, *bol;
|
||||
|
||||
if(file == 0) {
|
||||
file = "stdin";
|
||||
fid = 0;
|
||||
flag |= Bflag;
|
||||
} else
|
||||
fid = open(file, OREAD);
|
||||
|
||||
if(fid < 0) {
|
||||
fprint(2, "grep: can't open %s: %r\n", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(flags['b'])
|
||||
flag ^= Bflag; /* dont buffer output */
|
||||
if(flags['c'])
|
||||
flag |= Cflag; /* count */
|
||||
if(flags['h'])
|
||||
flag &= ~Hflag; /* do not print file name in output */
|
||||
if(flags['i'])
|
||||
flag |= Iflag; /* fold upper-lower */
|
||||
if(flags['l'])
|
||||
flag |= Llflag; /* print only name of file if any match */
|
||||
if(flags['L'])
|
||||
flag |= LLflag; /* print only name of file if any non match */
|
||||
if(flags['n'])
|
||||
flag |= Nflag; /* count only */
|
||||
if(flags['s'])
|
||||
flag |= Sflag; /* status only */
|
||||
if(flags['v'])
|
||||
flag |= Vflag; /* inverse match */
|
||||
|
||||
s = state0;
|
||||
lineno = 0;
|
||||
count = 0;
|
||||
eof = 0;
|
||||
empty = 1;
|
||||
nl = 0;
|
||||
lp = u.u.buf;
|
||||
bol = lp;
|
||||
|
||||
loop0:
|
||||
n = lp-bol;
|
||||
if(n > sizeof(u.u.pre))
|
||||
n = sizeof(u.u.pre);
|
||||
memmove(u.u.buf-n, bol, n);
|
||||
bol = u.u.buf-n;
|
||||
n = read(fid, u.u.buf, sizeof(u.u.buf));
|
||||
/* if file has no final newline, simulate one to emit matches to last line */
|
||||
if(n > 0) {
|
||||
empty = 0;
|
||||
nl = u.u.buf[n-1]=='\n';
|
||||
} else {
|
||||
if(n < 0){
|
||||
fprint(2, "grep: read error on %s: %r\n", file);
|
||||
return count != 0;
|
||||
}
|
||||
if(!eof && !nl && !empty) {
|
||||
u.u.buf[0] = '\n';
|
||||
n = 1;
|
||||
eof = 1;
|
||||
}
|
||||
}
|
||||
if(n <= 0) {
|
||||
close(fid);
|
||||
if(flag & Cflag) {
|
||||
if(flag & Hflag)
|
||||
Bprint(&bout, "%s:", file);
|
||||
Bprint(&bout, "%ld\n", count);
|
||||
}
|
||||
if(((flag&Llflag) && count != 0) || ((flag&LLflag) && count == 0))
|
||||
Bprint(&bout, "%s\n", file);
|
||||
Bflush(&bout);
|
||||
return count != 0;
|
||||
}
|
||||
lp = u.u.buf;
|
||||
elp = lp+n;
|
||||
if(flag & Iflag)
|
||||
goto loopi;
|
||||
|
||||
/*
|
||||
* normal character loop
|
||||
*/
|
||||
loop:
|
||||
c = *lp;
|
||||
ns = s->next[c];
|
||||
if(ns == 0) {
|
||||
increment(s, c);
|
||||
goto loop;
|
||||
}
|
||||
// if(flags['2'])
|
||||
// if(s->match)
|
||||
// print("%d: %.2x**\n", s, c);
|
||||
// else
|
||||
// print("%d: %.2x\n", s, c);
|
||||
lp++;
|
||||
s = ns;
|
||||
if(c == '\n') {
|
||||
lineno++;
|
||||
if(!!s->match == !(flag&Vflag)) {
|
||||
count++;
|
||||
if(flag & (Cflag|Sflag|Llflag|LLflag))
|
||||
goto cont;
|
||||
if(flag & Hflag)
|
||||
Bprint(&bout, "%s:", file);
|
||||
if(flag & Nflag)
|
||||
Bprint(&bout, "%ld: ", lineno);
|
||||
/* suppress extra newline at EOF unless we are labeling matches with file name */
|
||||
Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
|
||||
if(flag & Bflag)
|
||||
Bflush(&bout);
|
||||
}
|
||||
if((lineno & Flshcnt) == 0)
|
||||
Bflush(&bout);
|
||||
cont:
|
||||
bol = lp;
|
||||
}
|
||||
if(lp != elp)
|
||||
goto loop;
|
||||
goto loop0;
|
||||
|
||||
/*
|
||||
* character loop for -i flag
|
||||
* for speed
|
||||
*/
|
||||
loopi:
|
||||
c = *lp;
|
||||
if(c >= 'A' && c <= 'Z')
|
||||
c += 'a'-'A';
|
||||
ns = s->next[c];
|
||||
if(ns == 0) {
|
||||
increment(s, c);
|
||||
goto loopi;
|
||||
}
|
||||
lp++;
|
||||
s = ns;
|
||||
if(c == '\n') {
|
||||
lineno++;
|
||||
if(!!s->match == !(flag&Vflag)) {
|
||||
count++;
|
||||
if(flag & (Cflag|Sflag|Llflag|LLflag))
|
||||
goto conti;
|
||||
if(flag & Hflag)
|
||||
Bprint(&bout, "%s:", file);
|
||||
if(flag & Nflag)
|
||||
Bprint(&bout, "%ld: ", lineno);
|
||||
/* suppress extra newline at EOF unless we are labeling matches with file name */
|
||||
Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
|
||||
if(flag & Bflag)
|
||||
Bflush(&bout);
|
||||
}
|
||||
if((lineno & Flshcnt) == 0)
|
||||
Bflush(&bout);
|
||||
conti:
|
||||
bol = lp;
|
||||
}
|
||||
if(lp != elp)
|
||||
goto loopi;
|
||||
goto loop0;
|
||||
}
|
||||
|
||||
State*
|
||||
initstate(Re *r)
|
||||
{
|
||||
State *s;
|
||||
int i;
|
||||
|
||||
addcase(r);
|
||||
if(flags['1'])
|
||||
reprint("r", r);
|
||||
nfollow = 0;
|
||||
gen++;
|
||||
fol1(r, Cbegin);
|
||||
follow[nfollow++] = r;
|
||||
qsort(follow, nfollow, sizeof(*follow), fcmp);
|
||||
|
||||
s = sal(nfollow);
|
||||
for(i=0; i<nfollow; i++)
|
||||
s->re[i] = follow[i];
|
||||
return s;
|
||||
}
|
317
grep/sub.c
Normal file
317
grep/sub.c
Normal file
@@ -0,0 +1,317 @@
|
||||
#include "grep.h"
|
||||
|
||||
void*
|
||||
mal(int n)
|
||||
{
|
||||
static char *s;
|
||||
static int m = 0;
|
||||
void *v;
|
||||
|
||||
n = (n+3) & ~3;
|
||||
if(m < n) {
|
||||
if(n > Nhunk) {
|
||||
v = sbrk(n);
|
||||
memset(v, 0, n);
|
||||
return v;
|
||||
}
|
||||
s = sbrk(Nhunk);
|
||||
m = Nhunk;
|
||||
}
|
||||
v = s;
|
||||
s += n;
|
||||
m -= n;
|
||||
memset(v, 0, n);
|
||||
return v;
|
||||
}
|
||||
|
||||
State*
|
||||
sal(int n)
|
||||
{
|
||||
State *s;
|
||||
|
||||
s = mal(sizeof(*s));
|
||||
// s->next = mal(256*sizeof(*s->next));
|
||||
s->count = n;
|
||||
s->re = mal(n*sizeof(*state0->re));
|
||||
return s;
|
||||
}
|
||||
|
||||
Re*
|
||||
ral(int type)
|
||||
{
|
||||
Re *r;
|
||||
|
||||
r = mal(sizeof(*r));
|
||||
r->type = type;
|
||||
maxfollow++;
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
error(char *s)
|
||||
{
|
||||
fprint(2, "grep: internal error: %s\n", s);
|
||||
exits(s);
|
||||
}
|
||||
|
||||
int
|
||||
countor(Re *r)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = 0;
|
||||
loop:
|
||||
switch(r->type) {
|
||||
case Tor:
|
||||
n += countor(r->u.alt);
|
||||
r = r->next;
|
||||
goto loop;
|
||||
case Tclass:
|
||||
return n + r->u.x.hi - r->u.x.lo + 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
Re*
|
||||
oralloc(int t, Re *r, Re *b)
|
||||
{
|
||||
Re *a;
|
||||
|
||||
if(b == 0)
|
||||
return r;
|
||||
a = ral(t);
|
||||
a->u.alt = r;
|
||||
a->next = b;
|
||||
return a;
|
||||
}
|
||||
|
||||
void
|
||||
case1(Re *c, Re *r)
|
||||
{
|
||||
int n;
|
||||
|
||||
loop:
|
||||
switch(r->type) {
|
||||
case Tor:
|
||||
case1(c, r->u.alt);
|
||||
r = r->next;
|
||||
goto loop;
|
||||
|
||||
case Tclass: /* add to character */
|
||||
for(n=r->u.x.lo; n<=r->u.x.hi; n++)
|
||||
c->u.cases[n] = oralloc(Tor, r->next, c->u.cases[n]);
|
||||
break;
|
||||
|
||||
default: /* add everything unknown to next */
|
||||
c->next = oralloc(Talt, r, c->next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Re*
|
||||
addcase(Re *r)
|
||||
{
|
||||
int i, n;
|
||||
Re *a;
|
||||
|
||||
if(r->gen == gen)
|
||||
return r;
|
||||
r->gen = gen;
|
||||
switch(r->type) {
|
||||
default:
|
||||
error("addcase");
|
||||
|
||||
case Tor:
|
||||
n = countor(r);
|
||||
if(n >= Caselim) {
|
||||
a = ral(Tcase);
|
||||
a->u.cases = mal(256*sizeof(*a->u.cases));
|
||||
case1(a, r);
|
||||
for(i=0; i<256; i++)
|
||||
if(a->u.cases[i]) {
|
||||
r = a->u.cases[i];
|
||||
if(countor(r) < n)
|
||||
a->u.cases[i] = addcase(r);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return r;
|
||||
|
||||
case Talt:
|
||||
r->next = addcase(r->next);
|
||||
r->u.alt = addcase(r->u.alt);
|
||||
return r;
|
||||
|
||||
case Tbegin:
|
||||
case Tend:
|
||||
case Tclass:
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
str2top(char *p)
|
||||
{
|
||||
Re2 oldtop;
|
||||
|
||||
oldtop = topre;
|
||||
input = p;
|
||||
topre.beg = 0;
|
||||
topre.end = 0;
|
||||
yyparse();
|
||||
gen++;
|
||||
if(topre.beg == 0)
|
||||
yyerror("syntax");
|
||||
if(oldtop.beg)
|
||||
topre = re2or(oldtop, topre);
|
||||
}
|
||||
|
||||
void
|
||||
appendnext(Re *a, Re *b)
|
||||
{
|
||||
Re *n;
|
||||
|
||||
while(n = a->next)
|
||||
a = n;
|
||||
a->next = b;
|
||||
}
|
||||
|
||||
void
|
||||
patchnext(Re *a, Re *b)
|
||||
{
|
||||
Re *n;
|
||||
|
||||
while(a) {
|
||||
n = a->next;
|
||||
a->next = b;
|
||||
a = n;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getrec(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
if(flags['f']) {
|
||||
c = Bgetc(rein);
|
||||
if(c <= 0)
|
||||
return 0;
|
||||
} else
|
||||
c = *input++ & 0xff;
|
||||
if(flags['i'] && c >= 'A' && c <= 'Z')
|
||||
c += 'a'-'A';
|
||||
if(c == '\n')
|
||||
lineno++;
|
||||
return c;
|
||||
}
|
||||
|
||||
Re2
|
||||
re2cat(Re2 a, Re2 b)
|
||||
{
|
||||
Re2 c;
|
||||
|
||||
c.beg = a.beg;
|
||||
c.end = b.end;
|
||||
patchnext(a.end, b.beg);
|
||||
return c;
|
||||
}
|
||||
|
||||
Re2
|
||||
re2star(Re2 a)
|
||||
{
|
||||
Re2 c;
|
||||
|
||||
c.beg = ral(Talt);
|
||||
c.beg->u.alt = a.beg;
|
||||
patchnext(a.end, c.beg);
|
||||
c.end = c.beg;
|
||||
return c;
|
||||
}
|
||||
|
||||
Re2
|
||||
re2or(Re2 a, Re2 b)
|
||||
{
|
||||
Re2 c;
|
||||
|
||||
c.beg = ral(Tor);
|
||||
c.beg->u.alt = b.beg;
|
||||
c.beg->next = a.beg;
|
||||
c.end = b.end;
|
||||
appendnext(c.end, a.end);
|
||||
return c;
|
||||
}
|
||||
|
||||
Re2
|
||||
re2char(int c0, int c1)
|
||||
{
|
||||
Re2 c;
|
||||
|
||||
c.beg = ral(Tclass);
|
||||
c.beg->u.x.lo = c0 & 0xff;
|
||||
c.beg->u.x.hi = c1 & 0xff;
|
||||
c.end = c.beg;
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
reprint1(Re *a)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
loop:
|
||||
if(a == 0)
|
||||
return;
|
||||
if(a->gen == gen)
|
||||
return;
|
||||
a->gen = gen;
|
||||
print("%p: ", a);
|
||||
switch(a->type) {
|
||||
default:
|
||||
print("type %d\n", a->type);
|
||||
error("print1 type");
|
||||
|
||||
case Tcase:
|
||||
print("case ->%p\n", a->next);
|
||||
for(i=0; i<256; i++)
|
||||
if(a->u.cases[i]) {
|
||||
for(j=i+1; j<256; j++)
|
||||
if(a->u.cases[i] != a->u.cases[j])
|
||||
break;
|
||||
print(" [%.2x-%.2x] ->%p\n", i, j-1, a->u.cases[i]);
|
||||
i = j-1;
|
||||
}
|
||||
for(i=0; i<256; i++)
|
||||
reprint1(a->u.cases[i]);
|
||||
break;
|
||||
|
||||
case Tbegin:
|
||||
print("^ ->%p\n", a->next);
|
||||
break;
|
||||
|
||||
case Tend:
|
||||
print("$ ->%p\n", a->next);
|
||||
break;
|
||||
|
||||
case Tclass:
|
||||
print("[%.2x-%.2x] ->%p\n", a->u.x.lo, a->u.x.hi, a->next);
|
||||
break;
|
||||
|
||||
case Tor:
|
||||
case Talt:
|
||||
print("| %p ->%p\n", a->u.alt, a->next);
|
||||
reprint1(a->u.alt);
|
||||
break;
|
||||
}
|
||||
a = a->next;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
void
|
||||
reprint(char *s, Re *r)
|
||||
{
|
||||
print("%s:\n", s);
|
||||
gen++;
|
||||
reprint1(r);
|
||||
print("\n\n");
|
||||
}
|
19
lib9/LICENSE
Normal file
19
lib9/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* The authors of this software are Rob Pike and Ken Thompson.
|
||||
* Copyright (c) 2002 by Lucent Technologies.
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
This is a Unix port of the Plan 9 formatted I/O package.
|
||||
|
||||
Please send comments about the packaging
|
||||
to Russ Cox <rsc@post.harvard.edu>.
|
||||
|
208
lib9/Makefile
Normal file
208
lib9/Makefile
Normal file
@@ -0,0 +1,208 @@
|
||||
# lib9 - unix port from plan9 lib9
|
||||
|
||||
# this works in gnu make
|
||||
SYSNAME:=${shell uname}
|
||||
OBJTYPE:=${shell uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'}
|
||||
|
||||
# this works in bsd make
|
||||
SYSNAME!=uname
|
||||
OBJTYPE!=uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'
|
||||
|
||||
# the gnu rules will mess up bsd but not vice versa,
|
||||
# hence the gnu rules come first.
|
||||
|
||||
include ../config.mk
|
||||
|
||||
LIB=lib9.a
|
||||
TARG=lib9
|
||||
|
||||
# following objects are not compiled for several reasons
|
||||
# crypt.o
|
||||
# netcrypt.o
|
||||
OFILES=\
|
||||
fmt/dofmt.o\
|
||||
fmt/fltfmt.o\
|
||||
fmt/fmt.o\
|
||||
fmt/fmtfd.o\
|
||||
fmt/fmtfdflush.o\
|
||||
fmt/fmtlock.o\
|
||||
fmt/fmtprint.o\
|
||||
fmt/fmtquote.o\
|
||||
fmt/fmtrune.o\
|
||||
fmt/fmtstr.o\
|
||||
fmt/fmtvprint.o\
|
||||
fmt/fprint.o\
|
||||
fmt/nan64.o\
|
||||
fmt/print.o\
|
||||
fmt/runefmtstr.o\
|
||||
fmt/runeseprint.o\
|
||||
fmt/runesmprint.o\
|
||||
fmt/runesnprint.o\
|
||||
fmt/runesprint.o\
|
||||
fmt/runevseprint.o\
|
||||
fmt/runevsmprint.o\
|
||||
fmt/runevsnprint.o\
|
||||
fmt/seprint.o\
|
||||
fmt/smprint.o\
|
||||
fmt/snprint.o\
|
||||
fmt/sprint.o\
|
||||
fmt/strtod.o\
|
||||
fmt/vfprint.o\
|
||||
fmt/vseprint.o\
|
||||
fmt/vsmprint.o\
|
||||
fmt/vsnprint.o\
|
||||
fmt/charstod.o\
|
||||
fmt/pow10.o\
|
||||
utf/rune.o\
|
||||
utf/runestrcat.o\
|
||||
utf/runestrchr.o\
|
||||
utf/runestrcmp.o\
|
||||
utf/runestrcpy.o\
|
||||
utf/runestrdup.o\
|
||||
utf/runestrlen.o\
|
||||
utf/runestrecpy.o\
|
||||
utf/runestrncat.o\
|
||||
utf/runestrncmp.o\
|
||||
utf/runestrncpy.o\
|
||||
utf/runestrrchr.o\
|
||||
utf/runestrstr.o\
|
||||
utf/runetype.o\
|
||||
utf/utfecpy.o\
|
||||
utf/utflen.o\
|
||||
utf/utfnlen.o\
|
||||
utf/utfrrune.o\
|
||||
utf/utfrune.o\
|
||||
utf/utfutf.o\
|
||||
bio/bbuffered.o\
|
||||
bio/bfildes.o\
|
||||
bio/bflush.o\
|
||||
bio/bgetc.o\
|
||||
bio/bgetd.o\
|
||||
bio/bgetrune.o\
|
||||
bio/binit.o\
|
||||
bio/boffset.o\
|
||||
bio/bprint.o\
|
||||
bio/bputc.o\
|
||||
bio/bputrune.o\
|
||||
bio/brdline.o\
|
||||
bio/brdstr.o\
|
||||
bio/bread.o\
|
||||
bio/bseek.o\
|
||||
bio/bvprint.o\
|
||||
bio/bwrite.o\
|
||||
regex/regcomp.o\
|
||||
regex/regerror.o\
|
||||
regex/regexec.o\
|
||||
regex/regsub.o\
|
||||
regex/regaux.o\
|
||||
regex/rregexec.o\
|
||||
regex/rregsub.o\
|
||||
_exits.o\
|
||||
_p9dialparse.o\
|
||||
_p9dir.o\
|
||||
announce.o\
|
||||
argv0.o\
|
||||
atexit.o\
|
||||
atoi.o\
|
||||
atol.o\
|
||||
atoll.o\
|
||||
atnotify.o\
|
||||
await.o\
|
||||
cistrcmp.o\
|
||||
cistrncmp.o\
|
||||
cistrstr.o\
|
||||
cleanname.o\
|
||||
convD2M.o\
|
||||
convM2D.o\
|
||||
convM2S.o\
|
||||
convS2M.o\
|
||||
create.o\
|
||||
ctime.o\
|
||||
date.o\
|
||||
dial.o\
|
||||
dirfstat.o\
|
||||
dirfwstat.o\
|
||||
dirmodefmt.o\
|
||||
dirread.o\
|
||||
dirstat.o\
|
||||
dirwstat.o\
|
||||
dup.o\
|
||||
encodefmt.o\
|
||||
errstr.o\
|
||||
exec.o\
|
||||
execl.o\
|
||||
fcallfmt.o\
|
||||
get9root.o\
|
||||
getcallerpc-$(OBJTYPE).o\
|
||||
getenv.o\
|
||||
getfields.o\
|
||||
getnetconn.o\
|
||||
getns.o\
|
||||
getuser.o\
|
||||
getwd.o\
|
||||
jmp.o\
|
||||
lrand.o\
|
||||
lnrand.o\
|
||||
main.o\
|
||||
malloc.o\
|
||||
malloctag.o\
|
||||
mallocz.o\
|
||||
nan.o\
|
||||
needsrcquote.o\
|
||||
needstack.o\
|
||||
netmkaddr.o\
|
||||
notify.o\
|
||||
nrand.o\
|
||||
nulldir.o\
|
||||
open.o\
|
||||
opentemp.o\
|
||||
pipe.o\
|
||||
post9p.o\
|
||||
postnote.o\
|
||||
qlock.o\
|
||||
quote.o\
|
||||
rand.o\
|
||||
read9pmsg.o\
|
||||
readcons.o\
|
||||
readn.o\
|
||||
rfork.o\
|
||||
searchpath.o\
|
||||
seek.o\
|
||||
sendfd.o\
|
||||
sleep.o\
|
||||
strdup.o\
|
||||
strecpy.o\
|
||||
sysfatal.o\
|
||||
syslog.o\
|
||||
sysname.o\
|
||||
time.o\
|
||||
tokenize.o\
|
||||
truerand.o\
|
||||
u16.o\
|
||||
u32.o\
|
||||
u64.o\
|
||||
unsharp.o\
|
||||
wait.o\
|
||||
waitpid.o\
|
||||
|
||||
all: ${LIB}
|
||||
@echo built lib9
|
||||
|
||||
install:
|
||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man7
|
||||
@cp -f regexp.7 ${DESTDIR}${MANPREFIX}/man7
|
||||
@chmod 444 ${DESTDIR}${MANPREFIX}/man7/regexp.7
|
||||
|
||||
uninstall:
|
||||
rm -f ${DESTDIR}${MANPREFIX}/man7/regexp.7
|
||||
|
||||
${LIB}: ${OFILES}
|
||||
@echo AR ${TARG}
|
||||
@${AR} ${LIB} ${OFILES}
|
||||
|
||||
.c.o:
|
||||
@echo CC $*.c
|
||||
@${CC} -o $*.o ${CFLAGS} -I${PREFIX}/include $*.c
|
||||
|
||||
clean:
|
||||
rm -f ${OFILES} ${LIB}
|
10
lib9/_exits.c
Normal file
10
lib9/_exits.c
Normal file
@@ -0,0 +1,10 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
_exits(char *s)
|
||||
{
|
||||
if(s && *s)
|
||||
_exit(1);
|
||||
_exit(0);
|
||||
}
|
185
lib9/_p9dialparse.c
Normal file
185
lib9/_p9dialparse.c
Normal file
@@ -0,0 +1,185 @@
|
||||
#include <u.h>
|
||||
#define NOPLAN9DEFINES
|
||||
#include <libc.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
static char *nets[] = { "tcp", "udp", nil };
|
||||
#define CLASS(p) ((*(uchar*)(p))>>6)
|
||||
|
||||
static struct {
|
||||
char *net;
|
||||
char *service;
|
||||
int port;
|
||||
} porttbl[] = {
|
||||
"tcp", "9fs", 564,
|
||||
"tcp", "whoami", 565,
|
||||
"tcp", "guard", 566,
|
||||
"tcp", "ticket", 567,
|
||||
"tcp", "exportfs", 17007,
|
||||
"tcp", "rexexec", 17009,
|
||||
"tcp", "ncpu", 17010,
|
||||
"tcp", "cpu", 17013,
|
||||
"tcp", "venti", 17034,
|
||||
"tcp", "wiki", 17035,
|
||||
"tcp", "secstore", 5356,
|
||||
};
|
||||
|
||||
static int
|
||||
parseip(char *host, u32int *pip)
|
||||
{
|
||||
uchar addr[4];
|
||||
int x, i;
|
||||
char *p;
|
||||
|
||||
p = host;
|
||||
for(i=0; i<4 && *p; i++){
|
||||
x = strtoul(p, &p, 0);
|
||||
if(x < 0 || x >= 256)
|
||||
return -1;
|
||||
if(*p != '.' && *p != 0)
|
||||
return -1;
|
||||
if(*p == '.')
|
||||
p++;
|
||||
addr[i] = x;
|
||||
}
|
||||
|
||||
switch(CLASS(addr)){
|
||||
case 0:
|
||||
case 1:
|
||||
if(i == 3){
|
||||
addr[3] = addr[2];
|
||||
addr[2] = addr[1];
|
||||
addr[1] = 0;
|
||||
}else if(i == 2){
|
||||
addr[3] = addr[1];
|
||||
addr[2] = 0;
|
||||
addr[1] = 0;
|
||||
}else if(i != 4)
|
||||
return -1;
|
||||
break;
|
||||
case 2:
|
||||
if(i == 3){
|
||||
addr[3] = addr[2];
|
||||
addr[2] = 0;
|
||||
}else if(i != 4)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
*pip = *(u32int*)addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
p9dialparse(char *addr, char **pnet, char **punix, u32int *phost, int *pport)
|
||||
{
|
||||
char *net, *host, *port, *e;
|
||||
int i;
|
||||
struct servent *se;
|
||||
struct hostent *he;
|
||||
struct sockaddr_un *sockun;
|
||||
|
||||
if(strncmp(addr, "/net/", 5) == 0)
|
||||
addr += 5;
|
||||
|
||||
*punix = nil;
|
||||
net = addr;
|
||||
if((host = strchr(net, '!')) == nil){
|
||||
werrstr("malformed address");
|
||||
return -1;
|
||||
}
|
||||
*host++ = 0;
|
||||
if((port = strchr(host, '!')) == nil){
|
||||
if(strcmp(net, "unix")==0 || strcmp(net, "net")==0){
|
||||
Unix:
|
||||
if(strlen(host)+1 > sizeof sockun->sun_path){
|
||||
werrstr("unix socket name too long");
|
||||
return -1;
|
||||
}
|
||||
*punix = host;
|
||||
*pnet = "unix";
|
||||
*phost = 0;
|
||||
*pport = 0;
|
||||
return 0;
|
||||
}
|
||||
werrstr("malformed address");
|
||||
return -1;
|
||||
}
|
||||
*port++ = 0;
|
||||
|
||||
if(*host == 0){
|
||||
werrstr("malformed address (empty host)");
|
||||
return -1;
|
||||
}
|
||||
if(*port == 0){
|
||||
werrstr("malformed address (empty port)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strcmp(net, "unix") == 0)
|
||||
goto Unix;
|
||||
|
||||
if(strcmp(net, "tcp")!=0 && strcmp(net, "udp")!=0 && strcmp(net, "net") != 0){
|
||||
werrstr("bad network %s!%s!%s", net, host, port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* translate host */
|
||||
if(strcmp(host, "*") == 0)
|
||||
*phost = 0;
|
||||
else if(parseip(host, phost) == 0)
|
||||
{}
|
||||
else if((he = gethostbyname(host)) != nil)
|
||||
*phost = *(u32int*)(he->h_addr);
|
||||
else{
|
||||
werrstr("unknown host %s", host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* translate network and port; should return list rather than first */
|
||||
if(strcmp(net, "net") == 0){
|
||||
for(i=0; nets[i]; i++){
|
||||
if((se = getservbyname(port, nets[i])) != nil){
|
||||
*pnet = nets[i];
|
||||
*pport = ntohs(se->s_port);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<nelem(porttbl); i++){
|
||||
if(strcmp(net, "net") == 0 || strcmp(porttbl[i].net, net) == 0)
|
||||
if(strcmp(porttbl[i].service, port) == 0){
|
||||
*pnet = porttbl[i].net;
|
||||
*pport = porttbl[i].port;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(strcmp(net, "net") == 0){
|
||||
werrstr("unknown service net!*!%s", port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strcmp(net, "tcp") != 0 && strcmp(net, "udp") != 0){
|
||||
werrstr("unknown network %s", net);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pnet = net;
|
||||
i = strtol(port, &e, 0);
|
||||
if(*e == 0){
|
||||
*pport = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((se = getservbyname(port, net)) != nil){
|
||||
*pport = ntohs(se->s_port);
|
||||
return 0;
|
||||
}
|
||||
werrstr("unknown service %s!*!%s", net, port);
|
||||
return -1;
|
||||
}
|
231
lib9/_p9dir.c
Normal file
231
lib9/_p9dir.c
Normal file
@@ -0,0 +1,231 @@
|
||||
#include <u.h>
|
||||
#define NOPLAN9DEFINES
|
||||
#include <libc.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/ioctl.h>
|
||||
static int diskdev[] = {
|
||||
151, /* aacd */
|
||||
116, /* ad */
|
||||
157, /* ar */
|
||||
118, /* afd */
|
||||
133, /* amrd */
|
||||
13, /* da */
|
||||
102, /* fla */
|
||||
109, /* idad */
|
||||
95, /* md */
|
||||
131, /* mlxd */
|
||||
168, /* pst */
|
||||
147, /* twed */
|
||||
43, /* vn */
|
||||
3, /* wd */
|
||||
87, /* wfd */
|
||||
};
|
||||
static int
|
||||
isdisk(struct stat *st)
|
||||
{
|
||||
int i, dev;
|
||||
|
||||
if(!S_ISCHR(st->st_mode))
|
||||
return 0;
|
||||
dev = major(st->st_rdev);
|
||||
for(i=0; i<nelem(diskdev); i++)
|
||||
if(diskdev[i] == dev)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#define _HAVEDISKLABEL
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/fs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#undef major
|
||||
#define major(dev) ((int)(((dev) >> 8) & 0xff))
|
||||
static vlong
|
||||
disksize(int fd, int dev)
|
||||
{
|
||||
u64int u64;
|
||||
long l;
|
||||
struct hd_geometry geo;
|
||||
|
||||
memset(&geo, 0, sizeof geo);
|
||||
l = 0;
|
||||
u64 = 0;
|
||||
#ifdef BLKGETSIZE64
|
||||
if(ioctl(fd, BLKGETSIZE64, &u64) >= 0)
|
||||
return u64;
|
||||
#endif
|
||||
if(ioctl(fd, BLKGETSIZE, &l) >= 0)
|
||||
return (vlong)l*512;
|
||||
if(ioctl(fd, HDIO_GETGEO, &geo) >= 0)
|
||||
return (vlong)geo.heads*geo.sectors*geo.cylinders*512;
|
||||
return 0;
|
||||
}
|
||||
#define _HAVEDISKSIZE
|
||||
#endif
|
||||
|
||||
#if !defined(__linux__) && !defined(__sun__)
|
||||
#define _HAVESTGEN
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Caching the last group and passwd looked up is
|
||||
* a significant win (stupidly enough) on most systems.
|
||||
* It's not safe for threaded programs, but neither is using
|
||||
* getpwnam in the first place, so I'm not too worried.
|
||||
*/
|
||||
int
|
||||
_p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *estr)
|
||||
{
|
||||
char *s;
|
||||
char tmp[20];
|
||||
static struct group *g;
|
||||
static struct passwd *p;
|
||||
static int gid, uid;
|
||||
int sz, fd;
|
||||
|
||||
fd = -1;
|
||||
USED(fd);
|
||||
sz = 0;
|
||||
if(d)
|
||||
memset(d, 0, sizeof *d);
|
||||
|
||||
/* name */
|
||||
s = strrchr(name, '/');
|
||||
if(s)
|
||||
s++;
|
||||
if(!s || !*s)
|
||||
s = name;
|
||||
if(*s == '/')
|
||||
s++;
|
||||
if(*s == 0)
|
||||
s = "/";
|
||||
if(d){
|
||||
if(*str + strlen(s)+1 > estr)
|
||||
d->name = "oops";
|
||||
else{
|
||||
strcpy(*str, s);
|
||||
d->name = *str;
|
||||
*str += strlen(*str)+1;
|
||||
}
|
||||
}
|
||||
sz += strlen(s)+1;
|
||||
|
||||
/* user */
|
||||
if(p && st->st_uid == uid && p->pw_uid == uid)
|
||||
;
|
||||
else{
|
||||
p = getpwuid(st->st_uid);
|
||||
uid = st->st_uid;
|
||||
}
|
||||
if(p == nil){
|
||||
snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
|
||||
s = tmp;
|
||||
}else
|
||||
s = p->pw_name;
|
||||
sz += strlen(s)+1;
|
||||
if(d){
|
||||
if(*str+strlen(s)+1 > estr)
|
||||
d->uid = "oops";
|
||||
else{
|
||||
strcpy(*str, s);
|
||||
d->uid = *str;
|
||||
*str += strlen(*str)+1;
|
||||
}
|
||||
}
|
||||
|
||||
/* group */
|
||||
if(g && st->st_gid == gid && g->gr_gid == gid)
|
||||
;
|
||||
else{
|
||||
g = getgrgid(st->st_gid);
|
||||
gid = st->st_gid;
|
||||
}
|
||||
if(g == nil){
|
||||
snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
|
||||
s = tmp;
|
||||
}else
|
||||
s = g->gr_name;
|
||||
sz += strlen(s)+1;
|
||||
if(d){
|
||||
if(*str + strlen(s)+1 > estr)
|
||||
d->gid = "oops";
|
||||
else{
|
||||
strcpy(*str, s);
|
||||
d->gid = *str;
|
||||
*str += strlen(*str)+1;
|
||||
}
|
||||
}
|
||||
|
||||
if(d){
|
||||
d->type = 'M';
|
||||
|
||||
d->muid = "";
|
||||
d->qid.path = ((uvlong)st->st_dev<<32) | st->st_ino;
|
||||
#ifdef _HAVESTGEN
|
||||
d->qid.vers = st->st_gen;
|
||||
#endif
|
||||
d->mode = st->st_mode&0777;
|
||||
d->atime = st->st_atime;
|
||||
d->mtime = st->st_mtime;
|
||||
d->length = st->st_size;
|
||||
|
||||
if(S_ISDIR(st->st_mode)){
|
||||
d->length = 0;
|
||||
d->mode |= DMDIR;
|
||||
d->qid.type = QTDIR;
|
||||
}
|
||||
if(S_ISLNK(lst->st_mode)) /* yes, lst not st */
|
||||
d->mode |= DMSYMLINK;
|
||||
if(S_ISFIFO(st->st_mode))
|
||||
d->mode |= DMNAMEDPIPE;
|
||||
if(S_ISSOCK(st->st_mode))
|
||||
d->mode |= DMSOCKET;
|
||||
if(S_ISBLK(st->st_mode)){
|
||||
d->mode |= DMDEVICE;
|
||||
d->qid.path = ('b'<<16)|st->st_rdev;
|
||||
}
|
||||
if(S_ISCHR(st->st_mode)){
|
||||
d->mode |= DMDEVICE;
|
||||
d->qid.path = ('c'<<16)|st->st_rdev;
|
||||
}
|
||||
/* fetch real size for disks */
|
||||
#ifdef _HAVEDISKSIZE
|
||||
if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){
|
||||
d->length = disksize(fd, major(st->st_dev));
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
#ifdef _HAVEDISKLABEL
|
||||
if(isdisk(st)){
|
||||
int fd, n;
|
||||
struct disklabel lab;
|
||||
|
||||
if((fd = open(name, O_RDONLY)) < 0)
|
||||
goto nosize;
|
||||
if(ioctl(fd, DIOCGDINFO, &lab) < 0)
|
||||
goto nosize;
|
||||
n = minor(st->st_rdev)&7;
|
||||
if(n >= lab.d_npartitions)
|
||||
goto nosize;
|
||||
|
||||
d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize;
|
||||
|
||||
nosize:
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
46
lib9/_p9translate.c
Normal file
46
lib9/_p9translate.c
Normal file
@@ -0,0 +1,46 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
/*
|
||||
* I don't want too many of these,
|
||||
* but the ones we have are just too useful.
|
||||
*/
|
||||
static struct {
|
||||
char *old;
|
||||
char *new;
|
||||
} replace[] = {
|
||||
"#9", nil, /* must be first */
|
||||
"#d", "/dev/fd",
|
||||
};
|
||||
|
||||
char*
|
||||
plan9translate(char *old)
|
||||
{
|
||||
char *new;
|
||||
int i, olen, nlen, len;
|
||||
|
||||
if(replace[0].new == nil){
|
||||
replace[0].new = getenv("PLAN9");
|
||||
if(replace[0].new == nil)
|
||||
replace[0].new = "/usr/local/plan9";
|
||||
}
|
||||
|
||||
for(i=0; i<nelem(replace); i++){
|
||||
if(!replace[i].new)
|
||||
continue;
|
||||
olen = strlen(replace[i].old);
|
||||
if(strncmp(old, replace[i].old, olen) != 0
|
||||
|| (old[olen] != '\0' && old[olen] != '/'))
|
||||
continue;
|
||||
nlen = strlen(replace[i].new);
|
||||
len = strlen(old)+nlen-olen;
|
||||
new = malloc(len+1);
|
||||
if(new == nil)
|
||||
return "<out of memory>";
|
||||
strcpy(new, replace[i].new);
|
||||
strcpy(new+nlen, old+olen);
|
||||
assert(strlen(new) == len);
|
||||
return new;
|
||||
}
|
||||
return old;
|
||||
}
|
152
lib9/announce.c
Normal file
152
lib9/announce.c
Normal file
@@ -0,0 +1,152 @@
|
||||
#include <u.h>
|
||||
#define NOPLAN9DEFINES
|
||||
#include <libc.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
|
||||
#undef sun
|
||||
#define sun sockun
|
||||
|
||||
int
|
||||
_p9netfd(char *dir)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if(strncmp(dir, "/dev/fd/", 8) != 0)
|
||||
return -1;
|
||||
fd = strtol(dir+8, &dir, 0);
|
||||
if(*dir != 0)
|
||||
return -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void
|
||||
putfd(char *dir, int fd)
|
||||
{
|
||||
snprint(dir, NETPATHLEN, "/dev/fd/%d", fd);
|
||||
}
|
||||
|
||||
#undef unix
|
||||
#define unix sockunix
|
||||
|
||||
int
|
||||
p9announce(char *addr, char *dir)
|
||||
{
|
||||
int proto;
|
||||
char *buf, *unix;
|
||||
char *net;
|
||||
u32int host;
|
||||
int port, s;
|
||||
int n;
|
||||
socklen_t sn;
|
||||
struct sockaddr_in sa;
|
||||
struct sockaddr_un sun;
|
||||
|
||||
buf = strdup(addr);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
|
||||
if(p9dialparse(buf, &net, &unix, &host, &port) < 0){
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
if(strcmp(net, "tcp") == 0)
|
||||
proto = SOCK_STREAM;
|
||||
else if(strcmp(net, "udp") == 0)
|
||||
proto = SOCK_DGRAM;
|
||||
else if(strcmp(net, "unix") == 0)
|
||||
goto Unix;
|
||||
else{
|
||||
werrstr("can only handle tcp, udp, and unix: not %s", net);
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
free(buf);
|
||||
|
||||
memset(&sa, 0, sizeof sa);
|
||||
memmove(&sa.sin_addr, &host, 4);
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(port);
|
||||
if((s = socket(AF_INET, proto, 0)) < 0)
|
||||
return -1;
|
||||
sn = sizeof n;
|
||||
if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
|
||||
&& n == SOCK_STREAM){
|
||||
n = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
|
||||
}
|
||||
if(bind(s, (struct sockaddr*)&sa, sizeof sa) < 0){
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
if(proto == SOCK_STREAM){
|
||||
listen(s, 8);
|
||||
putfd(dir, s);
|
||||
}
|
||||
return s;
|
||||
|
||||
Unix:
|
||||
memset(&sun, 0, sizeof sun);
|
||||
sun.sun_family = AF_UNIX;
|
||||
strcpy(sun.sun_path, unix);
|
||||
if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
return -1;
|
||||
sn = sizeof sun;
|
||||
if(bind(s, (struct sockaddr*)&sun, sizeof sun) < 0){
|
||||
if(errno == EADDRINUSE
|
||||
&& connect(s, (struct sockaddr*)&sun, sizeof sun) < 0
|
||||
&& errno == ECONNREFUSED){
|
||||
/* dead socket, so remove it */
|
||||
remove(unix);
|
||||
close(s);
|
||||
if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
return -1;
|
||||
if(bind(s, (struct sockaddr*)&sun, sizeof sun) >= 0)
|
||||
goto Success;
|
||||
}
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
Success:
|
||||
listen(s, 8);
|
||||
putfd(dir, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
p9listen(char *dir, char *newdir)
|
||||
{
|
||||
int fd, one;
|
||||
|
||||
if((fd = _p9netfd(dir)) < 0){
|
||||
werrstr("bad 'directory' in listen: %s", dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((fd = accept(fd, nil, nil)) < 0)
|
||||
return -1;
|
||||
|
||||
one = 1;
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one);
|
||||
|
||||
putfd(newdir, fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
p9accept(int cfd, char *dir)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if((fd = _p9netfd(dir)) < 0){
|
||||
werrstr("bad 'directory' in accept");
|
||||
return -1;
|
||||
}
|
||||
/* need to dup because the listen fd will be closed */
|
||||
return dup(fd);
|
||||
}
|
||||
|
9
lib9/argv0.c
Normal file
9
lib9/argv0.c
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <lib9.h>
|
||||
|
||||
char *argv0;
|
||||
|
||||
/*
|
||||
* Mac OS can't deal with files that only declare data.
|
||||
* ARGBEGIN mentions this function so that this file gets pulled in.
|
||||
*/
|
||||
void __fixargv0(void) { }
|
54
lib9/atexit.c
Normal file
54
lib9/atexit.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#define NEXIT 33
|
||||
|
||||
static Lock onexlock;
|
||||
static struct
|
||||
{
|
||||
void (*f)(void);
|
||||
int pid;
|
||||
}onex[NEXIT];
|
||||
|
||||
int
|
||||
atexit(void (*f)(void))
|
||||
{
|
||||
int i;
|
||||
|
||||
lock(&onexlock);
|
||||
for(i=0; i<NEXIT; i++)
|
||||
if(onex[i].f == 0) {
|
||||
onex[i].pid = getpid();
|
||||
onex[i].f = f;
|
||||
unlock(&onexlock);
|
||||
return 1;
|
||||
}
|
||||
unlock(&onexlock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
atexitdont(void (*f)(void))
|
||||
{
|
||||
int i, pid;
|
||||
|
||||
pid = getpid();
|
||||
for(i=0; i<NEXIT; i++)
|
||||
if(onex[i].f == f && onex[i].pid == pid)
|
||||
onex[i].f = 0;
|
||||
}
|
||||
|
||||
void
|
||||
exits(char *s)
|
||||
{
|
||||
int i, pid;
|
||||
void (*f)(void);
|
||||
|
||||
pid = getpid();
|
||||
for(i = NEXIT-1; i >= 0; i--)
|
||||
if((f = onex[i].f) && pid == onex[i].pid) {
|
||||
onex[i].f = 0;
|
||||
(*f)();
|
||||
}
|
||||
exit(s && *s ? 1 : 0);
|
||||
}
|
58
lib9/atnotify.c
Normal file
58
lib9/atnotify.c
Normal file
@@ -0,0 +1,58 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#define NFN 33
|
||||
static int (*onnot[NFN])(void*, char*);
|
||||
static Lock onnotlock;
|
||||
|
||||
static
|
||||
void
|
||||
notifier(void *v, char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<NFN; i++)
|
||||
if(onnot[i] && ((*onnot[i])(v, s))){
|
||||
noted(NCONT);
|
||||
return;
|
||||
}
|
||||
noted(NDFLT);
|
||||
}
|
||||
|
||||
int
|
||||
atnotify(int (*f)(void*, char*), int in)
|
||||
{
|
||||
int i, n, ret;
|
||||
static int init;
|
||||
|
||||
if(!init){
|
||||
notify(notifier);
|
||||
init = 1; /* assign = */
|
||||
}
|
||||
ret = 0;
|
||||
lock(&onnotlock);
|
||||
if(in){
|
||||
for(i=0; i<NFN; i++)
|
||||
if(onnot[i] == 0) {
|
||||
onnot[i] = f;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
n = 0;
|
||||
for(i=0; i<NFN; i++)
|
||||
if(onnot[i]){
|
||||
if(ret==0 && onnot[i]==f){
|
||||
onnot[i] = 0;
|
||||
ret = 1;
|
||||
}else
|
||||
n++;
|
||||
}
|
||||
if(n == 0){
|
||||
init = 0;
|
||||
notify(0);
|
||||
}
|
||||
}
|
||||
unlock(&onnotlock);
|
||||
return ret;
|
||||
}
|
9
lib9/atoi.c
Normal file
9
lib9/atoi.c
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
atoi(char *s)
|
||||
{
|
||||
return strtol(s, 0, 0);
|
||||
}
|
||||
|
9
lib9/atol.c
Normal file
9
lib9/atol.c
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
long
|
||||
atol(char *s)
|
||||
{
|
||||
return strtol(s, 0, 0);
|
||||
}
|
||||
|
9
lib9/atoll.c
Normal file
9
lib9/atoll.c
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
vlong
|
||||
atoll(char *s)
|
||||
{
|
||||
return strtoll(s, 0, 0);
|
||||
}
|
||||
|
137
lib9/await.c
Normal file
137
lib9/await.c
Normal file
@@ -0,0 +1,137 @@
|
||||
#define NOPLAN9DEFINES
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#ifndef WCOREDUMP /* not on Mac OS X Tiger */
|
||||
#define WCOREDUMP(status) 0
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
int sig;
|
||||
char *str;
|
||||
} tab[] = {
|
||||
SIGHUP, "hangup",
|
||||
SIGINT, "interrupt",
|
||||
SIGQUIT, "quit",
|
||||
SIGILL, "sys: illegal instruction",
|
||||
SIGTRAP, "sys: breakpoint",
|
||||
SIGABRT, "sys: abort",
|
||||
#ifdef SIGEMT
|
||||
SIGEMT, "sys: emulate instruction executed",
|
||||
#endif
|
||||
SIGFPE, "sys: fp: trap",
|
||||
SIGKILL, "sys: kill",
|
||||
SIGBUS, "sys: bus error",
|
||||
SIGSEGV, "sys: segmentation violation",
|
||||
SIGALRM, "alarm",
|
||||
SIGTERM, "kill",
|
||||
SIGURG, "sys: urgent condition on socket",
|
||||
SIGSTOP, "sys: stop",
|
||||
SIGTSTP, "sys: tstp",
|
||||
SIGCONT, "sys: cont",
|
||||
SIGCHLD, "sys: child",
|
||||
SIGTTIN, "sys: ttin",
|
||||
SIGTTOU, "sys: ttou",
|
||||
#ifdef SIGIO /* not on Mac OS X Tiger */
|
||||
SIGIO, "sys: i/o possible on fd",
|
||||
#endif
|
||||
SIGXCPU, "sys: cpu time limit exceeded",
|
||||
SIGXFSZ, "sys: file size limit exceeded",
|
||||
SIGVTALRM, "sys: virtual time alarm",
|
||||
SIGPROF, "sys: profiling timer alarm",
|
||||
#ifdef SIGWINCH /* not on Mac OS X Tiger */
|
||||
SIGWINCH, "sys: window size change",
|
||||
#endif
|
||||
#ifdef SIGINFO
|
||||
SIGINFO, "sys: status request",
|
||||
#endif
|
||||
SIGUSR1, "sys: usr1",
|
||||
SIGUSR2, "sys: usr2",
|
||||
SIGPIPE, "sys: write on closed pipe",
|
||||
};
|
||||
|
||||
char*
|
||||
_p9sigstr(int sig, char *tmp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<nelem(tab); i++)
|
||||
if(tab[i].sig == sig)
|
||||
return tab[i].str;
|
||||
if(tmp == nil)
|
||||
return nil;
|
||||
sprint(tmp, "sys: signal %d", sig);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int
|
||||
_p9strsig(char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<nelem(tab); i++)
|
||||
if(strcmp(s, tab[i].str) == 0)
|
||||
return tab[i].sig;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_await(int pid4, char *str, int n, int opt)
|
||||
{
|
||||
int pid, status, cd;
|
||||
struct rusage ru;
|
||||
char buf[128], tmp[64];
|
||||
ulong u, s;
|
||||
|
||||
for(;;){
|
||||
/* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */
|
||||
if(pid4 == -1)
|
||||
pid = wait3(&status, opt, &ru);
|
||||
else
|
||||
pid = wait4(pid4, &status, opt, &ru);
|
||||
if(pid <= 0)
|
||||
return -1;
|
||||
u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
|
||||
s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
|
||||
if(WIFEXITED(status)){
|
||||
status = WEXITSTATUS(status);
|
||||
if(status)
|
||||
snprint(buf, sizeof buf, "%d %lud %lud %lud %d", pid, u, s, u+s, status);
|
||||
else
|
||||
snprint(buf, sizeof buf, "%d %lud %lud %lud ''", pid, u, s, u+s, status);
|
||||
strecpy(str, str+n, buf);
|
||||
return strlen(str);
|
||||
}
|
||||
if(WIFSIGNALED(status)){
|
||||
cd = WCOREDUMP(status);
|
||||
snprint(buf, sizeof buf, "%d %lud %lud %lud 'signal: %s%s'", pid, u, s, u+s, _p9sigstr(WTERMSIG(status), tmp), cd ? " (core dumped)" : "");
|
||||
strecpy(str, str+n, buf);
|
||||
return strlen(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
await(char *str, int n)
|
||||
{
|
||||
return _await(-1, str, n, 0);
|
||||
}
|
||||
|
||||
int
|
||||
awaitnohang(char *str, int n)
|
||||
{
|
||||
return _await(-1, str, n, WNOHANG);
|
||||
}
|
||||
|
||||
int
|
||||
awaitfor(int pid, char *str, int n)
|
||||
{
|
||||
return _await(pid, str, n, 0);
|
||||
}
|
||||
|
106
lib9/bio.h
Normal file
106
lib9/bio.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#ifndef _BIO_H_
|
||||
#define _BIO_H_ 1
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef AUTOLIB
|
||||
AUTOLIB(bio)
|
||||
#endif
|
||||
|
||||
#include <sys/types.h> /* for off_t */
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
|
||||
|
||||
#define OREAD 0 /* open for read */
|
||||
#define OWRITE 1 /* write */
|
||||
#define ORDWR 2 /* read and write */
|
||||
#define OEXEC 3 /* execute, == read but check execute permission */
|
||||
#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
|
||||
#define OCEXEC 32 /* or'ed in, close on exec */
|
||||
#define ORCLOSE 64 /* or'ed in, remove on close */
|
||||
#define ODIRECT 128 /* or'ed in, direct access */
|
||||
#define ONONBLOCK 256 /* or'ed in, non-blocking call */
|
||||
#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */
|
||||
#define OLOCK 0x2000 /* or'ed in, lock after opening */
|
||||
#define OAPPEND 0x4000 /* or'ed in, append only */
|
||||
|
||||
typedef struct Biobuf Biobuf;
|
||||
|
||||
enum
|
||||
{
|
||||
Bsize = 8*1024,
|
||||
Bungetsize = 4, /* space for ungetc */
|
||||
Bmagic = 0x314159,
|
||||
Beof = -1,
|
||||
Bbad = -2,
|
||||
|
||||
Binactive = 0, /* states */
|
||||
Bractive,
|
||||
Bwactive,
|
||||
Bracteof,
|
||||
|
||||
Bend
|
||||
};
|
||||
|
||||
struct Biobuf
|
||||
{
|
||||
int icount; /* neg num of bytes at eob */
|
||||
int ocount; /* num of bytes at bob */
|
||||
int rdline; /* num of bytes after rdline */
|
||||
int runesize; /* num of bytes of last getrune */
|
||||
int state; /* r/w/inactive */
|
||||
int fid; /* open file */
|
||||
int flag; /* magic if malloc'ed */
|
||||
off_t offset; /* offset of buffer in file */
|
||||
int bsize; /* size of buffer */
|
||||
unsigned char* bbuf; /* pointer to beginning of buffer */
|
||||
unsigned char* ebuf; /* pointer to end of buffer */
|
||||
unsigned char* gbuf; /* pointer to good data in buf */
|
||||
unsigned char b[Bungetsize+Bsize];
|
||||
};
|
||||
|
||||
#define BGETC(bp)\
|
||||
((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
|
||||
#define BPUTC(bp,c)\
|
||||
((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
|
||||
#define BOFFSET(bp)\
|
||||
(((bp)->state==Bractive)?\
|
||||
(bp)->offset + (bp)->icount:\
|
||||
(((bp)->state==Bwactive)?\
|
||||
(bp)->offset + ((bp)->bsize + (bp)->ocount):\
|
||||
-1))
|
||||
#define BLINELEN(bp)\
|
||||
(bp)->rdline
|
||||
#define BFILDES(bp)\
|
||||
(bp)->fid
|
||||
|
||||
int Bbuffered(Biobuf*);
|
||||
Biobuf* Bfdopen(int, int);
|
||||
int Bfildes(Biobuf*);
|
||||
int Bflush(Biobuf*);
|
||||
int Bgetc(Biobuf*);
|
||||
int Bgetd(Biobuf*, double*);
|
||||
long Bgetrune(Biobuf*);
|
||||
int Binit(Biobuf*, int, int);
|
||||
int Binits(Biobuf*, int, int, unsigned char*, int);
|
||||
int Blinelen(Biobuf*);
|
||||
off_t Boffset(Biobuf*);
|
||||
Biobuf* Bopen(char*, int);
|
||||
int Bprint(Biobuf*, char*, ...);
|
||||
int Bputc(Biobuf*, int);
|
||||
int Bputrune(Biobuf*, long);
|
||||
void* Brdline(Biobuf*, int);
|
||||
char* Brdstr(Biobuf*, int, int);
|
||||
long Bread(Biobuf*, void*, long);
|
||||
off_t Bseek(Biobuf*, off_t, int);
|
||||
int Bterm(Biobuf*);
|
||||
int Bungetc(Biobuf*);
|
||||
int Bungetrune(Biobuf*);
|
||||
long Bwrite(Biobuf*, void*, long);
|
||||
int Bvprint(Biobuf*, char*, va_list);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif
|
12
lib9/bio/_lib9.h
Normal file
12
lib9/bio/_lib9.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <fmt.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define OREAD O_RDONLY
|
||||
#define OWRITE O_WRONLY
|
||||
|
||||
#include <utf.h>
|
||||
|
||||
#define nil ((void*)0)
|
21
lib9/bio/bbuffered.c
Normal file
21
lib9/bio/bbuffered.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <fmt.h>
|
||||
|
||||
int
|
||||
Bbuffered(Biobuf *bp)
|
||||
{
|
||||
switch(bp->state) {
|
||||
case Bracteof:
|
||||
case Bractive:
|
||||
return -bp->icount;
|
||||
|
||||
case Bwactive:
|
||||
return bp->bsize + bp->ocount;
|
||||
|
||||
case Binactive:
|
||||
return 0;
|
||||
}
|
||||
fprint(2, "Bbuffered: unknown state %d\n", bp->state);
|
||||
return 0;
|
||||
}
|
46
lib9/bio/bcat.c
Normal file
46
lib9/bio/bcat.c
Normal file
@@ -0,0 +1,46 @@
|
||||
#include <fmt.h>
|
||||
#include "bio.h"
|
||||
|
||||
Biobuf bout;
|
||||
|
||||
void
|
||||
bcat(Biobuf *b, char *name)
|
||||
{
|
||||
char buf[1000];
|
||||
int n;
|
||||
|
||||
while((n = Bread(b, buf, sizeof buf)) > 0){
|
||||
if(Bwrite(&bout, buf, n) < 0)
|
||||
fprint(2, "writing during %s: %r\n", name);
|
||||
}
|
||||
if(n < 0)
|
||||
fprint(2, "reading %s: %r\n", name);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
Biobuf b, *bp;
|
||||
Fmt fmt;
|
||||
|
||||
Binit(&bout, 1, O_WRONLY);
|
||||
Bfmtinit(&fmt, &bout);
|
||||
fmtprint(&fmt, "hello, world\n");
|
||||
Bfmtflush(&fmt);
|
||||
|
||||
if(argc == 1){
|
||||
Binit(&b, 0, O_RDONLY);
|
||||
bcat(&b, "<stdin>");
|
||||
}else{
|
||||
for(i=1; i<argc; i++){
|
||||
if((bp = Bopen(argv[i], O_RDONLY)) == 0){
|
||||
fprint(2, "Bopen %s: %r\n", argv[i]);
|
||||
continue;
|
||||
}
|
||||
bcat(bp, argv[i]);
|
||||
Bterm(bp);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
9
lib9/bio/bfildes.c
Normal file
9
lib9/bio/bfildes.c
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
|
||||
int
|
||||
Bfildes(Biobuf *bp)
|
||||
{
|
||||
|
||||
return bp->fid;
|
||||
}
|
34
lib9/bio/bflush.c
Normal file
34
lib9/bio/bflush.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
Bflush(Biobuf *bp)
|
||||
{
|
||||
int n, c;
|
||||
|
||||
switch(bp->state) {
|
||||
case Bwactive:
|
||||
n = bp->bsize+bp->ocount;
|
||||
if(n == 0)
|
||||
return 0;
|
||||
c = write(bp->fid, bp->bbuf, n);
|
||||
if(n == c) {
|
||||
bp->offset += n;
|
||||
bp->ocount = -bp->bsize;
|
||||
return 0;
|
||||
}
|
||||
bp->state = Binactive;
|
||||
bp->ocount = 0;
|
||||
break;
|
||||
|
||||
case Bracteof:
|
||||
bp->state = Bractive;
|
||||
|
||||
case Bractive:
|
||||
bp->icount = 0;
|
||||
bp->gbuf = bp->ebuf;
|
||||
return 0;
|
||||
}
|
||||
return Beof;
|
||||
}
|
54
lib9/bio/bgetc.c
Normal file
54
lib9/bio/bgetc.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
Bgetc(Biobuf *bp)
|
||||
{
|
||||
int i;
|
||||
|
||||
loop:
|
||||
i = bp->icount;
|
||||
if(i != 0) {
|
||||
bp->icount = i+1;
|
||||
return bp->ebuf[i];
|
||||
}
|
||||
if(bp->state != Bractive) {
|
||||
if(bp->state == Bracteof)
|
||||
bp->state = Bractive;
|
||||
return Beof;
|
||||
}
|
||||
/*
|
||||
* get next buffer, try to keep Bungetsize
|
||||
* characters pre-catenated from the previous
|
||||
* buffer to allow that many ungets.
|
||||
*/
|
||||
memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize);
|
||||
i = read(bp->fid, bp->bbuf, bp->bsize);
|
||||
bp->gbuf = bp->bbuf;
|
||||
if(i <= 0) {
|
||||
bp->state = Bracteof;
|
||||
if(i < 0)
|
||||
bp->state = Binactive;
|
||||
return Beof;
|
||||
}
|
||||
if(i < bp->bsize) {
|
||||
memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, i+Bungetsize);
|
||||
bp->gbuf = bp->ebuf-i;
|
||||
}
|
||||
bp->icount = -i;
|
||||
bp->offset += i;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
int
|
||||
Bungetc(Biobuf *bp)
|
||||
{
|
||||
|
||||
if(bp->state == Bracteof)
|
||||
bp->state = Bractive;
|
||||
if(bp->state != Bractive)
|
||||
return Beof;
|
||||
bp->icount--;
|
||||
return 1;
|
||||
}
|
37
lib9/bio/bgetd.c
Normal file
37
lib9/bio/bgetd.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <fmt.h>
|
||||
|
||||
struct bgetd
|
||||
{
|
||||
Biobuf* b;
|
||||
int eof;
|
||||
};
|
||||
|
||||
static int
|
||||
Bgetdf(void *vp)
|
||||
{
|
||||
int c;
|
||||
struct bgetd *bg = vp;
|
||||
|
||||
c = Bgetc(bg->b);
|
||||
if(c == Beof)
|
||||
bg->eof = 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
int
|
||||
Bgetd(Biobuf *bp, double *dp)
|
||||
{
|
||||
double d;
|
||||
struct bgetd b;
|
||||
|
||||
b.b = bp;
|
||||
b.eof = 0;
|
||||
d = fmtcharstod(Bgetdf, &b);
|
||||
if(b.eof)
|
||||
return -1;
|
||||
Bungetc(bp);
|
||||
*dp = d;
|
||||
return 1;
|
||||
}
|
47
lib9/bio/bgetrune.c
Normal file
47
lib9/bio/bgetrune.c
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <utf.h>
|
||||
|
||||
long
|
||||
Bgetrune(Biobuf *bp)
|
||||
{
|
||||
int c, i;
|
||||
Rune rune;
|
||||
char str[4];
|
||||
|
||||
c = Bgetc(bp);
|
||||
if(c < Runeself) { /* one char */
|
||||
bp->runesize = 1;
|
||||
return c;
|
||||
}
|
||||
str[0] = c;
|
||||
|
||||
for(i=1;;) {
|
||||
c = Bgetc(bp);
|
||||
if(c < 0)
|
||||
return c;
|
||||
str[i++] = c;
|
||||
|
||||
if(fullrune(str, i)) {
|
||||
bp->runesize = chartorune(&rune, str);
|
||||
while(i > bp->runesize) {
|
||||
Bungetc(bp);
|
||||
i--;
|
||||
}
|
||||
return rune;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Bungetrune(Biobuf *bp)
|
||||
{
|
||||
|
||||
if(bp->state == Bracteof)
|
||||
bp->state = Bractive;
|
||||
if(bp->state != Bractive)
|
||||
return Beof;
|
||||
bp->icount -= bp->runesize;
|
||||
bp->runesize = 0;
|
||||
return 1;
|
||||
}
|
156
lib9/bio/binit.c
Normal file
156
lib9/bio/binit.c
Normal file
@@ -0,0 +1,156 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <fmt.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
enum
|
||||
{
|
||||
MAXBUFS = 20
|
||||
};
|
||||
|
||||
static Biobuf* wbufs[MAXBUFS];
|
||||
static int atexitflag;
|
||||
|
||||
static
|
||||
void
|
||||
batexit(void)
|
||||
{
|
||||
Biobuf *bp;
|
||||
int i;
|
||||
|
||||
for(i=0; i<MAXBUFS; i++) {
|
||||
bp = wbufs[i];
|
||||
if(bp != 0) {
|
||||
wbufs[i] = 0;
|
||||
Bflush(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
deinstall(Biobuf *bp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<MAXBUFS; i++)
|
||||
if(wbufs[i] == bp)
|
||||
wbufs[i] = 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
install(Biobuf *bp)
|
||||
{
|
||||
int i;
|
||||
|
||||
deinstall(bp);
|
||||
for(i=0; i<MAXBUFS; i++)
|
||||
if(wbufs[i] == 0) {
|
||||
wbufs[i] = bp;
|
||||
break;
|
||||
}
|
||||
if(atexitflag == 0) {
|
||||
atexitflag = 1;
|
||||
atexit(batexit);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Binits(Biobuf *bp, int f, int mode, unsigned char *p, int size)
|
||||
{
|
||||
|
||||
p += Bungetsize; /* make room for Bungets */
|
||||
size -= Bungetsize;
|
||||
|
||||
switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
|
||||
default:
|
||||
fprint(2, "Bopen: unknown mode %d\n", mode);
|
||||
return Beof;
|
||||
|
||||
case OREAD:
|
||||
bp->state = Bractive;
|
||||
bp->ocount = 0;
|
||||
break;
|
||||
|
||||
case OWRITE:
|
||||
install(bp);
|
||||
bp->state = Bwactive;
|
||||
bp->ocount = -size;
|
||||
break;
|
||||
}
|
||||
bp->bbuf = p;
|
||||
bp->ebuf = p+size;
|
||||
bp->bsize = size;
|
||||
bp->icount = 0;
|
||||
bp->gbuf = bp->ebuf;
|
||||
bp->fid = f;
|
||||
bp->flag = 0;
|
||||
bp->rdline = 0;
|
||||
bp->offset = 0;
|
||||
bp->runesize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Binit(Biobuf *bp, int f, int mode)
|
||||
{
|
||||
return Binits(bp, f, mode, bp->b, sizeof(bp->b));
|
||||
}
|
||||
|
||||
Biobuf*
|
||||
Bfdopen(int f, int mode)
|
||||
{
|
||||
Biobuf *bp;
|
||||
|
||||
bp = malloc(sizeof(Biobuf));
|
||||
if(bp == 0)
|
||||
return 0;
|
||||
Binits(bp, f, mode, bp->b, sizeof(bp->b));
|
||||
bp->flag = Bmagic;
|
||||
return bp;
|
||||
}
|
||||
|
||||
Biobuf*
|
||||
Bopen(char *name, int mode)
|
||||
{
|
||||
Biobuf *bp;
|
||||
int f;
|
||||
|
||||
switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
|
||||
default:
|
||||
fprint(2, "Bopen: unknown mode %d\n", mode);
|
||||
return 0;
|
||||
|
||||
case OREAD:
|
||||
f = open(name, OREAD);
|
||||
if(f < 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case OWRITE:
|
||||
f = creat(name, 0666);
|
||||
if(f < 0)
|
||||
return 0;
|
||||
}
|
||||
bp = Bfdopen(f, mode);
|
||||
if(bp == 0)
|
||||
close(f);
|
||||
return bp;
|
||||
}
|
||||
|
||||
int
|
||||
Bterm(Biobuf *bp)
|
||||
{
|
||||
|
||||
deinstall(bp);
|
||||
Bflush(bp);
|
||||
if(bp->flag == Bmagic) {
|
||||
bp->flag = 0;
|
||||
close(bp->fid);
|
||||
free(bp);
|
||||
}
|
||||
return 0;
|
||||
}
|
26
lib9/bio/boffset.c
Normal file
26
lib9/bio/boffset.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <fmt.h>
|
||||
|
||||
off_t
|
||||
Boffset(Biobuf *bp)
|
||||
{
|
||||
off_t n;
|
||||
|
||||
switch(bp->state) {
|
||||
default:
|
||||
fprint(2, "Boffset: unknown state %d\n", bp->state);
|
||||
n = Beof;
|
||||
break;
|
||||
|
||||
case Bracteof:
|
||||
case Bractive:
|
||||
n = bp->offset + bp->icount;
|
||||
break;
|
||||
|
||||
case Bwactive:
|
||||
n = bp->offset + (bp->bsize + bp->ocount);
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
}
|
14
lib9/bio/bprint.c
Normal file
14
lib9/bio/bprint.c
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
|
||||
int
|
||||
Bprint(Biobuf *bp, char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
n = Bvprint(bp, fmt, arg);
|
||||
va_end(arg);
|
||||
return n;
|
||||
}
|
20
lib9/bio/bputc.c
Normal file
20
lib9/bio/bputc.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
|
||||
int
|
||||
Bputc(Biobuf *bp, int c)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(;;) {
|
||||
i = bp->ocount;
|
||||
if(i) {
|
||||
bp->ebuf[i++] = c;
|
||||
bp->ocount = i;
|
||||
return 0;
|
||||
}
|
||||
if(Bflush(bp) == Beof)
|
||||
break;
|
||||
}
|
||||
return Beof;
|
||||
}
|
23
lib9/bio/bputrune.c
Normal file
23
lib9/bio/bputrune.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <utf.h>
|
||||
|
||||
int
|
||||
Bputrune(Biobuf *bp, long c)
|
||||
{
|
||||
Rune rune;
|
||||
char str[4];
|
||||
int n;
|
||||
|
||||
rune = c;
|
||||
if(rune < Runeself) {
|
||||
Bputc(bp, rune);
|
||||
return 1;
|
||||
}
|
||||
n = runetochar(str, &rune);
|
||||
if(n == 0)
|
||||
return Bbad;
|
||||
if(Bwrite(bp, str, n) != n)
|
||||
return Beof;
|
||||
return n;
|
||||
}
|
95
lib9/bio/brdline.c
Normal file
95
lib9/bio/brdline.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void*
|
||||
Brdline(Biobuf *bp, int delim)
|
||||
{
|
||||
char *ip, *ep;
|
||||
int i, j;
|
||||
|
||||
i = -bp->icount;
|
||||
if(i == 0) {
|
||||
/*
|
||||
* eof or other error
|
||||
*/
|
||||
if(bp->state != Bractive) {
|
||||
if(bp->state == Bracteof)
|
||||
bp->state = Bractive;
|
||||
bp->rdline = 0;
|
||||
bp->gbuf = bp->ebuf;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* first try in remainder of buffer (gbuf doesn't change)
|
||||
*/
|
||||
ip = (char*)bp->ebuf - i;
|
||||
ep = memchr(ip, delim, i);
|
||||
if(ep) {
|
||||
j = (ep - ip) + 1;
|
||||
bp->rdline = j;
|
||||
bp->icount += j;
|
||||
return ip;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy data to beginning of buffer
|
||||
*/
|
||||
if(i < bp->bsize)
|
||||
memmove(bp->bbuf, ip, i);
|
||||
bp->gbuf = bp->bbuf;
|
||||
|
||||
/*
|
||||
* append to buffer looking for the delim
|
||||
*/
|
||||
ip = (char*)bp->bbuf + i;
|
||||
while(i < bp->bsize) {
|
||||
j = read(bp->fid, ip, bp->bsize-i);
|
||||
if(j <= 0) {
|
||||
/*
|
||||
* end of file with no delim
|
||||
*/
|
||||
memmove(bp->ebuf-i, bp->bbuf, i);
|
||||
bp->rdline = i;
|
||||
bp->icount = -i;
|
||||
bp->gbuf = bp->ebuf-i;
|
||||
return 0;
|
||||
}
|
||||
bp->offset += j;
|
||||
i += j;
|
||||
ep = memchr(ip, delim, j);
|
||||
if(ep) {
|
||||
/*
|
||||
* found in new piece
|
||||
* copy back up and reset everything
|
||||
*/
|
||||
ip = (char*)bp->ebuf - i;
|
||||
if(i < bp->bsize){
|
||||
memmove(ip, bp->bbuf, i);
|
||||
bp->gbuf = (unsigned char*)ip;
|
||||
}
|
||||
j = (ep - (char*)bp->bbuf) + 1;
|
||||
bp->rdline = j;
|
||||
bp->icount = j - i;
|
||||
return ip;
|
||||
}
|
||||
ip += j;
|
||||
}
|
||||
|
||||
/*
|
||||
* full buffer without finding
|
||||
*/
|
||||
bp->rdline = bp->bsize;
|
||||
bp->icount = -bp->bsize;
|
||||
bp->gbuf = bp->bbuf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
Blinelen(Biobuf *bp)
|
||||
{
|
||||
|
||||
return bp->rdline;
|
||||
}
|
113
lib9/bio/brdstr.c
Normal file
113
lib9/bio/brdstr.c
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static char*
|
||||
badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = *np;
|
||||
p = realloc(p, n+ndata+1);
|
||||
if(p){
|
||||
memmove(p+n, data, ndata);
|
||||
n += ndata;
|
||||
if(n>0 && nulldelim && p[n-1]==delim)
|
||||
p[--n] = '\0';
|
||||
else
|
||||
p[n] = '\0';
|
||||
*np = n;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
char*
|
||||
Brdstr(Biobuf *bp, int delim, int nulldelim)
|
||||
{
|
||||
char *ip, *ep, *p;
|
||||
int i, j;
|
||||
|
||||
i = -bp->icount;
|
||||
bp->rdline = 0;
|
||||
if(i == 0) {
|
||||
/*
|
||||
* eof or other error
|
||||
*/
|
||||
if(bp->state != Bractive) {
|
||||
if(bp->state == Bracteof)
|
||||
bp->state = Bractive;
|
||||
bp->gbuf = bp->ebuf;
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* first try in remainder of buffer (gbuf doesn't change)
|
||||
*/
|
||||
ip = (char*)bp->ebuf - i;
|
||||
ep = memchr(ip, delim, i);
|
||||
if(ep) {
|
||||
j = (ep - ip) + 1;
|
||||
bp->icount += j;
|
||||
return badd(nil, &bp->rdline, ip, j, delim, nulldelim);
|
||||
}
|
||||
|
||||
/*
|
||||
* copy data to beginning of buffer
|
||||
*/
|
||||
if(i < bp->bsize)
|
||||
memmove(bp->bbuf, ip, i);
|
||||
bp->gbuf = bp->bbuf;
|
||||
|
||||
/*
|
||||
* append to buffer looking for the delim
|
||||
*/
|
||||
p = nil;
|
||||
for(;;){
|
||||
ip = (char*)bp->bbuf + i;
|
||||
while(i < bp->bsize) {
|
||||
j = read(bp->fid, ip, bp->bsize-i);
|
||||
if(j <= 0 && i == 0)
|
||||
return p;
|
||||
if(j <= 0 && i > 0){
|
||||
/*
|
||||
* end of file but no delim. pretend we got a delim
|
||||
* by making the delim \0 and smashing it with nulldelim.
|
||||
*/
|
||||
j = 1;
|
||||
ep = ip;
|
||||
delim = '\0';
|
||||
nulldelim = 1;
|
||||
*ep = delim; /* there will be room for this */
|
||||
}else{
|
||||
bp->offset += j;
|
||||
ep = memchr(ip, delim, j);
|
||||
}
|
||||
i += j;
|
||||
if(ep) {
|
||||
/*
|
||||
* found in new piece
|
||||
* copy back up and reset everything
|
||||
*/
|
||||
ip = (char*)bp->ebuf - i;
|
||||
if(i < bp->bsize){
|
||||
memmove(ip, bp->bbuf, i);
|
||||
bp->gbuf = (unsigned char*)ip;
|
||||
}
|
||||
j = (ep - (char*)bp->bbuf) + 1;
|
||||
bp->icount = j - i;
|
||||
return badd(p, &bp->rdline, ip, j, delim, nulldelim);
|
||||
}
|
||||
ip += j;
|
||||
}
|
||||
|
||||
/*
|
||||
* full buffer without finding; add to user string and continue
|
||||
*/
|
||||
p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0);
|
||||
i = 0;
|
||||
bp->icount = 0;
|
||||
bp->gbuf = bp->ebuf;
|
||||
}
|
||||
}
|
46
lib9/bio/bread.c
Normal file
46
lib9/bio/bread.c
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
long
|
||||
Bread(Biobuf *bp, void *ap, long count)
|
||||
{
|
||||
long c;
|
||||
unsigned char *p;
|
||||
int i, n, ic;
|
||||
|
||||
p = ap;
|
||||
c = count;
|
||||
ic = bp->icount;
|
||||
|
||||
while(c > 0) {
|
||||
n = -ic;
|
||||
if(n > c)
|
||||
n = c;
|
||||
if(n == 0) {
|
||||
if(bp->state != Bractive)
|
||||
break;
|
||||
i = read(bp->fid, bp->bbuf, bp->bsize);
|
||||
if(i <= 0) {
|
||||
bp->state = Bracteof;
|
||||
if(i < 0)
|
||||
bp->state = Binactive;
|
||||
break;
|
||||
}
|
||||
bp->gbuf = bp->bbuf;
|
||||
bp->offset += i;
|
||||
if(i < bp->bsize) {
|
||||
memmove(bp->ebuf-i, bp->bbuf, i);
|
||||
bp->gbuf = bp->ebuf-i;
|
||||
}
|
||||
ic = -i;
|
||||
continue;
|
||||
}
|
||||
memmove(p, bp->ebuf+ic, n);
|
||||
c -= n;
|
||||
ic += n;
|
||||
p += n;
|
||||
}
|
||||
bp->icount = ic;
|
||||
return count-c;
|
||||
}
|
63
lib9/bio/bseek.c
Normal file
63
lib9/bio/bseek.c
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <fmt.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
off_t
|
||||
Bseek(Biobuf *bp, off_t offset, int base)
|
||||
{
|
||||
long long n, d;
|
||||
int bufsz;
|
||||
|
||||
switch(bp->state) {
|
||||
default:
|
||||
fprint(2, "Bseek: unknown state %d\n", bp->state);
|
||||
return Beof;
|
||||
|
||||
case Bracteof:
|
||||
bp->state = Bractive;
|
||||
bp->icount = 0;
|
||||
bp->gbuf = bp->ebuf;
|
||||
|
||||
case Bractive:
|
||||
n = offset;
|
||||
if(base == 1) {
|
||||
n += Boffset(bp);
|
||||
base = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* try to seek within buffer
|
||||
*/
|
||||
if(base == 0) {
|
||||
d = n - Boffset(bp);
|
||||
bufsz = bp->ebuf - bp->gbuf;
|
||||
if(-bufsz <= d && d <= bufsz){
|
||||
bp->icount += d;
|
||||
if(d >= 0) {
|
||||
if(bp->icount <= 0)
|
||||
return n;
|
||||
} else {
|
||||
if(bp->ebuf - bp->gbuf >= -bp->icount)
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* reset the buffer
|
||||
*/
|
||||
n = lseek(bp->fid, n, base);
|
||||
bp->icount = 0;
|
||||
bp->gbuf = bp->ebuf;
|
||||
break;
|
||||
|
||||
case Bwactive:
|
||||
Bflush(bp);
|
||||
n = lseek(bp->fid, offset, base);
|
||||
break;
|
||||
}
|
||||
bp->offset = n;
|
||||
return n;
|
||||
}
|
39
lib9/bio/bvprint.c
Normal file
39
lib9/bio/bvprint.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <fmt.h>
|
||||
|
||||
static int
|
||||
fmtBflush(Fmt *f)
|
||||
{
|
||||
Biobuf *bp;
|
||||
|
||||
bp = f->farg;
|
||||
bp->ocount = (char*)f->to - (char*)f->stop;
|
||||
if(Bflush(bp) < 0)
|
||||
return 0;
|
||||
f->stop = bp->ebuf;
|
||||
f->to = (char*)f->stop + bp->ocount;
|
||||
f->start = f->to;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
Bvprint(Biobuf *bp, char *fmt, va_list arg)
|
||||
{
|
||||
int n;
|
||||
Fmt f;
|
||||
|
||||
f.runes = 0;
|
||||
f.stop = bp->ebuf;
|
||||
f.start = (char*)f.stop + bp->ocount;
|
||||
f.to = f.start;
|
||||
f.flush = fmtBflush;
|
||||
f.farg = bp;
|
||||
f.nfmt = 0;
|
||||
n = fmtvprint(&f, fmt, arg);
|
||||
bp->ocount = (char*)f.to - (char*)f.stop;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
39
lib9/bio/bwrite.c
Normal file
39
lib9/bio/bwrite.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "lib9.h"
|
||||
#include <bio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
long
|
||||
Bwrite(Biobuf *bp, void *ap, long count)
|
||||
{
|
||||
long c;
|
||||
unsigned char *p;
|
||||
int i, n, oc;
|
||||
|
||||
p = ap;
|
||||
c = count;
|
||||
oc = bp->ocount;
|
||||
|
||||
while(c > 0) {
|
||||
n = -oc;
|
||||
if(n > c)
|
||||
n = c;
|
||||
if(n == 0) {
|
||||
if(bp->state != Bwactive)
|
||||
return Beof;
|
||||
i = write(bp->fid, bp->bbuf, bp->bsize);
|
||||
if(i != bp->bsize) {
|
||||
bp->state = Binactive;
|
||||
return Beof;
|
||||
}
|
||||
bp->offset += i;
|
||||
oc = -bp->bsize;
|
||||
continue;
|
||||
}
|
||||
memmove(bp->ebuf+oc, p, n);
|
||||
oc += n;
|
||||
c -= n;
|
||||
p += n;
|
||||
}
|
||||
bp->ocount = oc;
|
||||
return count-c;
|
||||
}
|
20
lib9/bio/lib9.std.h
Normal file
20
lib9/bio/lib9.std.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <utf.h>
|
||||
#include <fmt.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define OREAD O_RDONLY
|
||||
#define OWRITE O_WRONLY
|
||||
|
||||
#define OCEXEC 0
|
||||
#define ORCLOSE 0
|
||||
#define OTRUNC 0
|
||||
|
||||
|
||||
#define nil ((void*)0)
|
||||
|
||||
typedef long long vlong;
|
||||
typedef unsigned long long uvlong;
|
26
lib9/cistrcmp.c
Normal file
26
lib9/cistrcmp.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
cistrcmp(char *s1, char *s2)
|
||||
{
|
||||
int c1, c2;
|
||||
|
||||
while(*s1){
|
||||
c1 = *(uchar*)s1++;
|
||||
c2 = *(uchar*)s2++;
|
||||
|
||||
if(c1 == c2)
|
||||
continue;
|
||||
|
||||
if(c1 >= 'A' && c1 <= 'Z')
|
||||
c1 -= 'A' - 'a';
|
||||
|
||||
if(c2 >= 'A' && c2 <= 'Z')
|
||||
c2 -= 'A' - 'a';
|
||||
|
||||
if(c1 != c2)
|
||||
return c1 - c2;
|
||||
}
|
||||
return -*s2;
|
||||
}
|
28
lib9/cistrncmp.c
Normal file
28
lib9/cistrncmp.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int
|
||||
cistrncmp(char *s1, char *s2, int n)
|
||||
{
|
||||
int c1, c2;
|
||||
|
||||
while(*s1 && n-- > 0){
|
||||
c1 = *(uchar*)s1++;
|
||||
c2 = *(uchar*)s2++;
|
||||
|
||||
if(c1 == c2)
|
||||
continue;
|
||||
|
||||
if(c1 >= 'A' && c1 <= 'Z')
|
||||
c1 -= 'A' - 'a';
|
||||
|
||||
if(c2 >= 'A' && c2 <= 'Z')
|
||||
c2 -= 'A' - 'a';
|
||||
|
||||
if(c1 != c2)
|
||||
return c1 - c2;
|
||||
}
|
||||
if(n <= 0)
|
||||
return 0;
|
||||
return -*s2;
|
||||
}
|
23
lib9/cistrstr.c
Normal file
23
lib9/cistrstr.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
char*
|
||||
cistrstr(char *s, char *sub)
|
||||
{
|
||||
int c, csub, n;
|
||||
|
||||
csub = *sub;
|
||||
if(csub == '\0')
|
||||
return s;
|
||||
if(csub >= 'A' && csub <= 'Z')
|
||||
csub -= 'A' - 'a';
|
||||
sub++;
|
||||
n = strlen(sub);
|
||||
for(; c = *s; s++){
|
||||
if(c >= 'A' && c <= 'Z')
|
||||
c -= 'A' - 'a';
|
||||
if(c == csub && cistrncmp(s+1, sub, n) == 0)
|
||||
return s;
|
||||
}
|
||||
return nil;
|
||||
}
|
52
lib9/cleanname.c
Normal file
52
lib9/cleanname.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
/*
|
||||
* In place, rewrite name to compress multiple /, eliminate ., and process ..
|
||||
*/
|
||||
#define SEP(x) ((x)=='/' || (x) == 0)
|
||||
char*
|
||||
cleanname(char *name)
|
||||
{
|
||||
char *p, *q, *dotdot;
|
||||
int rooted;
|
||||
|
||||
rooted = name[0] == '/';
|
||||
|
||||
/*
|
||||
* invariants:
|
||||
* p points at beginning of path element we're considering.
|
||||
* q points just past the last path element we wrote (no slash).
|
||||
* dotdot points just past the point where .. cannot backtrack
|
||||
* any further (no slash).
|
||||
*/
|
||||
p = q = dotdot = name+rooted;
|
||||
while(*p) {
|
||||
if(p[0] == '/') /* null element */
|
||||
p++;
|
||||
else if(p[0] == '.' && SEP(p[1]))
|
||||
p += 1; /* don't count the separator in case it is nul */
|
||||
else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
|
||||
p += 2;
|
||||
if(q > dotdot) { /* can backtrack */
|
||||
while(--q > dotdot && *q != '/')
|
||||
;
|
||||
} else if(!rooted) { /* /.. is / but ./../ is .. */
|
||||
if(q != name)
|
||||
*q++ = '/';
|
||||
*q++ = '.';
|
||||
*q++ = '.';
|
||||
dotdot = q;
|
||||
}
|
||||
} else { /* real path element */
|
||||
if(q != name+rooted)
|
||||
*q++ = '/';
|
||||
while((*q = *p) != '/' && *q != 0)
|
||||
p++, q++;
|
||||
}
|
||||
}
|
||||
if(q == name) /* empty string is really ``.'' */
|
||||
*q++ = '.';
|
||||
*q = '\0';
|
||||
return name;
|
||||
}
|
95
lib9/convD2M.c
Normal file
95
lib9/convD2M.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
uint
|
||||
sizeD2M(Dir *d)
|
||||
{
|
||||
char *sv[4];
|
||||
int i, ns;
|
||||
|
||||
sv[0] = d->name;
|
||||
sv[1] = d->uid;
|
||||
sv[2] = d->gid;
|
||||
sv[3] = d->muid;
|
||||
|
||||
ns = 0;
|
||||
for(i = 0; i < 4; i++)
|
||||
if(sv[i])
|
||||
ns += strlen(sv[i]);
|
||||
|
||||
return STATFIXLEN + ns;
|
||||
}
|
||||
|
||||
uint
|
||||
convD2M(Dir *d, uchar *buf, uint nbuf)
|
||||
{
|
||||
uchar *p, *ebuf;
|
||||
char *sv[4];
|
||||
int i, ns, nsv[4], ss;
|
||||
|
||||
if(nbuf < BIT16SZ)
|
||||
return 0;
|
||||
|
||||
p = buf;
|
||||
ebuf = buf + nbuf;
|
||||
|
||||
sv[0] = d->name;
|
||||
sv[1] = d->uid;
|
||||
sv[2] = d->gid;
|
||||
sv[3] = d->muid;
|
||||
|
||||
ns = 0;
|
||||
for(i = 0; i < 4; i++){
|
||||
if(sv[i])
|
||||
nsv[i] = strlen(sv[i]);
|
||||
else
|
||||
nsv[i] = 0;
|
||||
ns += nsv[i];
|
||||
}
|
||||
|
||||
ss = STATFIXLEN + ns;
|
||||
|
||||
/* set size befor erroring, so user can know how much is needed */
|
||||
/* note that length excludes count field itself */
|
||||
PBIT16(p, ss-BIT16SZ);
|
||||
p += BIT16SZ;
|
||||
|
||||
if(ss > nbuf)
|
||||
return BIT16SZ;
|
||||
|
||||
PBIT16(p, d->type);
|
||||
p += BIT16SZ;
|
||||
PBIT32(p, d->dev);
|
||||
p += BIT32SZ;
|
||||
PBIT8(p, d->qid.type);
|
||||
p += BIT8SZ;
|
||||
PBIT32(p, d->qid.vers);
|
||||
p += BIT32SZ;
|
||||
PBIT64(p, d->qid.path);
|
||||
p += BIT64SZ;
|
||||
PBIT32(p, d->mode);
|
||||
p += BIT32SZ;
|
||||
PBIT32(p, d->atime);
|
||||
p += BIT32SZ;
|
||||
PBIT32(p, d->mtime);
|
||||
p += BIT32SZ;
|
||||
PBIT64(p, d->length);
|
||||
p += BIT64SZ;
|
||||
|
||||
for(i = 0; i < 4; i++){
|
||||
ns = nsv[i];
|
||||
if(p + ns + BIT16SZ > ebuf)
|
||||
return 0;
|
||||
PBIT16(p, ns);
|
||||
p += BIT16SZ;
|
||||
if(ns)
|
||||
memmove(p, sv[i], ns);
|
||||
p += ns;
|
||||
}
|
||||
|
||||
if(ss != p - buf)
|
||||
return 0;
|
||||
|
||||
return p - buf;
|
||||
}
|
94
lib9/convM2D.c
Normal file
94
lib9/convM2D.c
Normal file
@@ -0,0 +1,94 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
int
|
||||
statcheck(uchar *buf, uint nbuf)
|
||||
{
|
||||
uchar *ebuf;
|
||||
int i;
|
||||
|
||||
ebuf = buf + nbuf;
|
||||
|
||||
if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
|
||||
return -1;
|
||||
|
||||
buf += STATFIXLEN - 4 * BIT16SZ;
|
||||
|
||||
for(i = 0; i < 4; i++){
|
||||
if(buf + BIT16SZ > ebuf)
|
||||
return -1;
|
||||
buf += BIT16SZ + GBIT16(buf);
|
||||
}
|
||||
|
||||
if(buf != ebuf)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char nullstring[] = "";
|
||||
|
||||
uint
|
||||
convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
|
||||
{
|
||||
uchar *p, *ebuf;
|
||||
char *sv[4];
|
||||
int i, ns;
|
||||
|
||||
if(nbuf < STATFIXLEN)
|
||||
return 0;
|
||||
|
||||
p = buf;
|
||||
ebuf = buf + nbuf;
|
||||
|
||||
p += BIT16SZ; /* ignore size */
|
||||
d->type = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
d->dev = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
d->qid.type = GBIT8(p);
|
||||
p += BIT8SZ;
|
||||
d->qid.vers = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
d->qid.path = GBIT64(p);
|
||||
p += BIT64SZ;
|
||||
d->mode = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
d->atime = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
d->mtime = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
d->length = GBIT64(p);
|
||||
p += BIT64SZ;
|
||||
|
||||
for(i = 0; i < 4; i++){
|
||||
if(p + BIT16SZ > ebuf)
|
||||
return 0;
|
||||
ns = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
if(p + ns > ebuf)
|
||||
return 0;
|
||||
if(strs){
|
||||
sv[i] = strs;
|
||||
memmove(strs, p, ns);
|
||||
strs += ns;
|
||||
*strs++ = '\0';
|
||||
}
|
||||
p += ns;
|
||||
}
|
||||
|
||||
if(strs){
|
||||
d->name = sv[0];
|
||||
d->uid = sv[1];
|
||||
d->gid = sv[2];
|
||||
d->muid = sv[3];
|
||||
}else{
|
||||
d->name = nullstring;
|
||||
d->uid = nullstring;
|
||||
d->gid = nullstring;
|
||||
d->muid = nullstring;
|
||||
}
|
||||
|
||||
return p - buf;
|
||||
}
|
323
lib9/convM2S.c
Normal file
323
lib9/convM2S.c
Normal file
@@ -0,0 +1,323 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
static
|
||||
uchar*
|
||||
gstring(uchar *p, uchar *ep, char **s)
|
||||
{
|
||||
uint n;
|
||||
|
||||
if(p+BIT16SZ > ep)
|
||||
return nil;
|
||||
n = GBIT16(p);
|
||||
p += BIT16SZ - 1;
|
||||
if(p+n+1 > ep)
|
||||
return nil;
|
||||
/* move it down, on top of count, to make room for '\0' */
|
||||
memmove(p, p + 1, n);
|
||||
p[n] = '\0';
|
||||
*s = (char*)p;
|
||||
p += n+1;
|
||||
return p;
|
||||
}
|
||||
|
||||
static
|
||||
uchar*
|
||||
gqid(uchar *p, uchar *ep, Qid *q)
|
||||
{
|
||||
if(p+QIDSZ > ep)
|
||||
return nil;
|
||||
q->type = GBIT8(p);
|
||||
p += BIT8SZ;
|
||||
q->vers = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
q->path = GBIT64(p);
|
||||
p += BIT64SZ;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* no syntactic checks.
|
||||
* three causes for error:
|
||||
* 1. message size field is incorrect
|
||||
* 2. input buffer too short for its own data (counts too long, etc.)
|
||||
* 3. too many names or qids
|
||||
* gqid() and gstring() return nil if they would reach beyond buffer.
|
||||
* main switch statement checks range and also can fall through
|
||||
* to test at end of routine.
|
||||
*/
|
||||
uint
|
||||
convM2S(uchar *ap, uint nap, Fcall *f)
|
||||
{
|
||||
uchar *p, *ep;
|
||||
uint i, size;
|
||||
|
||||
p = ap;
|
||||
ep = p + nap;
|
||||
|
||||
if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
|
||||
return 0;
|
||||
size = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
|
||||
if(size < BIT32SZ+BIT8SZ+BIT16SZ)
|
||||
return 0;
|
||||
|
||||
f->type = GBIT8(p);
|
||||
p += BIT8SZ;
|
||||
f->tag = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
|
||||
switch(f->type)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
|
||||
case Tversion:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->msize = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
p = gstring(p, ep, &f->version);
|
||||
break;
|
||||
|
||||
case Tflush:
|
||||
if(p+BIT16SZ > ep)
|
||||
return 0;
|
||||
f->oldtag = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
break;
|
||||
|
||||
case Tauth:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->afid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
p = gstring(p, ep, &f->uname);
|
||||
if(p == nil)
|
||||
break;
|
||||
p = gstring(p, ep, &f->aname);
|
||||
if(p == nil)
|
||||
break;
|
||||
break;
|
||||
|
||||
case Tattach:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->afid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
p = gstring(p, ep, &f->uname);
|
||||
if(p == nil)
|
||||
break;
|
||||
p = gstring(p, ep, &f->aname);
|
||||
if(p == nil)
|
||||
break;
|
||||
break;
|
||||
|
||||
case Twalk:
|
||||
if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->newfid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->nwname = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
if(f->nwname > MAXWELEM)
|
||||
return 0;
|
||||
for(i=0; i<f->nwname; i++){
|
||||
p = gstring(p, ep, &f->wname[i]);
|
||||
if(p == nil)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Topen:
|
||||
case Topenfd:
|
||||
if(p+BIT32SZ+BIT8SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->mode = GBIT8(p);
|
||||
p += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tcreate:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
p = gstring(p, ep, &f->name);
|
||||
if(p == nil)
|
||||
break;
|
||||
if(p+BIT32SZ+BIT8SZ > ep)
|
||||
return 0;
|
||||
f->perm = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->mode = GBIT8(p);
|
||||
p += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tread:
|
||||
if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->offset = GBIT64(p);
|
||||
p += BIT64SZ;
|
||||
f->count = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twrite:
|
||||
if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->offset = GBIT64(p);
|
||||
p += BIT64SZ;
|
||||
f->count = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
if(p+f->count > ep)
|
||||
return 0;
|
||||
f->data = (char*)p;
|
||||
p += f->count;
|
||||
break;
|
||||
|
||||
case Tclunk:
|
||||
case Tremove:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Tstat:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twstat:
|
||||
if(p+BIT32SZ+BIT16SZ > ep)
|
||||
return 0;
|
||||
f->fid = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
f->nstat = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
if(p+f->nstat > ep)
|
||||
return 0;
|
||||
f->stat = p;
|
||||
p += f->nstat;
|
||||
break;
|
||||
|
||||
/*
|
||||
*/
|
||||
case Rversion:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->msize = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
p = gstring(p, ep, &f->version);
|
||||
break;
|
||||
|
||||
case Rerror:
|
||||
p = gstring(p, ep, &f->ename);
|
||||
break;
|
||||
|
||||
case Rflush:
|
||||
break;
|
||||
|
||||
case Rauth:
|
||||
p = gqid(p, ep, &f->aqid);
|
||||
if(p == nil)
|
||||
break;
|
||||
break;
|
||||
|
||||
case Rattach:
|
||||
p = gqid(p, ep, &f->qid);
|
||||
if(p == nil)
|
||||
break;
|
||||
break;
|
||||
|
||||
case Rwalk:
|
||||
if(p+BIT16SZ > ep)
|
||||
return 0;
|
||||
f->nwqid = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
if(f->nwqid > MAXWELEM)
|
||||
return 0;
|
||||
for(i=0; i<f->nwqid; i++){
|
||||
p = gqid(p, ep, &f->wqid[i]);
|
||||
if(p == nil)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Ropen:
|
||||
case Ropenfd:
|
||||
case Rcreate:
|
||||
p = gqid(p, ep, &f->qid);
|
||||
if(p == nil)
|
||||
break;
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->iounit = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
if(f->type == Ropenfd){
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->unixfd = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
}
|
||||
break;
|
||||
|
||||
case Rread:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->count = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
if(p+f->count > ep)
|
||||
return 0;
|
||||
f->data = (char*)p;
|
||||
p += f->count;
|
||||
break;
|
||||
|
||||
case Rwrite:
|
||||
if(p+BIT32SZ > ep)
|
||||
return 0;
|
||||
f->count = GBIT32(p);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Rclunk:
|
||||
case Rremove:
|
||||
break;
|
||||
|
||||
case Rstat:
|
||||
if(p+BIT16SZ > ep)
|
||||
return 0;
|
||||
f->nstat = GBIT16(p);
|
||||
p += BIT16SZ;
|
||||
if(p+f->nstat > ep)
|
||||
return 0;
|
||||
f->stat = p;
|
||||
p += f->nstat;
|
||||
break;
|
||||
|
||||
case Rwstat:
|
||||
break;
|
||||
}
|
||||
|
||||
if(p==nil || p>ep)
|
||||
return 0;
|
||||
if(ap+size == p)
|
||||
return size;
|
||||
return 0;
|
||||
}
|
399
lib9/convS2M.c
Normal file
399
lib9/convS2M.c
Normal file
@@ -0,0 +1,399 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <fcall.h>
|
||||
|
||||
static
|
||||
uchar*
|
||||
pstring(uchar *p, char *s)
|
||||
{
|
||||
uint n;
|
||||
|
||||
if(s == nil){
|
||||
PBIT16(p, 0);
|
||||
p += BIT16SZ;
|
||||
return p;
|
||||
}
|
||||
|
||||
n = strlen(s);
|
||||
PBIT16(p, n);
|
||||
p += BIT16SZ;
|
||||
memmove(p, s, n);
|
||||
p += n;
|
||||
return p;
|
||||
}
|
||||
|
||||
static
|
||||
uchar*
|
||||
pqid(uchar *p, Qid *q)
|
||||
{
|
||||
PBIT8(p, q->type);
|
||||
p += BIT8SZ;
|
||||
PBIT32(p, q->vers);
|
||||
p += BIT32SZ;
|
||||
PBIT64(p, q->path);
|
||||
p += BIT64SZ;
|
||||
return p;
|
||||
}
|
||||
|
||||
static
|
||||
uint
|
||||
stringsz(char *s)
|
||||
{
|
||||
if(s == nil)
|
||||
return BIT16SZ;
|
||||
|
||||
return BIT16SZ+strlen(s);
|
||||
}
|
||||
|
||||
uint
|
||||
sizeS2M(Fcall *f)
|
||||
{
|
||||
uint n;
|
||||
int i;
|
||||
|
||||
n = 0;
|
||||
n += BIT32SZ; /* size */
|
||||
n += BIT8SZ; /* type */
|
||||
n += BIT16SZ; /* tag */
|
||||
|
||||
switch(f->type)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
|
||||
case Tversion:
|
||||
n += BIT32SZ;
|
||||
n += stringsz(f->version);
|
||||
break;
|
||||
|
||||
case Tflush:
|
||||
n += BIT16SZ;
|
||||
break;
|
||||
|
||||
case Tauth:
|
||||
n += BIT32SZ;
|
||||
n += stringsz(f->uname);
|
||||
n += stringsz(f->aname);
|
||||
break;
|
||||
|
||||
case Tattach:
|
||||
n += BIT32SZ;
|
||||
n += BIT32SZ;
|
||||
n += stringsz(f->uname);
|
||||
n += stringsz(f->aname);
|
||||
break;
|
||||
|
||||
case Twalk:
|
||||
n += BIT32SZ;
|
||||
n += BIT32SZ;
|
||||
n += BIT16SZ;
|
||||
for(i=0; i<f->nwname; i++)
|
||||
n += stringsz(f->wname[i]);
|
||||
break;
|
||||
|
||||
case Topen:
|
||||
case Topenfd:
|
||||
n += BIT32SZ;
|
||||
n += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tcreate:
|
||||
n += BIT32SZ;
|
||||
n += stringsz(f->name);
|
||||
n += BIT32SZ;
|
||||
n += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tread:
|
||||
n += BIT32SZ;
|
||||
n += BIT64SZ;
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twrite:
|
||||
n += BIT32SZ;
|
||||
n += BIT64SZ;
|
||||
n += BIT32SZ;
|
||||
n += f->count;
|
||||
break;
|
||||
|
||||
case Tclunk:
|
||||
case Tremove:
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Tstat:
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twstat:
|
||||
n += BIT32SZ;
|
||||
n += BIT16SZ;
|
||||
n += f->nstat;
|
||||
break;
|
||||
/*
|
||||
*/
|
||||
|
||||
case Rversion:
|
||||
n += BIT32SZ;
|
||||
n += stringsz(f->version);
|
||||
break;
|
||||
|
||||
case Rerror:
|
||||
n += stringsz(f->ename);
|
||||
break;
|
||||
|
||||
case Rflush:
|
||||
break;
|
||||
|
||||
case Rauth:
|
||||
n += QIDSZ;
|
||||
break;
|
||||
|
||||
case Rattach:
|
||||
n += QIDSZ;
|
||||
break;
|
||||
|
||||
case Rwalk:
|
||||
n += BIT16SZ;
|
||||
n += f->nwqid*QIDSZ;
|
||||
break;
|
||||
|
||||
case Ropen:
|
||||
case Rcreate:
|
||||
n += QIDSZ;
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Ropenfd:
|
||||
n += QIDSZ;
|
||||
n += BIT32SZ;
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Rread:
|
||||
n += BIT32SZ;
|
||||
n += f->count;
|
||||
break;
|
||||
|
||||
case Rwrite:
|
||||
n += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Rclunk:
|
||||
break;
|
||||
|
||||
case Rremove:
|
||||
break;
|
||||
|
||||
case Rstat:
|
||||
n += BIT16SZ;
|
||||
n += f->nstat;
|
||||
break;
|
||||
|
||||
case Rwstat:
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
uint
|
||||
convS2M(Fcall *f, uchar *ap, uint nap)
|
||||
{
|
||||
uchar *p;
|
||||
uint i, size;
|
||||
|
||||
size = sizeS2M(f);
|
||||
if(size == 0)
|
||||
return 0;
|
||||
if(size > nap)
|
||||
return 0;
|
||||
|
||||
p = (uchar*)ap;
|
||||
|
||||
PBIT32(p, size);
|
||||
p += BIT32SZ;
|
||||
PBIT8(p, f->type);
|
||||
p += BIT8SZ;
|
||||
PBIT16(p, f->tag);
|
||||
p += BIT16SZ;
|
||||
|
||||
switch(f->type)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
|
||||
case Tversion:
|
||||
PBIT32(p, f->msize);
|
||||
p += BIT32SZ;
|
||||
p = pstring(p, f->version);
|
||||
break;
|
||||
|
||||
case Tflush:
|
||||
PBIT16(p, f->oldtag);
|
||||
p += BIT16SZ;
|
||||
break;
|
||||
|
||||
case Tauth:
|
||||
PBIT32(p, f->afid);
|
||||
p += BIT32SZ;
|
||||
p = pstring(p, f->uname);
|
||||
p = pstring(p, f->aname);
|
||||
break;
|
||||
|
||||
case Tattach:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT32(p, f->afid);
|
||||
p += BIT32SZ;
|
||||
p = pstring(p, f->uname);
|
||||
p = pstring(p, f->aname);
|
||||
break;
|
||||
|
||||
case Twalk:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT32(p, f->newfid);
|
||||
p += BIT32SZ;
|
||||
PBIT16(p, f->nwname);
|
||||
p += BIT16SZ;
|
||||
if(f->nwname > MAXWELEM)
|
||||
return 0;
|
||||
for(i=0; i<f->nwname; i++)
|
||||
p = pstring(p, f->wname[i]);
|
||||
break;
|
||||
|
||||
case Topen:
|
||||
case Topenfd:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT8(p, f->mode);
|
||||
p += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tcreate:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
p = pstring(p, f->name);
|
||||
PBIT32(p, f->perm);
|
||||
p += BIT32SZ;
|
||||
PBIT8(p, f->mode);
|
||||
p += BIT8SZ;
|
||||
break;
|
||||
|
||||
case Tread:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT64(p, f->offset);
|
||||
p += BIT64SZ;
|
||||
PBIT32(p, f->count);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twrite:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT64(p, f->offset);
|
||||
p += BIT64SZ;
|
||||
PBIT32(p, f->count);
|
||||
p += BIT32SZ;
|
||||
memmove(p, f->data, f->count);
|
||||
p += f->count;
|
||||
break;
|
||||
|
||||
case Tclunk:
|
||||
case Tremove:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Tstat:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Twstat:
|
||||
PBIT32(p, f->fid);
|
||||
p += BIT32SZ;
|
||||
PBIT16(p, f->nstat);
|
||||
p += BIT16SZ;
|
||||
memmove(p, f->stat, f->nstat);
|
||||
p += f->nstat;
|
||||
break;
|
||||
/*
|
||||
*/
|
||||
|
||||
case Rversion:
|
||||
PBIT32(p, f->msize);
|
||||
p += BIT32SZ;
|
||||
p = pstring(p, f->version);
|
||||
break;
|
||||
|
||||
case Rerror:
|
||||
p = pstring(p, f->ename);
|
||||
break;
|
||||
|
||||
case Rflush:
|
||||
break;
|
||||
|
||||
case Rauth:
|
||||
p = pqid(p, &f->aqid);
|
||||
break;
|
||||
|
||||
case Rattach:
|
||||
p = pqid(p, &f->qid);
|
||||
break;
|
||||
|
||||
case Rwalk:
|
||||
PBIT16(p, f->nwqid);
|
||||
p += BIT16SZ;
|
||||
if(f->nwqid > MAXWELEM)
|
||||
return 0;
|
||||
for(i=0; i<f->nwqid; i++)
|
||||
p = pqid(p, &f->wqid[i]);
|
||||
break;
|
||||
|
||||
case Ropen:
|
||||
case Rcreate:
|
||||
case Ropenfd:
|
||||
p = pqid(p, &f->qid);
|
||||
PBIT32(p, f->iounit);
|
||||
p += BIT32SZ;
|
||||
if(f->type == Ropenfd){
|
||||
PBIT32(p, f->unixfd);
|
||||
p += BIT32SZ;
|
||||
}
|
||||
break;
|
||||
|
||||
case Rread:
|
||||
PBIT32(p, f->count);
|
||||
p += BIT32SZ;
|
||||
memmove(p, f->data, f->count);
|
||||
p += f->count;
|
||||
break;
|
||||
|
||||
case Rwrite:
|
||||
PBIT32(p, f->count);
|
||||
p += BIT32SZ;
|
||||
break;
|
||||
|
||||
case Rclunk:
|
||||
break;
|
||||
|
||||
case Rremove:
|
||||
break;
|
||||
|
||||
case Rstat:
|
||||
PBIT16(p, f->nstat);
|
||||
p += BIT16SZ;
|
||||
memmove(p, f->stat, f->nstat);
|
||||
p += f->nstat;
|
||||
break;
|
||||
|
||||
case Rwstat:
|
||||
break;
|
||||
}
|
||||
if(size != p-ap)
|
||||
return 0;
|
||||
return size;
|
||||
}
|
75
lib9/create.c
Normal file
75
lib9/create.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#define _GNU_SOURCE /* for Linux O_DIRECT */
|
||||
#include <u.h>
|
||||
#define NOPLAN9DEFINES
|
||||
#include <sys/file.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <libc.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef O_DIRECT
|
||||
#define O_DIRECT 0
|
||||
#endif
|
||||
|
||||
int
|
||||
p9create(char *path, int mode, ulong perm)
|
||||
{
|
||||
int fd, cexec, umode, rclose, lock, rdwr;
|
||||
struct flock fl;
|
||||
|
||||
rdwr = mode&3;
|
||||
lock = mode&OLOCK;
|
||||
cexec = mode&OCEXEC;
|
||||
rclose = mode&ORCLOSE;
|
||||
mode &= ~(ORCLOSE|OCEXEC|OLOCK);
|
||||
|
||||
/* XXX should get mode mask right? */
|
||||
fd = -1;
|
||||
if(perm&DMDIR){
|
||||
if(mode != OREAD){
|
||||
werrstr("bad mode in directory create");
|
||||
goto out;
|
||||
}
|
||||
if(mkdir(path, perm&0777) < 0)
|
||||
goto out;
|
||||
fd = open(path, O_RDONLY);
|
||||
}else{
|
||||
umode = (mode&3)|O_CREAT|O_TRUNC;
|
||||
mode &= ~(3|OTRUNC);
|
||||
if(mode&ODIRECT){
|
||||
umode |= O_DIRECT;
|
||||
mode &= ~ODIRECT;
|
||||
}
|
||||
if(mode&OEXCL){
|
||||
umode |= O_EXCL;
|
||||
mode &= ~OEXCL;
|
||||
}
|
||||
if(mode&OAPPEND){
|
||||
umode |= O_APPEND;
|
||||
mode &= ~OAPPEND;
|
||||
}
|
||||
if(mode){
|
||||
werrstr("unsupported mode in create");
|
||||
goto out;
|
||||
}
|
||||
fd = open(path, umode, perm);
|
||||
}
|
||||
out:
|
||||
if(fd >= 0){
|
||||
if(lock){
|
||||
fl.l_type = (rdwr==OREAD) ? F_RDLCK : F_WRLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
if(fcntl(fd, F_SETLK, &fl) < 0){
|
||||
close(fd);
|
||||
werrstr("lock: %r");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(cexec)
|
||||
fcntl(fd, F_SETFL, FD_CLOEXEC);
|
||||
if(rclose)
|
||||
remove(path);
|
||||
}
|
||||
return fd;
|
||||
}
|
58
lib9/ctime.c
Normal file
58
lib9/ctime.c
Normal file
@@ -0,0 +1,58 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static
|
||||
void
|
||||
ct_numb(char *cp, int n)
|
||||
{
|
||||
|
||||
cp[0] = ' ';
|
||||
if(n >= 10)
|
||||
cp[0] = (n/10)%10 + '0';
|
||||
cp[1] = n%10 + '0';
|
||||
}
|
||||
|
||||
char*
|
||||
asctime(Tm *t)
|
||||
{
|
||||
int i;
|
||||
char *ncp;
|
||||
static char cbuf[30];
|
||||
|
||||
strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n");
|
||||
ncp = &"SunMonTueWedThuFriSat"[t->wday*3];
|
||||
cbuf[0] = *ncp++;
|
||||
cbuf[1] = *ncp++;
|
||||
cbuf[2] = *ncp;
|
||||
ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3];
|
||||
cbuf[4] = *ncp++;
|
||||
cbuf[5] = *ncp++;
|
||||
cbuf[6] = *ncp;
|
||||
ct_numb(cbuf+8, t->mday);
|
||||
ct_numb(cbuf+11, t->hour+100);
|
||||
ct_numb(cbuf+14, t->min+100);
|
||||
ct_numb(cbuf+17, t->sec+100);
|
||||
ncp = t->zone;
|
||||
for(i=0; i<3; i++)
|
||||
if(ncp[i] == 0)
|
||||
break;
|
||||
for(; i<3; i++)
|
||||
ncp[i] = '?';
|
||||
ncp = t->zone;
|
||||
cbuf[20] = *ncp++;
|
||||
cbuf[21] = *ncp++;
|
||||
cbuf[22] = *ncp;
|
||||
if(t->year >= 100) {
|
||||
cbuf[24] = '2';
|
||||
cbuf[25] = '0';
|
||||
}
|
||||
ct_numb(cbuf+26, t->year+100);
|
||||
return cbuf;
|
||||
}
|
||||
|
||||
char*
|
||||
ctime(long t)
|
||||
{
|
||||
return asctime(localtime(t));
|
||||
}
|
||||
|
125
lib9/date.c
Normal file
125
lib9/date.c
Normal file
@@ -0,0 +1,125 @@
|
||||
#include <u.h>
|
||||
#include <stdlib.h> /* setenv etc. */
|
||||
#define NOPLAN9DEFINES
|
||||
#include <libc.h>
|
||||
#include <time.h>
|
||||
|
||||
#define _HAVETIMEGM 1
|
||||
#define _HAVETMZONE 1
|
||||
#define _HAVETMTZOFF 1
|
||||
|
||||
#if defined(__linux__)
|
||||
# undef _HAVETMZONE
|
||||
# undef _HAVETMTZOFF
|
||||
|
||||
#elif defined(__sun__)
|
||||
# undef _HAVETIMEGM
|
||||
# undef _HAVETMZONE
|
||||
# undef _HAVETMTZOFF
|
||||
|
||||
#endif
|
||||
|
||||
static Tm bigtm;
|
||||
|
||||
static void
|
||||
tm2Tm(struct tm *tm, Tm *bigtm)
|
||||
{
|
||||
char *s;
|
||||
|
||||
memset(bigtm, 0, sizeof *bigtm);
|
||||
bigtm->sec = tm->tm_sec;
|
||||
bigtm->min = tm->tm_min;
|
||||
bigtm->hour = tm->tm_hour;
|
||||
bigtm->mday = tm->tm_mday;
|
||||
bigtm->mon = tm->tm_mon;
|
||||
bigtm->year = tm->tm_year;
|
||||
bigtm->wday = tm->tm_wday;
|
||||
strftime(bigtm->zone, sizeof bigtm->zone, "%Z", tm);
|
||||
#ifdef _HAVETZOFF
|
||||
bigtm->tzoff = tm->tm_gmtoff;
|
||||
#endif
|
||||
|
||||
if(bigtm->zone[0] == 0){
|
||||
s = getenv("TIMEZONE");
|
||||
if(s){
|
||||
strecpy(bigtm->zone, bigtm->zone+4, s);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Tm2tm(Tm *bigtm, struct tm *tm)
|
||||
{
|
||||
memset(tm, 0, sizeof *tm);
|
||||
tm->tm_sec = bigtm->sec;
|
||||
tm->tm_min = bigtm->min;
|
||||
tm->tm_hour = bigtm->hour;
|
||||
tm->tm_mday = bigtm->mday;
|
||||
tm->tm_mon = bigtm->mon;
|
||||
tm->tm_year = bigtm->year;
|
||||
tm->tm_wday = bigtm->wday;
|
||||
#ifdef _HAVETMZONE
|
||||
tm->tm_zone = bigtm->zone;
|
||||
#endif
|
||||
#ifdef _HAVETZOFF
|
||||
tm->tm_gmtoff = bigtm->tzoff;
|
||||
#endif
|
||||
}
|
||||
|
||||
Tm*
|
||||
p9gmtime(long x)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tm;
|
||||
|
||||
t = (time_t)x;
|
||||
tm = *gmtime(&t);
|
||||
tm2Tm(&tm, &bigtm);
|
||||
return &bigtm;
|
||||
}
|
||||
|
||||
Tm*
|
||||
p9localtime(long x)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tm;
|
||||
|
||||
t = (time_t)x;
|
||||
tm = *localtime(&t);
|
||||
tm2Tm(&tm, &bigtm);
|
||||
return &bigtm;
|
||||
}
|
||||
|
||||
#if !defined(_HAVETIMEGM)
|
||||
static time_t
|
||||
timegm(struct tm *tm)
|
||||
{
|
||||
time_t ret;
|
||||
char *tz;
|
||||
char *s;
|
||||
|
||||
tz = getenv("TZ");
|
||||
putenv("TZ=");
|
||||
tzset();
|
||||
ret = mktime(tm);
|
||||
if(tz){
|
||||
s = smprint("TZ=%s", tz);
|
||||
if(s)
|
||||
putenv(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
long
|
||||
p9tm2sec(Tm *bigtm)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
Tm2tm(bigtm, &tm);
|
||||
if(strcmp(bigtm->zone, "GMT") == 0 || strcmp(bigtm->zone, "UCT") == 0)
|
||||
return timegm(&tm);
|
||||
return mktime(&tm); /* local time zone */
|
||||
}
|
||||
|
166
lib9/debugmalloc.c
Normal file
166
lib9/debugmalloc.c
Normal file
@@ -0,0 +1,166 @@
|
||||
#include <u.h>
|
||||
#define NOPLAN9DEFINES
|
||||
#include <libc.h>
|
||||
|
||||
/*
|
||||
* The Unix libc routines cannot be trusted to do their own locking.
|
||||
* Sad but apparently true.
|
||||
*/
|
||||
static Lock malloclock;
|
||||
static int mallocpid;
|
||||
|
||||
/*
|
||||
* The Unix mallocs don't do nearly enough error checking
|
||||
* for my tastes. We'll waste another 24 bytes per guy so that
|
||||
* we can. This is severely antisocial, since now free and p9free
|
||||
* are not interchangeable.
|
||||
*/
|
||||
int debugmalloc;
|
||||
|
||||
#define Overhead (debugmalloc ? (6*sizeof(ulong)) : 0)
|
||||
#define MallocMagic 0xA110C09
|
||||
#define ReallocMagic 0xB110C09
|
||||
#define CallocMagic 0xC110C09
|
||||
#define FreeMagic 0xF533F533
|
||||
#define CheckMagic 0
|
||||
#define END "\x7F\x2E\x55\x23"
|
||||
|
||||
static void
|
||||
whoops(void *v)
|
||||
{
|
||||
fprint(2, "bad malloc block %p\n", v);
|
||||
abort();
|
||||
}
|
||||
|
||||
static void*
|
||||
mark(void *v, ulong pc, ulong n, ulong magic)
|
||||
{
|
||||
ulong *u;
|
||||
char *p;
|
||||
|
||||
if(!debugmalloc)
|
||||
return v;
|
||||
|
||||
if(v == nil)
|
||||
return nil;
|
||||
|
||||
if(magic == FreeMagic || magic == CheckMagic){
|
||||
u = (ulong*)((char*)v-4*sizeof(ulong));
|
||||
if(u[0] != MallocMagic && u[0] != ReallocMagic && u[0] != CallocMagic)
|
||||
whoops(v);
|
||||
n = u[1];
|
||||
p = (char*)v+n;
|
||||
if(memcmp(p, END, 4) != 0)
|
||||
whoops(v);
|
||||
if(magic != CheckMagic){
|
||||
u[0] = FreeMagic;
|
||||
u[1] = u[2] = u[3] = pc;
|
||||
if(n > 16){
|
||||
u[4] = u[5] = u[6] = u[7] = pc;
|
||||
memset((char*)v+16, 0xFB, n-16);
|
||||
}
|
||||
}
|
||||
return u;
|
||||
}else{
|
||||
u = v;
|
||||
u[0] = magic;
|
||||
u[1] = n;
|
||||
u[2] = 0;
|
||||
u[3] = 0;
|
||||
if(magic == ReallocMagic)
|
||||
u[3] = pc;
|
||||
else
|
||||
u[2] = pc;
|
||||
p = (char*)(u+4)+n;
|
||||
memmove(p, END, 4);
|
||||
return u+4;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
setmalloctag(void *v, ulong t)
|
||||
{
|
||||
ulong *u;
|
||||
|
||||
if(!debugmalloc)
|
||||
return;
|
||||
|
||||
if(v == nil)
|
||||
return;
|
||||
u = mark(v, 0, 0, 0);
|
||||
u[2] = t;
|
||||
}
|
||||
|
||||
void
|
||||
setrealloctag(void *v, ulong t)
|
||||
{
|
||||
ulong *u;
|
||||
|
||||
if(!debugmalloc)
|
||||
return;
|
||||
|
||||
if(v == nil)
|
||||
return;
|
||||
u = mark(v, 0, 0, 0);
|
||||
u[3] = t;
|
||||
}
|
||||
|
||||
void*
|
||||
p9malloc(ulong n)
|
||||
{
|
||||
void *v;
|
||||
if(n == 0)
|
||||
n++;
|
||||
//fprint(2, "%s %d malloc\n", argv0, getpid());
|
||||
lock(&malloclock);
|
||||
mallocpid = getpid();
|
||||
v = malloc(n+Overhead);
|
||||
v = mark(v, getcallerpc(&n), n, MallocMagic);
|
||||
unlock(&malloclock);
|
||||
//fprint(2, "%s %d donemalloc\n", argv0, getpid());
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
p9free(void *v)
|
||||
{
|
||||
if(v == nil)
|
||||
return;
|
||||
|
||||
//fprint(2, "%s %d free\n", argv0, getpid());
|
||||
lock(&malloclock);
|
||||
mallocpid = getpid();
|
||||
v = mark(v, getcallerpc(&v), 0, FreeMagic);
|
||||
free(v);
|
||||
unlock(&malloclock);
|
||||
//fprint(2, "%s %d donefree\n", argv0, getpid());
|
||||
}
|
||||
|
||||
void*
|
||||
p9calloc(ulong a, ulong b)
|
||||
{
|
||||
void *v;
|
||||
|
||||
//fprint(2, "%s %d calloc\n", argv0, getpid());
|
||||
lock(&malloclock);
|
||||
mallocpid = getpid();
|
||||
v = calloc(a*b+Overhead, 1);
|
||||
v = mark(v, getcallerpc(&a), a*b, CallocMagic);
|
||||
unlock(&malloclock);
|
||||
//fprint(2, "%s %d donecalloc\n", argv0, getpid());
|
||||
return v;
|
||||
}
|
||||
|
||||
void*
|
||||
p9realloc(void *v, ulong n)
|
||||
{
|
||||
//fprint(2, "%s %d realloc\n", argv0, getpid());
|
||||
lock(&malloclock);
|
||||
mallocpid = getpid();
|
||||
v = mark(v, getcallerpc(&v), 0, CheckMagic);
|
||||
v = realloc(v, n+Overhead);
|
||||
v = mark(v, getcallerpc(&v), n, ReallocMagic);
|
||||
unlock(&malloclock);
|
||||
//fprint(2, "%s %d donerealloc\n", argv0, getpid());
|
||||
return v;
|
||||
}
|
137
lib9/dial.c
Normal file
137
lib9/dial.c
Normal file
@@ -0,0 +1,137 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#undef accept
|
||||
#undef announce
|
||||
#undef dial
|
||||
#undef setnetmtpt
|
||||
#undef hangup
|
||||
#undef listen
|
||||
#undef netmkaddr
|
||||
#undef reject
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/un.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#undef unix
|
||||
#define unix xunix
|
||||
|
||||
int
|
||||
p9dial(char *addr, char *local, char *dummy2, int *dummy3)
|
||||
{
|
||||
char *buf;
|
||||
char *net, *unix;
|
||||
u32int host;
|
||||
int port;
|
||||
int proto;
|
||||
socklen_t sn;
|
||||
int n;
|
||||
struct sockaddr_in sa, sal;
|
||||
struct sockaddr_un su;
|
||||
int s;
|
||||
|
||||
if(dummy2 || dummy3){
|
||||
werrstr("cannot handle extra arguments in dial");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = strdup(addr);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
|
||||
if(p9dialparse(buf, &net, &unix, &host, &port) < 0){
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strcmp(net, "tcp") == 0)
|
||||
proto = SOCK_STREAM;
|
||||
else if(strcmp(net, "udp") == 0)
|
||||
proto = SOCK_DGRAM;
|
||||
else if(strcmp(net, "unix") == 0)
|
||||
goto Unix;
|
||||
else{
|
||||
werrstr("can only handle tcp, udp, and unix: not %s", net);
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
free(buf);
|
||||
|
||||
memset(&sa, 0, sizeof sa);
|
||||
memmove(&sa.sin_addr, &host, 4);
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(port);
|
||||
if((s = socket(AF_INET, proto, 0)) < 0)
|
||||
return -1;
|
||||
|
||||
if(local){
|
||||
buf = strdup(local);
|
||||
if(buf == nil){
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
if(p9dialparse(buf, &net, &unix, &host, &port) < 0){
|
||||
badlocal:
|
||||
free(buf);
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
if(unix){
|
||||
werrstr("bad local address %s for dial %s", local, addr);
|
||||
goto badlocal;
|
||||
}
|
||||
memset(&sal, 0, sizeof sal);
|
||||
memmove(&sal.sin_addr, &local, 4);
|
||||
sal.sin_family = AF_INET;
|
||||
sal.sin_port = htons(port);
|
||||
sn = sizeof n;
|
||||
if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
|
||||
&& n == SOCK_STREAM){
|
||||
n = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
|
||||
}
|
||||
if(bind(s, (struct sockaddr*)&sal, sizeof sal) < 0)
|
||||
goto badlocal;
|
||||
free(buf);
|
||||
}
|
||||
|
||||
if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
if(proto == SOCK_STREAM){
|
||||
int one = 1;
|
||||
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one);
|
||||
}
|
||||
return s;
|
||||
|
||||
Unix:
|
||||
if(local){
|
||||
werrstr("local address not supported on unix network");
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
memset(&su, 0, sizeof su);
|
||||
su.sun_family = AF_UNIX;
|
||||
if(strlen(unix)+1 > sizeof su.sun_path){
|
||||
werrstr("unix socket name too long");
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
strcpy(su.sun_path, unix);
|
||||
free(buf);
|
||||
if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
|
||||
werrstr("socket: %r");
|
||||
return -1;
|
||||
}
|
||||
if(connect(s, (struct sockaddr*)&su, sizeof su) < 0){
|
||||
werrstr("connect %s: %r", su.sun_path);
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
29
lib9/dirfstat.c
Normal file
29
lib9/dirfstat.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <u.h>
|
||||
#define NOPLAN9DEFINES
|
||||
#include <libc.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
|
||||
|
||||
Dir*
|
||||
dirfstat(int fd)
|
||||
{
|
||||
struct stat st;
|
||||
int nstr;
|
||||
Dir *d;
|
||||
char *str, tmp[100];
|
||||
|
||||
if(fstat(fd, &st) < 0)
|
||||
return nil;
|
||||
|
||||
snprint(tmp, sizeof tmp, "/dev/fd/%d", fd);
|
||||
nstr = _p9dir(&st, &st, tmp, nil, nil, nil);
|
||||
d = mallocz(sizeof(Dir)+nstr, 1);
|
||||
if(d == nil)
|
||||
return nil;
|
||||
str = (char*)&d[1];
|
||||
_p9dir(&st, &st, tmp, d, &str, str+nstr);
|
||||
return d;
|
||||
}
|
||||
|
53
lib9/dirfwstat.c
Normal file
53
lib9/dirfwstat.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#define NOPLAN9DEFINES
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__)
|
||||
/* do nothing -- futimes exists and is fine */
|
||||
|
||||
#elif defined(__SunOS5_9__)
|
||||
/* use futimesat */
|
||||
static int
|
||||
futimes(int fd, struct timeval *tv)
|
||||
{
|
||||
return futimesat(fd, 0, tv);
|
||||
}
|
||||
|
||||
#else
|
||||
/* provide dummy */
|
||||
/* rename just in case -- linux provides an unusable one */
|
||||
#undef futimes
|
||||
#define futimes myfutimes
|
||||
static int
|
||||
futimes(int fd, struct timeval *tv)
|
||||
{
|
||||
werrstr("futimes not available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
dirfwstat(int fd, Dir *dir)
|
||||
{
|
||||
int ret;
|
||||
struct timeval tv[2];
|
||||
|
||||
ret = 0;
|
||||
if(~dir->mode != 0){
|
||||
if(fchmod(fd, dir->mode) < 0)
|
||||
ret = -1;
|
||||
}
|
||||
if(~dir->mtime != 0){
|
||||
tv[0].tv_sec = dir->mtime;
|
||||
tv[0].tv_usec = 0;
|
||||
tv[1].tv_sec = dir->mtime;
|
||||
tv[1].tv_usec = 0;
|
||||
if(futimes(fd, tv) < 0)
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
62
lib9/dirmodefmt.c
Normal file
62
lib9/dirmodefmt.c
Normal file
@@ -0,0 +1,62 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static char *modes[] =
|
||||
{
|
||||
"---",
|
||||
"--x",
|
||||
"-w-",
|
||||
"-wx",
|
||||
"r--",
|
||||
"r-x",
|
||||
"rw-",
|
||||
"rwx",
|
||||
};
|
||||
|
||||
static void
|
||||
rwx(long m, char *s)
|
||||
{
|
||||
strncpy(s, modes[m], 3);
|
||||
}
|
||||
|
||||
int
|
||||
dirmodefmt(Fmt *f)
|
||||
{
|
||||
static char buf[16];
|
||||
ulong m;
|
||||
|
||||
m = va_arg(f->args, ulong);
|
||||
|
||||
if(m & DMDIR)
|
||||
buf[0]='d';
|
||||
else if(m & DMAPPEND)
|
||||
buf[0]='a';
|
||||
else if(m & DMAUTH)
|
||||
buf[0]='A';
|
||||
else if(m & DMDEVICE)
|
||||
buf[0] = 'D';
|
||||
else if(m & DMSOCKET)
|
||||
buf[0] = 'S';
|
||||
else if(m & DMNAMEDPIPE)
|
||||
buf[0] = 'P';
|
||||
else
|
||||
buf[0]='-';
|
||||
|
||||
/*
|
||||
* It's a little weird to have DMSYMLINK conflict with DMEXCL
|
||||
* here, but since you can have symlinks to any of the above
|
||||
* things, this is a better display. Especially since we don't do
|
||||
* DMEXCL on any of the supported systems.
|
||||
*/
|
||||
if(m & DMEXCL)
|
||||
buf[1]='l';
|
||||
else if(m & DMSYMLINK)
|
||||
buf[1] = 'L';
|
||||
else
|
||||
buf[1]='-';
|
||||
rwx((m>>6)&7, buf+2);
|
||||
rwx((m>>3)&7, buf+5);
|
||||
rwx((m>>0)&7, buf+8);
|
||||
buf[11] = 0;
|
||||
return fmtstrcpy(f, buf);
|
||||
}
|
188
lib9/dirread.c
Normal file
188
lib9/dirread.c
Normal file
@@ -0,0 +1,188 @@
|
||||
#include <u.h>
|
||||
#define NOPLAN9DEFINES
|
||||
#include <libc.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
|
||||
|
||||
#if defined(__linux__)
|
||||
static int
|
||||
mygetdents(int fd, struct dirent *buf, int n)
|
||||
{
|
||||
off_t off;
|
||||
int nn;
|
||||
|
||||
/* This doesn't match the man page, but it works in Debian with a 2.2 kernel */
|
||||
off = p9seek(fd, 0, 1);
|
||||
nn = getdirentries(fd, (void*)buf, n, &off);
|
||||
return nn;
|
||||
}
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
static int
|
||||
mygetdents(int fd, struct dirent *buf, int n)
|
||||
{
|
||||
long off;
|
||||
return getdirentries(fd, (void*)buf, n, &off);
|
||||
}
|
||||
#elif defined(__sun__)
|
||||
static int
|
||||
mygetdents(int fd, struct dirent *buf, int n)
|
||||
{
|
||||
return getdents(fd, (void*)buf, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
countde(char *p, int n)
|
||||
{
|
||||
char *e;
|
||||
int m;
|
||||
struct dirent *de;
|
||||
|
||||
e = p+n;
|
||||
m = 0;
|
||||
while(p < e){
|
||||
de = (struct dirent*)p;
|
||||
if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)
|
||||
break;
|
||||
if(de->d_name[0]=='.' && de->d_name[1]==0)
|
||||
de->d_name[0] = 0;
|
||||
else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)
|
||||
de->d_name[0] = 0;
|
||||
m++;
|
||||
p += de->d_reclen;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
static int
|
||||
dirpackage(int fd, char *buf, int n, Dir **dp)
|
||||
{
|
||||
int oldwd;
|
||||
char *p, *str, *estr;
|
||||
int i, nstr, m;
|
||||
struct dirent *de;
|
||||
struct stat st, lst;
|
||||
Dir *d;
|
||||
|
||||
n = countde(buf, n);
|
||||
if(n <= 0)
|
||||
return n;
|
||||
|
||||
if((oldwd = open(".", O_RDONLY)) < 0)
|
||||
return -1;
|
||||
if(fchdir(fd) < 0)
|
||||
return -1;
|
||||
|
||||
p = buf;
|
||||
nstr = 0;
|
||||
|
||||
for(i=0; i<n; i++){
|
||||
de = (struct dirent*)p;
|
||||
memset(&lst, 0, sizeof lst);
|
||||
if(de->d_name[0] == 0)
|
||||
/* nothing */ {}
|
||||
else if(lstat(de->d_name, &lst) < 0)
|
||||
de->d_name[0] = 0;
|
||||
else{
|
||||
st = lst;
|
||||
if(S_ISLNK(lst.st_mode))
|
||||
stat(de->d_name, &st);
|
||||
nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
|
||||
}
|
||||
p += de->d_reclen;
|
||||
}
|
||||
|
||||
d = malloc(sizeof(Dir)*n+nstr);
|
||||
if(d == nil){
|
||||
fchdir(oldwd);
|
||||
close(oldwd);
|
||||
return -1;
|
||||
}
|
||||
str = (char*)&d[n];
|
||||
estr = str+nstr;
|
||||
|
||||
p = buf;
|
||||
m = 0;
|
||||
for(i=0; i<n; i++){
|
||||
de = (struct dirent*)p;
|
||||
if(de->d_name[0] != 0 && lstat(de->d_name, &lst) >= 0){
|
||||
st = lst;
|
||||
if((lst.st_mode&S_IFMT) == S_IFLNK)
|
||||
stat(de->d_name, &st);
|
||||
_p9dir(&lst, &st, de->d_name, &d[m++], &str, estr);
|
||||
}
|
||||
p += de->d_reclen;
|
||||
}
|
||||
|
||||
fchdir(oldwd);
|
||||
close(oldwd);
|
||||
*dp = d;
|
||||
return m;
|
||||
}
|
||||
|
||||
long
|
||||
dirread(int fd, Dir **dp)
|
||||
{
|
||||
char *buf;
|
||||
struct stat st;
|
||||
int n;
|
||||
|
||||
*dp = 0;
|
||||
|
||||
if(fstat(fd, &st) < 0)
|
||||
return -1;
|
||||
|
||||
if(st.st_blksize < 8192)
|
||||
st.st_blksize = 8192;
|
||||
|
||||
buf = malloc(st.st_blksize);
|
||||
if(buf == nil)
|
||||
return -1;
|
||||
|
||||
n = mygetdents(fd, (void*)buf, st.st_blksize);
|
||||
if(n < 0){
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
n = dirpackage(fd, buf, n, dp);
|
||||
free(buf);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
long
|
||||
dirreadall(int fd, Dir **d)
|
||||
{
|
||||
uchar *buf, *nbuf;
|
||||
long n, ts;
|
||||
struct stat st;
|
||||
|
||||
if(fstat(fd, &st) < 0)
|
||||
return -1;
|
||||
|
||||
if(st.st_blksize < 8192)
|
||||
st.st_blksize = 8192;
|
||||
|
||||
buf = nil;
|
||||
ts = 0;
|
||||
for(;;){
|
||||
nbuf = realloc(buf, ts+st.st_blksize);
|
||||
if(nbuf == nil){
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
buf = nbuf;
|
||||
n = mygetdents(fd, (void*)(buf+ts), st.st_blksize);
|
||||
if(n <= 0)
|
||||
break;
|
||||
ts += n;
|
||||
}
|
||||
if(ts >= 0)
|
||||
ts = dirpackage(fd, (char*)buf, ts, d);
|
||||
free(buf);
|
||||
if(ts == 0 && n < 0)
|
||||
return -1;
|
||||
return ts;
|
||||
}
|
32
lib9/dirstat.c
Normal file
32
lib9/dirstat.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include <u.h>
|
||||
#define NOPLAN9DEFINES
|
||||
#include <libc.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
|
||||
|
||||
Dir*
|
||||
dirstat(char *file)
|
||||
{
|
||||
struct stat lst;
|
||||
struct stat st;
|
||||
int nstr;
|
||||
Dir *d;
|
||||
char *str;
|
||||
|
||||
if(lstat(file, &lst) < 0)
|
||||
return nil;
|
||||
st = lst;
|
||||
if((lst.st_mode&S_IFMT) == S_IFLNK)
|
||||
stat(file, &st);
|
||||
|
||||
nstr = _p9dir(&lst, &st, file, nil, nil, nil);
|
||||
d = mallocz(sizeof(Dir)+nstr, 1);
|
||||
if(d == nil)
|
||||
return nil;
|
||||
str = (char*)&d[1];
|
||||
_p9dir(&lst, &st, file, d, &str, str+nstr);
|
||||
return d;
|
||||
}
|
||||
|
19
lib9/dirwstat.c
Normal file
19
lib9/dirwstat.c
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <u.h>
|
||||
#define NOPLAN9DEFINES
|
||||
#include <libc.h>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
|
||||
int
|
||||
dirwstat(char *file, Dir *dir)
|
||||
{
|
||||
struct utimbuf ub;
|
||||
|
||||
/* BUG handle more */
|
||||
if(~dir->mtime == 0)
|
||||
return 0;
|
||||
|
||||
ub.actime = dir->mtime;
|
||||
ub.modtime = dir->mtime;
|
||||
return utime(file, &ub);
|
||||
}
|
12
lib9/dup.c
Normal file
12
lib9/dup.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#undef dup
|
||||
|
||||
int
|
||||
p9dup(int old, int new)
|
||||
{
|
||||
if(new == -1)
|
||||
return dup(old);
|
||||
return dup2(old, new);
|
||||
}
|
83
lib9/encodefmt.c
Normal file
83
lib9/encodefmt.c
Normal file
@@ -0,0 +1,83 @@
|
||||
#include <lib9.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include "fmt.h"
|
||||
|
||||
extern int enc64(char*, int, uchar*, int);
|
||||
extern int enc32(char*, int, uchar*, int);
|
||||
extern int enc16(char*, int, uchar*, int);
|
||||
|
||||
int
|
||||
encodefmt(Fmt *f)
|
||||
{
|
||||
char *out;
|
||||
char *buf, *p;
|
||||
int len;
|
||||
int ilen;
|
||||
int rv;
|
||||
uchar *b;
|
||||
char obuf[64]; // rsc optimization
|
||||
|
||||
b = va_arg(f->args, uchar*);
|
||||
if(b == 0)
|
||||
return fmtstrcpy(f, "<nil>");
|
||||
|
||||
ilen = f->prec;
|
||||
f->prec = 0;
|
||||
|
||||
if(!(f->flags&FmtPrec) || ilen < 0)
|
||||
goto error;
|
||||
|
||||
f->flags &= ~FmtPrec;
|
||||
|
||||
switch(f->r){
|
||||
case '<':
|
||||
len = (8*ilen+4)/5 + 3;
|
||||
break;
|
||||
case '[':
|
||||
len = (8*ilen+5)/6 + 4;
|
||||
break;
|
||||
case 'H':
|
||||
len = 2*ilen + 1;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(len > sizeof(obuf)){
|
||||
buf = malloc(len);
|
||||
if(buf == nil)
|
||||
goto error;
|
||||
} else
|
||||
buf = obuf;
|
||||
|
||||
// convert
|
||||
out = buf;
|
||||
switch(f->r){
|
||||
case '<':
|
||||
rv = enc32(out, len, b, ilen);
|
||||
break;
|
||||
case '[':
|
||||
rv = enc64(out, len, b, ilen);
|
||||
break;
|
||||
case 'H':
|
||||
rv = enc16(out, len, b, ilen);
|
||||
if(rv >= 0 && (f->flags & FmtLong))
|
||||
for(p = buf; *p; p++)
|
||||
*p = tolower((uchar)*p);
|
||||
break;
|
||||
default:
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
if(rv < 0)
|
||||
goto error;
|
||||
|
||||
fmtstrcpy(f, buf);
|
||||
if(buf != obuf)
|
||||
free(buf);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return fmtstrcpy(f, "<encodefmt>");
|
||||
}
|
81
lib9/errstr.c
Normal file
81
lib9/errstr.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* We assume there's only one error buffer for the whole system.
|
||||
* If you use ffork, you need to provide a _syserrstr. Since most
|
||||
* people will use libthread (which provides a _syserrstr), this is
|
||||
* okay.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <libc.h>
|
||||
|
||||
enum
|
||||
{
|
||||
EPLAN9 = 0x19283745,
|
||||
};
|
||||
|
||||
char *(*_syserrstr)(void);
|
||||
static char xsyserr[ERRMAX];
|
||||
static char*
|
||||
getsyserr(void)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = nil;
|
||||
if(_syserrstr)
|
||||
s = (*_syserrstr)();
|
||||
if(s == nil)
|
||||
s = xsyserr;
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
errstr(char *err, uint n)
|
||||
{
|
||||
char tmp[ERRMAX];
|
||||
char *syserr;
|
||||
|
||||
strecpy(tmp, tmp+ERRMAX, err);
|
||||
rerrstr(err, n);
|
||||
syserr = getsyserr();
|
||||
strecpy(syserr, syserr+ERRMAX, tmp);
|
||||
errno = EPLAN9;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
rerrstr(char *err, uint n)
|
||||
{
|
||||
char *syserr;
|
||||
|
||||
syserr = getsyserr();
|
||||
if(errno == EINTR)
|
||||
strcpy(syserr, "interrupted");
|
||||
else if(errno != EPLAN9)
|
||||
strcpy(syserr, strerror(errno));
|
||||
strecpy(err, err+n, syserr);
|
||||
}
|
||||
|
||||
/* replaces __errfmt in libfmt */
|
||||
|
||||
int
|
||||
__errfmt(Fmt *f)
|
||||
{
|
||||
if(errno == EPLAN9)
|
||||
return fmtstrcpy(f, getsyserr());
|
||||
return fmtstrcpy(f, strerror(errno));
|
||||
}
|
||||
|
||||
void
|
||||
werrstr(char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char buf[ERRMAX];
|
||||
|
||||
va_start(arg, fmt);
|
||||
vseprint(buf, buf+ERRMAX, fmt, arg);
|
||||
va_end(arg);
|
||||
errstr(buf, ERRMAX);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user