From 20a0fb8ecde5cc12092ac51c8dd6fa43f2c74da6 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Mon, 19 Feb 2018 13:53:17 +0900 Subject: [PATCH] Imported Upstream version 1.7.0 Change-Id: Ibd838d76a8c0d5bc9bcf3afd1250191207abbdc1 Signed-off-by: DongHun Kwak --- CHANGES | 29 +++++- Makefile | 15 +-- README | 37 +++++++ color.c | 2 +- doc/tree.1 | 51 +++++++--- hash.c | 16 +-- html.c | 67 +++++++------ json.c | 305 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tree.c | 323 ++++++++++++++++++++++++++++++++++++++++++++----------------- tree.h | 19 +++- unix.c | 6 +- xml.c | 18 ++-- 12 files changed, 723 insertions(+), 165 deletions(-) create mode 100644 json.c diff --git a/CHANGES b/CHANGES index 10f2e20..1a6baa9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,30 @@ +Version 1.7.0 + - Allow user/group names up to 32 characters before clipping. + - Made -i compress XML and JSON output as much as possible by eliminating + extraneous whitespace. + - Added --caseinsensitive (renamed --ignore-case ala grep) flag so patterns + match without regard to case, courtesy of Jason A Donenfeld. + - Added --matchdirs option courtesy of Brian Mattern & Jason A. Donenfeld + . + - Fixed possible buffer overflow on large uid/gids w/o user names/group + names (Alexandre Wendling ) + - Added JSON support courtesy of Florian Sesser . + - Fixed formatting error with HTML output when -L 1 specified. (Sascha Zorn + ) + - Added file size sorting (Philipp M?ller ) + - Added '--sort[=]' option, ala ls. + - Fixed OS X makefile problems (Ryan Hollis ) + - Fixed possible memory overflow in read_dir (path/lbuf not equal in size + to pathsize/lbufsize.) (Han Hui ) + - Fix S_ISDOOR/S_IFDOOR spelling mistake for Solaris. (Tim Mooney + ) + - Make tree more reliably detect UTF-8 locales. (Mantas Mikulnas + and others.) + - Return non-zero exit status on option errors, print usage to stdout when + not an error, add the posix '--' option terminator, Change -S description + to mean CP437 (console) output codes, not ASCII. (Ivan Shmakov + ) + Version 1.6.0 - Re-org of code into multiple files, split HTML and Unix listdir() into separate functions, various code cleanups and optimizations. @@ -142,7 +169,7 @@ Version 1.3 - Added -S to show ASCII tree lines (Gerald Scheidl) - Made tree more portable (Guido Socher and others) - Following options curtsey of Francesc Rocher: + Following options courtesy of Francesc Rocher: - Added -o to redirect the output. - Added -H to print the tree in HTML format. - Added -L to set the maximum level of directories to print. diff --git a/Makefile b/Makefile index 7501eee..e91f1f6 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # $Copyright: $ -# Copyright (c) 1996 - 2011 by Steve Baker +# Copyright (c) 1996 - 2014 by Steve Baker # All Rights reserved # # This program is free software; you can redistribute it and/or modify @@ -20,19 +20,19 @@ prefix = /usr CC=gcc -VERSION=1.6.0 +VERSION=1.7.0 TREE_DEST=tree BINDIR=${prefix}/bin MAN=tree.1 MANDIR=${prefix}/man/man1 -OBJS=tree.o unix.o html.o xml.o hash.o color.o +OBJS=tree.o unix.o html.o xml.o json.o hash.o color.o # Uncomment options below for your particular OS: # Linux defaults: -#CFLAGS=-ggdb -Wall -DLINUX -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -CFLAGS=-O4 -Wall -DLINUX -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -LDFLAGS=-s +CFLAGS=-ggdb -Wall -DLINUX -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +#CFLAGS=-O4 -Wall -DLINUX -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +#LDFLAGS=-s # Uncomment for FreeBSD: #CFLAGS=-O2 -Wall -fomit-frame-pointer @@ -56,6 +56,7 @@ LDFLAGS=-s #CC=cc #CFLAGS=-O2 -Wall -fomit-frame-pointer -no-cpp-precomp #LDFLAGS= +#MANDIR=/usr/share/man/man1 #OBJS+=strverscmp.o # Uncomment for HP/UX: @@ -97,7 +98,7 @@ install: tree install -d $(BINDIR) install -d $(MANDIR) if [ -e $(TREE_DEST) ]; then \ - install -s $(TREE_DEST) $(BINDIR)/$(TREE_DEST); \ + install $(TREE_DEST) $(BINDIR)/$(TREE_DEST); \ fi install doc/$(MAN) $(MANDIR)/$(MAN) diff --git a/README b/README index ab58d82..ad67207 100644 --- a/README +++ b/README @@ -141,6 +141,43 @@ 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. + + And many others whom I've failed to keep track of. I should have started this list years ago. diff --git a/color.c b/color.c index 6b8254b..1da3363 100644 --- a/color.c +++ b/color.c @@ -1,5 +1,5 @@ /* $Copyright: $ - * Copyright (c) 1996 - 2011 by Steve Baker (ice@mama.indstate.edu) + * Copyright (c) 1996 - 2014 by Steve Baker (ice@mama.indstate.edu) * All Rights reserved * * This program is free software; you can redistribute it and/or modify diff --git a/doc/tree.1 b/doc/tree.1 index 4b80852..96a6606 100644 --- a/doc/tree.1 +++ b/doc/tree.1 @@ -1,5 +1,5 @@ .\" $Copyright: $ -.\" Copyright (c) 1996 - 2011 by Steve Baker +.\" Copyright (c) 1996 - 2012 by Steve Baker .\" All Rights reserved .\" .\" This program is free software; you can redistribute it and/or modify @@ -17,11 +17,12 @@ .\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA .\" ... -.TH TREE 1 "\*(V)" "Tree 1.6.0" +.TH TREE 1 "" "Tree 1.7.0" .SH NAME tree \- list contents of directories in a tree-like format. .SH SYNOPSIS -\fBtree\fP [\fB-acdfghilnpqrstuvxACDFQNSUX\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--nolinks\fP] [\fB-P\fP \fIpattern\fP] [\fB-I\fP \fIpattern\fP] [\fB--inodes\fP] [\fB--device\fP] [\fB--noreport\fP] [\fB--dirsfirst\fP] [\fB--version\fP] [\fB--help\fP] [\fB--filelimit\fP \fI#\fP] [\fB--si\fP] [\fB--prune\fP] [\fB--du\fP] [\fB--timefmt\fP \fIformat\fP] [\fIdirectory\fP ...] +\fBtree\fP [\fB-acdfghilnpqrstuvxACDFQNSUX\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--nolinks\fP] [\fB-P\fP \fIpattern\fP] [\fB-I\fP \fIpattern\fP] [\fB--inodes\fP] [\fB--device\fP] [\fB--noreport\fP] [\fB--dirsfirst\fP] [\fB--version\fP] [\fB--help\fP] [\fB--filelimit\fP \fI#\fP] [\fB--si\fP] [\fB--prune\fP] [\fB--du\fP] [\fB--timefmt\fP \fIformat\fP] [\fB--matchdirs\fP] [\fB--\fP] [\fIdirectory\fP ...] + .br .SH DESCRIPTION \fITree\fP is a recursive directory listing program that produces a depth @@ -98,6 +99,19 @@ alternate patterns. .B -I \fIpattern\fP Do not list those files that match the wild-card \fIpattern\fP. .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 regards 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 --prune Makes tree prune empty directories from the output, useful when used in @@ -202,10 +216,6 @@ Prints the device number to which the file or directory belongs Sort the output by version. .PP .TP -.B -r -Sort the output in reverse alphabetic order. -.PP -.TP .B -t Sort the output by last modification time instead of alphabetically. .PP @@ -220,17 +230,26 @@ modification time. 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 --sort[=] +Sort the output by name (as per ls): name (default), ctime (\fP-c\fP), mtime +(\fP-t\fB), size or version (\fP-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. +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 @@ -238,7 +257,7 @@ Turn on ANSI line graphics hack when printing the indentation lines. .PP .TP .B -S -Turn on ASCII line graphics (useful when using Linux console mode fonts). This +Turn on CP437 line graphics (useful when using Linux console mode fonts). This option is now equivalent to `--charset=IBM437' and may eventually be depreciated. .PP .TP @@ -251,13 +270,17 @@ Turn colorization on always, using built-in color defaults if the LS_COLORS environment variable is not set. Useful to colorize output to a pipe. .PP -.SH XML/HTML OPTIONS +.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 an 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 @@ -287,6 +310,10 @@ Outputs a verbose usage listing. .B --version Outputs the version of tree. .PP +.TP +.B -- +Option processing terminator. No further options will be processed after this. +.PP .br .SH FILES @@ -333,7 +360,7 @@ 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 trees are not colored, which is a bit of a shame. +XML/JSON trees are not colored, which is a bit of a shame. Probably more. diff --git a/hash.c b/hash.c index 62b6964..f367ee1 100644 --- a/hash.c +++ b/hash.c @@ -1,5 +1,5 @@ /* $Copyright: $ - * Copyright (c) 1996 - 2011 by Steve Baker (ice@mama.indstate.edu) + * Copyright (c) 1996 - 2014 by Steve Baker (ice@mama.indstate.edu) * All Rights reserved * * This program is free software; you can redistribute it and/or modify @@ -25,11 +25,11 @@ struct xtable *gtable[256], *utable[256]; #define inohash(x) ((x)&255) struct inotable *itable[256]; -char *uidtoname(int uid) +char *uidtoname(uid_t uid) { struct xtable *o, *p, *t; struct passwd *ent; - char ubuf[6]; + char ubuf[32]; int uent = HASH(uid); for(o = p = utable[uent]; p ; p=p->nxt) { @@ -41,7 +41,8 @@ char *uidtoname(int uid) t = xmalloc(sizeof(struct xtable)); if ((ent = getpwuid(uid)) != NULL) t->name = scopy(ent->pw_name); else { - sprintf(ubuf,"%d",uid); + snprintf(ubuf,30,"%d",uid); + ubuf[31] = 0; t->name = scopy(ubuf); } t->xid = uid; @@ -51,11 +52,11 @@ char *uidtoname(int uid) return t->name; } -char *gidtoname(int gid) +char *gidtoname(gid_t gid) { struct xtable *o, *p, *t; struct group *ent; - char gbuf[6]; + char gbuf[32]; int gent = HASH(gid); for(o = p = gtable[gent]; p ; p=p->nxt) { @@ -67,7 +68,8 @@ char *gidtoname(int gid) t = xmalloc(sizeof(struct xtable)); if ((ent = getgrgid(gid)) != NULL) t->name = scopy(ent->gr_name); else { - sprintf(gbuf,"%d",gid); + snprintf(gbuf,30,"%d",gid); + gbuf[31] = 0; t->name = scopy(gbuf); } t->xid = gid; diff --git a/html.c b/html.c index 1062faf..75e2ed1 100644 --- a/html.c +++ b/html.c @@ -1,5 +1,5 @@ /* $Copyright: $ - * Copyright (c) 1996 - 2011 by Steve Baker (ice@mama.indstate.edu) + * Copyright (c) 1996 - 2014 by Steve Baker (ice@mama.indstate.edu) * All Rights reserved * * This program is free software; you can redistribute it and/or modify @@ -20,7 +20,7 @@ extern bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag; extern bool Dflag, inodeflag, devflag, Rflag; -extern bool noindent, force_color, xdev, nolinks, flimit, nosort; +extern bool noindent, force_color, xdev, nolinks, flimit; //extern char *title, extern char *host, *sp; @@ -38,34 +38,34 @@ void url_encode(FILE *fd, char *s); void emit_html_header(const char *charset, char *title, char *version) { fprintf(outfile, - "\n" - "\n" - "\n" - " \n" - " \n" - " \n" - " %s\n" - " \n" - "\n" - "\n" - "\t

%s

\n\t",charset ? charset : "iso-8859-1", version, title, title); + "\n" + "\n" + "\n" + " \n" + " \n" + " \n" + " %s\n" + " \n" + "\n" + "\n" + "\t

%s

\n\t",charset ? charset : "iso-8859-1", version, title, title); } off_t html_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev) @@ -78,7 +78,10 @@ off_t html_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev) int i,n,c; char hclr[20], *hdir, *hcmd; - if ((Level >= 0) && (lev > Level)) return 0; + if ((Level >= 0) && (lev > Level)) { + fprintf(outfile, "
\n"); + return 0; + } if (xdev && lev == 0) { stat(d,&sb); @@ -101,7 +104,7 @@ off_t html_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev) return 0; } - if (!nosort) qsort(dir,n,sizeof(struct _info *),cmpfunc); + if (cmpfunc) qsort(dir,n,sizeof(struct _info *),cmpfunc); if (lev >= maxdirs-1) { dirs = xrealloc(dirs,sizeof(int) * (maxdirs += 1024)); memset(dirs+(maxdirs-1024), 0, sizeof(int) * 1024); diff --git a/json.c b/json.c new file mode 100644 index 0000000..4b15e0d --- /dev/null +++ b/json.c @@ -0,0 +1,305 @@ +/* $Copyright: $ + * Copyright (c) 1996 - 2014 by Steve Baker (ice@mama.indstate.edu) + * 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 + */ +#include "tree.h" + +extern bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag; +extern bool Dflag, inodeflag, devflag, Rflag, cflag; +extern bool noindent, force_color, xdev, nolinks, flimit; + +extern const int ifmt[]; +extern const char fmt[], *ftype[]; + +extern void (*listdir)(char *, int *, int *, u_long, dev_t); +extern int (*cmpfunc)(); +extern FILE *outfile; +extern int Level, *dirs, maxdirs; + +extern char *endcode; + +/* JSON code courtesy of Florian Sesser +[ + {"type": "directory", "name": "name", "mode": "0777", "user": "user", "group": "group", "inode": ###, "dev": ####, "time": "00:00 00-00-0000", "contents": [ + {"type": "link", "name": "name", "target": "name", "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"} + {"type": "socket", "name": "", "error": "some error" ...} + {"type": "block", "name": "" ...}, + {"type": "char", "name": "" ...}, + {"type": "fifo", "name": "" ...}, + {"type": "door", "name": "" ...}, + {"type": "port", "name": "" ...} + ]}, + {"type": "report", "size": ###, "files": ###, "directories": ###} +] +*/ + +off_t json_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev) +{ + char *path; + bool nlf = FALSE; + long pathsize = 0; + struct _info **dir, **sav; + struct stat sb; + int t, n, mt; + + if ((Level >= 0) && (lev > Level)) { + if (!noindent) fputc('\n',outfile); + return 0; + } + + if (xdev && lev == 0) { + stat(d,&sb); + dev = sb.st_dev; + } + + sav = dir = read_dir(d,&n); + if (!dir && n) { + fprintf(outfile,"{\"error\": \"opening dir\"}%s",noindent?"":"\n"); + return 0; + } + if (!n) { + if (!noindent) fputc('\n', outfile); + free_dir(sav); + return 0; + } + if (flimit > 0 && n > flimit) { + fprintf(outfile,", \"error\": \"%d entries exceeds filelimit, not opening dir\"\n",n); + free_dir(sav); + return 0; + } + + if (cmpfunc) qsort(dir,n,sizeof(struct _info *),cmpfunc); + if (lev >= maxdirs-1) { + dirs = xrealloc(dirs,sizeof(int) * (maxdirs += 1024)); + memset(dirs+(maxdirs-1024), 0, sizeof(int) * 1024); + } + dirs[lev] = 1; + if (!*(dir+1)) dirs[lev] = 2; + if (!noindent) fprintf(outfile,"\n"); + + path = malloc(pathsize=4096); + + while(*dir) { + if (!noindent) json_indent(lev); + + if ((*dir)->lnk) mt = (*dir)->mode & S_IFMT; + else mt = (*dir)->mode & S_IFMT; + for(t=0;ifmt[t];t++) + if (ifmt[t] == mt) break; + fprintf(outfile,"{\"type\":\"%s\"", ftype[t]); + + if (fflag) { + if (sizeof(char) * (strlen(d)+strlen((*dir)->name)+2) > pathsize) + path=xrealloc(path,pathsize=(sizeof(char) * (strlen(d)+strlen((*dir)->name)+1024))); + if (!strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->name); + else sprintf(path,"%s/%s",d,(*dir)->name); + } else { + if (sizeof(char) * (strlen((*dir)->name)+1) > pathsize) + path=xrealloc(path,pathsize=(sizeof(char) * (strlen((*dir)->name)+1024))); + sprintf(path,"%s",(*dir)->name); + } + + fprintf(outfile, ",\"name\":\""); + html_encode(outfile,path); + fputc('"',outfile); + + if ((*dir)->lnk) { + fprintf(outfile, ",\"target\":\""); + html_encode(outfile,(*dir)->lnk); + fputc('"',outfile); + } + json_fillinfo(*dir); + if (!(*dir)->isdir && !(*dir)->lnk) { + fputc('}',outfile); + if (*(dir+1)) fputc(',',outfile); + } else + fprintf(outfile, ",\"contents\":["); + + if ((*dir)->isdir) { + if ((*dir)->lnk) { + if (lflag && !(xdev && dev != (*dir)->dev)) { + if (findino((*dir)->inode,(*dir)->dev)) { + fprintf(outfile,"{\"error\":\"recursive, not followed\"}"); + } else { + saveino((*dir)->inode, (*dir)->dev); + if (*(*dir)->lnk == '/') + listdir((*dir)->lnk,dt,ft,lev+1,dev); + else { + if (strlen(d)+strlen((*dir)->lnk)+2 > pathsize) path=xrealloc(path,pathsize=(strlen(d)+strlen((*dir)->name)+1024)); + if (fflag && !strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->lnk); + else sprintf(path,"%s/%s",d,(*dir)->lnk); + listdir(path,dt,ft,lev+1,dev); + } + nlf = TRUE; + } + } + } else if (!(xdev && dev != (*dir)->dev)) { + if (strlen(d)+strlen((*dir)->name)+2 > pathsize) path=xrealloc(path,pathsize=(strlen(d)+strlen((*dir)->name)+1024)); + if (fflag && !strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->name); + else sprintf(path,"%s/%s",d,(*dir)->name); + saveino((*dir)->inode, (*dir)->dev); + listdir(path,dt,ft,lev+1,dev); + nlf = TRUE; + } + *dt += 1; + } else *ft += 1; + if (*(dir+1) && !*(dir+2)) dirs[lev] = 2; + if (nlf) { + nlf = FALSE; + if (!noindent) json_indent(lev); + } + if ((*dir)->isdir || (*dir)->lnk) { + fprintf(outfile, "]}"); + if (*(dir+1)) fputc(',',outfile); + } + if (!noindent) fputc('\n', outfile); + dir++; + } + dirs[lev] = 0; + free(path); + free_dir(sav); + return 0; +} + +off_t json_rlistdir(char *d, int *dt, int *ft, u_long lev, dev_t dev) +{ + struct _info **dir; + off_t size = 0; + char *err; + + dir = getfulltree(d, lev, dev, &size, &err); + + memset(dirs, 0, sizeof(int) * maxdirs); + + jsonr_listdir(dir, d, dt, ft, lev); + + return size; +} + +void jsonr_listdir(struct _info **dir, char *d, int *dt, int *ft, u_long lev) +{ + char *path; + long pathsize = 0; + struct _info **sav = dir; + bool nlf = FALSE; + int mt, t; + + if (dir == NULL) return; + + dirs[lev] = 1; + if (!*(dir+1)) dirs[lev] = 2; + if (!noindent) fprintf(outfile,"\n"); + + path = malloc(pathsize=4096); + + while(*dir) { + if (!noindent) json_indent(lev); + + if ((*dir)->lnk) mt = (*dir)->mode & S_IFMT; + else mt = (*dir)->mode & S_IFMT; + for(t=0;ifmt[t];t++) + if (ifmt[t] == mt) break; + fprintf(outfile,"{\"type\":\"%s\"", ftype[t]); + + if (fflag) { + if (sizeof(char) * (strlen(d)+strlen((*dir)->name)+2) > pathsize) + path=xrealloc(path,pathsize=(sizeof(char) * (strlen(d)+strlen((*dir)->name)+1024))); + if (!strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->name); + else sprintf(path,"%s/%s",d,(*dir)->name); + } else { + if (sizeof(char) * (strlen((*dir)->name)+1) > pathsize) + path=xrealloc(path,pathsize=(sizeof(char) * (strlen((*dir)->name)+1024))); + sprintf(path,"%s",(*dir)->name); + } + + fprintf(outfile, ",\"name\":\""); + html_encode(outfile,path); + fputc('"',outfile); + + if ((*dir)->lnk) { + fprintf(outfile, ",\"target\":\""); + html_encode(outfile,(*dir)->lnk); + fputc('"',outfile); + } + + json_fillinfo(*dir); + if (mt != S_IFDIR && mt != S_IFLNK && (*dir)->err == NULL) fprintf(outfile,"},"); + else fprintf(outfile, ",\"contents\":["); + + if ((*dir)->err) { + fprintf(outfile,",\"error\":\"%s\"", (*dir)->err); + free((*dir)->err); + (*dir)->err = NULL; + } + if ((*dir)->child) { + if (fflag) { + if (strlen(d)+strlen((*dir)->name)+2 > pathsize) path=xrealloc(path,pathsize=(strlen(d)+strlen((*dir)->name)+1024)); + if (!strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->name); + else sprintf(path,"%s/%s",d,(*dir)->name); + } + jsonr_listdir((*dir)->child, fflag? path : NULL, dt, ft, lev+1); + nlf = TRUE; + *dt += 1; + } else { + if ((*dir)->isdir) *dt += 1; + else *ft += 1; + } + + if (*(dir+1) && !*(dir+2)) dirs[lev] = 2; + if (nlf) { + nlf = FALSE; + if (!noindent) json_indent(lev); + } + if (mt == S_IFDIR || mt == S_IFLNK || (*dir)->err != NULL) fprintf(outfile,"]},%s",noindent?"":"\n"); + else { + if (!noindent) putc('\n',outfile); + } + dir++; + } + dirs[lev] = 0; + free(path); + free_dir(sav); +} + +void json_indent(int maxlevel) +{ + int i; + + fprintf(outfile, " "); + for(i=0; iinode); + #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)); +} diff --git a/tree.c b/tree.c index 19cf368..e7d85d2 100644 --- a/tree.c +++ b/tree.c @@ -1,5 +1,5 @@ /* $Copyright: $ - * Copyright (c) 1996 - 2011 by Steve Baker (ice@mama.indstate.edu) + * Copyright (c) 1996 - 2014 by Steve Baker (ice@mama.indstate.edu) * All Rights reserved * * This program is free software; you can redistribute it and/or modify @@ -19,17 +19,20 @@ #include "tree.h" -static char *version ="$Version: $ tree v1.6.0 (c) 1996 - 2011 by Steve Baker, Thomas Moore, Francesc Rocher, Kyosuke Tokoro $"; -static char *hversion="\t\t tree v1.6.0 %s 1996 - 2011 by Steve Baker and Thomas Moore
\n" +static char *version ="$Version: $ tree v1.7.0 (c) 1996 - 2014 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro $"; +static char *hversion="\t\t tree v1.7.0 %s 1996 - 2014 by Steve Baker and Thomas Moore
\n" "\t\t HTML output hacked and copyleft %s 1998 by Francesc Rocher
\n" + "\t\t JSON output hacked and copyleft %s 2014 by Florian Sesser
\n" "\t\t Charsets / OS/2 support %s 2001 by Kyosuke Tokoro\n"; /* Globals */ bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag; bool qflag, Nflag, Qflag, Dflag, inodeflag, devflag, hflag, Rflag; -bool Hflag, siflag, cflag, Xflag, duflag, pruneflag; -bool noindent, force_color, nocolor, xdev, noreport, nolinks, flimit, dirsfirst, nosort; -char *pattern = NULL, *ipattern = NULL, *host = NULL, *title = "Directory Tree", *sp = " "; +bool Hflag, siflag, cflag, Xflag, Jflag, duflag, pruneflag; +bool noindent, force_color, nocolor, xdev, noreport, nolinks, flimit, dirsfirst; +bool ignorecase, matchdirs; +bool reverse; +char *pattern = NULL, *ipattern = NULL, *host = NULL, *title = "Directory Tree", *sp = " ", *_nl = "\n"; char *timefmt = NULL; const char *charset = NULL; @@ -45,8 +48,8 @@ int mb_cur_max; #ifdef __EMX__ const u_short ifmt[]={ FILE_ARCHIVED, FILE_DIRECTORY, FILE_SYSTEM, FILE_HIDDEN, FILE_READONLY, 0}; #else - #ifdef S_ISPORT - const u_int ifmt[] = {S_IFREG, S_IFDIR, S_IFLNK, S_IFCHR, S_IFBLK, S_IFSOCK, S_IFIFO, S_ISDOOR, S_ISPORT, 0}; + #ifdef S_IFPORT + const u_int ifmt[] = {S_IFREG, S_IFDIR, S_IFLNK, S_IFCHR, S_IFBLK, S_IFSOCK, S_IFIFO, S_IFDOOR, S_IFPORT, 0}; const char fmt[] = "-dlcbspDP?"; const char *ftype[] = {"file", "directory", "link", "char", "block", "socket", "fifo", "door", "port", "unknown", NULL}; #else @@ -56,6 +59,17 @@ const u_short ifmt[]={ FILE_ARCHIVED, FILE_DIRECTORY, FILE_SYSTEM, FILE_HIDDEN, #endif #endif +struct sorts { + char *name; + int (*cmpfunc)(); +} sorts[] = { + {"name", alnumsort}, + {"version", versort}, + {"size", fsizesort}, + {"mtime", mtimesort}, + {"ctime", ctimesort}, + {NULL, NULL} +}; /* Externs */ /* hash.c */ @@ -70,17 +84,18 @@ extern const struct linedraw *linedraw; int main(int argc, char **argv) { char **dirname = NULL; - int i,j=0,n,p,q,dtotal,ftotal,colored = FALSE; + int i,j=0,k,n,optf,p,q,dtotal,ftotal,colored = FALSE; struct stat st; - char sizebuf[64]; + char sizebuf[64], *stmp; off_t size = 0; mode_t mt; + bool needfulltree; q = p = dtotal = ftotal = 0; aflag = dflag = fflag = lflag = pflag = sflag = Fflag = uflag = gflag = FALSE; Dflag = qflag = Nflag = Qflag = Rflag = hflag = Hflag = siflag = cflag = FALSE; - noindent = force_color = nocolor = xdev = noreport = nolinks = FALSE; - dirsfirst = nosort = inodeflag = devflag = Xflag = FALSE; + noindent = force_color = nocolor = xdev = noreport = nolinks = reverse = FALSE; + ignorecase = matchdirs = dirsfirst = inodeflag = devflag = Xflag = Jflag = FALSE; duflag = pruneflag = FALSE; flimit = 0; dirs = xmalloc(sizeof(int) * (maxdirs=4096)); @@ -92,7 +107,7 @@ int main(int argc, char **argv) setlocale(LC_COLLATE, ""); charset = getcharset(); - if (charset == NULL && patmatch(setlocale(LC_CTYPE,NULL), "*[Uu][Tt][Ff]-8") == 1) { + if (charset == NULL && strcmp(nl_langinfo(CODESET), "UTF-8") == 0) { charset = "UTF-8"; } @@ -107,9 +122,10 @@ int main(int argc, char **argv) memset(gtable,0,sizeof(gtable)); memset(itable,0,sizeof(itable)); + optf = TRUE; for(n=i=1;i\n\n"); - } + fprintf(outfile,"?>%s%s",_nl,_nl); + } else if (Jflag) + fputc('[',outfile); if (dirname) { for(colored=i=0;dirname[i];i++,colored=0) { @@ -435,16 +510,16 @@ int main(int argc, char **argv) if (colorize) colored = color(st.st_mode,dirname[i],n<0,FALSE); size += st.st_size; } - if (Xflag) { + if (Xflag || Jflag) { mt = st.st_mode & S_IFMT; for(j=0;ifmt[j];j++) if (ifmt[j] == mt) break; - fprintf(outfile," <%s", ftype[j]); - if (mt == S_IFDIR) { - fprintf(outfile, " name=\"%s\"", dirname[i]); + if (Xflag) + fprintf(outfile,"%s<%s name=\"%s\">", noindent?"":" ", ftype[j], dirname[i]); + else if (Jflag) { + if (i) fprintf(outfile, ","); + fprintf(outfile,"%s{\"type\":\"%s\",\"name\":\"%s\",\"contents\":[", noindent?"":"\n ", ftype[j], dirname[i]); } - fputc('>',outfile); - if (mt != S_IFDIR) fprintf(outfile,"%s", dirname[i]); } else if (!Hflag) printit(dirname[i]); if (colored) fprintf(outfile,"%s",endcode); if (!Hflag) size += listdir(dirname[i],&dtotal,&ftotal,0,0); @@ -457,7 +532,8 @@ int main(int argc, char **argv) chdir(curdir); } } - if (Xflag) fprintf(outfile," \n",ftype[j]); + if (Xflag) fprintf(outfile,"%s\n",noindent?"":" ", ftype[j]); + if (Jflag) fprintf(outfile,"%s]}",noindent?"":" "); } } else { if ((n = lstat(".",&st)) >= 0) { @@ -465,11 +541,13 @@ int main(int argc, char **argv) if (colorize) colored = color(st.st_mode,".",n<0,FALSE); size = st.st_size; } - if (Xflag) fprintf(outfile," "); + if (Xflag) fprintf(outfile,"%s",noindent?"":" "); + else if (Jflag) fprintf(outfile, "{\"type\":\"directory\",\"name\": \".\",\"contents\":["); else if (!Hflag) fprintf(outfile,"."); if (colored) fprintf(outfile,"%s",endcode); size += listdir(".",&dtotal,&ftotal,0,0); - if (Xflag) fprintf(outfile," \n"); + if (Xflag) fprintf(outfile,"%s%s",noindent?"":" ", _nl); + if (Jflag) fprintf(outfile,"%s]}",noindent?"":" "); } if (Hflag) @@ -477,11 +555,17 @@ int main(int argc, char **argv) if (!noreport) { if (Xflag) { - fprintf(outfile," \n"); - if (duflag) fprintf(outfile," %lld\n", size); - fprintf(outfile," %d\n", dtotal); - if (!dflag) fprintf(outfile," %d\n", ftotal); - fprintf(outfile," \n"); + fprintf(outfile,"%s%s",noindent?"":" ", _nl); + if (duflag) fprintf(outfile,"%s%lld%s", noindent?"":" ", (long long int)size, _nl); + fprintf(outfile,"%s%d%s", noindent?"":" ", dtotal, _nl); + if (!dflag) fprintf(outfile,"%s%d%s", noindent?"":" ", ftotal, _nl); + fprintf(outfile,"%s%s",noindent?"":" ", _nl); + } else if (Jflag) { + fprintf(outfile, ",%s{\"type\":\"report\"",noindent?"":"\n "); + if (duflag) fprintf(outfile,",\"size\":%lld", (long long int)size); + fprintf(outfile,",\"directories\":%d", dtotal); + if (!dflag) fprintf(outfile,",\"files\":%d", ftotal); + fprintf(outfile, "}"); } else { if (duflag) { psize(sizebuf, size); @@ -498,12 +582,14 @@ int main(int argc, char **argv) fprintf(outfile,"\t

\n\t

\n"); fprintf(outfile,"\t
\n"); fprintf(outfile,"\t

\n"); - fprintf(outfile,hversion,linedraw->copy, linedraw->copy, linedraw->copy); + fprintf(outfile,hversion,linedraw->copy, linedraw->copy, linedraw->copy, linedraw->copy); fprintf(outfile,"\t

\n"); fprintf(outfile,"\n"); fprintf(outfile,"\n"); } else if (Xflag) { fprintf(outfile,"\n"); + } else if (Jflag) { + fprintf(outfile, "%s]\n",_nl); } if (outfilename != NULL) fclose(outfile); @@ -513,13 +599,16 @@ int main(int argc, char **argv) void usage(int n) { - fprintf(stderr, - "usage: tree [-acdfghilnpqrstuvxACDFQNSUX] [-H baseHREF] [-T title ] [-L level [-R]]\n" - "\t[-P pattern] [-I pattern] [-o filename] [--version] [--help] [--inodes]\n" - "\t[--device] [--noreport] [--nolinks] [--dirsfirst] [--charset charset]\n" - "\t[--filelimit[=]#] [--si] [--timefmt[=]] []\n"); - if (n < 2) exit(0); - fprintf(stderr, + /* 123456789!123456789!123456789!123456789!123456789!123456789!123456789!123456789! */ + /* \t9!123456789!123456789!123456789!123456789!123456789!123456789!123456789! */ + fprintf(n < 2? stderr: stdout, + "usage: tree [-acdfghilnpqrstuvxACDFJQNSUX] [-H baseHREF] [-T title ]\n" + "\t[-L level [-R]] [-P pattern] [-I pattern] [-o filename] [--version]\n" + "\t[--help] [--inodes] [--device] [--noreport] [--nolinks] [--dirsfirst]\n" + "\t[--charset charset] [--filelimit[=]#] [--si] [--timefmt[=]]\n" + "\t[--sort[=]] [--matchdirs] [--ignore-case] [--] []\n"); + if (n < 2) return; + fprintf(stdout, " ------- Listing options -------\n" " -a All files are listed.\n" " -d List directories only.\n" @@ -530,6 +619,8 @@ void usage(int n) " -R Rerun tree when max dir level reached.\n" " -P pattern List only those files that match the pattern given.\n" " -I pattern Do not list files that match the given pattern.\n" + " --ignore-case Ignore case when pattern matching.\n" + " --matchdirs Include directory names in -P pattern matching.\n" " --noreport Turn off file/directory count at end of tree listing.\n" " --charset X Use charset X for terminal/HTML and indentation line output.\n" " --filelimit # Do not descend dirs with more than # files in them.\n" @@ -551,25 +642,28 @@ void usage(int n) " --device Print device ID number to which each file belongs.\n" " ------- Sorting options -------\n" " -v Sort files alphanumerically by version.\n" - " -r Sort files in reverse alphanumeric order.\n" " -t Sort files by last modification time.\n" " -c Sort files by last status change time.\n" " -U Leave files unsorted.\n" + " -r Reverse the order of the sort.\n" " --dirsfirst List directories before files (-U disables).\n" + " --sort X Select sort: name,version,size,mtime,ctime.\n" " ------- Graphics options ------\n" " -i Don't print indentation lines.\n" " -A Print ANSI lines graphic indentation lines.\n" - " -S Print with ASCII graphics indentation lines.\n" + " -S Print with CP437 (console) graphics indentation lines.\n" " -n Turn colorization off always (-C overrides).\n" " -C Turn colorization on always.\n" - " ------- XML/HTML options -------\n" + " ------- XML/HTML/JSON options -------\n" " -X Prints out an XML representation of the tree.\n" + " -J Prints out an JSON representation of the tree.\n" " -H baseHREF Prints out HTML format with baseHREF as top directory.\n" " -T string Replace the default HTML title and H1 header with string.\n" " --nolinks Turn off hyperlinks in HTML output.\n" " ---- Miscellaneous options ----\n" " --version Print version and exit.\n" - " --help Print usage and this help message and exit.\n"); + " --help Print usage and this help message and exit.\n" + " -- Options processing terminator.\n"); exit(0); } @@ -584,8 +678,8 @@ struct _info **read_dir(char *dir, int *n) DIR *d; int ne, p = 0, len, rs; - pathsize = lbufsize = strlen(dir)+4096; if (path == NULL) { + pathsize = lbufsize = strlen(dir)+4096; path=xmalloc(pathsize); lbuf=xmalloc(lbufsize); } @@ -689,14 +783,38 @@ struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **e struct _info **dir, **sav, **p, *sp; struct stat sb; int n; - + u_long lev_tmp; + char *tmp_pattern = NULL, *start_rel_path; + *err = NULL; if (Level >= 0 && lev > Level) return NULL; if (xdev && lev == 0) { stat(d,&sb); dev = sb.st_dev; } + // if the directory name matches, turn off pattern matching for contents + if (matchdirs && pattern) { + lev_tmp = lev; + start_rel_path = d + strlen(d); + for (start_rel_path = d + strlen(d); start_rel_path != d; --start_rel_path) { + if (*start_rel_path == '/') + --lev_tmp; + if (lev_tmp <= 0) { + if (*start_rel_path) + ++start_rel_path; + break; + } + } + if (*start_rel_path && patmatch(start_rel_path,pattern) == 1) { + tmp_pattern = pattern; + pattern = NULL; + } + } sav = dir = read_dir(d,&n); + if (tmp_pattern) { + pattern = tmp_pattern; + tmp_pattern = NULL; + } if (dir == NULL) { *err = scopy("error opening dir"); return NULL; @@ -714,7 +832,7 @@ struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **e free(path); return NULL; } - if (!nosort) qsort(dir,n,sizeof(struct _info *),cmpfunc); + if (cmpfunc) qsort(dir,n,sizeof(struct _info *),cmpfunc); if (lev >= maxdirs-1) { dirs = xrealloc(dirs,sizeof(int) * (maxdirs += 1024)); @@ -745,7 +863,9 @@ struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **e saveino((*dir)->inode, (*dir)->dev); (*dir)->child = getfulltree(path,lev+1,dev,&((*dir)->size),&((*dir)->err)); } - if (pruneflag && (*dir)->child == NULL) { + // prune empty folders, unless they match the requested pattern + if (pruneflag && (*dir)->child == NULL && + !(matchdirs && pattern && patmatch((*dir)->name,pattern) == 1)) { sp = *dir; for(p=dir;*p;p++) *p = *(p+1); n--; @@ -769,57 +889,74 @@ struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **e /* Sorting functions */ int alnumsort(struct _info **a, struct _info **b) { - if (dirsfirst) { - if ((*a)->isdir == (*b)->isdir) return strcoll((*a)->name,(*b)->name); - else return (*a)->isdir ? -1 : 1; + int v; + + if (dirsfirst && ((*a)->isdir != (*b)->isdir)) { + return (*a)->isdir ? -1 : 1; } - return strcoll((*a)->name,(*b)->name); + v = strcoll((*a)->name,(*b)->name); + return reverse? -v : v; } int versort(struct _info **a, struct _info **b) { - if (dirsfirst) { - if ((*a)->isdir == (*b)->isdir) return strverscmp((*a)->name,(*b)->name); - else return (*a)->isdir ? -1 : 1; + int v; + + if (dirsfirst && ((*a)->isdir != (*b)->isdir)) { + return (*a)->isdir ? -1 : 1; } - return strverscmp((*a)->name,(*b)->name); + v = strverscmp((*a)->name,(*b)->name); + return reverse? -v : v; } -int reversealnumsort(struct _info **a, struct _info **b) +int mtimesort(struct _info **a, struct _info **b) { - if (dirsfirst) { - if ((*a)->isdir == (*b)->isdir) return strcoll((*b)->name,(*a)->name); - else return (*a)->isdir ? -1 : 1; + int v; + + if (dirsfirst && ((*a)->isdir != (*b)->isdir)) { + return (*a)->isdir ? -1 : 1; + } + if ((*a)->mtime == (*b)->mtime) { + v = strcoll((*a)->name,(*b)->name); + return reverse? -v : v; } - return strcoll((*b)->name,(*a)->name); + v = (*a)->mtime == (*b)->mtime? 0 : ((*a)->mtime < (*b)->mtime ? -1 : 1); + return reverse? -v : v; } -int mtimesort(struct _info **a, struct _info **b) +int ctimesort(struct _info **a, struct _info **b) { - if (dirsfirst) { - if ((*a)->isdir == (*b)->isdir) { - if ((*a)->mtime == (*b)->mtime) return strcoll((*a)->name,(*b)->name); - return (*a)->mtime < (*b)->mtime; - } - else return (*a)->isdir ? -1 : 1; + int v; + + if (dirsfirst && ((*a)->isdir != (*b)->isdir)) { + return (*a)->isdir ? -1 : 1; + } + if ((*a)->ctime == (*b)->ctime) { + v = strcoll((*a)->name,(*b)->name); + return reverse? -v : v; } - if ((*a)->mtime == (*b)->mtime) return strcoll((*a)->name,(*b)->name); - return (*a)->mtime < (*b)->mtime; + v = (*a)->ctime == (*b)->ctime? 0 : ((*a)->ctime < (*b)->ctime? -1 : 1); + return reverse? -v : v; } -int ctimesort(struct _info **a, struct _info **b) +int sizecmp(off_t a, off_t b) { - if (dirsfirst) { - if ((*a)->isdir == (*b)->isdir) { - if ((*a)->ctime == (*b)->ctime) return strcoll((*a)->name,(*b)->name); - return (*a)->ctime < (*b)->ctime; - } - else return (*a)->isdir ? -1 : 1; + return (a == b)? 0 : ((a < b)? 1 : -1); +} + +int fsizesort(struct _info **a, struct _info **b) +{ + int v; + + if (dirsfirst && ((*a)->isdir != (*b)->isdir)) { + return (*a)->isdir ? -1 : 1; } - if ((*a)->ctime == (*b)->ctime) return strcoll((*a)->name,(*b)->name); - return (*a)->ctime < (*b)->ctime; + v = sizecmp((*a)->size, (*b)->size); + if (v == 0) v = strcoll((*a)->name,(*b)->name); + return reverse? -v : v; } + void *xmalloc (size_t size) { register void *value = malloc (size); @@ -868,9 +1005,15 @@ char *gnu_getcwd() } } +static inline char cond_lower(char c) +{ + return ignorecase ? tolower(c) : c; +} + /* * Patmatch() code courtesy of Thomas Moore (dark@mama.indstate.edu) * '|' support added by David MacMahon (davidm@astron.Berkeley.EDU) + * Case insensitive support added by Jason A. Donenfeld (Jason@zx2c4.com) * returns: * 1 on a match * 0 on a mismatch @@ -918,11 +1061,11 @@ int patmatch(char *buf, char *pat) pat += 2; if(*pat == '\\' && *pat) pat++; - if(*buf >= m && *buf <= *pat) + if(cond_lower(*buf) >= cond_lower(m) && cond_lower(*buf) <= cond_lower(*pat)) match = n; if(!*pat) pat--; - } else if(*buf == *pat) match = n; + } else if(cond_lower(*buf) == cond_lower(*pat)) match = n; pat++; } buf++; @@ -940,7 +1083,7 @@ int patmatch(char *buf, char *pat) if(*pat) pat++; default: - match = (*buf++ == *pat); + match = (cond_lower(*buf++) == cond_lower(*pat)); break; } pat++; @@ -1104,7 +1247,7 @@ int psize(char *buf, off_t size) for (idx=size= (usize*usize); idx++,size/=usize); if (!idx) return sprintf(buf, " %4d", (int)size); else return sprintf(buf, ((size/usize) >= 10)? " %3.0f%c" : " %3.1f%c" , (float)size/(float)usize,unit[idx]); - } else return sprintf(buf, sizeof(off_t) == sizeof(long long)? " %11lld" : " %9ld", size); + } else return sprintf(buf, sizeof(off_t) == sizeof(long long)? " %11lld" : " %9ld", (long long int)size); } char Ftype(mode_t mode) @@ -1114,7 +1257,7 @@ char Ftype(mode_t mode) else if (m == S_IFSOCK) return '='; else if (m == S_IFIFO) return '|'; else if (m == S_IFLNK) return '@'; /* Here, but never actually used though. */ -#ifdef S_ISDOOR +#ifdef S_IFDOOR else if (m == S_ISDOOR) return '>'; #endif else if ((m == S_IFREG) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*'; @@ -1136,8 +1279,8 @@ char *fillinfo(char *buf, struct _info *ent) #else if (pflag) n += sprintf(buf+n, " %s", prot(ent->mode)); #endif - if (uflag) n += sprintf(buf+n, " %-8.8s", uidtoname(ent->uid)); - if (gflag) n += sprintf(buf+n, " %-8.8s", gidtoname(ent->gid)); + if (uflag) n += sprintf(buf+n, " %-8.32s", uidtoname(ent->uid)); + if (gflag) n += sprintf(buf+n, " %-8.32s", gidtoname(ent->gid)); if (sflag) n += psize(buf+n,ent->size); if (Dflag) n += sprintf(buf+n, " %s", do_date(cflag? ent->ctime : ent->mtime)); diff --git a/tree.h b/tree.h index 21e01ad..9be3570 100644 --- a/tree.h +++ b/tree.h @@ -1,5 +1,5 @@ /* $Copyright: $ - * Copyright (c) 1996 - 2011 by Steve Baker (ice@mama.indstate.edu) + * Copyright (c) 1996 - 2014 by Steve Baker (ice@mama.indstate.edu) * All Rights reserved * * This program is free software; you can redistribute it and/or modify @@ -52,6 +52,7 @@ #endif #include +#include #include #include @@ -93,7 +94,7 @@ struct _info { }; /* hash.c */ struct xtable { - u_short xid; + unsigned int xid; char *name; struct xtable *nxt; }; @@ -121,11 +122,15 @@ struct linedraw { void usage(int); struct _info **getfulltree(char *d, u_long lev, dev_t dev, off_t *size, char **err); struct _info **read_dir(char *, int *); + 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 *); @@ -161,6 +166,13 @@ void xmlr_listdir(struct _info **dir, char *d, int *dt, int *ft, u_long lev); void xml_indent(int maxlevel); void xml_fillinfo(struct _info *ent); +/* json.c */ +off_t json_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev); +off_t json_rlistdir(char *d, int *dt, int *ft, u_long lev, dev_t dev); +void jsonr_listdir(struct _info **dir, char *d, int *dt, int *ft, u_long lev); +void json_indent(int maxlevel); +void json_fillinfo(struct _info *ent); + /* color.c */ void parse_dir_colors(); int color(u_short mode, char *name, bool orphan, bool islink); @@ -168,7 +180,8 @@ const char *getcharset(void); void initlinedraw(int); /* hash.c */ -char *gidtoname(int), *uidtoname(int); +char *uidtoname(uid_t uid); +char *gidtoname(gid_t gid); int findino(ino_t, dev_t); void saveino(ino_t, dev_t); diff --git a/unix.c b/unix.c index 657269c..ca5f76f 100644 --- a/unix.c +++ b/unix.c @@ -1,5 +1,5 @@ /* $Copyright: $ - * Copyright (c) 1996 - 2011 by Steve Baker (ice@mama.indstate.edu) + * Copyright (c) 1996 - 2014 by Steve Baker (ice@mama.indstate.edu) * All Rights reserved * * This program is free software; you can redistribute it and/or modify @@ -20,7 +20,7 @@ extern bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag; extern bool Dflag, inodeflag, devflag, Rflag, duflag, pruneflag; -extern bool noindent, force_color, xdev, nolinks, flimit, nosort; +extern bool noindent, force_color, xdev, nolinks, flimit; extern void (*listdir)(char *, int *, int *, u_long, dev_t); extern int (*cmpfunc)(); @@ -65,7 +65,7 @@ off_t unix_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev) return 0; } - if (!nosort) qsort(dir,n,sizeof(struct _info *),cmpfunc); + if (cmpfunc) qsort(dir,n,sizeof(struct _info *), cmpfunc); if (lev >= maxdirs-1) { dirs = xrealloc(dirs,sizeof(int) * (maxdirs += 1024)); memset(dirs+(maxdirs-1024), 0, sizeof(int) * 1024); diff --git a/xml.c b/xml.c index cd8a32f..32f3c0c 100644 --- a/xml.c +++ b/xml.c @@ -1,5 +1,5 @@ /* $Copyright: $ - * Copyright (c) 1996 - 2011 by Steve Baker (ice@mama.indstate.edu) + * Copyright (c) 1996 - 2014 by Steve Baker (ice@mama.indstate.edu) * All Rights reserved * * This program is free software; you can redistribute it and/or modify @@ -20,7 +20,7 @@ extern bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag; extern bool Dflag, inodeflag, devflag, Rflag, cflag; -extern bool noindent, force_color, xdev, nolinks, flimit, nosort; +extern bool noindent, force_color, xdev, nolinks, flimit; extern const int ifmt[]; extern const char fmt[], *ftype[]; @@ -66,7 +66,7 @@ off_t xml_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev) int t, n, mt; if ((Level >= 0) && (lev > Level)) { - fputc('\n',outfile); + if (!noindent) fputc('\n',outfile); return 0; } @@ -81,24 +81,24 @@ off_t xml_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev) return 0; } if (!n) { - fputc('\n', outfile); + if (!noindent) fputc('\n', outfile); free_dir(sav); return 0; } if (flimit > 0 && n > flimit) { - fprintf(outfile,"%d entries exceeds filelimit, not opening dir\n",n); + fprintf(outfile,"%d entries exceeds filelimit, not opening dir%s",n,noindent?"":"\n"); free_dir(sav); return 0; } - if (!nosort) qsort(dir,n,sizeof(struct _info *),cmpfunc); + if (cmpfunc) qsort(dir,n,sizeof(struct _info *), cmpfunc); if (lev >= maxdirs-1) { dirs = xrealloc(dirs,sizeof(int) * (maxdirs += 1024)); memset(dirs+(maxdirs-1024), 0, sizeof(int) * 1024); } dirs[lev] = 1; if (!*(dir+1)) dirs[lev] = 2; - fprintf(outfile,"\n"); + if (!noindent) fprintf(outfile,"\n"); path = malloc(pathsize=4096); @@ -167,7 +167,7 @@ off_t xml_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev) nlf = FALSE; if (!noindent) xml_indent(lev); } - fprintf(outfile,"\n",ftype[t]); + fprintf(outfile,"%s",ftype[t],noindent?"":"\n"); dir++; } dirs[lev] = 0; @@ -298,6 +298,6 @@ void xml_fillinfo(struct _info *ent) #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\"", ent->size); + if (sflag) fprintf(outfile, " size=\"%lld\"", (long long int)(ent->size)); if (Dflag) fprintf(outfile, " time=\"%s\"", do_date(cflag? ent->ctime : ent->mtime)); } -- 2.7.4