mirror of https://github.com/nealey/eris.git
Import upstream 1.10
This commit is contained in:
commit
b58da7211d
|
@ -0,0 +1,101 @@
|
||||||
|
1.10:
|
||||||
|
have fallback in case sendfile fails
|
||||||
|
|
||||||
|
1.9:
|
||||||
|
chdir to cgi's base dir (Kuba Winnicki)
|
||||||
|
set HTTP_ACCEPT_ENCODING environment variable (Kuba Winnicki)
|
||||||
|
We actually should export all HTTP headers as HTTP_[header]
|
||||||
|
Any takers?
|
||||||
|
Try not to send error message HTTP headers if we already sent the
|
||||||
|
headers from the CGI (Kuba Winnicki)
|
||||||
|
<ims -> <=ims (Gerrit Pape)
|
||||||
|
64-bit file I/O cleanliness
|
||||||
|
fix HTTP ranges (Joachim Berdal Haga via Gerrit Pape)
|
||||||
|
|
||||||
|
1.8:
|
||||||
|
keep current environment in CGI (Laurent Bercot)
|
||||||
|
make fnord-conf use the UID and not the user name (Fridtjof Busse)
|
||||||
|
fix typo in buffer_putulonglong (Gerrit Pape)
|
||||||
|
fix CGI POST off-by-two typo (Mark Hopf)
|
||||||
|
fix gif->png conversion (Thomas Seck)
|
||||||
|
remove == bashism from fnord-conf (Thomas Seck)
|
||||||
|
add bittorrent mime type
|
||||||
|
make authorization data available to CGIs for GET, too (Paul Jarc)
|
||||||
|
fix conversion of host name to lower case (Gerrit Pape)
|
||||||
|
add small test cgi: cgi-post.c
|
||||||
|
fix CGI POST bug (Moe Wibble)
|
||||||
|
fix CGI PATH_TRANSLATED bug (Nicolas George)
|
||||||
|
add optional authentication support (Nicolas George, see README.auth)
|
||||||
|
make sure error messages are text/html
|
||||||
|
move /. -> /: conversion before demangling so it can actually be
|
||||||
|
used as security measure for installations that don't use chroot
|
||||||
|
|
||||||
|
1.7:
|
||||||
|
add .mov and .qt for quicktime, .mpg for video/mpeg and .wav for audio/x-wav
|
||||||
|
add mmap based file serving (should do zero-copy tcp just like sendfile)
|
||||||
|
add Pragma: no-cache to CGI responses
|
||||||
|
fix (apparently not exploitable) buffer overrun in do_cgi
|
||||||
|
This bug was found by Ralf Wildenhues. To my knowledge it is
|
||||||
|
impossible to exploit this bug on any platform known to me.
|
||||||
|
fix (harmless) access to uninitialized data
|
||||||
|
|
||||||
|
1.6:
|
||||||
|
add support for $PATH_INFO in CGI environment.
|
||||||
|
add .pac for netscape proxy autoconfig
|
||||||
|
add .sig for application/pgp-signature
|
||||||
|
|
||||||
|
1.5:
|
||||||
|
fix write timeout handling (found by Lukas Beeler)
|
||||||
|
fix fnord-conf to use the symbolic account name in run script
|
||||||
|
(Sebastian D.B. Krause)
|
||||||
|
|
||||||
|
1.4:
|
||||||
|
add dangling symlink based whole-host redirection (see README). This
|
||||||
|
has the advantage that it can serve normal sites and redirect sites
|
||||||
|
on the same IP.
|
||||||
|
add support for non-TCP UCSPI environments (like ucspi-ssl). Please
|
||||||
|
get the latest version of my ucspi-tcp IPv6 patch as I violated the
|
||||||
|
UCSPI spec with all versions before 0.88-diff11.
|
||||||
|
change logging from "127.0.0.1 200 23 Links_(0.96;_Unix) none /index.html"
|
||||||
|
to "127.0.0.1 200 23 localhost Links_(0.96;_Unix) none /index.html"
|
||||||
|
(i.e. include the Host: header). Suggested by Thomas Bader.
|
||||||
|
add "immediate mode". If you give fnord a command line argument, it
|
||||||
|
will change to that directory and if no "default" directory is
|
||||||
|
given, it will assume there are no virtual hosts and serve from the
|
||||||
|
current directory. I have a shell script called "http" that does
|
||||||
|
tcpserver -RHl localhost 0 8000 /home/leitner/bin/fnord-idx .
|
||||||
|
to share some directory on my hard drive with some poor Windows
|
||||||
|
users without npoll (http://www.fefe.de/ncp/). fnord-idx is a new
|
||||||
|
target (a fnord with DIR_LIST) that is auto-built by make.
|
||||||
|
|
||||||
|
1.3:
|
||||||
|
make directory listings use non-proportional fonts (thanks, Antonio Dias)
|
||||||
|
fnord will now optionally (default: enabled) normalize the incoming
|
||||||
|
host name, i.e. "www.domain.com" -> "www.domain.com:80". That
|
||||||
|
should cut down on the number of symbolic links. ;)
|
||||||
|
remove timeout error message. fnord will not drop the connection
|
||||||
|
without error message. Mozilla used to display the error message
|
||||||
|
when the user caused another request on the connection with the
|
||||||
|
timeout.
|
||||||
|
Uwe Ohse found two more compilation problems.
|
||||||
|
|
||||||
|
1.2:
|
||||||
|
Olaf: I changed my initial CGI-interface to NOT use the filesystem but
|
||||||
|
two pipes.
|
||||||
|
Add whole-host redirect (see README)
|
||||||
|
Olaf: added direcory-lists and "index.cgi" support (normal CGI only !
|
||||||
|
"nph-index.cgi" is not supported). Fixed some problematic parts in the
|
||||||
|
CGI-interface (\n -> \r\n converter for http-header and CGI crash
|
||||||
|
handling)
|
||||||
|
Fix gzip encoding bug that only happened with keep-alive
|
||||||
|
|
||||||
|
1.1:
|
||||||
|
ship with the parts from libowfat that we actually use
|
||||||
|
minor speed-up. sendfile is a drag for very small files, so those are
|
||||||
|
now sent through the same buffer the header is sent through. That
|
||||||
|
sends the whole answer in one TCP packet if you are lucky, even
|
||||||
|
without the TCP_CORK magic from Linux. Major speed-up for
|
||||||
|
benchmarks ;)
|
||||||
|
|
||||||
|
1.0:
|
||||||
|
initial release
|
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
675 Mass Ave, Cambridge, MA 02139, USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
Appendix: How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) 19yy <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
|
@ -0,0 +1,66 @@
|
||||||
|
CC=gcc
|
||||||
|
CXX=g++
|
||||||
|
|
||||||
|
#LIBOWFAT=../libowfat/
|
||||||
|
DIET=diet -Os
|
||||||
|
|
||||||
|
CFLAGS=-Os -fomit-frame-pointer
|
||||||
|
#CFLAGS=-g
|
||||||
|
|
||||||
|
all: fnord fnord-cgi fnord-idx
|
||||||
|
|
||||||
|
fnord: httpd
|
||||||
|
cp -p $^ $@
|
||||||
|
-strip -R .note -R .comment $@
|
||||||
|
|
||||||
|
httpd: httpd.o libowfat.a
|
||||||
|
$(DIET) $(CC) -o $@ $^ $(CFLAGS)
|
||||||
|
|
||||||
|
fnord-cgi: httpd-cgi.o libowfat.a
|
||||||
|
$(DIET) $(CC) -o $@ $^ $(CFLAGS)
|
||||||
|
-strip -R .note -R .comment $@
|
||||||
|
|
||||||
|
fnord-idx: httpd-idx.o libowfat.a
|
||||||
|
$(DIET) $(CC) -o $@ $^ $(CFLAGS)
|
||||||
|
-strip -R .note -R .comment $@
|
||||||
|
|
||||||
|
libowfat.a: httpd.o buffer_1.o buffer_puts.o buffer_flush.o buffer_put.o \
|
||||||
|
buffer_putulong.o buffer_2.o buffer_putspace.o buffer_stubborn.o \
|
||||||
|
buffer_putflush.o str_copy.o fmt_ulong.o byte_diff.o byte_copy.o \
|
||||||
|
str_len.o str_diff.o str_chr.o str_diffn.o str_start.o scan_ulong.o
|
||||||
|
ar cru $@ $^
|
||||||
|
-ranlib $@
|
||||||
|
|
||||||
|
httpd.o: httpd.c
|
||||||
|
$(DIET) $(CC) -pipe $(CFLAGS) -c $^ -DFNORD=\"fnord/$(shell head -n 1 CHANGES|sed 's/://')\"
|
||||||
|
|
||||||
|
httpd-cgi.o: httpd.c
|
||||||
|
$(DIET) $(CC) -pipe $(CFLAGS) -c httpd.c -o $@ -DCGI -DFNORD=\"fnord/$(shell head -n 1 CHANGES|sed 's/://')\"
|
||||||
|
|
||||||
|
httpd-idx.o: httpd.c
|
||||||
|
$(DIET) $(CC) -pipe $(CFLAGS) -c httpd.c -o $@ -DDIR_LIST -DFNORD=\"fnord/$(shell head -n 1 CHANGES|sed 's/://')\"
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(DIET) $(CC) -pipe $(CFLAGS) -c $^
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(DIET) $(CXX) -pipe $(CFLAGS) -c $^
|
||||||
|
|
||||||
|
.PHONY: rename clean install server
|
||||||
|
server: fnord
|
||||||
|
tcpserver -v -RHl localhost 0 8000 ./fnord
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.[oa] httpd fnord fnord-cgi fnord-idx
|
||||||
|
|
||||||
|
install:
|
||||||
|
test -d /command || mkdir /command
|
||||||
|
|
||||||
|
CURNAME=$(notdir $(shell pwd))
|
||||||
|
VERSION=fnord-$(shell head -n 1 CHANGES|sed 's/://')
|
||||||
|
|
||||||
|
tar: rename
|
||||||
|
cd .. && tar cvvf $(VERSION).tar.bz2 --use=bzip2 --exclude CVS --exclude bin-* --exclude .cvsignore --exclude default $(VERSION)
|
||||||
|
|
||||||
|
rename:
|
||||||
|
if test $(CURNAME) != $(VERSION); then cd .. && mv $(CURNAME) $(VERSION); fi
|
|
@ -0,0 +1,72 @@
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
tcpserver -v -RHl localhost -u 1234 -g 1234 0 80 ./httpd
|
||||||
|
|
||||||
|
Will log to stderr in the form
|
||||||
|
|
||||||
|
127.0.0.1 200 23 localhost Links_(0.96;_Unix) none /index.html
|
||||||
|
|
||||||
|
where 127.0.0.1 is the client IP, 200 is the HTTP exit code, 23 is the
|
||||||
|
size of the content that was served (or 0 for unsuccessful exit codes),
|
||||||
|
localhost is the Host: header (the virtual host), the next token is the
|
||||||
|
user agent with spaces replaced by underscores, the next token (none) is
|
||||||
|
the Referer HTTP header or "none" if none was given, and the rest of
|
||||||
|
each line is the decoded requested URL.
|
||||||
|
|
||||||
|
fnord-httpd does simple virtual hosting. If the Host: HTTP header is
|
||||||
|
there, fnord will try to chdir to a directory of that name, i.e. if the
|
||||||
|
client asks for "/" on host "www.fefe.de:80", fnord will look for
|
||||||
|
"www.fefe.de:80/index.html". Fnord will also try the directory
|
||||||
|
"default" if no specific directory for the virtual host was there. If
|
||||||
|
the directory is a dangling symlink and fnord was compiled with
|
||||||
|
-DREDIRECT (default), fnord will redirect the whole site. Examples:
|
||||||
|
|
||||||
|
lrwxrwxrwx 1 leitner users 19 May 5 01:09 www.foo.de:80 -> http://www.baz.de/
|
||||||
|
lrwxrwxrwx 1 leitner users 20 May 5 01:12 www.bar.de:80 -> =http://www.baz.de/
|
||||||
|
|
||||||
|
http://www.foo.de/blub.html will be redirected to http://www.baz.de/blub.html.
|
||||||
|
http://www.bar.de/blub.html will be redirected to http://www.baz.de/.
|
||||||
|
|
||||||
|
fnord implements el-cheapo HTTP ranges (only byte ranges and only of the
|
||||||
|
form x-y, not multiple ranges).
|
||||||
|
|
||||||
|
fnord implements content type matching and Accepts: parsing, but the
|
||||||
|
content type table is compiled in, i.e. to change it, you have to change
|
||||||
|
the source code. Shouldn't be a problem because you _have_ the source
|
||||||
|
code ;)
|
||||||
|
|
||||||
|
fnord implements HTTP redirection. If a file is not found, but a
|
||||||
|
dangling symlink is there under the same name, fnord will issue a
|
||||||
|
redirection to the contents of that symlink. To be RFC compliant, the
|
||||||
|
symlink must point to a full URL, i.e.
|
||||||
|
|
||||||
|
ln -s ftp://foobar.math.fu-berlin.de/pub/dietlibc/dietlibc-0.11.tar.bz2 dietlibc-0.11.tar.bz2
|
||||||
|
|
||||||
|
fnord implements in-place substitution of .gif to .png and of * to *.gz
|
||||||
|
if the file is available and the client supports the mime-type and
|
||||||
|
content-encoding. That means you can save substantial bandwidth by
|
||||||
|
having an index.html.gz for each index.html, as most clients can
|
||||||
|
transparently decode gzipped files.
|
||||||
|
|
||||||
|
fnord will change dots at the start of file or directory names to colons
|
||||||
|
in the query before trying to answer them.
|
||||||
|
|
||||||
|
fnord understands and implements keep-alive connections.
|
||||||
|
|
||||||
|
fnord can use sendfile on Linux to enable zero-copy TCP.
|
||||||
|
|
||||||
|
If fnord is compiled with CGI support enabled, it will regard files
|
||||||
|
whose names end with ".cgi" as CGI programs and try to execute them.
|
||||||
|
CGI programs starting with "nph-" will be handled as no-parse-header
|
||||||
|
CGIs. Please see http://hoohoo.ncsa.uiuc.edu/cgi/interface.html for the
|
||||||
|
CGI specification.
|
||||||
|
|
||||||
|
fnord 1.3 introduced a different method of whole-host redirection, which
|
||||||
|
can still be enabled by compiling fnord with with -DOLD_STYLE_REDIRECT.
|
||||||
|
Files that are not found locally will be redirected to $REDIRECT_HOST
|
||||||
|
with the current URI stripped of leading slashes, i.e. if
|
||||||
|
http://your.server/foo/bar.html is requested but not found, and
|
||||||
|
$REDIRECT_HOST is set to http://www.yahoo.com/, a redirect to
|
||||||
|
http://www.yahoo.com/foo/bar.html will be issued. If $REDIRECT_HOST is
|
||||||
|
unset but $REDIRECT_URI is set, the URI part will be discarded and all
|
||||||
|
URLs will be redirected to $REDIRECT_URI.
|
|
@ -0,0 +1,20 @@
|
||||||
|
The auth patch was contributed by Nicolas George. Here is the excerpt from his
|
||||||
|
email describing how to use it. Firstly, #define AUTH or add -DAUTH to CFLAGS.
|
||||||
|
|
||||||
|
Then, I have implemented some basic handling of HTTP authentication. The
|
||||||
|
concept is that if there is a file .http-auth in the root of one site,
|
||||||
|
then it is an executable (most likely a script) that handles
|
||||||
|
authorizations. It is called with first argument the virtual host name,
|
||||||
|
second argument the path to the requested file, and third argument the
|
||||||
|
value of the Authorization header, if present. If it exists
|
||||||
|
successfully, access is granted, else 401.
|
||||||
|
|
||||||
|
An example of .http-auth that grants the access only to the user Cigaes
|
||||||
|
with password foober is:
|
||||||
|
|
||||||
|
#!/bin/sh
|
||||||
|
[ x"$3" = x"Basic Q2lnYWVzOmZvb2Jhcg==" ]
|
||||||
|
|
||||||
|
The format of the Authorization is not very convenient. The mangled
|
||||||
|
string is the base64 encoding of "$username:$password".
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
fnord is meant to be used under Linux with the diet libc
|
||||||
|
(http://www.fefe.de/dietlibc/). These are actual apache bench results,
|
||||||
|
all on localhost on a 100k JPEG test file, 1000 requests with a
|
||||||
|
concurrency of 10.
|
||||||
|
|
||||||
|
To be fair, I linked thttpd, mini_httpd and fnord against the diet libc.
|
||||||
|
I did not try this with apache, though. Since apache does not exec
|
||||||
|
anything, it should not matter much, though.
|
||||||
|
|
||||||
|
mini_httpd forks for each request, apparently does not support
|
||||||
|
keep-alive and compared to fnord does not incur the overhead of execve
|
||||||
|
for each request.
|
||||||
|
|
||||||
|
thttpd is the fastest web server known to me.
|
||||||
|
|
||||||
|
Values are time in seconds for the whole transaction (1000 downloads, 10
|
||||||
|
parallel connections).
|
||||||
|
|
||||||
|
server software keep-alive no keep-alive
|
||||||
|
----------------------------------------------------------------
|
||||||
|
mini_httpd 1.15c 1.690 0.943
|
||||||
|
apache 1.3.22 1.236 1.178
|
||||||
|
thttpd 2.21b 0.896 0.839
|
||||||
|
fnord 1.008 1.331
|
||||||
|
fnord w/ sendfile 0.316 0.912
|
||||||
|
|
||||||
|
Please note that fnord actually plays in the same league as others even
|
||||||
|
without keep-alive and sendfile support. That is surprising since fnord
|
||||||
|
has one fork() _and_ one execve() as overhead for each request! As the
|
||||||
|
difference between keep-alive and non-keep-alive shows, that difference
|
||||||
|
is not very large. That is the achievement of the diet libc, which
|
||||||
|
reduces the normally significant libc overhead to zero.
|
|
@ -0,0 +1,70 @@
|
||||||
|
#ifndef BUFFER_H
|
||||||
|
#define BUFFER_H
|
||||||
|
|
||||||
|
typedef struct buffer {
|
||||||
|
char *x;
|
||||||
|
unsigned int p;
|
||||||
|
unsigned int n;
|
||||||
|
unsigned int a;
|
||||||
|
int fd;
|
||||||
|
int (*op)();
|
||||||
|
} buffer;
|
||||||
|
|
||||||
|
#define BUFFER_INIT(op,fd,buf,len) { (buf), 0, 0, (len), (fd), (op) }
|
||||||
|
#define BUFFER_INIT_READ(op,fd,buf,len) BUFFER_INIT(op,fd,buf,len) /*obsolete*/
|
||||||
|
#define BUFFER_INSIZE 8192
|
||||||
|
#define BUFFER_OUTSIZE 8192
|
||||||
|
|
||||||
|
extern void buffer_init(buffer* b,int (*op)(),int fd,char* y,unsigned int ylen);
|
||||||
|
|
||||||
|
extern int buffer_flush(buffer* b);
|
||||||
|
extern int buffer_put(buffer* b,const char* x,unsigned int len);
|
||||||
|
extern int buffer_putalign(buffer* b,const char* x,unsigned int len);
|
||||||
|
extern int buffer_putflush(buffer* b,const char* x,unsigned int len);
|
||||||
|
extern int buffer_puts(buffer* b,const char* x);
|
||||||
|
extern int buffer_putsalign(buffer* b,const char* x);
|
||||||
|
extern int buffer_putsflush(buffer* b,const char* x);
|
||||||
|
|
||||||
|
extern int buffer_putspace(buffer* b);
|
||||||
|
|
||||||
|
#define buffer_PUTC(s,c) \
|
||||||
|
( ((s)->a != (s)->p) \
|
||||||
|
? ( (s)->x[(s)->p++] = (c), 0 ) \
|
||||||
|
: buffer_put((s),&(c),1) \
|
||||||
|
)
|
||||||
|
|
||||||
|
extern int buffer_get(buffer* b,char* x,unsigned int len);
|
||||||
|
extern int buffer_bget(buffer* b,char* x,unsigned int len);
|
||||||
|
extern int buffer_feed(buffer* b);
|
||||||
|
extern int buffer_getc(buffer* b,char* x);
|
||||||
|
extern int buffer_getn(buffer* b,char* x,unsigned int len);
|
||||||
|
extern int buffer_get_token(buffer* b,char* x,unsigned int len,const char* charset,unsigned int setlen);
|
||||||
|
#define buffer_getline(b,x,len) buffer_get_token((b),(x),(len),"\n",1)
|
||||||
|
|
||||||
|
extern char *buffer_peek(buffer* b);
|
||||||
|
extern void buffer_seek(buffer* b,unsigned int len);
|
||||||
|
|
||||||
|
#define buffer_PEEK(s) ( (s)->x + (s)->p )
|
||||||
|
#define buffer_SEEK(s,len) ( (s)->p += (len) )
|
||||||
|
|
||||||
|
#define buffer_GETC(s,c) \
|
||||||
|
( ((s)->p < (s>->n) \
|
||||||
|
? ( *(c) = *buffer_PEEK(s), buffer_SEEK((s),1), 1 ) \
|
||||||
|
: buffer_get((s),(c),1) \
|
||||||
|
)
|
||||||
|
|
||||||
|
extern int buffer_copy(buffer* out,buffer* in);
|
||||||
|
|
||||||
|
extern int buffer_putulong(buffer *b,unsigned long l);
|
||||||
|
extern int buffer_put8long(buffer *b,unsigned long l);
|
||||||
|
extern int buffer_putxlong(buffer *b,unsigned long l);
|
||||||
|
extern int buffer_putlong(buffer *b,unsigned long l);
|
||||||
|
extern int buffer_putulonglong(buffer *b,unsigned long long l);
|
||||||
|
|
||||||
|
extern buffer *buffer_0;
|
||||||
|
extern buffer *buffer_0small;
|
||||||
|
extern buffer *buffer_1;
|
||||||
|
extern buffer *buffer_1small;
|
||||||
|
extern buffer *buffer_2;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
char buffer_1_space[BUFFER_INSIZE];
|
||||||
|
static buffer it = BUFFER_INIT(write,1,buffer_1_space,sizeof buffer_1_space);
|
||||||
|
buffer *buffer_1 = ⁢
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
char buffer_2_space[BUFFER_INSIZE];
|
||||||
|
static buffer it = BUFFER_INIT(write,2,buffer_2_space,sizeof buffer_2_space);
|
||||||
|
buffer *buffer_2 = ⁢
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
extern int buffer_stubborn(int (*op)(),int fd,const char* buf, unsigned int len);
|
||||||
|
|
||||||
|
extern int buffer_flush(buffer* b) {
|
||||||
|
register int p;
|
||||||
|
if (!(p=b->p)) return 0; /* buffer already empty */
|
||||||
|
b->p=0;
|
||||||
|
return buffer_stubborn(b->op,b->fd,b->x,p);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include "byte.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
extern int buffer_stubborn(int (*op)(),int fd,const char* buf, unsigned int len);
|
||||||
|
|
||||||
|
int buffer_put(buffer* b,const char* buf,unsigned int len) {
|
||||||
|
if (len>b->a-b->p) { /* doesn't fit */
|
||||||
|
if (buffer_flush(b)==-1) return -1;
|
||||||
|
if (len>b->a) {
|
||||||
|
if (buffer_stubborn(b->op,b->fd,buf,len)<0) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte_copy(b->x+b->p, len, buf);
|
||||||
|
b->p+=len;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
int buffer_putflush(buffer* b,const char* x,unsigned int len) {
|
||||||
|
if (buffer_put(b,x,len)<0) return -1;
|
||||||
|
if (buffer_flush(b)<0) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "str.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
int buffer_puts(buffer* b,const char* x) {
|
||||||
|
return buffer_put(b,x,str_len(x));
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "str.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
int buffer_putspace(buffer* b) {
|
||||||
|
static char space=' ';
|
||||||
|
return buffer_put(b,&space,1);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "fmt.h"
|
||||||
|
|
||||||
|
int buffer_putulong(buffer *b,unsigned long l) {
|
||||||
|
char buf[FMT_ULONG];
|
||||||
|
return buffer_put(b,buf,fmt_ulong(buf,l));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "fmt.h"
|
||||||
|
|
||||||
|
int buffer_putulonglong(buffer *b,unsigned long long l) {
|
||||||
|
char buf[FMT_ULONG];
|
||||||
|
return buffer_put(b,buf,fmt_ulonglong(buf,l));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
int buffer_stubborn(int (*op)(),int fd,const char* buf, unsigned int len) {
|
||||||
|
int w;
|
||||||
|
while (len) {
|
||||||
|
if ((w=op(fd,buf,len))<0) {
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
buf+=w;
|
||||||
|
len-=w;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef BYTE_H
|
||||||
|
#define BYTE_H
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
#ifndef __pure__
|
||||||
|
#define __pure__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* byte_chr returns the smallest integer i between 0 and len-1
|
||||||
|
* inclusive such that one[i] equals needle, or len it not found. */
|
||||||
|
unsigned int byte_chr(const void* haystack, unsigned int len, char needle) __pure__;
|
||||||
|
|
||||||
|
/* byte_rchr returns the largest integer i between 0 and len-1 inclusive
|
||||||
|
* such that one[i] equals needle, or len if not found. */
|
||||||
|
unsigned int byte_rchr(const void* haystack,unsigned int len,char needle) __pure__;
|
||||||
|
|
||||||
|
/* byte_copy copies in[0] to out[0], in[1] to out[1], ... and in[len-1]
|
||||||
|
* to out[len-1]. */
|
||||||
|
void byte_copy(void* out, unsigned int len, const void* in);
|
||||||
|
|
||||||
|
/* byte_copyr copies in[len-1] to out[len-1], in[len-2] to out[len-2],
|
||||||
|
* ... and in[0] to out[0] */
|
||||||
|
void byte_copyr(void* out, unsigned int len, const void* in);
|
||||||
|
|
||||||
|
/* byte_diff returns negative, 0, or positive, depending on whether the
|
||||||
|
* string a[0], a[1], ..., a[len-1] is lexicographically smaller
|
||||||
|
* than, equal to, or greater than the string b[0], b[1], ...,
|
||||||
|
* b[len-1]. When the strings are different, byte_diff does not read
|
||||||
|
* bytes past the first difference. */
|
||||||
|
int byte_diff(const void* a, unsigned int len, const void* b) __pure__;
|
||||||
|
|
||||||
|
/* byte_zero sets the bytes out[0], out[1], ..., out[len-1] to 0 */
|
||||||
|
void byte_zero(void* out, unsigned len);
|
||||||
|
|
||||||
|
#define byte_equal(s,n,t) (!byte_diff((s),(n),(t)))
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include "byte.h"
|
||||||
|
|
||||||
|
/* byte_copy copies in[0] to out[0], in[1] to out[1], ... and in[len-1]
|
||||||
|
* to out[len-1]. */
|
||||||
|
void byte_copy(void* out, unsigned int len, const void* in) {
|
||||||
|
register char* s=out;
|
||||||
|
register const char* t=in;
|
||||||
|
register const char* u=t+len;
|
||||||
|
if (len>127) {
|
||||||
|
while ((unsigned long)s&(sizeof(unsigned long)-1)) {
|
||||||
|
if (t==u) break; *s=*t; ++s; ++t;
|
||||||
|
}
|
||||||
|
/* s (destination) is now unsigned long aligned */
|
||||||
|
#ifndef __i386__
|
||||||
|
if (!((unsigned long)t&(sizeof(unsigned long)-1)))
|
||||||
|
#endif
|
||||||
|
while (t+sizeof(unsigned long)<=u) {
|
||||||
|
*(unsigned long*)s=*(unsigned long*)t;
|
||||||
|
s+=sizeof(unsigned long); t+=sizeof(unsigned long);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
if (t==u) break; *s=*t; ++s; ++t;
|
||||||
|
if (t==u) break; *s=*t; ++s; ++t;
|
||||||
|
if (t==u) break; *s=*t; ++s; ++t;
|
||||||
|
if (t==u) break; *s=*t; ++s; ++t;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include "byte.h"
|
||||||
|
|
||||||
|
/* byte_diff returns negative, 0, or positive, depending on whether the
|
||||||
|
* string one[0], one[1], ..., one[len-1] is lexicographically smaller
|
||||||
|
* than, equal to, or greater than the string one[0], one[1], ...,
|
||||||
|
* one[len-1]. When the strings are different, byte_diff does not read
|
||||||
|
* bytes past the first difference. */
|
||||||
|
int byte_diff(const void* a, unsigned int len, const void* b) {
|
||||||
|
register const char* s=a;
|
||||||
|
register const char* t=b;
|
||||||
|
register const char* u=t+len;
|
||||||
|
register int j;
|
||||||
|
j=0;
|
||||||
|
for (;;) {
|
||||||
|
if (t==u) break; if ((j=(*s-*t))) break; ++s; ++t;
|
||||||
|
if (t==u) break; if ((j=(*s-*t))) break; ++s; ++t;
|
||||||
|
if (t==u) break; if ((j=(*s-*t))) break; ++s; ++t;
|
||||||
|
if (t==u) break; if ((j=(*s-*t))) break; ++s; ++t;
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <write12.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
char* method=getenv("REQUEST_METHOD");
|
||||||
|
if (!method) {
|
||||||
|
__write1("Content-Type: text/plain\r\n\r\nFatal: $REQUEST_METHOD not set!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!strcmp(method,"GET")) {
|
||||||
|
char* c=getenv("QUERY_STRING");
|
||||||
|
__write1("Content-Type: text/plain\r\n\r\n");
|
||||||
|
if (c)
|
||||||
|
write(1,c,strlen(c));
|
||||||
|
else {
|
||||||
|
__write1("Fatal: $QUERY_STRING not set!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (!strcmp(method,"POST")) {
|
||||||
|
char* c=getenv("CONTENT_TYPE");
|
||||||
|
char* d=getenv("CONTENT_LENGTH");
|
||||||
|
int l;
|
||||||
|
if (!c) {
|
||||||
|
__write1("Content-Type: text/plain\r\n\r\nFatal: $CONTENT_TYPE not set!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!d) {
|
||||||
|
__write1("Content-Type: text/plain\r\n\r\nFatal: $CONTENT_LENGTH not set!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char* e;
|
||||||
|
l=strtoul(d,&e,10);
|
||||||
|
if (e==d || *e) {
|
||||||
|
__write1("Content-Type: text/plain\r\n\r\nFatal: $CONTENT_LENGTH not a number: ");
|
||||||
|
__write1(d);
|
||||||
|
__write1("\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__write1("Content-Type: "); __write1(c); __write1("\r\n");
|
||||||
|
__write1("Content-Length: "); __write1(d); __write1("\r\n\r\n");
|
||||||
|
while (l>0) {
|
||||||
|
char buf[2048];
|
||||||
|
int r;
|
||||||
|
r=read(0,buf,sizeof(buf));
|
||||||
|
if (r==-1) return 1;
|
||||||
|
if (r==0) break;
|
||||||
|
l-=r;
|
||||||
|
write(1,buf,r);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
puts("Content-Type: text/plain\r\n\r\nFatal: $REQUEST_METHOD is neither GET nor POST!\n");
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,40 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use Compress::Zlib;
|
||||||
|
|
||||||
|
$PWD=`pwd`;
|
||||||
|
chomp $PWD;
|
||||||
|
push @dirs,$PWD;
|
||||||
|
|
||||||
|
while ($#dirs>=0) {
|
||||||
|
my $x=shift @dirs;
|
||||||
|
opendir DIR,$x || die "can't chdir to $x\n";
|
||||||
|
foreach $i (readdir DIR) {
|
||||||
|
next if (substr($i,0,1) eq ".");
|
||||||
|
if (-d "$x/$i") {
|
||||||
|
push @dirs,"$x/$i";
|
||||||
|
} elsif (-f "$x/$i") {
|
||||||
|
next if ($i =~ m/\.gz$/);
|
||||||
|
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$x/$i");
|
||||||
|
my $gzmtime=(stat("$x/$i.gz"))[9];
|
||||||
|
if (not defined $gzmtime or $gzmtime<$mtime) {
|
||||||
|
print "gzipping $x/$i...\n";
|
||||||
|
if ($#ARGV<0) {
|
||||||
|
open FILE,"$x/$i" || die "can't open $x/$i\n";
|
||||||
|
my $gz = gzopen("$x/$i.gz","wb")
|
||||||
|
or die "can't open $x/$i.gz: $gzerrno\n";
|
||||||
|
while (<FILE>) {
|
||||||
|
$gz->gzwrite($_)
|
||||||
|
or die "error writing: $gzerrno\n";
|
||||||
|
}
|
||||||
|
$gz->gzclose;
|
||||||
|
close FILE;
|
||||||
|
utime $atime, $mtime, "$x/$i.gz" or die "can't utime $x/$i.gz\n";
|
||||||
|
my $gzsize=(stat("$x/$i.gz"))[7];
|
||||||
|
unlink "$x/$i.gz" if ($gzsize>=$size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir DIR;
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
#ifndef FMT_H
|
||||||
|
#define FMT_H
|
||||||
|
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
|
||||||
|
#define FMT_8LONG 44 /* enough space to hold 2^128 - 1 in octal, plus \0 */
|
||||||
|
#define FMT_XLONG 33 /* enough space to hold 2^128 - 1 in hexadecimal, plus \0 */
|
||||||
|
#define FMT_LEN ((char *) 0) /* convenient abbreviation */
|
||||||
|
|
||||||
|
/* The formatting routines do not append \0!
|
||||||
|
* Use them like this: buf[fmt_ulong(buf,number)]=0; */
|
||||||
|
|
||||||
|
/* convert signed src integer -23 to ASCII '-','2','3', return length.
|
||||||
|
* If dest is not NULL, write result to dest */
|
||||||
|
unsigned int fmt_long(char *dest,signed long src);
|
||||||
|
|
||||||
|
/* convert unsigned src integer 23 to ASCII '2','3', return length.
|
||||||
|
* If dest is not NULL, write result to dest */
|
||||||
|
unsigned int fmt_ulong(char *dest,unsigned long src);
|
||||||
|
|
||||||
|
/* same for long long */
|
||||||
|
unsigned int fmt_ulonglong(char *dest,unsigned long long src);
|
||||||
|
|
||||||
|
/* convert unsigned src integer 0x23 to ASCII '2','3', return length.
|
||||||
|
* If dest is not NULL, write result to dest */
|
||||||
|
unsigned int fmt_xlong(char *dest,unsigned long src);
|
||||||
|
|
||||||
|
/* convert unsigned src integer 023 to ASCII '2','3', return length.
|
||||||
|
* If dest is not NULL, write result to dest */
|
||||||
|
unsigned int fmt_8long(char *dest,unsigned long src);
|
||||||
|
|
||||||
|
#define fmt_uint(dest,src) fmt_ulong(dest,src)
|
||||||
|
#define fmt_int(dest,src) fmt_long(dest,src)
|
||||||
|
#define fmt_xint(dest,src) fmt_xlong(dest,src)
|
||||||
|
#define fmt_8int(dest,src) fmt_8long(dest,src)
|
||||||
|
|
||||||
|
/* Like fmt_ulong, but prepend '0' while length is smaller than padto.
|
||||||
|
* Does not truncate! */
|
||||||
|
unsigned int fmt_ulong0(char *,unsigned long src,unsigned int padto);
|
||||||
|
|
||||||
|
#define fmt_uint0(buf,src,padto) fmt_ulong0(buf,src,padto)
|
||||||
|
|
||||||
|
/* convert src double 1.7 to ASCII '1','.','7', return length.
|
||||||
|
* If dest is not NULL, write result to dest */
|
||||||
|
unsigned int fmt_double(char *dest, double d,int max,int prec);
|
||||||
|
|
||||||
|
/* if src is negative, write '-' and return 1.
|
||||||
|
* if src is positive, write '+' and return 1.
|
||||||
|
* otherwise return 0 */
|
||||||
|
unsigned int fmt_plusminus(char *dest,int src);
|
||||||
|
|
||||||
|
/* if src is negative, write '-' and return 1.
|
||||||
|
* otherwise return 0. */
|
||||||
|
unsigned int fmt_minus(char *dest,int src);
|
||||||
|
|
||||||
|
/* copy str to dest until \0 byte, return number of copied bytes. */
|
||||||
|
unsigned int fmt_str(char *dest,const char *src);
|
||||||
|
|
||||||
|
/* copy str to dest until \0 byte or limit bytes copied.
|
||||||
|
* return number of copied bytes. */
|
||||||
|
unsigned int fmt_strn(char *dest,const char *src,unsigned int limit);
|
||||||
|
|
||||||
|
/* "foo" -> " foo"
|
||||||
|
* write padlen-srclen spaces, if that is >= 0. Then copy srclen
|
||||||
|
* characters from src. Truncate only if total length is larger than
|
||||||
|
* maxlen. Return number of characters written. */
|
||||||
|
unsigned int fmt_pad(char* dest,const char* src,unsigned int srclen,unsigned int padlen,unsigned int maxlen);
|
||||||
|
|
||||||
|
/* "foo" -> "foo "
|
||||||
|
* append padlen-srclen spaces after dest, if that is >= 0. Truncate
|
||||||
|
* only if total length is larger than maxlen. Return number of
|
||||||
|
* characters written. */
|
||||||
|
unsigned int fmt_fill(char* dest,unsigned int srclen,unsigned int padlen,unsigned int maxlen);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "fmt.h"
|
||||||
|
|
||||||
|
unsigned int fmt_ulong(char *dest,unsigned long i) {
|
||||||
|
register unsigned long len,tmp,len2;
|
||||||
|
/* first count the number of bytes needed */
|
||||||
|
for (len=1, tmp=i; tmp>9; ++len) tmp/=10;
|
||||||
|
if (dest)
|
||||||
|
for (tmp=i, dest+=len, len2=len+1; --len2; tmp/=10)
|
||||||
|
*--dest = (tmp%10)+'0';
|
||||||
|
return len;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "fmt.h"
|
||||||
|
|
||||||
|
unsigned int fmt_ulonglong(char *dest,unsigned long long i) {
|
||||||
|
register unsigned long len,len2;
|
||||||
|
register unsigned long long tmp;
|
||||||
|
/* first count the number of bytes needed */
|
||||||
|
for (len=1, tmp=i; tmp>9; ++len) tmp/=10;
|
||||||
|
if (dest)
|
||||||
|
for (tmp=i, dest+=len, len2=len+1; --len2; tmp/=10)
|
||||||
|
*--dest = (tmp%10)+'0';
|
||||||
|
return len;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
acct=$1
|
||||||
|
logacct=$2
|
||||||
|
dir=$3
|
||||||
|
webroot=$4
|
||||||
|
myip=$5
|
||||||
|
|
||||||
|
if test x$webroot = x; then
|
||||||
|
echo "fnord-conf: usage: fnord-conf acct logacct /fnord /webroot [ myip ]"
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
# install stuff
|
||||||
|
mkdir -p $dir
|
||||||
|
echo "#!/bin/sh" > $dir/run
|
||||||
|
echo "cd $webroot" >> $dir/run
|
||||||
|
echo "exec envuidgid $acct tcpserver -RHl localhost ${myip:-0} 80 fnord 2>&1" >> $dir/run
|
||||||
|
chmod 755 $dir/run
|
||||||
|
|
||||||
|
# tell old daemontools that it should spawn a log process, too
|
||||||
|
chmod a+t $dir
|
||||||
|
|
||||||
|
# install logging stuff
|
||||||
|
mkdir $dir/log
|
||||||
|
echo "#!/bin/sh" > $dir/log/run
|
||||||
|
echo "exec setuidgid $logacct multilog t ./main" >> $dir/log/run
|
||||||
|
chmod 755 $dir/log/run
|
||||||
|
|
||||||
|
mkdir $dir/log/main
|
||||||
|
chown $logacct $dir/log/main
|
|
@ -0,0 +1,61 @@
|
||||||
|
#ifndef SCAN_H
|
||||||
|
#define SCAN_H
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef __pure__
|
||||||
|
#define __pure__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* interpret src as ASCII decimal number, write number to dest and
|
||||||
|
* return the number of bytes that were parsed */
|
||||||
|
extern unsigned int scan_ulong(const char *src,unsigned long *dest);
|
||||||
|
|
||||||
|
/* same, for long long */
|
||||||
|
extern unsigned int scan_ulonglong(const char *src,unsigned long long *dest);
|
||||||
|
|
||||||
|
/* interpret src as ASCII hexadecimal number, write number to dest and
|
||||||
|
* return the number of bytes that were parsed */
|
||||||
|
extern unsigned int scan_xlong(const char *src,unsigned long *dest);
|
||||||
|
|
||||||
|
/* interpret src as ASCII octal number, write number to dest and
|
||||||
|
* return the number of bytes that were parsed */
|
||||||
|
extern unsigned int scan_8long(const char *src,unsigned long *dest);
|
||||||
|
|
||||||
|
/* interpret src as signed ASCII decimal number, write number to dest
|
||||||
|
* and return the number of bytes that were parsed */
|
||||||
|
extern unsigned int scan_long(const char *src,signed long *dest);
|
||||||
|
|
||||||
|
extern unsigned int scan_uint(const char *src,unsigned int *dest);
|
||||||
|
extern unsigned int scan_xint(const char *src,unsigned int *dest);
|
||||||
|
extern unsigned int scan_8int(const char *src,unsigned int *dest);
|
||||||
|
extern unsigned int scan_int(const char *src,signed int *dest);
|
||||||
|
|
||||||
|
extern unsigned int scan_ushort(const char *src,unsigned short *dest);
|
||||||
|
extern unsigned int scan_xshort(const char *src,unsigned short *dest);
|
||||||
|
extern unsigned int scan_8short(const char *src,unsigned short *dest);
|
||||||
|
extern unsigned int scan_short(const char *src,signed short *dest);
|
||||||
|
|
||||||
|
/* interpret src as double precision floating point number,
|
||||||
|
* write number to dest and return the number of bytes that were parsed */
|
||||||
|
extern unsigned int scan_double(const char *in, double *dest);
|
||||||
|
|
||||||
|
/* if *src=='-', set *dest to -1 and return 1.
|
||||||
|
* if *src=='+', set *dest to 1 and return 1.
|
||||||
|
* otherwise set *dest to 1 return 0. */
|
||||||
|
extern unsigned int scan_plusminus(const char *src,signed int *dest);
|
||||||
|
|
||||||
|
/* return the highest integer n<=limit so that isspace(in[i]) for all 0<=i<=n */
|
||||||
|
extern unsigned int scan_whitenskip(const char *in,unsigned int limit) __pure__;
|
||||||
|
|
||||||
|
/* return the highest integer n<=limit so that !isspace(in[i]) for all 0<=i<=n */
|
||||||
|
extern unsigned int scan_nonwhitenskip(const char *in,unsigned int limit) __pure__;
|
||||||
|
|
||||||
|
/* return the highest integer n<=limit so that in[i] is element of
|
||||||
|
* charset (ASCIIZ string) for all 0<=i<=n */
|
||||||
|
extern unsigned int scan_charsetnskip(const char *in,const char *charset,unsigned int limit) __pure__;
|
||||||
|
|
||||||
|
/* return the highest integer n<=limit so that in[i] is not element of
|
||||||
|
* charset (ASCIIZ string) for all 0<=i<=n */
|
||||||
|
extern unsigned int scan_noncharsetnskip(const char *in,const char *charset,unsigned int limit) __pure__;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "scan.h"
|
||||||
|
|
||||||
|
unsigned int scan_ulong(const char *src,unsigned long *dest) {
|
||||||
|
register const char *tmp=src;
|
||||||
|
register int l=0;
|
||||||
|
register unsigned char c;
|
||||||
|
while ((c=*tmp-'0')<10) {
|
||||||
|
l=l*10+c;
|
||||||
|
++tmp;
|
||||||
|
}
|
||||||
|
*dest=l;
|
||||||
|
return tmp-src;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "scan.h"
|
||||||
|
|
||||||
|
unsigned int scan_ulonglong(const char *src,unsigned long long *dest) {
|
||||||
|
register const char *tmp=src;
|
||||||
|
register unsigned long long int l=0;
|
||||||
|
register unsigned char c;
|
||||||
|
while ((c=*tmp-'0')<10) {
|
||||||
|
l=l*10+c;
|
||||||
|
++tmp;
|
||||||
|
}
|
||||||
|
*dest=l;
|
||||||
|
return tmp-src;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef STR_H
|
||||||
|
#define STR_H
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef __pure__
|
||||||
|
#define __pure__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* str_copy copies leading bytes from in to out until \0.
|
||||||
|
* return number of copied bytes. */
|
||||||
|
extern unsigned int str_copy(char *out,const char *in);
|
||||||
|
|
||||||
|
/* str_diff returns negative, 0, or positive, depending on whether the
|
||||||
|
* string a[0], a[1], ..., a[n]=='\0' is lexicographically smaller than,
|
||||||
|
* equal to, or greater than the string b[0], b[1], ..., b[m-1]=='\0'.
|
||||||
|
* If the strings are different, str_diff does not read bytes past the
|
||||||
|
* first difference. */
|
||||||
|
extern int str_diff(const char *a,const char *b) __pure__;
|
||||||
|
|
||||||
|
/* str_diffn returns negative, 0, or positive, depending on whether the
|
||||||
|
* string a[0], a[1], ..., a[n]=='\0' is lexicographically smaller than,
|
||||||
|
* equal to, or greater than the string b[0], b[1], ..., b[m-1]=='\0'.
|
||||||
|
* If the strings are different, str_diffn does not read bytes past the
|
||||||
|
* first difference. The strings will be considered equal if the first
|
||||||
|
* limit characters match. */
|
||||||
|
extern int str_diffn(const char *a,const char *b,unsigned int limit) __pure__;
|
||||||
|
|
||||||
|
/* str_len returns the index of \0 in s */
|
||||||
|
extern unsigned int str_len(const char *s) __pure__;
|
||||||
|
|
||||||
|
/* str_chr returns the index of the first occurance of needle or \0 in haystack */
|
||||||
|
extern unsigned int str_chr(const char *haystack,char needle) __pure__;
|
||||||
|
|
||||||
|
/* str_rchr returns the index of the last occurance of needle or \0 in haystack */
|
||||||
|
extern unsigned int str_rchr(const char *haystack,char needle) __pure__;
|
||||||
|
|
||||||
|
/* str_start returns 1 if the b is a prefix of a, 0 otherwise */
|
||||||
|
extern int str_start(const char *a,const char *b) __pure__;
|
||||||
|
|
||||||
|
/* convenience shortcut to test for string equality */
|
||||||
|
#define str_equal(s,t) (!str_diff((s),(t)))
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
unsigned int str_chr(const char *in, char needle) {
|
||||||
|
register const char* t=in;
|
||||||
|
register const char c=needle;
|
||||||
|
for (;;) {
|
||||||
|
if (!*t || *t==c) break; ++t;
|
||||||
|
if (!*t || *t==c) break; ++t;
|
||||||
|
if (!*t || *t==c) break; ++t;
|
||||||
|
if (!*t || *t==c) break; ++t;
|
||||||
|
}
|
||||||
|
return t-in;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
unsigned int str_copy(char *out,const char *in) {
|
||||||
|
register char* s=out;
|
||||||
|
register const char* t=in;
|
||||||
|
for (;;) {
|
||||||
|
if (!(*s=*t)) break; ++s; ++t;
|
||||||
|
if (!(*s=*t)) break; ++s; ++t;
|
||||||
|
if (!(*s=*t)) break; ++s; ++t;
|
||||||
|
if (!(*s=*t)) break; ++s; ++t;
|
||||||
|
}
|
||||||
|
return s-out;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include "byte.h"
|
||||||
|
|
||||||
|
/* str_diff returns negative, 0, or positive, depending on whether the
|
||||||
|
* string a[0], a[1], ..., a[n]=='\0' is lexicographically smaller than,
|
||||||
|
* equal to, or greater than the string b[0], b[1], ..., b[m-1]=='\0'.
|
||||||
|
* When the strings are different, str_diff does not read bytes past the
|
||||||
|
* first difference. */
|
||||||
|
int str_diff(const char* a, const char* b) {
|
||||||
|
register const char* s=a;
|
||||||
|
register const char* t=b;
|
||||||
|
register int j;
|
||||||
|
j=0;
|
||||||
|
for (;;) {
|
||||||
|
if ((j=(*s-*t))) break; if (!*t) break; ++s; ++t;
|
||||||
|
if ((j=(*s-*t))) break; if (!*t) break; ++s; ++t;
|
||||||
|
if ((j=(*s-*t))) break; if (!*t) break; ++s; ++t;
|
||||||
|
if ((j=(*s-*t))) break; if (!*t) break; ++s; ++t;
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include "byte.h"
|
||||||
|
|
||||||
|
/* str_diff returns negative, 0, or positive, depending on whether the
|
||||||
|
* string a[0], a[1], ..., a[n]=='\0' is lexicographically smaller than,
|
||||||
|
* equal to, or greater than the string b[0], b[1], ..., b[m-1]=='\0'.
|
||||||
|
* When the strings are different, str_diff does not read bytes past the
|
||||||
|
* first difference. */
|
||||||
|
int str_diffn(const char* a, const char* b, unsigned int limit) {
|
||||||
|
register const char* s=a;
|
||||||
|
register const char* t=b;
|
||||||
|
register const char* u=t+limit;
|
||||||
|
register int j;
|
||||||
|
j=0;
|
||||||
|
for (;;) {
|
||||||
|
if (t>=u) break; if ((j=(*s-*t))) break; if (!*t) break; ++s; ++t;
|
||||||
|
if (t>=u) break; if ((j=(*s-*t))) break; if (!*t) break; ++s; ++t;
|
||||||
|
if (t>=u) break; if ((j=(*s-*t))) break; if (!*t) break; ++s; ++t;
|
||||||
|
if (t>=u) break; if ((j=(*s-*t))) break; if (!*t) break; ++s; ++t;
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
unsigned int str_len(const char *in) {
|
||||||
|
register const char* t=in;
|
||||||
|
for (;;) {
|
||||||
|
if (!*t) break; ++t;
|
||||||
|
if (!*t) break; ++t;
|
||||||
|
if (!*t) break; ++t;
|
||||||
|
if (!*t) break; ++t;
|
||||||
|
}
|
||||||
|
return t-in;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
int str_start (register const char *s, register const char *t)
|
||||||
|
{
|
||||||
|
register char x ;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
x = *t++; if (!x) return 1; if (x != *s++) return 0;
|
||||||
|
x = *t++; if (!x) return 1; if (x != *s++) return 0;
|
||||||
|
x = *t++; if (!x) return 1; if (x != *s++) return 0;
|
||||||
|
x = *t++; if (!x) return 1; if (x != *s++) return 0;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue