mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Add tree command to third_party
This commit is contained in:
parent
7b8024d088
commit
d1300623d2
19 changed files with 5303 additions and 4 deletions
1
Makefile
1
Makefile
|
@ -224,6 +224,7 @@ include third_party/maxmind/maxmind.mk
|
||||||
include net/finger/finger.mk
|
include net/finger/finger.mk
|
||||||
include third_party/double-conversion/test/test.mk
|
include third_party/double-conversion/test/test.mk
|
||||||
include third_party/lua/lua.mk
|
include third_party/lua/lua.mk
|
||||||
|
include third_party/tree/tree.mk
|
||||||
include third_party/zstd/zstd.mk
|
include third_party/zstd/zstd.mk
|
||||||
include third_party/tr/tr.mk
|
include third_party/tr/tr.mk
|
||||||
include third_party/sed/sed.mk
|
include third_party/sed/sed.mk
|
||||||
|
|
9
third_party/third_party.mk
vendored
9
third_party/third_party.mk
vendored
|
@ -14,7 +14,6 @@ o/$(MODE)/third_party: \
|
||||||
o/$(MODE)/third_party/gdtoa \
|
o/$(MODE)/third_party/gdtoa \
|
||||||
o/$(MODE)/third_party/getopt \
|
o/$(MODE)/third_party/getopt \
|
||||||
o/$(MODE)/third_party/ggml \
|
o/$(MODE)/third_party/ggml \
|
||||||
o/$(MODE)/third_party/radpajama \
|
|
||||||
o/$(MODE)/third_party/hiredis \
|
o/$(MODE)/third_party/hiredis \
|
||||||
o/$(MODE)/third_party/libcxx \
|
o/$(MODE)/third_party/libcxx \
|
||||||
o/$(MODE)/third_party/linenoise \
|
o/$(MODE)/third_party/linenoise \
|
||||||
|
@ -23,12 +22,12 @@ o/$(MODE)/third_party: \
|
||||||
o/$(MODE)/third_party/make \
|
o/$(MODE)/third_party/make \
|
||||||
o/$(MODE)/third_party/maxmind \
|
o/$(MODE)/third_party/maxmind \
|
||||||
o/$(MODE)/third_party/mbedtls \
|
o/$(MODE)/third_party/mbedtls \
|
||||||
o/$(MODE)/third_party/xxhash \
|
|
||||||
o/$(MODE)/third_party/musl \
|
o/$(MODE)/third_party/musl \
|
||||||
o/$(MODE)/third_party/nsync \
|
o/$(MODE)/third_party/nsync \
|
||||||
o/$(MODE)/third_party/puff \
|
o/$(MODE)/third_party/puff \
|
||||||
o/$(MODE)/third_party/python \
|
o/$(MODE)/third_party/python \
|
||||||
o/$(MODE)/third_party/quickjs \
|
o/$(MODE)/third_party/quickjs \
|
||||||
|
o/$(MODE)/third_party/radpajama \
|
||||||
o/$(MODE)/third_party/regex \
|
o/$(MODE)/third_party/regex \
|
||||||
o/$(MODE)/third_party/sed \
|
o/$(MODE)/third_party/sed \
|
||||||
o/$(MODE)/third_party/smallz4 \
|
o/$(MODE)/third_party/smallz4 \
|
||||||
|
@ -36,9 +35,11 @@ o/$(MODE)/third_party: \
|
||||||
o/$(MODE)/third_party/stb \
|
o/$(MODE)/third_party/stb \
|
||||||
o/$(MODE)/third_party/tidy \
|
o/$(MODE)/third_party/tidy \
|
||||||
o/$(MODE)/third_party/tr \
|
o/$(MODE)/third_party/tr \
|
||||||
|
o/$(MODE)/third_party/tree \
|
||||||
o/$(MODE)/third_party/unzip \
|
o/$(MODE)/third_party/unzip \
|
||||||
o/$(MODE)/third_party/vqsort \
|
o/$(MODE)/third_party/vqsort \
|
||||||
o/$(MODE)/third_party/xed \
|
o/$(MODE)/third_party/xed \
|
||||||
|
o/$(MODE)/third_party/xxhash \
|
||||||
o/$(MODE)/third_party/zip \
|
o/$(MODE)/third_party/zip \
|
||||||
o/$(MODE)/third_party/zstd \
|
o/$(MODE)/third_party/zlib \
|
||||||
o/$(MODE)/third_party/zlib
|
o/$(MODE)/third_party/zstd
|
||||||
|
|
340
third_party/tree/LICENSE
vendored
Normal file
340
third_party/tree/LICENSE
vendored
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 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
|
||||||
|
|
||||||
|
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) <year> <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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) year 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.
|
325
third_party/tree/README
vendored
Normal file
325
third_party/tree/README
vendored
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
Please read the INSTALL file for installation instructions, particularly if
|
||||||
|
you are installing on a non-Linux machine.
|
||||||
|
|
||||||
|
This is a handy little utility to display a tree view of directories that
|
||||||
|
I wrote some time ago and just added color support to. I've decided that
|
||||||
|
since no one else has done something similar I would go ahead and release
|
||||||
|
it, even though it's barely a 1st year CS student hack. I've found it damn
|
||||||
|
handy to peruse a directory tree though, especially when someone is trying to
|
||||||
|
hide something from you.
|
||||||
|
|
||||||
|
The main distribution site for tree is here:
|
||||||
|
http://oldmanprogrammer.net/source.php?dir=projects/tree
|
||||||
|
|
||||||
|
Backup GIT sites are:
|
||||||
|
https://gitlab.com/OldManProgrammer/unix-tree
|
||||||
|
https://github.com/Old-Man-Programmer/tree
|
||||||
|
|
||||||
|
Old site for as long as it lasts:
|
||||||
|
http://mama.indstate.edu/users/ice/tree/
|
||||||
|
ftp://mama.indstate.edu/linux/tree/
|
||||||
|
|
||||||
|
If you don't like the way it looks let me know how you think it should be
|
||||||
|
formatted. Feel free to suggest modifications and additions.
|
||||||
|
|
||||||
|
Thanks go out so the following people who have helped bring tree to the
|
||||||
|
pinnacle of perfection that it is: ;)
|
||||||
|
|
||||||
|
Francesc Rocher
|
||||||
|
- Added HTML output (-H).
|
||||||
|
- Added options -o, -L and -R.
|
||||||
|
|
||||||
|
Gerald Scheidl
|
||||||
|
- Added -S option to print ASCII graphics lines for use under linux
|
||||||
|
console when an alternate console font has been selected (might also
|
||||||
|
work under DOS telnet).
|
||||||
|
|
||||||
|
Guido Socher (and others)
|
||||||
|
- Made tree more portable. Should compile under solaris.
|
||||||
|
|
||||||
|
Mitja Lacen
|
||||||
|
- Discovered bug where tree will segmentation fault on long pathnames.
|
||||||
|
- Discovered in -L argument processing.
|
||||||
|
|
||||||
|
Nathaniel Delage
|
||||||
|
- Discovered problem with recursive symlink detection
|
||||||
|
|
||||||
|
A. Karthik
|
||||||
|
- Suggested option to remove file and directory report at end of tree
|
||||||
|
listing.
|
||||||
|
|
||||||
|
Roger Luethi
|
||||||
|
- Spotted memory over-allocation bug in read_dir().
|
||||||
|
- Submitted several patches to fix various memory leaks.
|
||||||
|
|
||||||
|
Daniel Lee
|
||||||
|
- Reported that Tru64 defines TRUE/FALSE in sys/types.h (OSF1 standard?)
|
||||||
|
|
||||||
|
Paolo Violini
|
||||||
|
- Found bug in tree that caused it to seg-fault if 50 file arguments where
|
||||||
|
given and directory coloring was turned on.
|
||||||
|
|
||||||
|
Mitsuaki Masuhara
|
||||||
|
- Discovered tree crashed on missing arguments.
|
||||||
|
- Discovered that tree did not properly encode characters in filenames
|
||||||
|
when used as URLs when using the -H option.
|
||||||
|
- Fixed issue with --charset option processing.
|
||||||
|
|
||||||
|
Johan Fredrik
|
||||||
|
- Pointed out that tree did not list large files.
|
||||||
|
|
||||||
|
Ted Tiberio
|
||||||
|
- Submitted patch which fixed a compiler issue and cleaned up HTML and CSS
|
||||||
|
code, applied CSS to all output, and fixed up HTML to 4.01 strict
|
||||||
|
standards.
|
||||||
|
|
||||||
|
David MacMahon
|
||||||
|
- Added '|' support to the pattern matching routines.
|
||||||
|
|
||||||
|
Dan Jacobson
|
||||||
|
- Pointed out that -t did not sort properly for files with the same
|
||||||
|
timestamp.
|
||||||
|
- Suggested option to change HTML title and H1 string.
|
||||||
|
- Suggested -r option for reversed alphanumeric sort ala 'ls -r'.
|
||||||
|
|
||||||
|
Kyosuke Tokoro
|
||||||
|
- Provided patch to support OS/2, fix HTML encoding, provide charset
|
||||||
|
support. Added to authors list.
|
||||||
|
|
||||||
|
Florian Ernst
|
||||||
|
- Debian maintainer who pointed out problems and applied fire to feet to fix
|
||||||
|
stuff.
|
||||||
|
|
||||||
|
Jack Cuyler
|
||||||
|
- Suggested -h option for human readable output for -s, ala ls -lh.
|
||||||
|
|
||||||
|
Jonathon Cranford
|
||||||
|
- Supplied patch to make tree under cygwin.
|
||||||
|
|
||||||
|
Richard Houser
|
||||||
|
- Provided patch to fix a colorization bug when dealing with special
|
||||||
|
files and directories that seem to have an extension.
|
||||||
|
|
||||||
|
Zurd (?)
|
||||||
|
- Suggested removing trailing slash on user supplied directory names if -f
|
||||||
|
option is used.
|
||||||
|
|
||||||
|
John Nintendud
|
||||||
|
- Pointed out broken HTML output in 1.5.1.
|
||||||
|
|
||||||
|
Mark Braker
|
||||||
|
- Suggested --filelimit option.
|
||||||
|
|
||||||
|
Michael Vogt
|
||||||
|
- Suggested -v option (version sort).
|
||||||
|
|
||||||
|
Wang Quanhong
|
||||||
|
- Provided build options for Solaris.
|
||||||
|
|
||||||
|
Craig McDaniel
|
||||||
|
- Provided build options and source mods for HP NonStop support.
|
||||||
|
|
||||||
|
Christian Grigis
|
||||||
|
- Noted that setlocale() should come before MB_CUR_MAX check.
|
||||||
|
|
||||||
|
Kamaraju Kusumanchi
|
||||||
|
- Submitted patch to remove compiler warnings for Solaris.
|
||||||
|
|
||||||
|
Martin Nagy
|
||||||
|
- Provided patch which fixes issue where indent may output more than it
|
||||||
|
should when dirs[*] is not properly cleared before use.
|
||||||
|
|
||||||
|
William C. Lathan III
|
||||||
|
- Showed that tree was not properly quoting arguments to recursively called
|
||||||
|
tree instances when using -R.
|
||||||
|
|
||||||
|
Ulrich Eckhardt
|
||||||
|
- Submitted patch for --si option.
|
||||||
|
|
||||||
|
Tim Waugh (redhat)
|
||||||
|
- Pointed out a potential memory leak in listdir().
|
||||||
|
|
||||||
|
Markus Schnalke
|
||||||
|
- Tracked down bug where tree would print "argetm" before the filename of a
|
||||||
|
symbolic link when the "target" option was specified for LINK in dircolors.
|
||||||
|
|
||||||
|
Ujjwal Kumar
|
||||||
|
- Suggested that tree backslash spaces like ls does for script use. Made
|
||||||
|
output more like ls.
|
||||||
|
|
||||||
|
Ivan Shmakov
|
||||||
|
- Pointed out multiple CLI defenciencies (via Debian)
|
||||||
|
|
||||||
|
Mantas Mikulnas
|
||||||
|
- Provided patch to make tree more reliably detect the UTF-8 locale.
|
||||||
|
|
||||||
|
Tim Mooney
|
||||||
|
- Noticed S_ISDOOR/S_IFDOOR spelling mistake for under Solaris.
|
||||||
|
|
||||||
|
Han Hui
|
||||||
|
- Pointed out possible memory overflow in read_dir (path/lbuf not equal in size
|
||||||
|
to pathsize/lbufsize.)
|
||||||
|
|
||||||
|
Ryan Hollis
|
||||||
|
- Pointed out problems with the Makefile w/ respect to OSX.
|
||||||
|
|
||||||
|
Philipp M?ller
|
||||||
|
- Provided patch for filesize sorting.
|
||||||
|
|
||||||
|
Sascha Zorn
|
||||||
|
- Pointed out that the HTML output was broken when -L 1 option was used.
|
||||||
|
|
||||||
|
Alexandre Wendling
|
||||||
|
- Pointed out that modern systems may use 32 bit uid/gids which could lead
|
||||||
|
to a potential buffer overflow in the uid/gid to name mapping functions.
|
||||||
|
|
||||||
|
Florian Sesser
|
||||||
|
- Provided patch to add JSON support.
|
||||||
|
|
||||||
|
Brian Mattern & Jason A. Donenfeld
|
||||||
|
- Provided patch to add --matchdirs functionality.
|
||||||
|
|
||||||
|
Jason A. Donenfeld
|
||||||
|
- Added --caseinsentive, renamed --ignore-case option.
|
||||||
|
- Bugged me a lot.
|
||||||
|
|
||||||
|
Stephan Gabert
|
||||||
|
- Found a bug where the wrong inode (and device) information would be printed
|
||||||
|
for symbolic links.
|
||||||
|
|
||||||
|
Nick Craig-Wood
|
||||||
|
- Fixed issue where mbstowcs() fails to null terminate the string due to
|
||||||
|
improper UTF-8 encoding leading to garbage being printed.
|
||||||
|
|
||||||
|
Mantas Mikulėnas
|
||||||
|
- Fixed issue with malformed multibyte string handling.
|
||||||
|
|
||||||
|
Wagner Camarao
|
||||||
|
- Pointed out that JSON size output ignored -h/--si flags
|
||||||
|
|
||||||
|
John Lane, Tad, others
|
||||||
|
- Fixed JSON output hanging commas
|
||||||
|
|
||||||
|
Jacob Wahlgren
|
||||||
|
- Improved command line switch error reporting.
|
||||||
|
- Symbolic links not displayed if a -P pattern is active
|
||||||
|
- Missing argument error reporting fixes on long format switches.
|
||||||
|
|
||||||
|
Shawn Mehan
|
||||||
|
- Update BINDIR in Makefile for MacOS X -- It is not allowed to install
|
||||||
|
programs to /usr/bin on MacOS X any longer due to System Integrity
|
||||||
|
Protection (SIP)
|
||||||
|
|
||||||
|
Kirill Kolyshkin
|
||||||
|
- Some man page fixes and cleanups
|
||||||
|
|
||||||
|
Alyssa Ross
|
||||||
|
- Suggested adding support for BSD's CLICOLOR and CLICOLOR_FORCE environment
|
||||||
|
variables.
|
||||||
|
|
||||||
|
Tomáš Beránek
|
||||||
|
- Make sure we always use xmalloc / xrealloc
|
||||||
|
|
||||||
|
Sergei Maximov
|
||||||
|
- Make XML/HTML/JSON output mutually exclusive.
|
||||||
|
|
||||||
|
Jonas Stein
|
||||||
|
- Deprecate using local -DLINUX / -DCYGWIN and use the OS provided defines
|
||||||
|
|
||||||
|
John A. Fedoruk
|
||||||
|
- Suggested --filesfirst option.
|
||||||
|
|
||||||
|
Michael Osipov
|
||||||
|
- Optimized makefile, HP/UX support.
|
||||||
|
|
||||||
|
Richard Mitchell
|
||||||
|
- Suggested --metafirst option
|
||||||
|
|
||||||
|
Paul Seyfert
|
||||||
|
- Honor -n (no color) even if the CLICOLOR_FORCE environment variable is set
|
||||||
|
|
||||||
|
Filips Romāns via Debian
|
||||||
|
- Make tree colorization use reset (rs code in dir_colors,) not normal color
|
||||||
|
when resetting attributes.
|
||||||
|
|
||||||
|
Chentao Credungtao via Debian
|
||||||
|
- Properly sort --fromfile input
|
||||||
|
|
||||||
|
Jake Zimmerman (and others)
|
||||||
|
- Suggest support for .gitignore files (--gitignore option)
|
||||||
|
|
||||||
|
Eric Pruitt
|
||||||
|
- Always HTML escape filenames in HTML output even when -C is used.
|
||||||
|
|
||||||
|
Michiel Beijen (and others)
|
||||||
|
- Suggest Support multiple -I and -P instances.
|
||||||
|
- Suggest that / match directories in patterns (also Taylor Faubion)
|
||||||
|
- Suggested to update MANPATH for OS X
|
||||||
|
|
||||||
|
Michal Vasilek
|
||||||
|
- Various Makefile fixes
|
||||||
|
|
||||||
|
Josey Smith
|
||||||
|
- Reported an error with * in the patchmatch code where *foo*bar would match
|
||||||
|
*foo alone.
|
||||||
|
|
||||||
|
Maxim Cournoyer
|
||||||
|
- Reported HTML url output issue w/ 2.0.0-2.0.1
|
||||||
|
|
||||||
|
Kenta Arai
|
||||||
|
- Reported Segfault with --filelimit option
|
||||||
|
|
||||||
|
Ben Brown
|
||||||
|
- Updates to the Makefile
|
||||||
|
- Reported use after free error
|
||||||
|
|
||||||
|
Erik Skultety
|
||||||
|
- Reported same use after error
|
||||||
|
|
||||||
|
Saniya Maheshwari / Mig-hub ? / Carlos Pinto
|
||||||
|
- Reported various issues with --gitignore
|
||||||
|
|
||||||
|
Piotr Andruszkow
|
||||||
|
- Suggested adding support for --info and --gitignore for the --fromfile
|
||||||
|
option.
|
||||||
|
|
||||||
|
Kenta Arai
|
||||||
|
- Add NULL guard for json_printinfo() and xml_printinfo() (and fix ftype
|
||||||
|
printing for XML)
|
||||||
|
- Fix getcharset() to not return a getenv() pointer.
|
||||||
|
|
||||||
|
Sebastian Rose
|
||||||
|
- Another attempt at fixing extraneous /'s in HTML URLs/output.
|
||||||
|
|
||||||
|
Dave Rice
|
||||||
|
- Fixed XML output
|
||||||
|
|
||||||
|
Timm Fitschen
|
||||||
|
- Suggest adding support for the NO_COLOR environment variable.
|
||||||
|
|
||||||
|
Chentao Credungtao
|
||||||
|
- Suggested supporting symbolic links in --fromfile (--fflinks option)
|
||||||
|
|
||||||
|
Sith Wijesinghe and Matthew Sessions
|
||||||
|
- Remove many C90 isms to make compiling with C90 compilers easier.
|
||||||
|
|
||||||
|
simonpmind (gitlab)
|
||||||
|
- Reported issue where following links while doing JSON output would lead to
|
||||||
|
incorrect JSON output.
|
||||||
|
|
||||||
|
German Lashevich
|
||||||
|
- Reported an issue where .info patterns relative to the .info file that did
|
||||||
|
not use a wildcard for matching the prefix were not matching files properly.
|
||||||
|
|
||||||
|
Javier Jaramago Fernández
|
||||||
|
- Reported a buffer overflow in listdir() when file names are allowed to be
|
||||||
|
longer than 256 characters (like when using fromfile.)
|
||||||
|
|
||||||
|
6ramr (gitlab)
|
||||||
|
- Reported issue with following symbolic links when a full tree was gathered.
|
||||||
|
|
||||||
|
And many others whom I've failed to keep track of. I should have started
|
||||||
|
this list years ago.
|
||||||
|
|
||||||
|
- Steve Baker
|
||||||
|
oldmanprogrammer.llc@gmail.com
|
19
third_party/tree/README.cosmo
vendored
Normal file
19
third_party/tree/README.cosmo
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
DESCRIPTION
|
||||||
|
|
||||||
|
The tree command prints a chart of files and directories.
|
||||||
|
|
||||||
|
ORIGIN
|
||||||
|
|
||||||
|
https://mama.indstate.edu/users/ice/tree/
|
||||||
|
https://github.com/Old-Man-Programmer/tree
|
||||||
|
84fa3ddff51b30835a0f9c4a9e4c9225970f9aff
|
||||||
|
|
||||||
|
LICENSE
|
||||||
|
|
||||||
|
GPL v2+
|
||||||
|
|
||||||
|
LOCAL MODIFICATIONS
|
||||||
|
|
||||||
|
- Make the default mode a colorful mode. You no longer need to define
|
||||||
|
the CLICOLOR enviroment variable or pass the -C flag to get color
|
||||||
|
when standard output is a terminal.
|
477
third_party/tree/color.c
vendored
Normal file
477
third_party/tree/color.c
vendored
Normal file
|
@ -0,0 +1,477 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/sysv/consts/s.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "third_party/tree/tree.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hacked in DIR_COLORS support for linux. ------------------------------
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* If someone asked me, I'd extend dircolors, to provide more generic
|
||||||
|
* color support so that more programs could take advantage of it. This
|
||||||
|
* is really just hacked in support. The dircolors program should:
|
||||||
|
* 1) Put the valid terms in a environment var, like:
|
||||||
|
* COLOR_TERMS=linux:console:xterm:vt100...
|
||||||
|
* 2) Put the COLOR and OPTIONS directives in a env var too.
|
||||||
|
* 3) Have an option to dircolors to silently ignore directives that it
|
||||||
|
* doesn't understand (directives that other programs would
|
||||||
|
* understand).
|
||||||
|
* 4) Perhaps even make those unknown directives environment variables.
|
||||||
|
*
|
||||||
|
* The environment is the place for cryptic crap no one looks at, but
|
||||||
|
* programs. No one is going to care if it takes 30 variables to do
|
||||||
|
* something.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ERROR = -1, CMD_COLOR = 0, CMD_OPTIONS, CMD_TERM, CMD_EIGHTBIT, COL_RESET,
|
||||||
|
COL_NORMAL, COL_FILE, COL_DIR, COL_LINK, COL_FIFO, COL_DOOR, COL_BLK, COL_CHR,
|
||||||
|
COL_ORPHAN, COL_SOCK, COL_SETUID, COL_SETGID, COL_STICKY_OTHER_WRITABLE,
|
||||||
|
COL_OTHER_WRITABLE, COL_STICKY, COL_EXEC, COL_MISSING,
|
||||||
|
COL_LEFTCODE, COL_RIGHTCODE, COL_ENDCODE,
|
||||||
|
/* Keep this one last, sets the size of the color_code array: */
|
||||||
|
DOT_EXTENSION
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MCOL_INODE, MCOL_PERMS, MCOL_USER, MCOL_GROUP, MCOL_SIZE, MCOL_DATE,
|
||||||
|
MCOL_INDENTLINES
|
||||||
|
};
|
||||||
|
|
||||||
|
bool colorize = FALSE, ansilines = FALSE, linktargetcolor = FALSE;
|
||||||
|
char *term, termmatch = FALSE, istty;
|
||||||
|
|
||||||
|
char *color_code[DOT_EXTENSION+1] = {NULL};
|
||||||
|
|
||||||
|
char *vgacolor[] = {
|
||||||
|
"black", "red", "green", "yellow", "blue", "fuchsia", "aqua", "white",
|
||||||
|
NULL, NULL,
|
||||||
|
"transparent", "red", "green", "yellow", "blue", "fuchsia", "aqua", "black"
|
||||||
|
};
|
||||||
|
|
||||||
|
struct colortable colortable[11];
|
||||||
|
struct extensions *ext = NULL;
|
||||||
|
const struct linedraw *linedraw;
|
||||||
|
|
||||||
|
char **split(char *str, char *delim, int *nwrds);
|
||||||
|
int cmd(char *s);
|
||||||
|
|
||||||
|
extern FILE *outfile;
|
||||||
|
extern bool Hflag, force_color, nocolor;
|
||||||
|
extern const char *charset;
|
||||||
|
|
||||||
|
void parse_dir_colors()
|
||||||
|
{
|
||||||
|
char buf[1025], **arg, **c, *colors, *s;
|
||||||
|
int i, n, col, cc;
|
||||||
|
struct extensions *e;
|
||||||
|
|
||||||
|
if (Hflag) return;
|
||||||
|
|
||||||
|
s = getenv("NO_COLOR");
|
||||||
|
if (s && s[0]) nocolor = TRUE;
|
||||||
|
|
||||||
|
if (getenv("TERM") == NULL) {
|
||||||
|
colorize = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [jart] we're biased in favor of color
|
||||||
|
cc = true; // getenv("CLICOLOR") != NULL;
|
||||||
|
if (getenv("CLICOLOR_FORCE") != NULL && !nocolor) force_color=TRUE;
|
||||||
|
s = getenv("TREE_COLORS");
|
||||||
|
if (s == NULL) s = getenv("LS_COLORS");
|
||||||
|
if ((s == NULL || strlen(s) == 0) && (force_color || cc)) s = ":no=00:rs=0:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.bat=01;32:*.BAT=01;32:*.btm=01;32:*.BTM=01;32:*.cmd=01;32:*.CMD=01;32:*.com=01;32:*.COM=01;32:*.dll=01;32:*.DLL=01;32:*.exe=01;32:*.EXE=01;32:*.arj=01;31:*.bz2=01;31:*.deb=01;31:*.gz=01;31:*.lzh=01;31:*.rpm=01;31:*.tar=01;31:*.taz=01;31:*.tb2=01;31:*.tbz2=01;31:*.tbz=01;31:*.tgz=01;31:*.tz2=01;31:*.z=01;31:*.Z=01;31:*.zip=01;31:*.ZIP=01;31:*.zoo=01;31:*.asf=01;35:*.ASF=01;35:*.avi=01;35:*.AVI=01;35:*.bmp=01;35:*.BMP=01;35:*.flac=01;35:*.FLAC=01;35:*.gif=01;35:*.GIF=01;35:*.jpg=01;35:*.JPG=01;35:*.jpeg=01;35:*.JPEG=01;35:*.m2a=01;35:*.M2a=01;35:*.m2v=01;35:*.M2V=01;35:*.mov=01;35:*.MOV=01;35:*.mp3=01;35:*.MP3=01;35:*.mpeg=01;35:*.MPEG=01;35:*.mpg=01;35:*.MPG=01;35:*.ogg=01;35:*.OGG=01;35:*.ppm=01;35:*.rm=01;35:*.RM=01;35:*.tga=01;35:*.TGA=01;35:*.tif=01;35:*.TIF=01;35:*.wav=01;35:*.WAV=01;35:*.wmv=01;35:*.WMV=01;35:*.xbm=01;35:*.xpm=01;35:";
|
||||||
|
|
||||||
|
if (s == NULL || (!force_color && (nocolor || !isatty(1)))) {
|
||||||
|
colorize = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
colorize = TRUE;
|
||||||
|
|
||||||
|
for(i=0; i < DOT_EXTENSION; i++) color_code[i] = NULL;
|
||||||
|
|
||||||
|
colors = scopy(s);
|
||||||
|
|
||||||
|
arg = split(colors,":",&n);
|
||||||
|
|
||||||
|
for(i=0;arg[i];i++) {
|
||||||
|
c = split(arg[i],"=",&n);
|
||||||
|
|
||||||
|
switch(col = cmd(c[0])) {
|
||||||
|
case ERROR:
|
||||||
|
break;
|
||||||
|
case DOT_EXTENSION:
|
||||||
|
if (c[1]) {
|
||||||
|
e = xmalloc(sizeof(struct extensions));
|
||||||
|
e->ext = scopy(c[0]+1);
|
||||||
|
e->term_flg = scopy(c[1]);
|
||||||
|
e->nxt = ext;
|
||||||
|
ext = e;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COL_LINK:
|
||||||
|
if (c[1] && strcasecmp("target",c[1]) == 0) {
|
||||||
|
linktargetcolor = TRUE;
|
||||||
|
color_code[COL_LINK] = "01;36"; /* Should never actually be used */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if (c[1]) color_code[col] = scopy(c[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
free(arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure at least reset (not normal) is defined. We're going to assume
|
||||||
|
* ANSI/vt100 support:
|
||||||
|
*/
|
||||||
|
if (!color_code[COL_LEFTCODE]) color_code[COL_LEFTCODE] = scopy("\033[");
|
||||||
|
if (!color_code[COL_RIGHTCODE]) color_code[COL_RIGHTCODE] = scopy("m");
|
||||||
|
if (!color_code[COL_RESET]) color_code[COL_RESET] = scopy("0");
|
||||||
|
if (!color_code[COL_ENDCODE]) {
|
||||||
|
sprintf(buf,"%s%s%s",color_code[COL_LEFTCODE],color_code[COL_RESET],color_code[COL_RIGHTCODE]);
|
||||||
|
color_code[COL_ENDCODE] = scopy(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You must free the pointer that is allocated by split() after you
|
||||||
|
* are done using the array.
|
||||||
|
*/
|
||||||
|
char **split(char *str, char *delim, int *nwrds)
|
||||||
|
{
|
||||||
|
int n = 128;
|
||||||
|
char **w = xmalloc(sizeof(char *) * n);
|
||||||
|
|
||||||
|
w[*nwrds = 0] = strtok(str,delim);
|
||||||
|
|
||||||
|
while (w[*nwrds]) {
|
||||||
|
if (*nwrds == (n-2)) w = xrealloc(w,sizeof(char *) * (n+=256));
|
||||||
|
w[++(*nwrds)] = strtok(NULL,delim);
|
||||||
|
}
|
||||||
|
|
||||||
|
w[*nwrds] = NULL;
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd(char *s)
|
||||||
|
{
|
||||||
|
static struct {
|
||||||
|
char *cmd;
|
||||||
|
char cmdnum;
|
||||||
|
} cmds[] = {
|
||||||
|
{"rs", COL_RESET}, {"no", COL_NORMAL}, {"fi", COL_FILE}, {"di", COL_DIR},
|
||||||
|
{"ln", COL_LINK}, {"pi", COL_FIFO}, {"do", COL_DOOR}, {"bd", COL_BLK},
|
||||||
|
{"cd", COL_CHR}, {"or", COL_ORPHAN}, {"so", COL_SOCK}, {"su", COL_SETUID},
|
||||||
|
{"sg", COL_SETGID}, {"tw", COL_STICKY_OTHER_WRITABLE},
|
||||||
|
{"ow", COL_OTHER_WRITABLE}, {"st", COL_STICKY}, {"ex", COL_EXEC},
|
||||||
|
{"mi", COL_MISSING}, {"lc", COL_LEFTCODE}, {"rc", COL_RIGHTCODE},
|
||||||
|
{"ec", COL_ENDCODE}, {NULL, 0}
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (s == NULL) return ERROR; /* Probably can't happen */
|
||||||
|
|
||||||
|
if (s[0] == '*') return DOT_EXTENSION;
|
||||||
|
for(i=0;cmds[i].cmdnum;i++) {
|
||||||
|
if (!strcmp(cmds[i].cmd,s)) return cmds[i].cmdnum;
|
||||||
|
}
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int print_color(int color)
|
||||||
|
{
|
||||||
|
if (!color_code[color]) return FALSE;
|
||||||
|
|
||||||
|
fputs(color_code[COL_LEFTCODE],outfile);
|
||||||
|
fputs(color_code[color],outfile);
|
||||||
|
fputs(color_code[COL_RIGHTCODE],outfile);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void endcolor(void)
|
||||||
|
{
|
||||||
|
if (color_code[COL_ENDCODE])
|
||||||
|
fputs(color_code[COL_ENDCODE],outfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
int color(u_short mode, char *name, bool orphan, bool islink)
|
||||||
|
{
|
||||||
|
struct extensions *e;
|
||||||
|
int l, xl;
|
||||||
|
|
||||||
|
if (orphan) {
|
||||||
|
if (islink) {
|
||||||
|
if (print_color(COL_MISSING)) return TRUE;
|
||||||
|
} else {
|
||||||
|
if (print_color(COL_ORPHAN)) return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It's probably safe to assume short-circuit evaluation, but we'll do it this way: */
|
||||||
|
switch(mode & S_IFMT) {
|
||||||
|
case S_IFIFO:
|
||||||
|
return print_color(COL_FIFO);
|
||||||
|
case S_IFCHR:
|
||||||
|
return print_color(COL_CHR);
|
||||||
|
case S_IFDIR:
|
||||||
|
if (mode & S_ISVTX) {
|
||||||
|
if ((mode & S_IWOTH))
|
||||||
|
if (print_color(COL_STICKY_OTHER_WRITABLE)) return TRUE;
|
||||||
|
if (!(mode & S_IWOTH))
|
||||||
|
if (print_color(COL_STICKY)) return TRUE;
|
||||||
|
}
|
||||||
|
if ((mode & S_IWOTH))
|
||||||
|
if (print_color(COL_OTHER_WRITABLE)) return TRUE;
|
||||||
|
return print_color(COL_DIR);
|
||||||
|
#ifndef __EMX__
|
||||||
|
case S_IFBLK:
|
||||||
|
return print_color(COL_BLK);
|
||||||
|
case S_IFLNK:
|
||||||
|
return print_color(COL_LINK);
|
||||||
|
#ifdef S_IFDOOR
|
||||||
|
case S_IFDOOR:
|
||||||
|
return print_color(COL_DOOR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
case S_IFSOCK:
|
||||||
|
return print_color(COL_SOCK);
|
||||||
|
case S_IFREG:
|
||||||
|
if ((mode & S_ISUID))
|
||||||
|
if (print_color(COL_SETUID)) return TRUE;
|
||||||
|
if ((mode & S_ISGID))
|
||||||
|
if (print_color(COL_SETGID)) return TRUE;
|
||||||
|
if (mode & (S_IXUSR | S_IXGRP | S_IXOTH))
|
||||||
|
if (print_color(COL_EXEC)) return TRUE;
|
||||||
|
|
||||||
|
/* not a directory, link, special device, etc, so check for extension match */
|
||||||
|
l = strlen(name);
|
||||||
|
for(e=ext;e;e=e->nxt) {
|
||||||
|
xl = strlen(e->ext);
|
||||||
|
if (!strcmp((l>xl)?name+(l-xl):name,e->ext)) {
|
||||||
|
fputs(color_code[COL_LEFTCODE], outfile);
|
||||||
|
fputs(e->term_flg, outfile);
|
||||||
|
fputs(color_code[COL_RIGHTCODE], outfile);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* colorize just normal files too */
|
||||||
|
return print_color(COL_FILE);
|
||||||
|
}
|
||||||
|
return print_color(COL_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Charsets provided by Kyosuke Tokoro (NBG01720@nifty.ne.jp)
|
||||||
|
*/
|
||||||
|
const char *getcharset(void)
|
||||||
|
{
|
||||||
|
char *cs;
|
||||||
|
static char buffer[256];
|
||||||
|
|
||||||
|
cs = getenv("TREE_CHARSET");
|
||||||
|
if (cs) return strncpy(buffer,cs,255);
|
||||||
|
|
||||||
|
#ifndef __EMX__
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
|
ULONG aulCpList[3],ulListSize,codepage=0;
|
||||||
|
|
||||||
|
if(!getenv("WINDOWID"))
|
||||||
|
if(!DosQueryCp(sizeof aulCpList,aulCpList,&ulListSize))
|
||||||
|
if(ulListSize>=sizeof*aulCpList)
|
||||||
|
codepage=*aulCpList;
|
||||||
|
|
||||||
|
switch(codepage) {
|
||||||
|
case 437: case 775: case 850: case 851: case 852: case 855:
|
||||||
|
case 857: case 860: case 861: case 862: case 863: case 864:
|
||||||
|
case 865: case 866: case 868: case 869: case 891: case 903:
|
||||||
|
case 904:
|
||||||
|
sprintf(buffer,"IBM%03lu",codepage);
|
||||||
|
break;
|
||||||
|
case 367:
|
||||||
|
return"US-ASCII";
|
||||||
|
case 813:
|
||||||
|
return"ISO-8859-7";
|
||||||
|
case 819:
|
||||||
|
return"ISO-8859-1";
|
||||||
|
case 881: case 882: case 883: case 884: case 885:
|
||||||
|
sprintf(buffer,"ISO-8859-%lu",codepage-880);
|
||||||
|
break;
|
||||||
|
case 858: case 924:
|
||||||
|
sprintf(buffer,"IBM%05lu",codepage);
|
||||||
|
break;
|
||||||
|
case 874:
|
||||||
|
return"TIS-620";
|
||||||
|
case 897: case 932: case 942: case 943:
|
||||||
|
return"Shift_JIS";
|
||||||
|
case 912:
|
||||||
|
return"ISO-8859-2";
|
||||||
|
case 915:
|
||||||
|
return"ISO-8859-5";
|
||||||
|
case 916:
|
||||||
|
return"ISO-8859-8";
|
||||||
|
case 949: case 970:
|
||||||
|
return"EUC-KR";
|
||||||
|
case 950:
|
||||||
|
return"Big5";
|
||||||
|
case 954:
|
||||||
|
return"EUC-JP";
|
||||||
|
case 1051:
|
||||||
|
return"hp-roman8";
|
||||||
|
case 1089:
|
||||||
|
return"ISO-8859-6";
|
||||||
|
case 1250: case 1251: case 1253: case 1254: case 1255: case 1256:
|
||||||
|
case 1257: case 1258:
|
||||||
|
sprintf(buffer,"windows-%lu",codepage);
|
||||||
|
break;
|
||||||
|
case 1252:
|
||||||
|
return"ISO-8859-1-Windows-3.1-Latin-1";
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void initlinedraw(int flag)
|
||||||
|
{
|
||||||
|
static const char*latin1_3[]={
|
||||||
|
"ISO-8859-1", "ISO-8859-1:1987", "ISO_8859-1", "latin1", "l1", "IBM819",
|
||||||
|
"CP819", "csISOLatin1", "ISO-8859-3", "ISO_8859-3:1988", "ISO_8859-3",
|
||||||
|
"latin3", "ls", "csISOLatin3", NULL
|
||||||
|
};
|
||||||
|
static const char*iso8859_789[]={
|
||||||
|
"ISO-8859-7", "ISO_8859-7:1987", "ISO_8859-7", "ELOT_928", "ECMA-118",
|
||||||
|
"greek", "greek8", "csISOLatinGreek", "ISO-8859-8", "ISO_8859-8:1988",
|
||||||
|
"iso-ir-138", "ISO_8859-8", "hebrew", "csISOLatinHebrew", "ISO-8859-9",
|
||||||
|
"ISO_8859-9:1989", "iso-ir-148", "ISO_8859-9", "latin5", "l5",
|
||||||
|
"csISOLatin5", NULL
|
||||||
|
};
|
||||||
|
static const char*shift_jis[]={
|
||||||
|
"Shift_JIS", "MS_Kanji", "csShiftJIS", NULL
|
||||||
|
};
|
||||||
|
static const char*euc_jp[]={
|
||||||
|
"EUC-JP", "Extended_UNIX_Code_Packed_Format_for_Japanese",
|
||||||
|
"csEUCPkdFmtJapanese", NULL
|
||||||
|
};
|
||||||
|
static const char*euc_kr[]={
|
||||||
|
"EUC-KR", "csEUCKR", NULL
|
||||||
|
};
|
||||||
|
static const char*iso2022jp[]={
|
||||||
|
"ISO-2022-JP", "csISO2022JP", "ISO-2022-JP-2", "csISO2022JP2", NULL
|
||||||
|
};
|
||||||
|
static const char*ibm_pc[]={
|
||||||
|
"IBM437", "cp437", "437", "csPC8CodePage437", "IBM852", "cp852", "852",
|
||||||
|
"csPCp852", "IBM863", "cp863", "863", "csIBM863", "IBM855", "cp855",
|
||||||
|
"855", "csIBM855", "IBM865", "cp865", "865", "csIBM865", "IBM866",
|
||||||
|
"cp866", "866", "csIBM866", NULL
|
||||||
|
};
|
||||||
|
static const char*ibm_ps2[]={
|
||||||
|
"IBM850", "cp850", "850", "csPC850Multilingual", "IBM00858", "CCSID00858",
|
||||||
|
"CP00858", "PC-Multilingual-850+euro", NULL
|
||||||
|
};
|
||||||
|
static const char*ibm_gr[]={
|
||||||
|
"IBM869", "cp869", "869", "cp-gr", "csIBM869", NULL
|
||||||
|
};
|
||||||
|
static const char*gb[]={
|
||||||
|
"GB2312", "csGB2312", NULL
|
||||||
|
};
|
||||||
|
static const char*utf8[]={
|
||||||
|
"UTF-8", "utf8", NULL
|
||||||
|
};
|
||||||
|
static const char*big5[]={
|
||||||
|
"Big5", "csBig5", NULL
|
||||||
|
};
|
||||||
|
static const char*viscii[]={
|
||||||
|
"VISCII", "csVISCII", NULL
|
||||||
|
};
|
||||||
|
static const char*koi8ru[]={
|
||||||
|
"KOI8-R", "csKOI8R", "KOI8-U", NULL
|
||||||
|
};
|
||||||
|
static const char*windows[]={
|
||||||
|
"ISO-8859-1-Windows-3.1-Latin-1", "csWindows31Latin1",
|
||||||
|
"ISO-8859-2-Windows-Latin-2", "csWindows31Latin2", "windows-1250",
|
||||||
|
"windows-1251", "windows-1253", "windows-1254", "windows-1255",
|
||||||
|
"windows-1256", "windows-1256", "windows-1257", NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct linedraw cstable[]={
|
||||||
|
{ latin1_3, "| ", "|--", "·--", "©",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ iso8859_789, "| ", "|--", "·--", "(c)",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ shift_jis, "\204\240 ", "\204\245", "\204\244", "(c)",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ euc_jp, "\250\242 ", "\250\247", "\250\246", "(c)",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ euc_kr, "\246\242 ", "\246\247", "\246\246", "(c)",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ iso2022jp, "\033$B(\"\033(B ", "\033$B('\033(B", "\033$B(&\033(B", "(c)",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ ibm_pc, "\263 ", "\303\304\304", "\300\304\304", "(c)",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ ibm_ps2, "\263 ", "\303\304\304", "\300\304\304", "\227",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ ibm_gr, "\263 ", "\303\304\304", "\300\304\304", "\270",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ gb, "\251\246 ", "\251\300", "\251\270", "(c)",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ utf8, "\342\224\202\302\240\302\240", "\342\224\234\342\224\200\342\224\200",
|
||||||
|
"\342\224\224\342\224\200\342\224\200", "\302\251",
|
||||||
|
" \342\216\247", " \342\216\251", " \342\216\250", " \342\216\252", " {" },
|
||||||
|
{ big5, "\242x ", "\242u", "\242|", "(c)",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ viscii, "| ", "|--", "`--", "\371",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ koi8ru, "\201 ", "\206\200\200", "\204\200\200", "\277",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ windows, "| ", "|--", "`--", "\251",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
{ NULL, "| ", "|--", "`--", "(c)",
|
||||||
|
" [", " [", " [", " [", " [" },
|
||||||
|
};
|
||||||
|
const char**s;
|
||||||
|
|
||||||
|
if (flag) {
|
||||||
|
fprintf(stderr,"tree: missing argument to --charset, valid charsets include:\n");
|
||||||
|
for(linedraw=cstable;linedraw->name;++linedraw) {
|
||||||
|
for(s=linedraw->name;*s;++s) {
|
||||||
|
fprintf(stderr," %s\n",*s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (charset) {
|
||||||
|
for(linedraw=cstable;linedraw->name;++linedraw)
|
||||||
|
for(s=linedraw->name;*s;++s)
|
||||||
|
if(!strcasecmp(charset,*s)) return;
|
||||||
|
}
|
||||||
|
linedraw=cstable+sizeof cstable/sizeof*cstable-1;
|
||||||
|
}
|
312
third_party/tree/file.c
vendored
Normal file
312
third_party/tree/file.c
vendored
Normal file
|
@ -0,0 +1,312 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/mem/alg.h"
|
||||||
|
#include "libc/sysv/consts/s.h"
|
||||||
|
#include "third_party/tree/tree.h"
|
||||||
|
|
||||||
|
extern bool dflag, Fflag, aflag, fflag, pruneflag, gitignore, showinfo;
|
||||||
|
extern bool noindent, force_color, matchdirs, fflinks;
|
||||||
|
extern bool reverse;
|
||||||
|
extern int pattern, ipattern;
|
||||||
|
|
||||||
|
extern int (*topsort)();
|
||||||
|
extern FILE *outfile;
|
||||||
|
extern int Level, *dirs, maxdirs;
|
||||||
|
|
||||||
|
extern bool colorize;
|
||||||
|
extern char *endcode;
|
||||||
|
|
||||||
|
extern char *file_comment, *file_pathsep;
|
||||||
|
|
||||||
|
/* 64K paths maximum */
|
||||||
|
#define MAXPATH 64*1024
|
||||||
|
|
||||||
|
enum ftok { T_PATHSEP, T_DIR, T_FILE, T_EOP };
|
||||||
|
|
||||||
|
char *nextpc(char **p, int *tok)
|
||||||
|
{
|
||||||
|
static char prev = 0;
|
||||||
|
char *s = *p;
|
||||||
|
if (!**p) {
|
||||||
|
*tok = T_EOP; /* Shouldn't happen. */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (prev) {
|
||||||
|
prev = 0;
|
||||||
|
*tok = T_PATHSEP;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (strchr(file_pathsep, **p) != NULL) {
|
||||||
|
(*p)++;
|
||||||
|
*tok = T_PATHSEP;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
while(**p && strchr(file_pathsep,**p) == NULL) (*p)++;
|
||||||
|
|
||||||
|
if (**p) {
|
||||||
|
*tok = T_DIR;
|
||||||
|
prev = **p;
|
||||||
|
*(*p)++ = '\0';
|
||||||
|
} else *tok = T_FILE;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _info *newent(char *name) {
|
||||||
|
struct _info *n = xmalloc(sizeof(struct _info));
|
||||||
|
memset(n,0,sizeof(struct _info));
|
||||||
|
n->name = scopy(name);
|
||||||
|
n->child = NULL;
|
||||||
|
n->tchild = n->next = NULL;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should replace this with a Red-Black tree implementation or the like */
|
||||||
|
struct _info *search(struct _info **dir, char *name)
|
||||||
|
{
|
||||||
|
struct _info *ptr, *prev, *n;
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
if (*dir == NULL) return (*dir = newent(name));
|
||||||
|
|
||||||
|
for(prev = ptr = *dir; ptr != NULL; ptr=ptr->next) {
|
||||||
|
cmp = strcmp(ptr->name,name);
|
||||||
|
if (cmp == 0) return ptr;
|
||||||
|
if (cmp > 0) break;
|
||||||
|
prev = ptr;
|
||||||
|
}
|
||||||
|
n = newent(name);
|
||||||
|
n->next = ptr;
|
||||||
|
if (prev == ptr) *dir = n;
|
||||||
|
else prev->next = n;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freefiletree(struct _info *ent)
|
||||||
|
{
|
||||||
|
struct _info *ptr = ent, *t;
|
||||||
|
|
||||||
|
while (ptr != NULL) {
|
||||||
|
if (ptr->tchild) freefiletree(ptr->tchild);
|
||||||
|
t = ptr;
|
||||||
|
ptr = ptr->next;
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively prune (unset show flag) files/directories of matches/ignored
|
||||||
|
* patterns:
|
||||||
|
*/
|
||||||
|
struct _info **fprune(struct _info *head, char *path, bool matched, bool root)
|
||||||
|
{
|
||||||
|
struct _info **dir, *new = NULL, *end = NULL, *ent, *t;
|
||||||
|
struct comment *com;
|
||||||
|
struct ignorefile *ig = NULL;
|
||||||
|
struct infofile *inf = NULL;
|
||||||
|
char *cur, *fpath = xmalloc(sizeof(char) * MAXPATH);
|
||||||
|
int i, show, count = 0;
|
||||||
|
|
||||||
|
strcpy(fpath, path);
|
||||||
|
cur = fpath + strlen(fpath);
|
||||||
|
*(cur++) = '/';
|
||||||
|
|
||||||
|
push_files(path, &ig, &inf, root);
|
||||||
|
|
||||||
|
for(ent = head; ent != NULL;) {
|
||||||
|
strcpy(cur, ent->name);
|
||||||
|
if (ent->tchild) ent->isdir = 1;
|
||||||
|
|
||||||
|
show = 1;
|
||||||
|
if (dflag && !ent->isdir) show = 0;
|
||||||
|
if (!aflag && !root && ent->name[0] == '.') show = 0;
|
||||||
|
if (show && !matched) {
|
||||||
|
if (!ent->isdir) {
|
||||||
|
if (pattern && !patinclude(ent->name, 0)) show = 0;
|
||||||
|
if (ipattern && patignore(ent->name, 0)) show = 0;
|
||||||
|
}
|
||||||
|
if (ent->isdir && show && matchdirs && pattern) {
|
||||||
|
if (patinclude(ent->name, 1)) matched = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pruneflag && !matched && ent->isdir && ent->tchild == NULL) show = 0;
|
||||||
|
if (gitignore && filtercheck(path, ent->name, ent->isdir)) show = 0;
|
||||||
|
if (show && showinfo && (com = infocheck(path, ent->name, inf != NULL, ent->isdir))) {
|
||||||
|
for(i = 0; com->desc[i] != NULL; i++);
|
||||||
|
ent->comment = xmalloc(sizeof(char *) * (i+1));
|
||||||
|
for(i = 0; com->desc[i] != NULL; i++) ent->comment[i] = scopy(com->desc[i]);
|
||||||
|
ent->comment[i] = NULL;
|
||||||
|
}
|
||||||
|
if (show && ent->tchild != NULL) ent->child = fprune(ent->tchild, fpath, matched, FALSE);
|
||||||
|
|
||||||
|
|
||||||
|
t = ent;
|
||||||
|
ent = ent->next;
|
||||||
|
if (show) {
|
||||||
|
if (end) end = end->next = t;
|
||||||
|
else new = end = t;
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
t->next = NULL;
|
||||||
|
freefiletree(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (end) end->next = NULL;
|
||||||
|
|
||||||
|
dir = xmalloc(sizeof(struct _info *) * (count+1));
|
||||||
|
for(count = 0, ent = new; ent != NULL; ent = ent->next, count++) {
|
||||||
|
dir[count] = ent;
|
||||||
|
}
|
||||||
|
dir[count] = NULL;
|
||||||
|
|
||||||
|
if (topsort) qsort(dir,count,sizeof(struct _info *),topsort);
|
||||||
|
|
||||||
|
if (ig != NULL) ig = pop_filterstack();
|
||||||
|
if (inf != NULL) inf = pop_infostack();
|
||||||
|
free(fpath);
|
||||||
|
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _info **file_getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **err)
|
||||||
|
{
|
||||||
|
FILE *fp = (strcmp(d,".")? fopen(d,"r") : stdin);
|
||||||
|
char *path, *spath, *s, *link;
|
||||||
|
struct _info *root = NULL, **cwd, *ent;
|
||||||
|
int l, tok;
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
if (fp == NULL) {
|
||||||
|
fprintf(stderr,"tree: Error opening %s for reading.\n", d);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
path = xmalloc(sizeof(char) * MAXPATH);
|
||||||
|
|
||||||
|
while(fgets(path, MAXPATH, fp) != NULL) {
|
||||||
|
if (file_comment != NULL && strncmp(path,file_comment,strlen(file_comment)) == 0) continue;
|
||||||
|
l = strlen(path);
|
||||||
|
while(l && (path[l-1] == '\n' || path[l-1] == '\r')) path[--l] = '\0';
|
||||||
|
if (l == 0) continue;
|
||||||
|
|
||||||
|
spath = path;
|
||||||
|
cwd = &root;
|
||||||
|
|
||||||
|
link = fflinks? strstr(path, " -> ") : NULL;
|
||||||
|
if (link) {
|
||||||
|
*link = '\0';
|
||||||
|
link += 4;
|
||||||
|
}
|
||||||
|
ent = NULL;
|
||||||
|
do {
|
||||||
|
s = nextpc(&spath, &tok);
|
||||||
|
if (tok == T_PATHSEP) continue;
|
||||||
|
switch(tok) {
|
||||||
|
case T_PATHSEP: continue;
|
||||||
|
case T_FILE:
|
||||||
|
case T_DIR:
|
||||||
|
/* Should probably handle '.' and '..' entries here */
|
||||||
|
ent = search(cwd, s);
|
||||||
|
/* Might be empty, but should definitely be considered a directory: */
|
||||||
|
if (tok == T_DIR) {
|
||||||
|
ent->isdir = 1;
|
||||||
|
ent->mode = S_IFDIR;
|
||||||
|
} else {
|
||||||
|
ent->mode = S_IFREG;
|
||||||
|
}
|
||||||
|
|
||||||
|
cwd = &(ent->tchild);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (tok != T_FILE && tok != T_EOP);
|
||||||
|
|
||||||
|
if (link) {
|
||||||
|
ent->isdir = 0;
|
||||||
|
ent->mode = S_IFLNK;
|
||||||
|
ent->lnk = scopy(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fp != stdin) fclose(fp);
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
/* Prune accumulated directory tree: */
|
||||||
|
return fprune(root, "", FALSE, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _info **tabedfile_getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **err)
|
||||||
|
{
|
||||||
|
FILE *fp = (strcmp(d,".")? fopen(d,"r") : stdin);
|
||||||
|
char *path, *spath, *link;
|
||||||
|
struct _info *root = NULL, **istack, *ent;
|
||||||
|
int line = 0, tabs, maxstack = 2048, top = 0, l;
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
if (fp == NULL) {
|
||||||
|
fprintf(stderr,"tree: Error opening %s for reading.\n", d);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
path = xmalloc(sizeof(char) * MAXPATH);
|
||||||
|
istack = xmalloc(sizeof(struct _info *) * maxstack);
|
||||||
|
memset(istack, 0, sizeof(struct _info *) * maxstack);
|
||||||
|
|
||||||
|
while(fgets(path, MAXPATH, fp) != NULL) {
|
||||||
|
line++;
|
||||||
|
if (file_comment != NULL && strncmp(path,file_comment,strlen(file_comment)) == 0) continue;
|
||||||
|
l = strlen(path);
|
||||||
|
while(l && (path[l-1] == '\n' || path[l-1] == '\r')) path[--l] = '\0';
|
||||||
|
if (l == 0) continue;
|
||||||
|
|
||||||
|
for(tabs=0; path[tabs] == '\t'; tabs++);
|
||||||
|
if (tabs >= maxstack) {
|
||||||
|
fprintf(stderr, "tree: Tab depth exceeds maximum path depth (%d >= %d) on line %d\n", tabs, maxstack, line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
spath = path+tabs;
|
||||||
|
|
||||||
|
link = fflinks? strstr(spath, " -> ") : NULL;
|
||||||
|
if (link) {
|
||||||
|
*link = '\0';
|
||||||
|
link += 4;
|
||||||
|
}
|
||||||
|
if (tabs-1 > top) {
|
||||||
|
fprintf(stderr, "tree: Orphaned file [%s] on line %d, check tab depth in file.\n", spath, line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ent = istack[tabs] = search(tabs? &(istack[tabs-1]->tchild) : &root, spath);
|
||||||
|
ent->mode = S_IFREG;
|
||||||
|
if (tabs) {
|
||||||
|
istack[tabs-1]->isdir = 1;
|
||||||
|
istack[tabs-1]->mode = S_IFDIR;
|
||||||
|
}
|
||||||
|
if (link) {
|
||||||
|
ent->isdir = 0;
|
||||||
|
ent->mode = S_IFLNK;
|
||||||
|
ent->lnk = scopy(link);
|
||||||
|
}
|
||||||
|
top = tabs;
|
||||||
|
}
|
||||||
|
if (fp != stdin) fclose(fp);
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
free(istack);
|
||||||
|
|
||||||
|
/* Prune accumulated directory tree: */
|
||||||
|
return fprune(root, "", FALSE, TRUE);
|
||||||
|
}
|
187
third_party/tree/filter.c
vendored
Normal file
187
third_party/tree/filter.c
vendored
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "libc/sysv/consts/s.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "third_party/tree/tree.h"
|
||||||
|
|
||||||
|
extern char xpattern[PATH_MAX];
|
||||||
|
|
||||||
|
struct ignorefile *filterstack = NULL;
|
||||||
|
|
||||||
|
void gittrim(char *s)
|
||||||
|
{
|
||||||
|
int i, e = strlen(s)-1;
|
||||||
|
|
||||||
|
if (s[e] == '\n') e--;
|
||||||
|
|
||||||
|
for(i = e; i >= 0; i--) {
|
||||||
|
if (s[i] != ' ') break;
|
||||||
|
if (i && s[i-1] != '\\') e--;
|
||||||
|
}
|
||||||
|
s[e+1] = '\0';
|
||||||
|
for(i = e = 0; s[i] != '\0';) {
|
||||||
|
if (s[i] == '\\') i++;
|
||||||
|
s[e++] = s[i++];
|
||||||
|
}
|
||||||
|
s[e] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pattern *new_pattern(char *pattern)
|
||||||
|
{
|
||||||
|
struct pattern *p = xmalloc(sizeof(struct pattern));
|
||||||
|
p->pattern = scopy(pattern + ((pattern[0] == '/')? 1 : 0));
|
||||||
|
p->relative = (strchr(pattern,'/') == NULL);
|
||||||
|
p->next = NULL;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ignorefile *new_ignorefile(char *path, bool checkparents)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
char buf[PATH_MAX], rpath[PATH_MAX];
|
||||||
|
struct ignorefile *ig;
|
||||||
|
struct pattern *remove = NULL, *remend, *p;
|
||||||
|
struct pattern *reverse = NULL, *revend;
|
||||||
|
int rev;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
rev = stat(path, &st);
|
||||||
|
if (rev < 0 || !S_ISREG(st.st_mode)) {
|
||||||
|
snprintf(buf, PATH_MAX, "%s/.gitignore", path);
|
||||||
|
fp = fopen(buf, "r");
|
||||||
|
|
||||||
|
if (fp == NULL && checkparents) {
|
||||||
|
strcpy(rpath, path);
|
||||||
|
while ((fp == NULL) && (strcmp(rpath, "/") != 0)) {
|
||||||
|
snprintf(buf, PATH_MAX, "%.*s/..", PATH_MAX-4, rpath);
|
||||||
|
if (realpath(buf, rpath) == NULL) break;
|
||||||
|
snprintf(buf, PATH_MAX, "%.*s/.gitignore", PATH_MAX-12, rpath);
|
||||||
|
fp = fopen(buf, "r");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else fp = fopen(path, "r");
|
||||||
|
if (fp == NULL) return NULL;
|
||||||
|
|
||||||
|
while (fgets(buf, PATH_MAX, fp) != NULL) {
|
||||||
|
if (buf[0] == '#') continue;
|
||||||
|
rev = (buf[0] == '!');
|
||||||
|
gittrim(buf);
|
||||||
|
if (strlen(buf) == 0) continue;
|
||||||
|
p = new_pattern(buf + (rev? 1 : 0));
|
||||||
|
if (rev) {
|
||||||
|
if (reverse == NULL) reverse = revend = p;
|
||||||
|
else {
|
||||||
|
revend->next = p;
|
||||||
|
revend = p;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (remove == NULL) remove = remend = p;
|
||||||
|
else {
|
||||||
|
remend->next = p;
|
||||||
|
remend = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
ig = xmalloc(sizeof(struct ignorefile));
|
||||||
|
ig->remove = remove;
|
||||||
|
ig->reverse = reverse;
|
||||||
|
ig->path = scopy(path);
|
||||||
|
ig->next = NULL;
|
||||||
|
|
||||||
|
return ig;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_filterstack(struct ignorefile *ig)
|
||||||
|
{
|
||||||
|
if (ig == NULL) return;
|
||||||
|
ig->next = filterstack;
|
||||||
|
filterstack = ig;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ignorefile *pop_filterstack(void)
|
||||||
|
{
|
||||||
|
struct ignorefile *ig;
|
||||||
|
struct pattern *p, *c;
|
||||||
|
|
||||||
|
ig = filterstack;
|
||||||
|
if (ig == NULL) return NULL;
|
||||||
|
|
||||||
|
filterstack = filterstack->next;
|
||||||
|
|
||||||
|
for(p=c=ig->remove; p != NULL; c = p) {
|
||||||
|
p=p->next;
|
||||||
|
free(c->pattern);
|
||||||
|
}
|
||||||
|
for(p=c=ig->reverse; p != NULL; c = p) {
|
||||||
|
p=p->next;
|
||||||
|
free(c->pattern);
|
||||||
|
}
|
||||||
|
free(ig->path);
|
||||||
|
free(ig);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true if remove filter matches and no reverse filter matches.
|
||||||
|
*/
|
||||||
|
int filtercheck(char *path, char *name, int isdir)
|
||||||
|
{
|
||||||
|
int filter = 0;
|
||||||
|
struct ignorefile *ig;
|
||||||
|
struct pattern *p;
|
||||||
|
|
||||||
|
for(ig = filterstack; !filter && ig; ig = ig->next) {
|
||||||
|
int fpos = sprintf(xpattern, "%s/", ig->path);
|
||||||
|
|
||||||
|
for(p = ig->remove; p != NULL; p = p->next) {
|
||||||
|
if (p->relative) {
|
||||||
|
if (patmatch(name, p->pattern, isdir) == 1) {
|
||||||
|
filter = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sprintf(xpattern + fpos, "%s", p->pattern);
|
||||||
|
if (patmatch(path, xpattern, isdir) == 1) {
|
||||||
|
filter = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!filter) return 0;
|
||||||
|
|
||||||
|
for(ig = filterstack; ig; ig = ig->next) {
|
||||||
|
int fpos = sprintf(xpattern, "%s/", ig->path);
|
||||||
|
|
||||||
|
for(p = ig->reverse; p != NULL; p = p->next) {
|
||||||
|
if (p->relative) {
|
||||||
|
if (patmatch(name, p->pattern, isdir) == 1) return 0;
|
||||||
|
} else {
|
||||||
|
sprintf(xpattern + fpos, "%s", p->pattern);
|
||||||
|
if (patmatch(path, xpattern, isdir) == 1) return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
116
third_party/tree/hash.c
vendored
Normal file
116
third_party/tree/hash.c
vendored
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "third_party/musl/passwd.h"
|
||||||
|
#include "third_party/tree/tree.h"
|
||||||
|
|
||||||
|
/* Faster uid/gid -> name lookup with hash(tm)(r)(c) tables! */
|
||||||
|
#define HASH(x) ((x)&255)
|
||||||
|
struct xtable *gtable[256], *utable[256];
|
||||||
|
|
||||||
|
#define inohash(x) ((x)&255)
|
||||||
|
struct inotable *itable[256];
|
||||||
|
|
||||||
|
char *uidtoname(uid_t uid)
|
||||||
|
{
|
||||||
|
struct xtable *o, *p, *t;
|
||||||
|
struct passwd *ent;
|
||||||
|
char ubuf[32];
|
||||||
|
int uent = HASH(uid);
|
||||||
|
|
||||||
|
for(o = p = utable[uent]; p ; p=p->nxt) {
|
||||||
|
if (uid == p->xid) return p->name;
|
||||||
|
else if (uid < p->xid) break;
|
||||||
|
o = p;
|
||||||
|
}
|
||||||
|
/* Not found, do a real lookup and add to table */
|
||||||
|
t = xmalloc(sizeof(struct xtable));
|
||||||
|
if ((ent = getpwuid(uid)) != NULL) t->name = scopy(ent->pw_name);
|
||||||
|
else {
|
||||||
|
snprintf(ubuf,30,"%d",uid);
|
||||||
|
ubuf[31] = 0;
|
||||||
|
t->name = scopy(ubuf);
|
||||||
|
}
|
||||||
|
t->xid = uid;
|
||||||
|
t->nxt = p;
|
||||||
|
if (p == utable[uent]) utable[uent] = t;
|
||||||
|
else o->nxt = t;
|
||||||
|
return t->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *gidtoname(gid_t gid)
|
||||||
|
{
|
||||||
|
struct xtable *o, *p, *t;
|
||||||
|
struct group *ent;
|
||||||
|
char gbuf[32];
|
||||||
|
int gent = HASH(gid);
|
||||||
|
|
||||||
|
for(o = p = gtable[gent]; p ; p=p->nxt) {
|
||||||
|
if (gid == p->xid) return p->name;
|
||||||
|
else if (gid < p->xid) break;
|
||||||
|
o = p;
|
||||||
|
}
|
||||||
|
/* Not found, do a real lookup and add to table */
|
||||||
|
t = xmalloc(sizeof(struct xtable));
|
||||||
|
if ((ent = getgrgid(gid)) != NULL) t->name = scopy(ent->gr_name);
|
||||||
|
else {
|
||||||
|
snprintf(gbuf,30,"%d",gid);
|
||||||
|
gbuf[31] = 0;
|
||||||
|
t->name = scopy(gbuf);
|
||||||
|
}
|
||||||
|
t->xid = gid;
|
||||||
|
t->nxt = p;
|
||||||
|
if (p == gtable[gent]) gtable[gent] = t;
|
||||||
|
else o->nxt = t;
|
||||||
|
return t->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Record inode numbers of followed sym-links to avoid refollowing them */
|
||||||
|
void saveino(ino_t inode, dev_t device)
|
||||||
|
{
|
||||||
|
struct inotable *it, *ip, *pp;
|
||||||
|
int hp = inohash(inode);
|
||||||
|
|
||||||
|
for(pp = ip = itable[hp];ip;ip = ip->nxt) {
|
||||||
|
if (ip->inode > inode) break;
|
||||||
|
if (ip->inode == inode && ip->device >= device) break;
|
||||||
|
pp = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip && ip->inode == inode && ip->device == device) return;
|
||||||
|
|
||||||
|
it = xmalloc(sizeof(struct inotable));
|
||||||
|
it->inode = inode;
|
||||||
|
it->device = device;
|
||||||
|
it->nxt = ip;
|
||||||
|
if (ip == itable[hp]) itable[hp] = it;
|
||||||
|
else pp->nxt = it;
|
||||||
|
}
|
||||||
|
|
||||||
|
int findino(ino_t inode, dev_t device)
|
||||||
|
{
|
||||||
|
struct inotable *it;
|
||||||
|
|
||||||
|
for(it=itable[inohash(inode)]; it; it=it->nxt) {
|
||||||
|
if (it->inode > inode) break;
|
||||||
|
if (it->inode == inode && it->device >= device) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it && it->inode == inode && it->device == device) return TRUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
264
third_party/tree/html.c
vendored
Normal file
264
third_party/tree/html.c
vendored
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "third_party/tree/tree.h"
|
||||||
|
|
||||||
|
extern char *version, *hversion;
|
||||||
|
extern bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag;
|
||||||
|
extern bool Dflag, inodeflag, devflag, Rflag, duflag, hflag, siflag;
|
||||||
|
extern bool noindent, force_color, xdev, nolinks, metafirst, noreport;
|
||||||
|
extern char *host, *sp, *title, *Hintro, *Houtro;
|
||||||
|
extern const char *charset;
|
||||||
|
|
||||||
|
extern FILE *outfile;
|
||||||
|
extern int Level, *dirs, maxdirs;
|
||||||
|
|
||||||
|
extern bool colorize, linktargetcolor;
|
||||||
|
extern char *endcode;
|
||||||
|
extern const struct linedraw *linedraw;
|
||||||
|
|
||||||
|
int htmldirlen = 0;
|
||||||
|
|
||||||
|
char *class(struct _info *info)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
info->isdir ? "DIR" :
|
||||||
|
info->isexe ? "EXEC" :
|
||||||
|
info->isfifo ? "FIFO" :
|
||||||
|
info->issok ? "SOCK" : "NORM";
|
||||||
|
}
|
||||||
|
|
||||||
|
void html_encode(FILE *fd, char *s)
|
||||||
|
{
|
||||||
|
for(;*s;s++) {
|
||||||
|
switch(*s) {
|
||||||
|
case '<':
|
||||||
|
fputs("<",fd);
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
fputs(">",fd);
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
fputs("&",fd);
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
fputs(""",fd);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fputc(*s,fd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void url_encode(FILE *fd, char *s)
|
||||||
|
{
|
||||||
|
for(;*s;s++) {
|
||||||
|
switch(*s) {
|
||||||
|
case ' ':
|
||||||
|
case '"':
|
||||||
|
case '#':
|
||||||
|
case '%':
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '^':
|
||||||
|
case '\\':
|
||||||
|
case '?':
|
||||||
|
case '+':
|
||||||
|
fprintf(fd,"%%%02X",*s);
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
fprintf(fd,"&");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(fd,isprint((u_int)*s)?"%c":"%%%02X",(u_char)*s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fcat(char *filename)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if ((fp = fopen(filename, "r")) == NULL) return;
|
||||||
|
while((n = fread(buf, sizeof(char), PATH_MAX, fp)) > 0) {
|
||||||
|
fwrite(buf, sizeof(char), n, outfile);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void html_intro(void)
|
||||||
|
{
|
||||||
|
if (Hintro) fcat(Hintro);
|
||||||
|
else {
|
||||||
|
fprintf(outfile,
|
||||||
|
"<!DOCTYPE html>\n"
|
||||||
|
"<html>\n"
|
||||||
|
"<head>\n"
|
||||||
|
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n"
|
||||||
|
" <meta name=\"Author\" content=\"Made by 'tree'\">\n"
|
||||||
|
" <meta name=\"GENERATOR\" content=\"", charset ? charset : "iso-8859-1");
|
||||||
|
print_version(FALSE);
|
||||||
|
fprintf(outfile, "\">\n"
|
||||||
|
" <title>%s</title>\n"
|
||||||
|
" <style type=\"text/css\">\n"
|
||||||
|
" BODY { font-family : monospace, sans-serif; color: black;}\n"
|
||||||
|
" P { font-family : monospace, sans-serif; color: black; margin:0px; padding: 0px;}\n"
|
||||||
|
" A:visited { text-decoration : none; margin : 0px; padding : 0px;}\n"
|
||||||
|
" A:link { text-decoration : none; margin : 0px; padding : 0px;}\n"
|
||||||
|
" A:hover { text-decoration: underline; background-color : yellow; margin : 0px; padding : 0px;}\n"
|
||||||
|
" A:active { margin : 0px; padding : 0px;}\n"
|
||||||
|
" .VERSION { font-size: small; font-family : arial, sans-serif; }\n"
|
||||||
|
" .NORM { color: black; }\n"
|
||||||
|
" .FIFO { color: purple; }\n"
|
||||||
|
" .CHAR { color: yellow; }\n"
|
||||||
|
" .DIR { color: blue; }\n"
|
||||||
|
" .BLOCK { color: yellow; }\n"
|
||||||
|
" .LINK { color: aqua; }\n"
|
||||||
|
" .SOCK { color: fuchsia;}\n"
|
||||||
|
" .EXEC { color: green; }\n"
|
||||||
|
" </style>\n"
|
||||||
|
"</head>\n"
|
||||||
|
"<body>\n"
|
||||||
|
"\t<h1>%s</h1><p>\n", title, title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void html_outtro(void)
|
||||||
|
{
|
||||||
|
if (Houtro) fcat(Houtro);
|
||||||
|
else {
|
||||||
|
fprintf(outfile,"\t<hr>\n");
|
||||||
|
fprintf(outfile,"\t<p class=\"VERSION\">\n");
|
||||||
|
fprintf(outfile,hversion,linedraw->copy, linedraw->copy, linedraw->copy, linedraw->copy);
|
||||||
|
fprintf(outfile,"\t</p>\n");
|
||||||
|
fprintf(outfile,"</body>\n");
|
||||||
|
fprintf(outfile,"</html>\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void html_print(char *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; s[i]; i++) {
|
||||||
|
if (s[i] == ' ') fprintf(outfile,"%s",sp);
|
||||||
|
else fprintf(outfile,"%c", s[i]);
|
||||||
|
}
|
||||||
|
fprintf(outfile,"%s%s", sp, sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int html_printinfo(char *dirname, struct _info *file, int level)
|
||||||
|
{
|
||||||
|
char info[512];
|
||||||
|
|
||||||
|
fillinfo(info,file);
|
||||||
|
if (metafirst) {
|
||||||
|
if (info[0] == '[') {
|
||||||
|
html_print(info);
|
||||||
|
fprintf(outfile,"%s%s", sp, sp);
|
||||||
|
}
|
||||||
|
if (!noindent) indent(level);
|
||||||
|
} else {
|
||||||
|
if (!noindent) indent(level);
|
||||||
|
if (info[0] == '[') {
|
||||||
|
html_print(info);
|
||||||
|
fprintf(outfile,"%s%s", sp, sp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* descend == add 00Tree.html to the link */
|
||||||
|
int html_printfile(char *dirname, char *filename, struct _info *file, int descend)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* Switch to using 'a' elements only. Omit href attribute if not a link */
|
||||||
|
fprintf(outfile,"<a");
|
||||||
|
if (file) {
|
||||||
|
if (force_color) fprintf(outfile," class=\"%s\"", class(file));
|
||||||
|
if (file->comment) {
|
||||||
|
fprintf(outfile," title=\"");
|
||||||
|
for(i=0; file->comment[i]; i++) {
|
||||||
|
html_encode(outfile, file->comment[i]);
|
||||||
|
if (file->comment[i+1]) fprintf(outfile, "\n");
|
||||||
|
}
|
||||||
|
fprintf(outfile, "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nolinks) {
|
||||||
|
fprintf(outfile," href=\"%s",host);
|
||||||
|
if (dirname != NULL) {
|
||||||
|
int len = strlen(dirname);
|
||||||
|
int off = (len >= htmldirlen? htmldirlen : 0);
|
||||||
|
url_encode(outfile, dirname + off);
|
||||||
|
putc('/',outfile);
|
||||||
|
url_encode(outfile, filename);
|
||||||
|
fprintf(outfile,"%s%s\"",(descend > 1? "/00Tree.html" : ""), (file->isdir?"/":""));
|
||||||
|
} else {
|
||||||
|
fprintf(outfile,"%s/\"",(descend > 1? "/00Tree.html" : ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(outfile, ">");
|
||||||
|
|
||||||
|
if (dirname) html_encode(outfile,filename);
|
||||||
|
else html_encode(outfile, host);
|
||||||
|
|
||||||
|
fprintf(outfile,"</a>");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int html_error(char *error)
|
||||||
|
{
|
||||||
|
fprintf(outfile, " [%s]", error);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void html_newline(struct _info *file, int level, int postdir, int needcomma)
|
||||||
|
{
|
||||||
|
fprintf(outfile, "<br>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void html_close(struct _info *file, int level, int needcomma)
|
||||||
|
{
|
||||||
|
fprintf(outfile, "</%s><br>\n", file->tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void html_report(struct totals tot)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
fprintf(outfile,"<br><br><p>\n\n");
|
||||||
|
|
||||||
|
if (duflag) {
|
||||||
|
psize(buf, tot.size);
|
||||||
|
fprintf(outfile,"%s%s used in ", buf, hflag || siflag? "" : " bytes");
|
||||||
|
}
|
||||||
|
if (dflag)
|
||||||
|
fprintf(outfile,"%ld director%s\n",tot.dirs,(tot.dirs==1? "y":"ies"));
|
||||||
|
else
|
||||||
|
fprintf(outfile,"%ld director%s, %ld file%s\n",tot.dirs,(tot.dirs==1? "y":"ies"),tot.files,(tot.files==1? "":"s"));
|
||||||
|
|
||||||
|
fprintf(outfile, "\n</p>\n");
|
||||||
|
}
|
200
third_party/tree/info.c
vendored
Normal file
200
third_party/tree/info.c
vendored
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "libc/sysv/consts/s.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "third_party/tree/tree.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Make a "filenote" command for info comments.
|
||||||
|
* maybe TODO: Support language extensions (i.e. .info.en, .info.gr, etc)
|
||||||
|
* # comments
|
||||||
|
* pattern
|
||||||
|
* pattern
|
||||||
|
* info messages
|
||||||
|
* more info
|
||||||
|
*/
|
||||||
|
extern FILE *outfile;
|
||||||
|
extern const struct linedraw *linedraw;
|
||||||
|
extern char xpattern[PATH_MAX];
|
||||||
|
|
||||||
|
struct infofile *infostack = NULL;
|
||||||
|
|
||||||
|
struct comment *new_comment(struct pattern *phead, char **line, int lines)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
struct comment *com = xmalloc(sizeof(struct comment));
|
||||||
|
com->pattern = phead;
|
||||||
|
com->desc = xmalloc(sizeof(char *) * (lines+1));
|
||||||
|
for(i=0; i < lines; i++) com->desc[i] = line[i];
|
||||||
|
com->desc[i] = NULL;
|
||||||
|
com->next = NULL;
|
||||||
|
return com;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct infofile *new_infofile(char *path, bool checkparents)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
char buf[PATH_MAX], rpath[PATH_MAX];
|
||||||
|
struct infofile *inf;
|
||||||
|
struct comment *chead = NULL, *cend = NULL, *com;
|
||||||
|
struct pattern *phead = NULL, *pend = NULL, *p;
|
||||||
|
char *line[PATH_MAX];
|
||||||
|
FILE *fp;
|
||||||
|
int i, lines = 0;
|
||||||
|
|
||||||
|
i = stat(path, &st);
|
||||||
|
if (i < 0 || !S_ISREG(st.st_mode)) {
|
||||||
|
snprintf(buf, PATH_MAX, "%s/.info", path);
|
||||||
|
fp = fopen(buf, "r");
|
||||||
|
|
||||||
|
if (fp == NULL && checkparents) {
|
||||||
|
strcpy(rpath, path);
|
||||||
|
while ((fp == NULL) && (strcmp(rpath, "/") != 0)) {
|
||||||
|
snprintf(buf, PATH_MAX, "%.*s/..", PATH_MAX-4, rpath);
|
||||||
|
if (realpath(buf, rpath) == NULL) break;
|
||||||
|
snprintf(buf, PATH_MAX, "%.*s/.info", PATH_MAX-7, rpath);
|
||||||
|
fp = fopen(buf, "r");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else fp = fopen(path, "r");
|
||||||
|
if (fp == NULL) return NULL;
|
||||||
|
|
||||||
|
while (fgets(buf, PATH_MAX, fp) != NULL) {
|
||||||
|
if (buf[0] == '#') continue;
|
||||||
|
gittrim(buf);
|
||||||
|
if (strlen(buf) < 1) continue;
|
||||||
|
|
||||||
|
if (buf[0] == '\t') {
|
||||||
|
line[lines++] = scopy(buf+1);
|
||||||
|
} else {
|
||||||
|
if (lines) {
|
||||||
|
/* Save previous pattern/message: */
|
||||||
|
if (phead) {
|
||||||
|
com = new_comment(phead, line, lines);
|
||||||
|
if (!chead) chead = cend = com;
|
||||||
|
else cend = cend->next = com;
|
||||||
|
} else {
|
||||||
|
/* Accumulated info message lines w/ no associated pattern? */
|
||||||
|
for(i=0; i < lines; i++) free(line[i]);
|
||||||
|
}
|
||||||
|
/* Reset for next pattern/message: */
|
||||||
|
phead = pend = NULL;
|
||||||
|
lines = 0;
|
||||||
|
}
|
||||||
|
p = new_pattern(buf);
|
||||||
|
if (phead == NULL) phead = pend = p;
|
||||||
|
else pend = pend->next = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (phead) {
|
||||||
|
com = new_comment(phead, line, lines);
|
||||||
|
if (!chead) chead = cend = com;
|
||||||
|
else cend = cend->next = com;
|
||||||
|
} else {
|
||||||
|
for(i=0; i < lines; i++) free(line[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
inf = xmalloc(sizeof(struct infofile));
|
||||||
|
inf->comments = chead;
|
||||||
|
inf->path = scopy(path);
|
||||||
|
inf->next = NULL;
|
||||||
|
|
||||||
|
return inf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_infostack(struct infofile *inf)
|
||||||
|
{
|
||||||
|
if (inf == NULL) return;
|
||||||
|
inf->next = infostack;
|
||||||
|
infostack = inf;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct infofile *pop_infostack(void)
|
||||||
|
{
|
||||||
|
struct infofile *inf;
|
||||||
|
struct comment *cn, *cc;
|
||||||
|
struct pattern *p, *c;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
inf = infostack;
|
||||||
|
if (inf == NULL) return NULL;
|
||||||
|
|
||||||
|
infostack = infostack->next;
|
||||||
|
|
||||||
|
for(cn = cc = inf->comments; cn != NULL; cc = cn) {
|
||||||
|
cn = cn->next;
|
||||||
|
for(p=c=cc->pattern; p != NULL; c = p) {
|
||||||
|
p=p->next;
|
||||||
|
free(c->pattern);
|
||||||
|
}
|
||||||
|
for(i=0; cc->desc[i] != NULL; i++) free(cc->desc[i]);
|
||||||
|
free(cc->desc);
|
||||||
|
free(cc);
|
||||||
|
}
|
||||||
|
free(inf->path);
|
||||||
|
free(inf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an info pointer if a path matches a pattern.
|
||||||
|
* top == 1 if called in a directory with a .info file.
|
||||||
|
*/
|
||||||
|
struct comment *infocheck(char *path, char *name, int top, int isdir)
|
||||||
|
{
|
||||||
|
struct infofile *inf = infostack;
|
||||||
|
struct comment *com;
|
||||||
|
struct pattern *p;
|
||||||
|
|
||||||
|
if (inf == NULL) return NULL;
|
||||||
|
|
||||||
|
for(inf = infostack; inf != NULL; inf = inf->next) {
|
||||||
|
int fpos = sprintf(xpattern, "%s/", inf->path);
|
||||||
|
|
||||||
|
for(com = inf->comments; com != NULL; com = com->next) {
|
||||||
|
for(p = com->pattern; p != NULL; p = p->next) {
|
||||||
|
if (patmatch(path, p->pattern, isdir) == 1) return com;
|
||||||
|
if (top && patmatch(name, p->pattern, isdir) == 1) return com;
|
||||||
|
|
||||||
|
sprintf(xpattern + fpos, "%s", p->pattern);
|
||||||
|
if (patmatch(path, xpattern, isdir) == 1) return com;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
top = 0;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printcomment(int line, int lines, char *s)
|
||||||
|
{
|
||||||
|
if (lines == 1) fprintf(outfile, "%s ", linedraw->csingle);
|
||||||
|
else {
|
||||||
|
if (line == 0) fprintf(outfile, "%s ", linedraw->ctop);
|
||||||
|
else if (line < 2) {
|
||||||
|
fprintf(outfile, "%s ", (lines==2)? linedraw->cbot : linedraw->cmid);
|
||||||
|
} else {
|
||||||
|
fprintf(outfile, "%s ", (line == lines-1)? linedraw->cbot : linedraw->cext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(outfile, "%s\n", s);
|
||||||
|
}
|
194
third_party/tree/json.c
vendored
Normal file
194
third_party/tree/json.c
vendored
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "libc/sysv/consts/s.h"
|
||||||
|
#include "third_party/tree/tree.h"
|
||||||
|
|
||||||
|
extern bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag;
|
||||||
|
extern bool Dflag, inodeflag, devflag, Rflag, cflag, hflag, siflag, duflag;
|
||||||
|
extern bool noindent, force_color, xdev, nolinks, noreport;
|
||||||
|
|
||||||
|
extern const int ifmt[];
|
||||||
|
extern const char fmt[], *ftype[];
|
||||||
|
|
||||||
|
extern FILE *outfile;
|
||||||
|
extern int Level, *dirs, maxdirs, errors;
|
||||||
|
|
||||||
|
extern char *endcode;
|
||||||
|
|
||||||
|
/* JSON code courtesy of Florian Sesser <fs@it-agenten.com>
|
||||||
|
[
|
||||||
|
{"type": "directory", "name": "name", "mode": "0777", "user": "user", "group": "group", "inode": ###, "dev": ####, "time": "00:00 00-00-0000", "info": "<file comment>", "contents": [
|
||||||
|
{"type": "link", "name": "name", "target": "name", "info": "...", "contents": [... if link is followed, otherwise this is empty.]}
|
||||||
|
{"type": "file", "name": "name", "mode": "0777", "size": ###, "group": "group", "inode": ###, "dev": ###, "time": "00:00 00-00-0000", "info": "..."}
|
||||||
|
{"type": "socket", "name": "", "info": "...", "error": "some error" ...}
|
||||||
|
{"type": "block", "name": "" ...},
|
||||||
|
{"type": "char", "name": "" ...},
|
||||||
|
{"type": "fifo", "name": "" ...},
|
||||||
|
{"type": "door", "name": "" ...},
|
||||||
|
{"type": "port", "name": "" ...}
|
||||||
|
]},
|
||||||
|
{"type": "report", "size": ###, "files": ###, "directories": ###}
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON encoded strings are not HTML/XML strings:
|
||||||
|
* https://tools.ietf.org/html/rfc8259#section-7
|
||||||
|
* FIXME: Still not UTF-8
|
||||||
|
*/
|
||||||
|
void json_encode(FILE *fd, char *s)
|
||||||
|
{
|
||||||
|
char *ctrl = "0-------btn-fr------------------";
|
||||||
|
|
||||||
|
for(;*s;s++) {
|
||||||
|
if ((unsigned char)*s < 32) {
|
||||||
|
if (ctrl[(unsigned char)*s] != '-') fprintf(fd, "\\%c", ctrl[(unsigned char)*s]);
|
||||||
|
else fprintf(fd, "\\u%04x", (unsigned char)*s);
|
||||||
|
} else if (*s == '"' || *s == '\\') fprintf(fd, "\\%c", *s);
|
||||||
|
else fprintf(fd, "%c", *s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_indent(int maxlevel)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fprintf(outfile, " ");
|
||||||
|
for(i=0; i<maxlevel; i++)
|
||||||
|
fprintf(outfile, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_fillinfo(struct _info *ent)
|
||||||
|
{
|
||||||
|
#ifdef __USE_FILE_OFFSET64
|
||||||
|
if (inodeflag) fprintf(outfile,",\"inode\":%lld",(long long)ent->inode);
|
||||||
|
#else
|
||||||
|
if (inodeflag) fprintf(outfile,",\"inode\":%ld",(long int)ent->inode);
|
||||||
|
#endif
|
||||||
|
if (devflag) fprintf(outfile, ",\"dev\":%d", (int)ent->dev);
|
||||||
|
#ifdef __EMX__
|
||||||
|
if (pflag) fprintf(outfile, ",\"mode\":\"%04o\",\"prot\":\"%s\"",ent->attr, prot(ent->attr));
|
||||||
|
#else
|
||||||
|
if (pflag) fprintf(outfile, ",\"mode\":\"%04o\",\"prot\":\"%s\"", ent->mode & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID|S_ISVTX), prot(ent->mode));
|
||||||
|
#endif
|
||||||
|
if (uflag) fprintf(outfile, ",\"user\":\"%s\"", uidtoname(ent->uid));
|
||||||
|
if (gflag) fprintf(outfile, ",\"group\":\"%s\"", gidtoname(ent->gid));
|
||||||
|
if (sflag) {
|
||||||
|
if (hflag || siflag) {
|
||||||
|
char nbuf[64];
|
||||||
|
int i;
|
||||||
|
psize(nbuf,ent->size);
|
||||||
|
for(i=0; isspace(nbuf[i]); i++); /* trim() hack */
|
||||||
|
fprintf(outfile, ",\"size\":\"%s\"", nbuf+i);
|
||||||
|
} else
|
||||||
|
fprintf(outfile, ",\"size\":%lld", (long long int)ent->size);
|
||||||
|
}
|
||||||
|
if (Dflag) fprintf(outfile, ",\"time\":\"%s\"", do_date(cflag? ent->ctime : ent->mtime));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void json_intro(void)
|
||||||
|
{
|
||||||
|
extern char *_nl;
|
||||||
|
fprintf(outfile, "[%s", noindent? "" : _nl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_outtro(void)
|
||||||
|
{
|
||||||
|
extern char *_nl;
|
||||||
|
fprintf(outfile, "%s]\n", noindent? "" : _nl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_printinfo(char *dirname, struct _info *file, int level)
|
||||||
|
{
|
||||||
|
mode_t mt;
|
||||||
|
int t;
|
||||||
|
|
||||||
|
if (!noindent) json_indent(level);
|
||||||
|
|
||||||
|
if (file != NULL) {
|
||||||
|
if (file->lnk) mt = file->mode & S_IFMT;
|
||||||
|
else mt = file->mode & S_IFMT;
|
||||||
|
} else mt = 0;
|
||||||
|
|
||||||
|
for(t=0;ifmt[t];t++)
|
||||||
|
if (ifmt[t] == mt) break;
|
||||||
|
fprintf(outfile,"{\"type\":\"%s\"", ftype[t]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_printfile(char *dirname, char *filename, struct _info *file, int descend)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fprintf(outfile, ",\"name\":\"");
|
||||||
|
json_encode(outfile, filename);
|
||||||
|
fputc('"',outfile);
|
||||||
|
|
||||||
|
if (file && file->comment) {
|
||||||
|
fprintf(outfile, ",\"info\":\"");
|
||||||
|
for(i=0; file->comment[i]; i++) {
|
||||||
|
json_encode(outfile, file->comment[i]);
|
||||||
|
if (file->comment[i+1]) fprintf(outfile, "\\n");
|
||||||
|
}
|
||||||
|
fprintf(outfile, "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file && file->lnk) {
|
||||||
|
fprintf(outfile, ",\"target\":\"");
|
||||||
|
json_encode(outfile, file->lnk);
|
||||||
|
fputc('"',outfile);
|
||||||
|
}
|
||||||
|
if (file) json_fillinfo(file);
|
||||||
|
|
||||||
|
if (file && file->err) fprintf(outfile, ",\"error\": \"%s\"", file->err);
|
||||||
|
if (!descend) fputc('}',outfile);
|
||||||
|
else fprintf(outfile, ",\"contents\":[");
|
||||||
|
|
||||||
|
return descend;
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_error(char *error)
|
||||||
|
{
|
||||||
|
fprintf(outfile,"{\"error\": \"%s\"}%s",error, noindent?"":"\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_newline(struct _info *file, int level, int postdir, int needcomma)
|
||||||
|
{
|
||||||
|
extern char *_nl;
|
||||||
|
|
||||||
|
fprintf(outfile, "%s%s", needcomma? "," : "", _nl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_close(struct _info *file, int level, int needcomma)
|
||||||
|
{
|
||||||
|
if (!noindent) json_indent(level);
|
||||||
|
fprintf(outfile,"]}%s%s", needcomma? ",":"", noindent? "":"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_report(struct totals tot)
|
||||||
|
{
|
||||||
|
fprintf(outfile, ",%s{\"type\":\"report\"",noindent?"":"\n ");
|
||||||
|
if (duflag) fprintf(outfile,",\"size\":%lld", (long long int)tot.size);
|
||||||
|
fprintf(outfile,",\"directories\":%ld", tot.dirs);
|
||||||
|
if (!dflag) fprintf(outfile,",\"files\":%ld", tot.files);
|
||||||
|
fprintf(outfile, "}");
|
||||||
|
}
|
275
third_party/tree/list.c
vendored
Normal file
275
third_party/tree/list.c
vendored
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "libc/mem/alg.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "third_party/tree/tree.h"
|
||||||
|
|
||||||
|
extern bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag;
|
||||||
|
extern bool Dflag, Hflag, inodeflag, devflag, Rflag, duflag, pruneflag, metafirst;
|
||||||
|
extern bool Jflag, hflag, siflag, noreport, noindent, force_color, xdev, nolinks;
|
||||||
|
|
||||||
|
extern struct _info **(*getfulltree)(char *d, u_long lev, dev_t dev, off_t *size, char **err);
|
||||||
|
extern int (*topsort)();
|
||||||
|
extern FILE *outfile;
|
||||||
|
extern int flimit, Level, *dirs, maxdirs, errors;
|
||||||
|
extern int htmldirlen;
|
||||||
|
|
||||||
|
extern bool colorize, linktargetcolor;
|
||||||
|
extern char *endcode;
|
||||||
|
extern const struct linedraw *linedraw;
|
||||||
|
|
||||||
|
static char errbuf[256];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maybe TODO: Refactor the listing calls / when they are called. A more thorough
|
||||||
|
* analysis of the different outputs is required. This all is not as clean as I
|
||||||
|
* had hoped it to be.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern struct listingcalls lc;
|
||||||
|
|
||||||
|
void null_intro(void)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void null_outtro(void)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void null_close(struct _info *file, int level, int needcomma)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void emit_tree(char **dirname, bool needfulltree)
|
||||||
|
{
|
||||||
|
struct totals tot = { 0 }, subtotal;
|
||||||
|
struct ignorefile *ig = NULL;
|
||||||
|
struct infofile *inf = NULL;
|
||||||
|
struct _info **dir = NULL, *info = NULL;
|
||||||
|
char *err;
|
||||||
|
int i, j, n, needsclosed;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
lc.intro();
|
||||||
|
|
||||||
|
for(i=0; dirname[i]; i++) {
|
||||||
|
if (fflag) {
|
||||||
|
j=strlen(dirname[i]);
|
||||||
|
do {
|
||||||
|
if (j > 1 && dirname[i][j-1] == '/') dirname[i][--j] = 0;
|
||||||
|
} while (j > 1 && dirname[i][j-1] == '/');
|
||||||
|
}
|
||||||
|
if (Hflag) htmldirlen = strlen(dirname[i]);
|
||||||
|
|
||||||
|
if ((n = lstat(dirname[i],&st)) >= 0) {
|
||||||
|
saveino(st.st_ino, st.st_dev);
|
||||||
|
info = stat2info(&st);
|
||||||
|
info->name = dirname[i];
|
||||||
|
|
||||||
|
if (needfulltree) {
|
||||||
|
dir = getfulltree(dirname[i], 0, st.st_dev, &(info->size), &err);
|
||||||
|
n = err? -1 : 0;
|
||||||
|
} else {
|
||||||
|
push_files(dirname[i], &ig, &inf, TRUE);
|
||||||
|
dir = read_dir(dirname[i], &n, inf != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
lc.printinfo(dirname[i], info, 0);
|
||||||
|
} else info = NULL;
|
||||||
|
|
||||||
|
needsclosed = lc.printfile(NULL, dirname[i], info, (dir != NULL) || (!dir && n));
|
||||||
|
subtotal = (struct totals){0, 0, 0};
|
||||||
|
if (duflag) subtotal.size = info? info->size : 0;
|
||||||
|
|
||||||
|
if (!dir && n) {
|
||||||
|
lc.error("error opening dir");
|
||||||
|
lc.newline(info, 0, 0, dirname[i+1] != NULL);
|
||||||
|
if (!info) errors++;
|
||||||
|
else subtotal.files++;
|
||||||
|
} else if (flimit > 0 && n > flimit) {
|
||||||
|
sprintf(errbuf,"%d entries exceeds filelimit, not opening dir", n);
|
||||||
|
lc.error(errbuf);
|
||||||
|
lc.newline(info, 0, 0, dirname[i+1] != NULL);
|
||||||
|
subtotal.dirs++;
|
||||||
|
} else {
|
||||||
|
lc.newline(info, 0, 0, 0);
|
||||||
|
if (dir) {
|
||||||
|
subtotal = listdir(dirname[i], dir, 1, st.st_dev, needfulltree);
|
||||||
|
subtotal.dirs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dir) {
|
||||||
|
free_dir(dir);
|
||||||
|
dir = NULL;
|
||||||
|
}
|
||||||
|
if (needsclosed) lc.close(info, 0, dirname[i+1] != NULL);
|
||||||
|
|
||||||
|
tot.files += subtotal.files;
|
||||||
|
tot.dirs += subtotal.dirs;
|
||||||
|
tot.size += subtotal.size;
|
||||||
|
// if (duflag) tot.size = info->size;
|
||||||
|
// else tot.size += st.st_size;
|
||||||
|
|
||||||
|
if (ig != NULL) ig = pop_filterstack();
|
||||||
|
if (inf != NULL) inf = pop_infostack();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!noreport) lc.report(tot);
|
||||||
|
|
||||||
|
lc.outtro();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct totals listdir(char *dirname, struct _info **dir, int lev, dev_t dev, bool hasfulltree)
|
||||||
|
{
|
||||||
|
struct totals tot = {0}, subtotal;
|
||||||
|
struct ignorefile *ig = NULL;
|
||||||
|
struct infofile *inf = NULL;
|
||||||
|
struct _info **subdir = NULL;
|
||||||
|
int namemax = 257, namelen;
|
||||||
|
int descend, htmldescend = 0, found, n, dirlen = strlen(dirname), pathlen = dirlen + 257;
|
||||||
|
int needsclosed;
|
||||||
|
char *path, *newpath, *filename, *err = NULL;
|
||||||
|
|
||||||
|
int es = (dirname[strlen(dirname) - 1] == '/');
|
||||||
|
|
||||||
|
// Sanity check on dir, may or may not be necessary when using --fromfile:
|
||||||
|
if (dir == NULL || *dir == NULL) return tot;
|
||||||
|
|
||||||
|
for(n=0; dir[n]; n++);
|
||||||
|
if (topsort) qsort(dir, n, sizeof(struct _info *), topsort);
|
||||||
|
|
||||||
|
dirs[lev] = *(dir+1)? 1 : 2;
|
||||||
|
|
||||||
|
path = xmalloc(sizeof(char) * pathlen);
|
||||||
|
|
||||||
|
for (;*dir != NULL; dir++) {
|
||||||
|
lc.printinfo(dirname, *dir, lev);
|
||||||
|
|
||||||
|
namelen = strlen((*dir)->name) + 1;
|
||||||
|
if (namemax < namelen)
|
||||||
|
path = xrealloc(path, dirlen + (namemax = namelen));
|
||||||
|
if (es) sprintf(path,"%s%s",dirname,(*dir)->name);
|
||||||
|
else sprintf(path,"%s/%s",dirname,(*dir)->name);
|
||||||
|
if (fflag) filename = path;
|
||||||
|
else filename = (*dir)->name;
|
||||||
|
|
||||||
|
descend = 0;
|
||||||
|
err = NULL;
|
||||||
|
|
||||||
|
if ((*dir)->isdir) {
|
||||||
|
tot.dirs++;
|
||||||
|
|
||||||
|
if (!hasfulltree) {
|
||||||
|
found = findino((*dir)->inode,(*dir)->dev);
|
||||||
|
if (!found) {
|
||||||
|
saveino((*dir)->inode, (*dir)->dev);
|
||||||
|
}
|
||||||
|
} else found = FALSE;
|
||||||
|
|
||||||
|
if (!(xdev && dev != (*dir)->dev) && (!(*dir)->lnk || ((*dir)->lnk && lflag))) {
|
||||||
|
descend = 1;
|
||||||
|
newpath = path;
|
||||||
|
|
||||||
|
if ((*dir)->lnk) {
|
||||||
|
if (*(*dir)->lnk == '/') newpath = (*dir)->lnk;
|
||||||
|
else {
|
||||||
|
if (fflag && !strcmp(dirname,"/")) sprintf(path,"%s%s",dirname,(*dir)->lnk);
|
||||||
|
else sprintf(path,"%s/%s",dirname,(*dir)->lnk);
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
err = "recursive, not followed";
|
||||||
|
descend = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Level >= 0) && (lev > Level)) {
|
||||||
|
if (Rflag) {
|
||||||
|
FILE *outsave = outfile;
|
||||||
|
char *paths[2] = {newpath, NULL}, *output = xmalloc(strlen(newpath) + 13);
|
||||||
|
int *dirsave = xmalloc(sizeof(int) * (lev + 2));
|
||||||
|
|
||||||
|
memcpy(dirsave, dirs, sizeof(int) * (lev+1));
|
||||||
|
sprintf(output, "%s/00Tree.html", newpath);
|
||||||
|
setoutput(output);
|
||||||
|
emit_tree(paths, hasfulltree);
|
||||||
|
|
||||||
|
free(output);
|
||||||
|
fclose(outfile);
|
||||||
|
outfile = outsave;
|
||||||
|
|
||||||
|
memcpy(dirs, dirsave, sizeof(int) * (lev+1));
|
||||||
|
free(dirsave);
|
||||||
|
htmldescend = 10;
|
||||||
|
} else htmldescend = 0;
|
||||||
|
descend = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descend > 0) {
|
||||||
|
if (hasfulltree) {
|
||||||
|
subdir = (*dir)->child;
|
||||||
|
err = (*dir)->err;
|
||||||
|
} else {
|
||||||
|
push_files(newpath, &ig, &inf, FALSE);
|
||||||
|
subdir = read_dir(newpath, &n, inf != NULL);
|
||||||
|
if (!subdir && n) {
|
||||||
|
err = "error opening dir";
|
||||||
|
errors++;
|
||||||
|
} if (flimit > 0 && n > flimit) {
|
||||||
|
sprintf(err = errbuf,"%d entries exceeds filelimit, not opening dir", n);
|
||||||
|
errors++;
|
||||||
|
free_dir(subdir);
|
||||||
|
subdir = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (subdir == NULL) descend = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else tot.files++;
|
||||||
|
|
||||||
|
needsclosed = lc.printfile(dirname, filename, *dir, descend + htmldescend + (Jflag && errors));
|
||||||
|
if (err) lc.error(err);
|
||||||
|
|
||||||
|
if (descend > 0) {
|
||||||
|
lc.newline(*dir, lev, 0, 0);
|
||||||
|
|
||||||
|
subtotal = listdir(newpath, subdir, lev+1, dev, hasfulltree);
|
||||||
|
tot.dirs += subtotal.dirs;
|
||||||
|
tot.files += subtotal.files;
|
||||||
|
tot.size += subtotal.size;
|
||||||
|
} else if (!needsclosed) lc.newline(*dir, lev, 0, *(dir+1)!=NULL);
|
||||||
|
|
||||||
|
if (subdir) {
|
||||||
|
free_dir(subdir);
|
||||||
|
subdir = NULL;
|
||||||
|
}
|
||||||
|
if (needsclosed) lc.close(*dir, descend? lev : -1, *(dir+1)!=NULL);
|
||||||
|
|
||||||
|
if (*(dir+1) && !*(dir+2)) dirs[lev] = 2;
|
||||||
|
tot.size += (*dir)->size;
|
||||||
|
|
||||||
|
if (ig != NULL) ig = pop_filterstack();
|
||||||
|
if (inf != NULL) inf = pop_infostack();
|
||||||
|
}
|
||||||
|
|
||||||
|
dirs[lev] = 0;
|
||||||
|
free(path);
|
||||||
|
return tot;
|
||||||
|
}
|
512
third_party/tree/tree.1
vendored
Normal file
512
third_party/tree/tree.1
vendored
Normal file
|
@ -0,0 +1,512 @@
|
||||||
|
.\" $Copyright: $
|
||||||
|
.\" Copyright (c) 1996 - 2022 by Steve Baker
|
||||||
|
.\" All Rights reserved
|
||||||
|
.\"
|
||||||
|
.\" 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
.\"
|
||||||
|
...
|
||||||
|
.TH TREE 1 "" "Tree 2.1.1"
|
||||||
|
.SH NAME
|
||||||
|
tree \- list contents of directories in a tree-like format.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
\fBtree\fP
|
||||||
|
[\fB-acdfghilnpqrstuvxACDFJQNSUX\fP]
|
||||||
|
[\fB-L\fP \fIlevel\fP [\fB-R\fP]]
|
||||||
|
[\fB-H\fP \fIbaseHREF\fP]
|
||||||
|
[\fB-T\fP \fItitle\fP]
|
||||||
|
[\fB-o\fP \fIfilename\fP]
|
||||||
|
[\fB-P\fP \fIpattern\fP]
|
||||||
|
[\fB-I\fP \fIpattern\fP]
|
||||||
|
[\fB--gitignore\fP]
|
||||||
|
[\fB--gitfile\fP[\fB=\fP]\fIfile\fP]
|
||||||
|
[\fB--matchdirs\fP]
|
||||||
|
[\fB--metafirst\fP]
|
||||||
|
[\fB--ignore-case\fP]
|
||||||
|
[\fB--nolinks\fP]
|
||||||
|
[\fB--hintro\fP[\fB=\fP]\fIfile\fP]
|
||||||
|
[\fB--houtro\fP[\fB=\fP]\fIfile\fP]
|
||||||
|
[\fB--inodes\fP]
|
||||||
|
[\fB--device\fP]
|
||||||
|
[\fB--sort\fP[\fB=\fP]\fIname\fP]
|
||||||
|
[\fB--dirsfirst\fP]
|
||||||
|
[\fB--filesfirst\fP]
|
||||||
|
[\fB--filelimit\fP \fI#\fP]
|
||||||
|
[\fB--si\fP]
|
||||||
|
[\fB--du\fP]
|
||||||
|
[\fB--prune\fP]
|
||||||
|
[\fB--charset[\fB=\fP]X\fP]
|
||||||
|
[\fB--timefmt\fP[\fB=\fP]\fIformat\fP]
|
||||||
|
[\fB--fromfile\fP]
|
||||||
|
[\fB--fromtabfile\fP]
|
||||||
|
[\fB--fflinks\fP]
|
||||||
|
[\fB--info\fP]
|
||||||
|
[\fB--infofile\fP[\fB=\fP]\fIfile\fP]
|
||||||
|
[\fB--noreport\fP]
|
||||||
|
[\fB--version\fP]
|
||||||
|
[\fB--help\fP]
|
||||||
|
[\fB--\fP] [\fIdirectory\fP ...]
|
||||||
|
|
||||||
|
.br
|
||||||
|
.SH DESCRIPTION
|
||||||
|
\fITree\fP is a recursive directory listing program that produces a depth
|
||||||
|
indented listing of files, which is colorized ala \fIdircolors\fP if the
|
||||||
|
\fBLS_COLORS\fP environment variable is set and output is to tty. With no
|
||||||
|
arguments, \fItree\fP lists the files in the current directory. When directory
|
||||||
|
arguments are given, \fItree\fP lists all the files and/or directories found in
|
||||||
|
the given directories each in turn. Upon completion of listing all
|
||||||
|
files/directories found, \fItree\fP returns the total number of files and/or
|
||||||
|
directories listed.
|
||||||
|
|
||||||
|
By default, when a symbolic link is encountered, the path that the symbolic
|
||||||
|
link refers to is printed after the name of the link in the format:
|
||||||
|
.br
|
||||||
|
|
||||||
|
name -> real-path
|
||||||
|
.br
|
||||||
|
|
||||||
|
If the `\fB-l\fP' option is given and the symbolic link refers to an actual
|
||||||
|
directory, then \fItree\fP will follow the path of the symbolic link as if
|
||||||
|
it were a real directory.
|
||||||
|
.br
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
\fITree\fP understands the following command line switches:
|
||||||
|
|
||||||
|
.SH LISTING OPTIONS
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B -a
|
||||||
|
All files are printed. By default tree does not print hidden files (those
|
||||||
|
beginning with a dot `.'). In no event does tree print the file system
|
||||||
|
constructs `.' (current directory) and `..' (previous directory).
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -d
|
||||||
|
List directories only.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -l
|
||||||
|
Follows symbolic links if they point to directories, as if they were
|
||||||
|
directories. Symbolic links that will result in recursion are avoided when
|
||||||
|
detected.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -f
|
||||||
|
Prints the full path prefix for each file.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -x
|
||||||
|
Stay on the current file-system only. Ala \fBfind \fI-xdev\fP.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -L \fIlevel\fP
|
||||||
|
Max display depth of the directory tree.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -R
|
||||||
|
Recursively cross down the tree each \fIlevel\fP directories (see \fB-L\fP
|
||||||
|
option), and at each level outputting to a file named \fB00Tree.html\fP
|
||||||
|
(ala \fB-o\fP).
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -P \fIpattern\fP
|
||||||
|
List only those files that match the wild-card \fIpattern\fP. You may have
|
||||||
|
multiple -P options. Note: you must use the \fI-a\fP option to also consider
|
||||||
|
those files beginning with a dot `.' for matching. Valid wildcard operators
|
||||||
|
are `*' (any zero or more characters), `**` (any zero or more characters as
|
||||||
|
well as null /'s, i.e. /**/ may match a single /), `?' (any single character),
|
||||||
|
`[...]' (any single character listed between brackets (optional - (dash) for
|
||||||
|
character range may be used: ex: [A-Z]), and `[^...]' (any single character
|
||||||
|
not listed in brackets) and `|' separates alternate patterns. A '/' at the
|
||||||
|
end of the pattern matches directories, but not files.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -I \fIpattern\fP
|
||||||
|
Do not list those files that match the wild-card \fIpattern\fP. You may have
|
||||||
|
multiple -I options. See \fI-P\fP above for information on wildcard patterns.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --gitignore
|
||||||
|
Uses git \fB.gitignore\fP files for filtering files and directories. Also
|
||||||
|
uses \fB$GIT_DIR/info/exclude\fP if present.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --gitfile\fR[\fB=\fR]\fIfile\fP
|
||||||
|
Use \fIfile\fP explicitly as a gitignore file.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --ignore-case
|
||||||
|
If a match pattern is specified by the \fB-P\fP or \fB-I\fP option, this will
|
||||||
|
cause the pattern to match without regard to the case of each letter.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --matchdirs
|
||||||
|
If a match pattern is specified by the \fB-P\fP option, this will cause the
|
||||||
|
pattern to be applied to directory names (in addition to filenames). In the
|
||||||
|
event of a match on the directory name, matching is disabled for the directory's
|
||||||
|
contents. If the \fB--prune\fP option is used, empty folders that match the
|
||||||
|
pattern will not be pruned.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --metafirst
|
||||||
|
Print the meta-data information at the beginning of the line rather than
|
||||||
|
after the indentation lines.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --prune
|
||||||
|
Makes tree prune empty directories from the output, useful when used in
|
||||||
|
conjunction with \fB-P\fP or \fB-I\fP. See \fBBUGS AND NOTES\fP below for
|
||||||
|
more information on this option.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --info
|
||||||
|
Prints file comments found in .info files. See \fB.INFO FILES\fP below
|
||||||
|
for more information on the format of .info files.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --infofile\fR[\fB=\fR]\fIfile\fP
|
||||||
|
Use \fIfile\fP explicitly as a info file.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --noreport
|
||||||
|
Omits printing of the file and directory report at the end of the tree
|
||||||
|
listing.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --charset\fR[\fB=\fR]\fIcharset\fP
|
||||||
|
Set the character set to use when outputting HTML and for line drawing.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --filelimit\fR[\fB=\fR]\fI#\fP
|
||||||
|
Do not descend directories that contain more than \fI#\fP entries.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --timefmt\fR[\fB=\fR]\fIformat\fP
|
||||||
|
Prints (implies -D) and formats the date according to the format string
|
||||||
|
which uses the \fBstrftime\fP(3) syntax.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -o \fIfilename\fP
|
||||||
|
Send output to \fIfilename\fP.
|
||||||
|
.PP
|
||||||
|
|
||||||
|
.SH FILE OPTIONS
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B -q
|
||||||
|
Print non-printable characters in filenames as question marks instead of the
|
||||||
|
default.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -N
|
||||||
|
Print non-printable characters as is instead of as escaped octal numbers.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -Q
|
||||||
|
Quote the names of files in double quotes.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -p
|
||||||
|
Print the file type and permissions for each file (as per ls -l).
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -u
|
||||||
|
Print the username, or UID # if no username is available, of the file.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -g
|
||||||
|
Print the group name, or GID # if no group name is available, of the file.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -s
|
||||||
|
Print the size of each file in bytes along with the name.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -h
|
||||||
|
Print the size of each file but in a more human readable way, e.g. appending a
|
||||||
|
size letter for kilobytes (K), megabytes (M), gigabytes (G), terabytes (T),
|
||||||
|
petabytes (P) and exabytes (E).
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --si
|
||||||
|
Like \fB-h\fP but use SI units (powers of 1000) instead.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --du
|
||||||
|
For each directory report its size as the accumulation of sizes of all its files
|
||||||
|
and sub-directories (and their files, and so on). The total amount of used
|
||||||
|
space is also given in the final report (like the 'du -c' command.) This option
|
||||||
|
requires tree to read the entire directory tree before emitting it, see
|
||||||
|
\fBBUGS AND NOTES\fP below. Implies \fB-s\fP.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -D
|
||||||
|
Print the date of the last modification time or if \fB-c\fP is used, the last
|
||||||
|
status change time for the file listed.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -F
|
||||||
|
Append a `/' for directories, a `=' for socket files, a `*' for executable
|
||||||
|
files, a `>' for doors (Solaris) and a `|' for FIFO's, as per ls -F
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --inodes
|
||||||
|
Prints the inode number of the file or directory
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --device
|
||||||
|
Prints the device number to which the file or directory belongs
|
||||||
|
.PP
|
||||||
|
|
||||||
|
.SH SORTING OPTIONS
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B -v
|
||||||
|
Sort the output by version.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -t
|
||||||
|
Sort the output by last modification time instead of alphabetically.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -c
|
||||||
|
Sort the output by last status change instead of alphabetically. Modifies the
|
||||||
|
\fB-D\fP option (if used) to print the last status change instead of
|
||||||
|
modification time.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -U
|
||||||
|
Do not sort. Lists files in directory order. Disables \fB--dirsfirst\fP.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -r
|
||||||
|
Sort the output in reverse order. This is a meta-sort that alter the above sorts.
|
||||||
|
This option is disabled when \fB-U\fP is used.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --dirsfirst
|
||||||
|
List directories before files. This is a meta-sort that alters the above sorts.
|
||||||
|
This option is disabled when \fB-U\fP is used.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --filesfirst
|
||||||
|
List files before directories. This is a meta-sort that alters the above sorts.
|
||||||
|
This option is disabled when \fB-U\fP is used.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --sort\fR[\fB=\fR]\fItype\fR
|
||||||
|
Sort the output by \fItype\fR instead of name. Possible values are:
|
||||||
|
\fBctime\fR (\fB-c\fP),
|
||||||
|
\fBmtime\fR (\fB-t\fB), \fBsize\fR, or \fBversion\fR (\fB-v\fB).
|
||||||
|
|
||||||
|
.SH GRAPHICS OPTIONS
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B -i
|
||||||
|
Makes tree not print the indentation lines, useful when used in conjunction
|
||||||
|
with the \fB-f\fP option. Also removes as much whitespace as possible when used
|
||||||
|
with the \fB-J\fP or \fB-X\fP options.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -A
|
||||||
|
Turn on ANSI line graphics hack when printing the indentation lines.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -S
|
||||||
|
Turn on CP437 line graphics (useful when using Linux console mode fonts). This
|
||||||
|
option is now equivalent to `\fB--charset=IBM437\fP' and may eventually be depreciated.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -n
|
||||||
|
Turn colorization off always, over-ridden by the \fB-C\fP option, however
|
||||||
|
overrides CLICOLOR_FORCE if present.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -C
|
||||||
|
Turn colorization on always, using built-in color defaults if the LS_COLORS or
|
||||||
|
TREE_COLORS environment variables are not set. Useful to colorize output to a
|
||||||
|
pipe.
|
||||||
|
.PP
|
||||||
|
|
||||||
|
.SH XML/JSON/HTML OPTIONS
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B -X
|
||||||
|
Turn on XML output. Outputs the directory tree as an XML formatted file.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -J
|
||||||
|
Turn on JSON output. Outputs the directory tree as a JSON formatted array.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -H \fIbaseHREF\fP
|
||||||
|
Turn on HTML output, including HTTP references. Useful for ftp sites.
|
||||||
|
\fIbaseHREF\fP gives the base ftp location when using HTML output. That is, the
|
||||||
|
local directory may be `/local/ftp/pub', but it must be referenced as
|
||||||
|
`ftp://hostname.organization.domain/pub' (\fIbaseHREF\fP should be
|
||||||
|
`ftp://hostname.organization.domain'). Hint: don't use ANSI lines with this
|
||||||
|
option, and don't give more than one directory in the directory list. If you
|
||||||
|
wish to use colors via CSS style-sheet, use the -C option in addition to this
|
||||||
|
option to force color output.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --hintro\fR[\fB=\fR]\fIfile\fP
|
||||||
|
Use \fIfile\fP as the HTML intro in place of the default one. Use an empty
|
||||||
|
file or \fI/dev/null\fP to eliminate the intro altogether.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --houtro\fR[\fB=\fR]\fIfile\fP
|
||||||
|
Use \fIfile\fP as the HTML outro in place of the default one. Use an empty
|
||||||
|
file or \fI/dev/null\fP to eliminate the outro altogether.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B -T \fItitle\fP
|
||||||
|
Sets the title and H1 header string in HTML output mode.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --nolinks
|
||||||
|
Turns off hyperlinks in HTML output.
|
||||||
|
.PP
|
||||||
|
|
||||||
|
.SH INPUT OPTIONS
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B --fromfile
|
||||||
|
Reads a directory listing from a file rather than the file-system. Paths
|
||||||
|
provided on the command line are files to read from rather than directories to
|
||||||
|
search. The dot (.) directory indicates that tree should read paths from
|
||||||
|
standard input. NOTE: this is only suitable for reading the output of a program
|
||||||
|
such as find, not 'tree -fi' as symlinks are not distinguished from files that
|
||||||
|
simply contain ' -> ' as part of the filename unless the \fB--fflinks\fP option
|
||||||
|
is used.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --fromtabfile
|
||||||
|
Like \fB--fromfile\fP, tree reads a directory tree from a text file where the
|
||||||
|
files are tab indented in a tree like format to indicate the directory nesting
|
||||||
|
level.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --fflinks
|
||||||
|
Processes symbolic link information found in a file, as from the output of
|
||||||
|
\fB'tree -fi --noreport'\fP. Only the first occurrence of the string \fB' -> '\fP
|
||||||
|
is used to denote the separation of the filename from the link.
|
||||||
|
.PP
|
||||||
|
|
||||||
|
.SH MISC OPTIONS
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B --help
|
||||||
|
Outputs a verbose usage listing.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --version
|
||||||
|
Outputs the version of tree.
|
||||||
|
.PP
|
||||||
|
.TP
|
||||||
|
.B --
|
||||||
|
Option processing terminator. No further options will be processed after this.
|
||||||
|
.PP
|
||||||
|
|
||||||
|
.SH .INFO FILES
|
||||||
|
|
||||||
|
\fB.info\fP files are similar to \.gitignore files, if a .info file is found
|
||||||
|
while scanning a directory it is read and added to a stack of .info
|
||||||
|
information. Each file is composed of comments (lines starting with hash marks
|
||||||
|
(#),) or wild-card patterns which may match a file relative to the directory
|
||||||
|
the \.info file is found in. If a file should match a pattern, the tab indented
|
||||||
|
comment that follows the pattern is used as the file comment. A comment is
|
||||||
|
terminated by a non-tab indented line. Multiple patterns, each to a line, may
|
||||||
|
share the same comment.
|
||||||
|
|
||||||
|
.br
|
||||||
|
.SH FILES
|
||||||
|
\fB/etc/DIR_COLORS\fP System color database.
|
||||||
|
.br
|
||||||
|
\fB~/.dircolors\fP Users color database.
|
||||||
|
.br
|
||||||
|
\fB.gitignore\fP Git exclusion file
|
||||||
|
.br
|
||||||
|
\fB$GIT_DIR/info/exclude\fP Global git file exclusion list
|
||||||
|
.br
|
||||||
|
\fB.info\fP File comment file
|
||||||
|
.br
|
||||||
|
\fB/usr/share/finfo/global_info\fP Global file comment file
|
||||||
|
|
||||||
|
|
||||||
|
.SH ENVIRONMENT
|
||||||
|
\fBLS_COLORS\fP Color information created by dircolors
|
||||||
|
.br
|
||||||
|
\fBTREE_COLORS\fP Uses this for color information over LS_COLORS if it is set.
|
||||||
|
.br
|
||||||
|
\fBTREE_CHARSET\fP Character set for tree to use in HTML mode.
|
||||||
|
.br
|
||||||
|
\fBCLICOLOR\fP Enables colorization even if TREE_COLORS or LS_COLORS is not set.
|
||||||
|
.br
|
||||||
|
\fBCLICOLOR_FORCE\fP Always enables colorization (effectively -C)
|
||||||
|
.br
|
||||||
|
\fBNO_COLOR\fP Disable colorization (effectively -n) (see \fBhttps://no-color.org/\fP)
|
||||||
|
.br
|
||||||
|
\fBLC_CTYPE\fP Locale for filename output.
|
||||||
|
.br
|
||||||
|
\fBLC_TIME\fP Locale for timefmt output, see \fBstrftime\fP(3).
|
||||||
|
.br
|
||||||
|
\fBTZ\fP Timezone for timefmt output, see \fBstrftime\fP(3).
|
||||||
|
.br
|
||||||
|
\fBSTDDATA_FD\fP Enable the stddata feature, optionally set descriptor to use.
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
Steve Baker (ice@mama.indstate.edu)
|
||||||
|
.br
|
||||||
|
HTML output hacked by Francesc Rocher (rocher@econ.udg.es)
|
||||||
|
.br
|
||||||
|
Charsets and OS/2 support by Kyosuke Tokoro (NBG01720@nifty.ne.jp)
|
||||||
|
|
||||||
|
.SH BUGS AND NOTES
|
||||||
|
Tree does not prune "empty" directories when the -P and -I options are used by
|
||||||
|
default. Use the --prune option.
|
||||||
|
|
||||||
|
The -h and --si options round to the nearest whole number unlike the ls
|
||||||
|
implementations which rounds up always.
|
||||||
|
|
||||||
|
Pruning files and directories with the -I, -P and --filelimit options will
|
||||||
|
lead to incorrect file/directory count reports.
|
||||||
|
|
||||||
|
The --prune and --du options cause tree to accumulate the entire tree in memory
|
||||||
|
before emitting it. For large directory trees this can cause a significant delay
|
||||||
|
in output and the use of large amounts of memory.
|
||||||
|
|
||||||
|
The timefmt expansion buffer is limited to a ridiculously large 255 characters.
|
||||||
|
Output of time strings longer than this will be undefined, but are guaranteed
|
||||||
|
to not exceed 255 characters.
|
||||||
|
|
||||||
|
XML/JSON trees are not colored, which is a bit of a shame.
|
||||||
|
|
||||||
|
Probably more.
|
||||||
|
|
||||||
|
As of version 2.0.0, in Linux, tree will attempt to automatically output a
|
||||||
|
compact JSON tree on file descriptor 3 (what I call stddata,) if present and the
|
||||||
|
environment variable STDDATA_FD is defined or set to a positive non-zero file
|
||||||
|
descriptor value to use to output on. It is hoped that some day a better
|
||||||
|
Linux/Unix shell may take advantage of this feature, though BSON would probably
|
||||||
|
be a better format for this.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR dircolors (1),
|
||||||
|
.BR ls (1),
|
||||||
|
.BR find (1),
|
||||||
|
.BR du (1),
|
||||||
|
.BR strftime (3)
|
||||||
|
.BR gitignore (5)
|
1465
third_party/tree/tree.c
vendored
Normal file
1465
third_party/tree/tree.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
264
third_party/tree/tree.h
vendored
Normal file
264
third_party/tree/tree.h
vendored
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "libc/calls/weirdtypes.h"
|
||||||
|
#include "libc/calls/typedef/u.h"
|
||||||
|
#include "libc/calls/struct/stat.h"
|
||||||
|
#include "libc/stdio/internal.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
|
#ifdef __ANDROID
|
||||||
|
#define mbstowcs(w,m,x) mbsrtowcs(w,(const char**)(& #m),x,NULL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Start using PATH_MAX instead of the magic number 4096 everywhere. */
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef INFO_PATH
|
||||||
|
#define INFO_PATH "/usr/share/finfo/global_info"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ENV_STDDATA_FD "STDDATA_FD"
|
||||||
|
#define STDDATA_FILENO 3
|
||||||
|
|
||||||
|
/* Should probably use strdup(), but we like our xmalloc() */
|
||||||
|
#define scopy(x) strcpy(xmalloc(strlen(x)+1),(x))
|
||||||
|
#define MINIT 30 /* number of dir entries to initially allocate */
|
||||||
|
#define MINC 20 /* allocation increment */
|
||||||
|
|
||||||
|
struct _info {
|
||||||
|
char *name;
|
||||||
|
char *lnk;
|
||||||
|
bool isdir;
|
||||||
|
bool issok;
|
||||||
|
bool isfifo;
|
||||||
|
bool isexe;
|
||||||
|
bool orphan;
|
||||||
|
mode_t mode, lnkmode;
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
off_t size;
|
||||||
|
time_t atime, ctime, mtime;
|
||||||
|
dev_t dev, ldev;
|
||||||
|
ino_t inode, linode;
|
||||||
|
#ifdef __EMX__
|
||||||
|
long attr;
|
||||||
|
#endif
|
||||||
|
char *err;
|
||||||
|
const char *tag;
|
||||||
|
char **comment;
|
||||||
|
struct _info **child, *next, *tchild;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* list.c */
|
||||||
|
struct totals {
|
||||||
|
u_long files, dirs;
|
||||||
|
off_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct listingcalls {
|
||||||
|
void (*intro)(void);
|
||||||
|
void (*outtro)(void);
|
||||||
|
int (*printinfo)(char *dirname, struct _info *file, int level);
|
||||||
|
int (*printfile)(char *dirname, char *filename, struct _info *file, int descend);
|
||||||
|
int (*error)(char *error);
|
||||||
|
void (*newline)(struct _info *file, int level, int postdir, int needcomma);
|
||||||
|
void (*close)(struct _info *file, int level, int needcomma);
|
||||||
|
void (*report)(struct totals tot);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* hash.c */
|
||||||
|
struct xtable {
|
||||||
|
unsigned int xid;
|
||||||
|
char *name;
|
||||||
|
struct xtable *nxt;
|
||||||
|
};
|
||||||
|
struct inotable {
|
||||||
|
ino_t inode;
|
||||||
|
dev_t device;
|
||||||
|
struct inotable *nxt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* color.c */
|
||||||
|
struct colortable {
|
||||||
|
char *term_flg, *CSS_name, *font_fg, *font_bg;
|
||||||
|
};
|
||||||
|
struct extensions {
|
||||||
|
char *ext;
|
||||||
|
char *term_flg, *CSS_name, *web_fg, *web_bg, *web_extattr;
|
||||||
|
struct extensions *nxt;
|
||||||
|
};
|
||||||
|
struct linedraw {
|
||||||
|
const char **name, *vert, *vert_left, *corner, *copy;
|
||||||
|
const char *ctop, *cbot, *cmid, *cext, *csingle;
|
||||||
|
};
|
||||||
|
struct meta_ids {
|
||||||
|
char *name;
|
||||||
|
char *term_flg;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* filter.c */
|
||||||
|
struct pattern {
|
||||||
|
char *pattern;
|
||||||
|
int relative;
|
||||||
|
struct pattern *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ignorefile {
|
||||||
|
char *path;
|
||||||
|
struct pattern *remove, *reverse;
|
||||||
|
struct ignorefile *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* info.c */
|
||||||
|
struct comment {
|
||||||
|
struct pattern *pattern;
|
||||||
|
char **desc;
|
||||||
|
struct comment *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct infofile {
|
||||||
|
char *path;
|
||||||
|
struct comment *comments;
|
||||||
|
struct infofile *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Function prototypes: */
|
||||||
|
/* tree.c */
|
||||||
|
void setoutput(char *filename);
|
||||||
|
void print_version(int nl);
|
||||||
|
void usage(int);
|
||||||
|
void push_files(char *dir, struct ignorefile **ig, struct infofile **inf, bool top);
|
||||||
|
int patignore(char *name, int isdir);
|
||||||
|
int patinclude(char *name, int isdir);
|
||||||
|
struct _info **unix_getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **err);
|
||||||
|
struct _info **read_dir(char *dir, int *n, int infotop);
|
||||||
|
|
||||||
|
int filesfirst(struct _info **, struct _info **);
|
||||||
|
int dirsfirst(struct _info **, struct _info **);
|
||||||
|
int alnumsort(struct _info **, struct _info **);
|
||||||
|
int versort(struct _info **a, struct _info **b);
|
||||||
|
int reversealnumsort(struct _info **, struct _info **);
|
||||||
|
int mtimesort(struct _info **, struct _info **);
|
||||||
|
int ctimesort(struct _info **, struct _info **);
|
||||||
|
int sizecmp(off_t a, off_t b);
|
||||||
|
int fsizesort(struct _info **a, struct _info **b);
|
||||||
|
|
||||||
|
void *xmalloc(size_t), *xrealloc(void *, size_t);
|
||||||
|
char *gnu_getcwd();
|
||||||
|
int patmatch(char *, char *, int);
|
||||||
|
void indent(int maxlevel);
|
||||||
|
void free_dir(struct _info **);
|
||||||
|
#ifdef __EMX__
|
||||||
|
char *prot(long);
|
||||||
|
#else
|
||||||
|
char *prot(mode_t);
|
||||||
|
#endif
|
||||||
|
char *do_date(time_t);
|
||||||
|
void printit(char *);
|
||||||
|
int psize(char *buf, off_t size);
|
||||||
|
char Ftype(mode_t mode);
|
||||||
|
struct _info *stat2info(struct stat *st);
|
||||||
|
char *fillinfo(char *buf, struct _info *ent);
|
||||||
|
|
||||||
|
/* list.c */
|
||||||
|
void null_intro(void);
|
||||||
|
void null_outtro(void);
|
||||||
|
void null_close(struct _info *file, int level, int needcomma);
|
||||||
|
void emit_tree(char **dirname, bool needfulltree);
|
||||||
|
struct totals listdir(char *dirname, struct _info **dir, int lev, dev_t dev, bool hasfulltree);
|
||||||
|
|
||||||
|
/* unix.c */
|
||||||
|
int unix_printinfo(char *dirname, struct _info *file, int level);
|
||||||
|
int unix_printfile(char *dirname, char *filename, struct _info *file, int descend);
|
||||||
|
int unix_error(char *error);
|
||||||
|
void unix_newline(struct _info *file, int level, int postdir, int needcomma);
|
||||||
|
void unix_report(struct totals tot);
|
||||||
|
|
||||||
|
/* html.c */
|
||||||
|
void html_intro(void);
|
||||||
|
void html_outtro(void);
|
||||||
|
int html_printinfo(char *dirname, struct _info *file, int level);
|
||||||
|
int html_printfile(char *dirname, char *filename, struct _info *file, int descend);
|
||||||
|
int html_error(char *error);
|
||||||
|
void html_newline(struct _info *file, int level, int postdir, int needcomma);
|
||||||
|
void html_close(struct _info *file, int level, int needcomma);
|
||||||
|
void html_report(struct totals tot);
|
||||||
|
void html_encode(FILE *fd, char *s);
|
||||||
|
|
||||||
|
/* xml.c */
|
||||||
|
void xml_intro(void);
|
||||||
|
void xml_outtro(void);
|
||||||
|
int xml_printinfo(char *dirname, struct _info *file, int level);
|
||||||
|
int xml_printfile(char *dirname, char *filename, struct _info *file, int descend);
|
||||||
|
int xml_error(char *error);
|
||||||
|
void xml_newline(struct _info *file, int level, int postdir, int needcomma);
|
||||||
|
void xml_close(struct _info *file, int level, int needcomma);
|
||||||
|
void xml_report(struct totals tot);
|
||||||
|
|
||||||
|
/* json.c */
|
||||||
|
void json_indent(int maxlevel);
|
||||||
|
void json_fillinfo(struct _info *ent);
|
||||||
|
void json_intro(void);
|
||||||
|
void json_outtro(void);
|
||||||
|
int json_printinfo(char *dirname, struct _info *file, int level);
|
||||||
|
int json_printfile(char *dirname, char *filename, struct _info *file, int descend);
|
||||||
|
int json_error(char *error);
|
||||||
|
void json_newline(struct _info *file, int level, int postdir, int needcomma);
|
||||||
|
void json_close(struct _info *file, int level, int needcomma);
|
||||||
|
void json_report(struct totals tot);
|
||||||
|
|
||||||
|
/* color.c */
|
||||||
|
void parse_dir_colors();
|
||||||
|
int color(u_short mode, char *name, bool orphan, bool islink);
|
||||||
|
void endcolor(void);
|
||||||
|
const char *getcharset(void);
|
||||||
|
void initlinedraw(int);
|
||||||
|
|
||||||
|
/* hash.c */
|
||||||
|
char *uidtoname(uid_t uid);
|
||||||
|
char *gidtoname(gid_t gid);
|
||||||
|
int findino(ino_t, dev_t);
|
||||||
|
void saveino(ino_t, dev_t);
|
||||||
|
|
||||||
|
/* file.c */
|
||||||
|
struct _info **file_getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **err);
|
||||||
|
struct _info **tabedfile_getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **err);
|
||||||
|
|
||||||
|
/* filter.c */
|
||||||
|
void gittrim(char *s);
|
||||||
|
struct pattern *new_pattern(char *pattern);
|
||||||
|
int filtercheck(char *path, char *name, int isdir);
|
||||||
|
struct ignorefile *new_ignorefile(char *path, bool checkparents);
|
||||||
|
void push_filterstack(struct ignorefile *ig);
|
||||||
|
struct ignorefile *pop_filterstack(void);
|
||||||
|
|
||||||
|
/* info.c */
|
||||||
|
struct infofile *new_infofile(char *path, bool checkparents);
|
||||||
|
void push_infostack(struct infofile *inf);
|
||||||
|
struct infofile *pop_infostack(void);
|
||||||
|
struct comment *infocheck(char *path, char *name, int top, int isdir);
|
||||||
|
void printcomment(int line, int lines, char *s);
|
||||||
|
|
||||||
|
/* list.c */
|
||||||
|
void new_emit_unix(char **dirname, bool needfulltree);
|
58
third_party/tree/tree.mk
vendored
Normal file
58
third_party/tree/tree.mk
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||||
|
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||||
|
|
||||||
|
PKGS += THIRD_PARTY_TREE
|
||||||
|
|
||||||
|
THIRD_PARTY_TREE = $(THIRD_PARTY_TREE_A_DEPS) $(THIRD_PARTY_TREE_A)
|
||||||
|
THIRD_PARTY_TREE_A = o/$(MODE)/third_party/tree/tree.a
|
||||||
|
THIRD_PARTY_TREE_FILES := $(wildcard third_party/tree/*)
|
||||||
|
THIRD_PARTY_TREE_HDRS = $(filter %.h,$(THIRD_PARTY_TREE_FILES))
|
||||||
|
THIRD_PARTY_TREE_INCS = $(filter %.inc,$(THIRD_PARTY_TREE_FILES))
|
||||||
|
THIRD_PARTY_TREE_SRCS = $(filter %.c,$(THIRD_PARTY_TREE_FILES))
|
||||||
|
THIRD_PARTY_TREE_OBJS = $(THIRD_PARTY_TREE_SRCS:%.c=o/$(MODE)/%.o)
|
||||||
|
|
||||||
|
THIRD_PARTY_TREE_A_DIRECTDEPS = \
|
||||||
|
LIBC_CALLS \
|
||||||
|
LIBC_FMT \
|
||||||
|
LIBC_INTRIN \
|
||||||
|
LIBC_MEM \
|
||||||
|
LIBC_NEXGEN32E \
|
||||||
|
LIBC_RUNTIME \
|
||||||
|
LIBC_STDIO \
|
||||||
|
LIBC_STR \
|
||||||
|
LIBC_SYSV \
|
||||||
|
LIBC_TIME \
|
||||||
|
THIRD_PARTY_MUSL
|
||||||
|
|
||||||
|
THIRD_PARTY_TREE_A_DEPS := \
|
||||||
|
$(call uniq,$(foreach x,$(THIRD_PARTY_TREE_A_DIRECTDEPS),$($(x))))
|
||||||
|
|
||||||
|
THIRD_PARTY_TREE_CHECKS = \
|
||||||
|
$(THIRD_PARTY_TREE_A).pkg \
|
||||||
|
$(THIRD_PARTY_TREE_HDRS:%=o/$(MODE)/%.ok)
|
||||||
|
|
||||||
|
$(THIRD_PARTY_TREE_A): \
|
||||||
|
third_party/tree/ \
|
||||||
|
$(THIRD_PARTY_TREE_A).pkg \
|
||||||
|
$(THIRD_PARTY_TREE_OBJS)
|
||||||
|
|
||||||
|
$(THIRD_PARTY_TREE_A).pkg: \
|
||||||
|
$(THIRD_PARTY_TREE_OBJS) \
|
||||||
|
$(foreach x,$(THIRD_PARTY_TREE_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||||
|
|
||||||
|
o/$(MODE)/third_party/tree/tree.com.dbg: \
|
||||||
|
$(THIRD_PARTY_TREE) \
|
||||||
|
o/$(MODE)/third_party/tree/cmd.o \
|
||||||
|
$(CRT) \
|
||||||
|
$(APE_NO_MODIFY_SELF)
|
||||||
|
@$(APELINK)
|
||||||
|
|
||||||
|
THIRD_PARTY_TREE_BINS = $(THIRD_PARTY_TREE_COMS) $(THIRD_PARTY_TREE_COMS:%=%.dbg)
|
||||||
|
THIRD_PARTY_TREE_COMS = o/$(MODE)/third_party/tree/tree.com
|
||||||
|
THIRD_PARTY_TREE_LIBS = $(THIRD_PARTY_TREE_A)
|
||||||
|
$(THIRD_PARTY_TREE_OBJS): $(BUILD_FILES) third_party/tree/tree.mk
|
||||||
|
|
||||||
|
.PHONY: o/$(MODE)/third_party/tree
|
||||||
|
o/$(MODE)/third_party/tree: \
|
||||||
|
$(THIRD_PARTY_TREE_BINS) \
|
||||||
|
$(THIRD_PARTY_TREE_CHECKS)
|
112
third_party/tree/unix.c
vendored
Normal file
112
third_party/tree/unix.c
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "third_party/tree/tree.h"
|
||||||
|
|
||||||
|
extern FILE *outfile;
|
||||||
|
extern bool dflag, Fflag, duflag, metafirst, hflag, siflag, noindent;
|
||||||
|
extern bool colorize, linktargetcolor;
|
||||||
|
extern const struct linedraw *linedraw;
|
||||||
|
extern int *dirs;
|
||||||
|
|
||||||
|
static char info[512] = {0};
|
||||||
|
|
||||||
|
int unix_printinfo(char *dirname, struct _info *file, int level)
|
||||||
|
{
|
||||||
|
fillinfo(info, file);
|
||||||
|
if (metafirst) {
|
||||||
|
if (info[0] == '[') fprintf(outfile, "%s ",info);
|
||||||
|
if (!noindent) indent(level);
|
||||||
|
} else {
|
||||||
|
if (!noindent) indent(level);
|
||||||
|
if (info[0] == '[') fprintf(outfile, "%s ",info);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int unix_printfile(char *dirname, char *filename, struct _info *file, int descend)
|
||||||
|
{
|
||||||
|
int colored = FALSE, c;
|
||||||
|
|
||||||
|
if (file && colorize) {
|
||||||
|
if (file->lnk && linktargetcolor) colored = color(file->lnkmode,file->name,file->orphan,FALSE);
|
||||||
|
else colored = color(file->mode,file->name,file->orphan,FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
printit(filename);
|
||||||
|
|
||||||
|
if (colored) endcolor();
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
if (Fflag && !file->lnk) {
|
||||||
|
if ((c = Ftype(file->mode))) fputc(c, outfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file->lnk) {
|
||||||
|
fprintf(outfile," -> ");
|
||||||
|
if (colorize) colored = color(file->lnkmode,file->lnk,file->orphan,TRUE);
|
||||||
|
printit(file->lnk);
|
||||||
|
if (colored) endcolor();
|
||||||
|
if (Fflag) {
|
||||||
|
if ((c = Ftype(file->lnkmode))) fputc(c, outfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int unix_error(char *error)
|
||||||
|
{
|
||||||
|
fprintf(outfile, " [%s]", error);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unix_newline(struct _info *file, int level, int postdir, int needcomma)
|
||||||
|
{
|
||||||
|
if (postdir <= 0) fprintf(outfile, "\n");
|
||||||
|
if (file && file->comment) {
|
||||||
|
int infosize = 0, line, lines;
|
||||||
|
if (metafirst) infosize = info[0] == '['? strlen(info)+2 : 0;
|
||||||
|
|
||||||
|
for(lines = 0; file->comment[lines]; lines++);
|
||||||
|
dirs[level+1] = 1;
|
||||||
|
for(line = 0; line < lines; line++) {
|
||||||
|
if (metafirst) {
|
||||||
|
printf("%*s", infosize, "");
|
||||||
|
}
|
||||||
|
indent(level);
|
||||||
|
printcomment(line, lines, file->comment[line]);
|
||||||
|
}
|
||||||
|
dirs[level+1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unix_report(struct totals tot)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
fputc('\n', outfile);
|
||||||
|
if (duflag) {
|
||||||
|
psize(buf, tot.size);
|
||||||
|
fprintf(outfile,"%s%s used in ", buf, hflag || siflag? "" : " bytes");
|
||||||
|
}
|
||||||
|
if (dflag)
|
||||||
|
fprintf(outfile,"%ld director%s\n",tot.dirs,(tot.dirs==1? "y":"ies"));
|
||||||
|
else
|
||||||
|
fprintf(outfile,"%ld director%s, %ld file%s\n",tot.dirs,(tot.dirs==1? "y":"ies"),tot.files,(tot.files==1? "":"s"));
|
||||||
|
}
|
177
third_party/tree/xml.c
vendored
Normal file
177
third_party/tree/xml.c
vendored
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
// clang-format off
|
||||||
|
/* $Copyright: $
|
||||||
|
* Copyright (c) 1996 - 2023 by Steve Baker (ice@mama.indstate.edu)
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "libc/sysv/consts/s.h"
|
||||||
|
#include "third_party/tree/tree.h"
|
||||||
|
|
||||||
|
extern bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag;
|
||||||
|
extern bool Dflag, inodeflag, devflag, Rflag, cflag, duflag, siflag;
|
||||||
|
extern bool noindent, force_color, xdev, nolinks, noreport;
|
||||||
|
extern const char *charset;
|
||||||
|
|
||||||
|
extern const int ifmt[];
|
||||||
|
extern const char fmt[], *ftype[];
|
||||||
|
|
||||||
|
extern FILE *outfile;
|
||||||
|
extern int Level, *dirs, maxdirs, errors;
|
||||||
|
|
||||||
|
extern char *endcode;
|
||||||
|
|
||||||
|
extern struct listingcalls lc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
<tree>
|
||||||
|
<directory name="name" mode=0777 size=### user="user" group="group" inode=### dev=### time="00:00 00-00-0000">
|
||||||
|
<link name="name" target="name" ...>
|
||||||
|
... if link is followed, otherwise this is empty.
|
||||||
|
</link>
|
||||||
|
<file name="name" mode=0777 size=### user="user" group="group" inode=### dev=### time="00:00 00-00-0000"></file>
|
||||||
|
<socket name="" ...><error>some error</error></socket>
|
||||||
|
<block name="" ...></block>
|
||||||
|
<char name="" ...></char>
|
||||||
|
<fifo name="" ...></fifo>
|
||||||
|
<door name="" ...></door>
|
||||||
|
<port name="" ...></port>
|
||||||
|
...
|
||||||
|
</directory>
|
||||||
|
<report>
|
||||||
|
<size>#</size>
|
||||||
|
<files>#</files>
|
||||||
|
<directories>#</directories>
|
||||||
|
</report>
|
||||||
|
</tree>
|
||||||
|
*/
|
||||||
|
|
||||||
|
void xml_indent(int maxlevel)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fprintf(outfile, " ");
|
||||||
|
for(i=0; i<maxlevel; i++)
|
||||||
|
fprintf(outfile, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
void xml_fillinfo(struct _info *ent)
|
||||||
|
{
|
||||||
|
#ifdef __USE_FILE_OFFSET64
|
||||||
|
if (inodeflag) fprintf(outfile," inode=\"%lld\"",(long long)ent->inode);
|
||||||
|
#else
|
||||||
|
if (inodeflag) fprintf(outfile," inode=\"%ld\"",(long int)ent->inode);
|
||||||
|
#endif
|
||||||
|
if (devflag) fprintf(outfile, " dev=\"%d\"", (int)ent->dev);
|
||||||
|
#ifdef __EMX__
|
||||||
|
if (pflag) fprintf(outfile, " mode=\"%04o\" prot=\"%s\"",ent->attr, prot(ent->attr));
|
||||||
|
#else
|
||||||
|
if (pflag) fprintf(outfile, " mode=\"%04o\" prot=\"%s\"", ent->mode & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID|S_ISVTX), prot(ent->mode));
|
||||||
|
#endif
|
||||||
|
if (uflag) fprintf(outfile, " user=\"%s\"", uidtoname(ent->uid));
|
||||||
|
if (gflag) fprintf(outfile, " group=\"%s\"", gidtoname(ent->gid));
|
||||||
|
if (sflag) fprintf(outfile, " size=\"%lld\"", (long long int)(ent->size));
|
||||||
|
if (Dflag) fprintf(outfile, " time=\"%s\"", do_date(cflag? ent->ctime : ent->mtime));
|
||||||
|
}
|
||||||
|
|
||||||
|
void xml_intro(void)
|
||||||
|
{
|
||||||
|
extern char *_nl;
|
||||||
|
|
||||||
|
fprintf(outfile,"<?xml version=\"1.0\"");
|
||||||
|
if (charset) fprintf(outfile," encoding=\"%s\"",charset);
|
||||||
|
fprintf(outfile,"?>%s<tree>%s",_nl,_nl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xml_outtro(void)
|
||||||
|
{
|
||||||
|
fprintf(outfile,"</tree>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int xml_printinfo(char *dirname, struct _info *file, int level)
|
||||||
|
{
|
||||||
|
mode_t mt;
|
||||||
|
int t;
|
||||||
|
|
||||||
|
if (!noindent) xml_indent(level);
|
||||||
|
|
||||||
|
if (file != NULL) {
|
||||||
|
if (file->lnk) mt = file->mode & S_IFMT;
|
||||||
|
else mt = file->mode & S_IFMT;
|
||||||
|
} else mt = 0;
|
||||||
|
|
||||||
|
for(t=0;ifmt[t];t++)
|
||||||
|
if (ifmt[t] == mt) break;
|
||||||
|
fprintf(outfile,"<%s", (file->tag = ftype[t]));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xml_printfile(char *dirname, char *filename, struct _info *file, int descend)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fprintf(outfile, " name=\"");
|
||||||
|
html_encode(outfile, filename);
|
||||||
|
fputc('"',outfile);
|
||||||
|
|
||||||
|
if (file && file->comment) {
|
||||||
|
fprintf(outfile, " info=\"");
|
||||||
|
for(i=0; file->comment[i]; i++) {
|
||||||
|
html_encode(outfile, file->comment[i]);
|
||||||
|
if (file->comment[i+1]) fprintf(outfile, "\n");
|
||||||
|
}
|
||||||
|
fputc('"', outfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file && file->lnk) {
|
||||||
|
fprintf(outfile, " target=\"");
|
||||||
|
html_encode(outfile,file->lnk);
|
||||||
|
fputc('"',outfile);
|
||||||
|
}
|
||||||
|
if (file) xml_fillinfo(file);
|
||||||
|
fputc('>',outfile);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xml_error(char *error)
|
||||||
|
{
|
||||||
|
fprintf(outfile,"<error>%s</error>", error);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xml_newline(struct _info *file, int level, int postdir, int needcomma)
|
||||||
|
{
|
||||||
|
if (postdir >= 0) fprintf(outfile, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void xml_close(struct _info *file, int level, int needcomma)
|
||||||
|
{
|
||||||
|
if (!noindent && level >= 0) xml_indent(level);
|
||||||
|
fprintf(outfile,"</%s>%s", file? file->tag : "unknown", noindent? "" : "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xml_report(struct totals tot)
|
||||||
|
{
|
||||||
|
extern char *_nl;
|
||||||
|
|
||||||
|
fprintf(outfile,"%s<report>%s",noindent?"":" ", _nl);
|
||||||
|
if (duflag) fprintf(outfile,"%s<size>%lld</size>%s", noindent?"":" ", (long long int)tot.size, _nl);
|
||||||
|
fprintf(outfile,"%s<directories>%ld</directories>%s", noindent?"":" ", tot.dirs, _nl);
|
||||||
|
if (!dflag) fprintf(outfile,"%s<files>%ld</files>%s", noindent?"":" ", tot.files, _nl);
|
||||||
|
fprintf(outfile,"%s</report>%s",noindent?"":" ", _nl);
|
||||||
|
}
|
Loading…
Reference in a new issue