Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (07/04/90)
Submitted-by: kim@uts.amdahl.com (Kim E. DeVaughn) Posting-number: Volume 90, Issue 198 Archive-name: unix/ls-4.0k/part04 #!/bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 4 (of 4)." # Contents: src/ls.c.aa # Wrapped by tadguy@xanth on Tue Jul 3 15:22:14 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'src/ls.c.aa' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/ls.c.aa'\" else echo shar: Extracting \"'src/ls.c.aa'\" \(45212 characters\) sed "s/^X//" >'src/ls.c.aa' <<'END_OF_FILE' X/* ---------------------------------------------------------------------- X ls.c - main source code file for the "improved" directory utility. X Xls v4.0k is (c) Copyright 1990, Kim E. DeVaughn, all rights reserved. X X XFYI: X X UNIX is a registered trademark of AT&T. They had nothing to do with any X of this code, but did provide the "model" for some of its output formats X and options. X X XAuthor: X X Kim E. DeVaughn X X v4.0k May 11, 1990 Pretty much completely revised the output formats. X Much more like UNIX's "ls" in its output, options, X etc. Several bugs fixed. Many new options. X X Justin V. McCormick X X v3.1 July 29, 1989 Bug fixes, new output width and height options. X v3.0 July 25, 1989 Instant sorting, best-fit output, new features. X v2.2 December 1988 Fixed status return and multiple wildcard pathnames. X v2.1 December 1988 Minor size reduction, fixed a few bugs from 2.0. X v2.0 November 1988 Revised for Lattice 5.0 and made 1.3 compatible. X v1.0 August 1986 Written from scratch, my first Amiga project. X X XNotice: X XThis program is copyrighted. See the "License" accompanying this distribution Xfor limitations, and other details. X X XSynopsis: X XFeatures intelligent columnar listing, versatile sort options, UNIX-style Xpattern matching, UNIX-like output formats and flags, recursive subdirectory Xlisting, and more! X X XUsage: X ls [ [ -options <args> ] [ names ] ] ... X X XBugs and Limitations: X X"ls" cannot pattern match devices (like "dh*:"), since this would involve Xanother level of recursion and parsing the Device List. See the README file Xfor other limitations, and known bugs. X X XHistory: X X Changes From 3.1 to 4.0k: X X o New (default) long listing format that *looks* like UNIX's (except for X things like owner, group ID, etc). X o Block sizes now include *all* blocks associated with a file, and are X finally accurate for FFS devices. X o By default, upper/lower case *is* significant in the output listing, X and in the wildcard pattern matching. X o By default, directories and files are intermixed, according to their X alphabetic position. X o By default, the short listing format uses fixed width columns, based X on the length of the longest filename in the directory. Variable X width columns are still available. X o By default, "hidden", "*.info", and "dot" files (eg, .foo) are not X displayed. There are switches for each, as well as an "all" flag. X o Several new options like the ability to limit the "-R" recursion depth; X ability to show absolute and relative path names in the long format X listing; additional control of directory header and totalization X lines; elimination of redundent totalization lines; showing/sorting X on files' "disk keys"; control of the date format; sort by date/size X defaults to newest/biggest first; and a few other things. X o Improved error handling and error msgs. Better "break" handling. No X more "memory leaks" (yes, there is one in v3.1 ... it looses 300 bytes X on an error exit). X o The assignment of option flags has been "rationalized". Applicable X flags from the UNIX "ls" were assigned 1st, followed by other flags X from v3.1, followed by new flags added in this rev. However ... some X flag assignments from previous revs were changed when better mnemonic X values could be found, etc. So ... check the usage, and/or docs. X Caveat emptor! X o Flags requiring arguments (eg, -N) may or may not be seperated from X the argument by spaces. So, "-Nfoo" is just as legal as "-N foo". X X X Changes From 3.0 to 3.1: X X o Fixed random errors from uninitialized argument count in GetCLIArgs(). X o New -X and -Y options to specify short format columns and rows. X X X Changes From 2.2 to 3.0: X X o Added many new command line options! See Usage descriptions and docs. X o "Instant" output sorting, now using an on-the-fly insertion sort. X o New Short listing technique is row-by-row, redirects to PRT: or file. X o Better columnization of short listings, uses best-fit optimization. X o Formatted output parsing system implemented for long listings. X o Improved ^C handling, now breaks immediately in mid-output. X o New command line parser, now handles multiple options mixed with names. X o Added separate pattern matching for directories and files. [ DOESN'T WORK - KED ] X o Now inhibits system requesters from popping up by default. X o Added custom cres.o module for more size savings. X o Now uses Exec List functions for smaller, faster code. X o Fixed random cli_ReturnCode and pr_Result2 value CLI returns. X o Rewrote many sections, further code cleaning/commenting. X o Eliminated main(), LS handles the _main() function for smaller code. X o Compiled with 5.03.90 (beta) Lattice compiler, saved a few bytes. X X X Changes From 2.1 to 2.2: X X o Fixed erroneous Status returns. X o Fixed bug with multiple wildcarded pathnames. X o Compiled with LC 5.0 Patch 3 and CAPE 2.0, saved another 46 bytes. X o Eliminated an extra stpcpy(), saved another few bytes. X X X Changes From 2.0 to 2.1: X X o Fixed the show comment feature, a last minute bug in 2.0. X o Fixed the "Unknown option ''" message problem. X o Optimized the assembly branches, reduced code size another few bytes. X X X Changes From 1.0 to 2.0: X X o Source code prototyped, linted, traced, optimized, tweaked, etc. X o Made resident ("pseudo-pure") by linking with cres.o from LC 5.0. X o High-volume routines recoded in assembly (lssup.a). X o Now handles multiple paths/files on a command line, up to 30. X o New sort flags, including no sort. X o Enhanced wildcards, understands complex *.?*.* expressions now. X o More efficient ExNext() performance, less ram used for recursion. X o SIGBREAKF_CTRL_C signal (Ctrl-C) cleanly aborts at any point now. X o Command line parser handles quoted pathnames now (LC 5.0 benefit). X o Short listing finally auto-adjusts to new console window sizes! X o Pen color escape codes bypassed when redirecting long output. X o Sorting by size or date is also subsorted alphabetically now. X o Long listing shows new 1.3 file attributes, plus comment indicator. X o File dates are now in international format, YY-MM-DD. X o Fixed listings with files datestamped after 99-12-31 (overflow). X o Fixed listings with files datestamped before 78-01-01 (time < 0). X -------------------------------------------------------------------- */ X X/* ---------------------- LS SOURCE ---------------------------------- */ X X#include "ls.h" X X/* Extern CODE from lssup.a */ Xextern BYTE *aindex __ARGS((BYTE *, BYTE)); Xextern LONG __stdargs asprintf __ARGS((BYTE *, BYTE *,...)); Xextern LONG CompareDateStamps __ARGS((struct DateStamp *, struct DateStamp *)); Xextern LONG CompFibs __ARGS((LONG, struct FileInfoBlock *, struct FileInfoBlock *)); Xextern LONG FillFibEntry __ARGS((struct List *, struct FileInfoBlock *)); Xextern LONG GetFileString __ARGS((BYTE *, BYTE *)); Xextern LONG GetPathString __ARGS((BYTE *, BYTE *)); Xextern LONG iswild __ARGS((BYTE *)); Xextern LONG wildmatch __ARGS((BYTE *, BYTE *)); Xextern VOID *myalloc __ARGS((LONG)); Xextern VOID FibFileDate __ARGS((struct DateStamp *, BYTE *, BYTE *)); Xextern VOID GetWinBounds __ARGS((LONG *, LONG *)); Xextern VOID InsertFibNode __ARGS((struct List *, struct FibEntry *)); Xextern VOID MakePathString __ARGS((struct FileLock *, BYTE *)); Xextern VOID myfree __ARGS((VOID *)); X X/* Local DATA */ Xstruct DateStamp theolddate; /* Show files older than this date */ Xstruct DateStamp thenewdate; /* Show files newer than this date */ Xstruct FileHandle *ConOut; /* Standard output */ Xstruct FileHandle *ConIn; /* Standard input */ Xstruct FileLock *CurFLock = 0; /* Global Directory lock */ Xstruct FileInfoBlock *GFibp = 0; /* Global FIB for Examine/ExNext */ Xstruct InfoData *CurID = 0; /* Global InfoData for Info */ XAPTR OldWindowPtr; /* Copy of what was in pr_WindowPtr */ X X/* User flags (see ls.h for bit definitions) */ XULONG LSFlags = SHOWDIRS | SHOWFILES; XULONG LSFlagsX = 0; XULONG oldsig = 0; X XLONG gentrycnt; /* Grand klugde used to control printing of gtotals */ XLONG gdircount; /* Grand total # of dirs for Recursive */ XLONG gfilecount; /* Grand total # of files found */ XLONG gitemcnt; /* Grand kludge, the sequel ... for printing BS */ XLONG gtotblocks; /* Grand total # of blocks */ XLONG gtotbytes; /* Grand total # of bytes */ X XLONG dircount; /* Number of directories found */ XLONG filecount; /* Number of files found */ XLONG totblocks; /* total # of blocks */ XLONG totbytes; /* total # of bytes */ XLONG maxnamlen; /* Longest name found */ XLONG sortkey; /* 0=alpha, 1=size, 2=date, 3=diskkey */ XLONG datefmt = AGE_TO_YEARS; /* format for date in new long listing */ XLONG recurlevel = 0; XLONG recurlimit = MAXDEPTH; XLONG ioerrcode = 0; XLONG blksize = 0; X XBYTE padtab[PADTABSIZE]; /* Column table tab amounts */ XBYTE initialpath[WORKSIZE]; /* Path where we were when started */ XBYTE thePath[WORKSIZE]; /* Current filename space */ XBYTE theDirPat[WORKSIZE]; /* Dirname pattern workspace */ XBYTE theFilePat[WORKSIZE]; /* Filename pattern workspace */ XBYTE workstr[WORKSIZE+64]; /* Temp string space */ X XBYTE theblksstr[20]; XBYTE thedatestr[12]; XBYTE theprotstr[12]; XBYTE thesizestr[20]; XBYTE thetimestr[12]; X XLONG CurWinRows = 0; /* Window bounds, determined at runtime */ XLONG CurWinCols = 0; X X/* Initialized Strings */ XBYTE Author[] = "\23333mls v4.0k\2330m \251 Copyright Kim E. DeVaughn 05/11/90 [non-k revs: J. McCormick]\n"; XBYTE usage[] = "usage: ls [ [-options <args>] [names] ] ...\n"; XBYTE usage0[] = " a Show dot files s Sort by size M Ignore case w/wildcard\n"; XBYTE usage1[] = " b Show data blks t Sort by date N <name> Show newer than\n"; XBYTE usage2[] = " c Show filenotes u Usage [also -?] O <name> Show older than\n"; XBYTE usage3[] = " d Show dirs only v Vari col short list P Show full pathnames\n"; XBYTE usage4[] = " e Execute bit is \"e\" x <pat> Exclude files Q Requesters enabled\n"; XBYTE usage5[] = " f Show files only z Override blk calc R Recursive listing\n"; XBYTE usage6[] = " h Show hidden files A Show all [= -ahi] S Show dirs first\n"; XBYTE usage7[] = " i Show *.info files B <blk> Force blk size T Totals for all entries\n"; XBYTE usage8[] = " k Sort by disk key C Single column list V Show rel pathnames\n"; XBYTE usage9[] = " l Long listing D Show dirs last W No contents (wild dir)\n"; XBYTE usage10[] = " m Mixed case output E No ANSI escape codes X <wide> Set output cols\n"; XBYTE usage11[] = " n No sort G No subdir totals Y <high> Set output rows\n"; XBYTE usage12[] = " o Old long list fmt H No headings Z Force ANSI sequences\n"; XBYTE usage13[] = " p Append \"/\" to dirs I No page prompts 0-6 Date format (new long)\n"; XBYTE usage14[] = " q Quit on not found K Show disk keys - Next arg is filename\n"; XBYTE usage15[] = " r Reverse sort L <n> Limited recursion\n"; XBYTE usage16[] = " F <format> Format output [-o fmt] (default: \""; XBYTE usage17[] = "\")\n"; X X/* Date and output format strings */ XBYTE baddatestr[] = "00-00-00"; XBYTE badtimestr[] = "00:00:00"; XBYTE datepat[] = "%02ld-%02ld-%02ld"; XBYTE timepat[] = "%02ld:%02ld:%02ld"; XBYTE dayspermonth[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; XBYTE deffmtstr[40] = "%p %d %t %4b %8s %n\\n"; XBYTE LongFmtStr[] = "%ld"; XBYTE totalfmtstr[] = "Dirs: %-4ld Files: %-5ld Blocks: %-5ld Bytes: %-8ld\n"; XBYTE filefmtstr[] = " Files: %-5ld Blocks: %-5ld Bytes: %-8ld\n"; XBYTE TotHeaderMsg[] = "\nTotals:\n"; XBYTE ColonStr[] = ":"; XBYTE SlashStr[] = "/"; XBYTE RamNameStr[] = "RAM:"; Xchar *months[] = {"","Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"}; Xchar exbit = 'x'; X X/* ANSI color control strings */ XBYTE penstr0[] = "\2330m"; /* Reset CON: */ XBYTE penstr1[] = "\2330 p"; /* Cursor off */ XBYTE penstr2[] = "\233 p"; /* Cursor on */ XBYTE penstr3[] = "\23333m"; /* Color 3 NORM */ XBYTE penstr4[] = "\2331;33;40m"; /* Color 3 BOLD */ XBYTE penstr5[] = "\2331;31;40m"; /* Color 1 BOLD */ XBYTE penstr6[] = "\2337;33m\2330 p"; /* Color 3 INV w/cursor off */ X X/* CON: command sequence for window bounds report */ XBYTE gwbrstr[4] = { 0x9b, '0', ' ', 'q' }; X X/* Newline and "" source */ X#define NULLSTR &NLine[1] XBYTE NLine[4] = {10, 0, 0, 0}; XBYTE badopt[4] = {0, 0, 0, 0}; X X/* Pointers to usage strings for quick easy output */ XBYTE *usagestrs[] = X{ X Author, usage, usage0, usage1, usage2, usage3, usage4, usage5, X usage6, usage7, usage8, usage9, usage10, usage11, usage12, usage13, X usage14, usage15, usage16, deffmtstr, usage17, X 0L X}; X XBYTE *thefmtstr = deffmtstr; /* Format string pointer for long output */ XBYTE *curpath; XBYTE *theAntiPat; /* Avoid pattern string */ X X/* Local CODE */ XBYTE *GetDecNum __ARGS((BYTE *, LONG *)); XLONG CmpDateBounds __ARGS((struct DateStamp *)); XLONG GetFileDate __ARGS((BYTE *, struct DateStamp *)); XLONG ParseCmdOptions __ARGS((LONG, LONG, BYTE **)); Xstruct FibEntry *AllocFib __ARGS((VOID)); Xstruct FibEntry *ModNextFib __ARGS((struct FibEntry *, LONG)); Xstruct List *GetDir __ARGS((struct FileLock *, struct FileInfoBlock *)); XVOID DirIt __ARGS((struct FileLock *, BYTE *)); XVOID FreeAllFibs __ARGS((struct List *)); XVOID GetCLIArgs __ARGS((BYTE *, LONG *, BYTE **)); XVOID LListDir __ARGS((struct List *)); XVOID LListEntry __ARGS((struct FileInfoBlock *)); XVOID LongList __ARGS((LONG *, LONG *, struct List *)); XVOID PagePrompt __ARGS((LONG, LONG)); XVOID ParseFormatOpts __ARGS((struct FileInfoBlock *)); XVOID SetConPen __ARGS((BYTE *)); XVOID SListDir __ARGS((struct List *)); XVOID TestBreak __ARGS((VOID)); XVOID Usage __ARGS((LONG)); XVOID WCHR __ARGS((BYTE *)); XVOID WSTR __ARGS((BYTE *)); XVOID _main __ARGS((BYTE *)); XLONG attrstr __ARGS((register BYTE *, register LONG *, register LONG *)); XVOID fixNumBlocks __ARGS((struct FileLock *, FIB *)); XLONG blkalloc __ARGS((register FIB *)); XLONG datestr __ARGS((BYTE *, struct DateStamp *, LONG)); XVOID cleanup __ARGS((LONG, LONG)); XVOID errmsg __ARGS((BYTE *, LONG)); XVOID llistentry __ARGS((register FIB *)); X X X/* X * cleanup() - Unlock any locks we may have, free up allocations, turn the X * system requesters back on, and get on out ... X * X */ X XVOID cleanup(result2, retcode) X LONG result2; X LONG retcode; X{ X struct Process *procp; X X/* Make sure we unlock any locks we created! */ X if ((CurFLock != 0) && ((LSFlags & PATHNAMED) != 0)) X UnLock((BPTR)CurFLock); X X/* Free our fib and id */ X if (GFibp != 0) myfree(GFibp); X if (CurID != 0) myfree(CurID); X X/* Put windowptr back */ X procp = (struct Process *)FindTask(0L); X procp->pr_WindowPtr = OldWindowPtr; X X/* Set return status, exit */ X procp->pr_Result2 = result2; X exit((int)retcode); X} X X X/* X * errmsg() - Print meaningful error messages when something screws up. X * X */ X XVOID errmsg(fn, errcode) X BYTE *fn; X LONG errcode; X{ X LONG len; X X/* Make sure we unlock any locks we created! */ X if ((CurFLock != 0) && ((LSFlags & PATHNAMED) != 0)) X { X UnLock((BPTR)CurFLock); X CurFLock = 0; X } X X if (errcode == -1L) errcode = ioerrcode = IoErr(); X X len = strcspn(fn, ":") + 1; X strncpy(workstr, fn, len); X *(workstr + len) = '\0'; X X switch(errcode) X { X case ERROR_NO_FREE_STORE: X WSTR("ls: Out of memory\n"); X cleanup(errcode, 20L); X case ERROR_OBJECT_IN_USE: X asprintf(workstr, "%s: File or directory in use\n", fn); X break; X case ERROR_DIR_NOT_FOUND: X case ERROR_OBJECT_NOT_FOUND: X case ERROR_OBJECT_WRONG_TYPE: X asprintf(workstr, "%s: No such file or directory\n", fn); X break; X case ERROR_DISK_NOT_VALIDATED: X strcat(workstr, " Filesystem not validated\n"); X break; X case ERROR_DEVICE_NOT_MOUNTED: X strcat(workstr, " Device not mounted or assigned\n"); X break; X case ERROR_NOT_A_DOS_DISK: X strcat(workstr, " Invalid filesystem format [non-DOS]\n"); X break; X case ERROR_NO_DISK: X strcat(workstr, " Device empty\n"); X break; X case PATTERN_ERR: X WSTR("ls: Directory or filename pattern too long\n"); X return; X case WILDSPEC_ERR: X asprintf(workstr, "%s: Unable to pattern match paths\n", fn); X break; X default: X asprintf(workstr, "ls: %s: Error - %ld\n", fn, errcode); X WSTR(workstr); X cleanup(errcode, 20L); X } X WSTR(workstr); X} X X X/* X * datestr() - Converts an AmigaDOS "datestamp" into an ASCII string in one X * of several defined formats. X * X * A non-zero return indicates an unknown format was requested, X * in which case the return string is null'd. X * X */ X XLONG datestr(s, ds, format) X BYTE *s; X struct DateStamp *ds; X LONG format; X{ X register LONG t, mo, yr; X LONG y2, day, hr, min, sec; X struct DateStamp cds; X X t = ds->ds_Days - 2251; /* This date algorithm by Tom Rokicki. */ X yr = (4 * t + 3) / 1461; /* It was taken from Rob Peck's book: */ X t -= 1461 * yr / 4; /* "Programmer's Guide to the Amiga", */ X yr += 1984; /* and is supposed to be good until 2100; */ X mo = (5 * t + 2) / 153; /* doesn't work for dates before 03/01/84 */ X day = t - ((153 * mo + 2) / 5) + 1; X mo += 3; X if (mo > 12) { X yr++; X mo -= 12; X } X y2 = (yr < 2000) ? yr-1900 : yr-2000; /* after 2099 ... punt! */ X X X t = ds->ds_Minute * 60 + ds->ds_Tick/TICKS_PER_SECOND; X sec = t % 60; t /= 60; X min = t % 60; t /= 60; X hr = t % 24; X X X switch (format) { X X case AGE_TO_YEARS : X DateStamp(&cds); X if (((cds.ds_Days - ds->ds_Days) > TIME_YEAR_THRESHOLD) || X ((cds.ds_Days - ds->ds_Days) < 0)) { X asprintf(s, "%s %2ld %5ld\0", months[mo], day, yr); X } else { X asprintf(s, "%s %2ld %02ld:%02ld\0", months[mo], day, hr, min); X } X break; X X case FULL_FORM : X asprintf(s, "%s %02ld %4ld %02ld:%02ld:%02ld\0", months[mo], day, yr, hr, min, sec); X break; X X case DASHA_FORM : X asprintf(s, "%02ld-%s-%02ld %02ld:%02ld:%02ld\0", day, months[mo], y2, hr, min, sec); X break; X X case DASHN_FORM : X asprintf(s, "%02ld-%02ld-%02ld %02ld:%02ld:%02ld\0", mo, day, y2, hr, min, sec); X break; X X case SLASH_FORM : X asprintf(s, "%02ld/%02ld/%02ld %02ld:%02ld:%02ld\0", mo, day, y2, hr, min, sec); X break; X X case EURO_FORM : X asprintf(s, "%02ld/%02ld/%02ld %02ld:%02ld:%02ld\0", day, mo, y2, hr, min, sec); X break; X X case DOT_FORM : X asprintf(s, "%02ld.%02ld.%02ld %02ld:%02ld:%02ld\0", y2, mo, day, hr, min, sec); X break; X X default : X *s = '\0'; /* bad format ... null out the filedate string */ X return(1); X } X return(0); X} X X X/* X * attrstr() - Converts FileInfoBlock DirEntryType & Protection entries into X * an ASCII string representation. Format is: X * X * dhsparwxd ["h" may possibly be replaced by "H" or "+"] X * X * where a letter is replaced by a "-" if the corresponding X * attribute is not associated with the current FIB entry (i.e., X * if the bit is not "true"). [The "H" or "+" form indicates X * one or more of the currently reserved/undefined high-order X * bits (as of 1.3) are on. An "H" is used if the "hidden" bit X * is also on ... a "+" is used if it is not.] X * X * A non-zero return code indicates the "H" or "+" form was X * detected. X * X * Note: Due to historical braindamage in AmigaDOS, bits 0-3 X * (the original "protection" bits) are "active low", X * while bits 4-7 (more properly called "attribute" bits) X * are "active high". At least this is based on the way X * the 1.3 Delete, Resident, Shell, and Protect commands X * interpret the "d", "p", and "s" bits (and how the List X * command displays them). [ Thanks alot Tim ...! ] X * X */ X XLONG attrstr(s, type, prot) X register BYTE *s; X register LONG *type; X register LONG *prot; X{ X BYTE *t; X X t = s; X *s++ = (*type > 0) ? 'd' : '-'; X *s++ = (*prot & FIBF_HIDDEN) ? 'h' : '-'; X *s++ = (*prot & FIBF_SCRIPT) ? 's' : '-'; X *s++ = (*prot & FIBF_PURE) ? 'p' : '-'; X *s++ = (*prot & FIBF_ARCHIVE) ? 'a' : '-'; X *s++ = (*prot & FIBF_READ) ? '-' : 'r'; X *s++ = (*prot & FIBF_WRITE) ? '-' : 'w'; X *s++ = (*prot & FIBF_EXECUTE) ? '-' : exbit; X *s++ = (*prot & FIBF_DELETE) ? '-' : 'd'; X *s = '\0'; X X if (*prot & FIBF_RESERVED) { X if (*prot & FIBF_HIDDEN) { X t[1] = 'H'; X } else { X t[1] = '+'; X } X return(1); X } X return(0); X} X X X/* X * fixNumBlocks() - A hack to fix the fib_NumBlocks field so it is correct. X * X * It was busted with the introduction of the FFS in AmigaDOS 1.3. Don't X * ask where this is documented ... as far as I know, it isn't not in the X * 1.3 includes, autodocs, readme's, user's manual, RKM's, or DevCon notes. X * It is possible it may be mentioned in an AmigaMail (that wonderfully X * regular publication), and I'm told it was mentioned once in a message on X * USENET. X * X * Helluva way to run a ship ... X * X * As may be ... since fib_NumBlocks was in use thruout this code before X * this was discovered, it was easiest to just fixup the fib_NumBlocks when X * the file/dir gets initially Examine/ExNext'd, with a call to Info() for X * *all* files (which means alot of unnecessary calls get made [for files X * all in the same dir, etc]). The performance penalty ends up being about X * 1 sec, for a tree with 537 entries (which seems acceptable to me). X * X * If you don't like it ... I suggest you complain to CBM about their, er, X * uhmm, "documentation" efforts! X * X * Helluva way to run a ship ... X * X * /kim /\;;/\ X * X */ X XVOID fixNumBlocks(lock, fib) X struct FileLock *lock; X FIB *fib; X{ X LONG *nb; X LONG bsize; X static int errflag = 0; X X if ((LSFlagsX & NOFIXNUMBLOCKS) != 0) return; X X if (blksize == 0) X { X /* Try to fill InfoData, bomb if not readable for some reason (like */ X if (Info((BPTR)lock, CurID) == 0) /* ls'ing a "pathass'd" assign) */ X { X /* Print error msg only once, and only if we'll be printing block counts */ X if ((errflag == 0) && ((LSFlags & (LONGLIST | TOTALIZE)) != 0)) X { X errflag++; X asprintf(workstr, "\nls: warning (%ld): block count(s) may be inaccurate - see ls.doc\n\n", IoErr()); X WSTR(workstr); X } X return; X } X else X bsize = CurID->id_BytesPerBlock; X } X else X bsize = blksize; X X nb = (LONG *)&(fib->fib_NumBlocks); X *nb = (fib->fib_Size / bsize) + ((fib->fib_Size % bsize) ? 1 : 0); X} X X X/* X * blkalloc() - Returns the actual number of blocks allocated by a file/dir X * (or just the data blocks, if DATABLKSONLY is set). X * X * Assumes 1.3 original or fast filesystem (and a fixed up fib_NumBlocks). X * X */ X XLONG blkalloc(fib) X register FIB *fib; X{ X if ((LSFlagsX & DATABLKSONLY) == 0) { X return(fib->fib_NumBlocks + X (fib->fib_NumBlocks / MAX_BLKS_PER_EXTENT) + X ((fib->fib_NumBlocks % MAX_BLKS_PER_EXTENT) ? 1 : 0) + X ((fib->fib_Size == 0) ? 1 : 0) /* kludge for 0-len files (and dirs) */ X ); X } else { X return(fib->fib_NumBlocks); X } X} X X X/* X * llistentry() - Prints the data in a FIB entry. X * X */ X XVOID llistentry(fib) X register FIB *fib; X{ X BYTE tbuf[64]; /* shouldn't exceed about 47-53 chars max (but add some pad) */ X LONG len; X X attrstr(workstr, &(fib->fib_DirEntryType), &(fib->fib_Protection)); X X if (fib->fib_Comment[0] == 0) { X strcat(workstr, " "); X } else { X strcat(workstr, " c"); X } X X if ((LSFlags & SHOWDISKKEYS) != 0) X { X asprintf(tbuf, " %6ld", fib->fib_DiskKey); X strcat(workstr, tbuf); X } X X asprintf(tbuf, " %5ld %8ld ", blkalloc(fib), fib->fib_Size); X strcat(workstr, tbuf); X X datestr(tbuf, &(fib->fib_Date), datefmt); X strcat(workstr, tbuf); X strcat(workstr, " "); X X WSTR(workstr); X X if (fib->fib_DirEntryType > 0) SetConPen(penstr3); X X *workstr = '\0'; X if (((LSFlags & RELPATHNAMES) != 0) || ((LSFlags & FULLPATHNAMES) != 0)) X { X strcat(workstr, curpath); X len = strlen(workstr); X if ((len > 1) && (*(workstr + len - 1) != ':')) X strcat(workstr, "/"); X } X X strcat(workstr, fib->fib_FileName); X X len = 0; X if ((LSFlags & RELPATHNAMES) != 0) X { X len = strlen(initialpath); X if ((strnicmp(workstr, initialpath, len) == 0) && (len < strlen(workstr))) X { X if (*(workstr + len) == '/') X len++; X } X else X len = 0; X } X X if (((LSFlags & ADDDIRSLASH) != 0) && (fib->fib_DirEntryType > 0)) X strcat(workstr, "/"); X X/* commented out until there is more support for NOT defaulting to "x" */ X/* if (workstr[0] == 'd') { X * strcat(workstr, "/"); X * } else if (workstr[7] != '-') { X * strcat(workstr, "*"); X * } X */ X X strcat(workstr, "\n"); X WSTR(workstr + len); X X if (fib->fib_DirEntryType > 0) SetConPen(penstr0); X X if (((LSFlags & NOTEFLAG) != 0) && (fib->fib_Comment[0] != 0)) X { X SetConPen(penstr3); X asprintf(workstr, "\"%s\"\n", fib->fib_Comment); X WSTR (workstr); X SetConPen(penstr0); X } X} X X X/* -------------------------------------------------------------------- X * Allocate a FibEntry structure and associated FileInfoBlock. X * -------------------------------------------------------------------- */ Xstruct FibEntry *AllocFib() X{ X struct FibEntry *tfibp; X X if ((tfibp = myalloc((LONG)(sizeof(struct FibEntry) + sizeof(struct FileInfoBlock)))) != 0) X { X tfibp->fe_Fib = (struct FileInfoBlock *)((ULONG)tfibp + sizeof(struct FibEntry)); X } X else X LSFlags |= BREAKFLAG; X return(tfibp); X} X X X/* -------------------------------------------------------------------- X * Use AmigaDOS to output a string to the stdout channel X * -------------------------------------------------------------------- */ XVOID WSTR(tstring) X BYTE *tstring; X{ X LONG i; X X i = strlen(tstring); X if (i > 0) X { X (VOID) Write((BPTR)ConOut, tstring, i); X } X} X X X/* -------------------------------------------------------------------- X * Use AmigaDOS to put a character to the stdout X * -------------------------------------------------------------------- */ XVOID WCHR(ch) X BYTE *ch; X{ X (VOID) Write((BPTR)ConOut, ch, 1L); X} X X X/* -------------------------------------------------------------------- X * Check to see if the user hit ^C X * X * Coded in this arcane fashion since there seems to be a race/etc. between X * the SetSignal() call, and the WSTR() and or'ing in of the BREAKFLAG. If X * the outer "if" is omitted, "**BREAK" prints 3 times; if the outer "else" X * is omitted, the BREAKFLAG doesn't seem to get or'd in ... grumble, swear! X * X * As my be ... this is an ugly hack, but it seems to work ... X * X * C'est la vie ... /kim X * X * -------------------------------------------------------------------- */ XVOID TestBreak () X{ X if ((oldsig & SIGBREAKF_CTRL_C) == 0) X { X oldsig = SetSignal (0L, 0L); X if ((oldsig & SIGBREAKF_CTRL_C) != 0) X { X WSTR ("\2330m\233 p**BREAK\n"); X LSFlags |= BREAKFLAG; X } X } X else X { X LSFlags |= BREAKFLAG; X } X} X X X/* -------------------------------------------------------------------- X * Prompt the user to hit return, wait till return is hit X * -------------------------------------------------------------------- */ XVOID PagePrompt (page, maxpage) X LONG page, maxpage; X{ X if ((CurWinCols > maxnamlen) && (page > 1) && ((LSFlags & NOINTERACT) == 0)) X { X SetConPen(penstr6); X asprintf(workstr, " More (%ld of %ld) ... ", (page - 1), maxpage); X if (CurWinCols <= strlen(workstr)) X strcpy(workstr, "More ... "); X WSTR(workstr); X SetConPen(penstr0); X (VOID) Read((BPTR)ConIn, workstr, (long)WORKSIZE); X WSTR("\2330 p\233F\233K"); X TestBreak(); X } X} X X X/* -------------------------------------------------------------------- */ Xstruct FibEntry *ModNextFib(tfibp, rows) X struct FibEntry *tfibp; X LONG rows; X{ X LONG i; X X for (i = 0; i < rows && tfibp->fe_Node.mln_Succ != 0; i++) X { X tfibp = (struct FibEntry *)tfibp->fe_Node.mln_Succ; X } X return(tfibp); X} X X X/* -------------------------------------------------------------------- X * set CON: character color to default Pen1 colors X * -------------------------------------------------------------------- */ XVOID SetConPen (penstr) X BYTE *penstr; X{ X if ((LSFlags & CONSOLE) != 0) X WSTR (penstr); X} X X X/* #define DEBUGSLD 1 */ X/* -------------------------------------------------------------------- X * List a FibEntry list in a compact fashion X * -------------------------------------------------------------------- */ XVOID SListDir (fibheadp) X struct List *fibheadp; X{ X LONG avglen; X LONG colcnt; X LONG currow; X LONG dfcount; X LONG i, j, wlen; X LONG maxcol; X LONG maxpage; X LONG maxrow; X LONG maxwinrow; X LONG minpad = 2; /* minimum number of blanks between listing entries */ X LONG pagecnt; X LONG rowcnt; X LONG tlen; X LONG totlen; X struct FibEntry *hfibp, *tfibp; X X SetConPen (penstr1); /* Turn the cursor off since it will blink anyway */ X GetWinBounds (&colcnt, &currow); /* Get current window size */ X X if (CurWinCols == 0) X CurWinCols = colcnt; X if (CurWinRows == 0) X CurWinRows = currow; X X if ((LSFlags & VARCOLSFORMAT) != 0) X { X /* Make a average-case WxH estimate for # of display columns */ X for (totlen = dfcount = 0, hfibp = (struct FibEntry *)fibheadp->lh_Head; X hfibp->fe_Node.mln_Succ != 0; X hfibp = (struct FibEntry *)hfibp->fe_Node.mln_Succ) X { X if (hfibp->fe_Fib->fib_DirEntryType > 0 && (LSFlags & CONSOLE) == 0) X (VOID) strcat (hfibp->fe_Fib->fib_FileName, SlashStr); X totlen += strlen (hfibp->fe_Fib->fib_FileName); X dfcount++; X if (((LSFlags & WILDPATH) != 0) && (hfibp->fe_Fib->fib_DirEntryType > 0)) X { X totlen -= strlen (hfibp->fe_Fib->fib_FileName); X dfcount--; X } X } X if (dfcount == 0) dfcount++; X X /* Calc average length of all entries */ X avglen = totlen / dfcount; /* Avg name length = totlen/numentries */ X if ((totlen % dfcount) != 0) X avglen++; X X /* Longest name wider than window, or single column flag set? */ X if ((CurWinCols <= maxnamlen) || ((LSFlags & ONECOLFORMAT) != 0)) X maxcol = 1; /* Yep, just print one column */ X else X { X /* Else maxcols = winwidth/namewidth */ X for (maxcol = 0, colcnt = CurWinCols; colcnt >= avglen; maxcol++) X { X colcnt -= avglen + 2; X } X } X#ifdef DEBUGSLD X asprintf(workstr, "avg:%ld max:%ld\n", avglen, maxnamlen); WSTR(workstr); X#endif X X /* Dry run output avg-case WxH table to see if it needs adjusting */ X for (;;) X { X /* Clear out previous padtab */ X memset(padtab, 0, PADTABSIZE); X X /* Number of rows = total entries / entries per row */ X maxrow = dfcount / maxcol; X if ((dfcount % maxcol) != 0) /* Round up if non-integral */ X maxrow++; X#ifdef DEBUGSLD X asprintf(workstr, "avg: %ld rows by %ld cols\n", maxrow, maxcol); WSTR(workstr); X#endif X X for (rowcnt = 0, hfibp = (struct FibEntry *)fibheadp->lh_Head; X rowcnt < maxrow && hfibp->fe_Node.mln_Succ != 0; X rowcnt++, hfibp = (struct FibEntry *)hfibp->fe_Node.mln_Succ) X { X for (colcnt = 0, tfibp = hfibp; X colcnt < maxcol && tfibp->fe_Node.mln_Succ != 0; X colcnt++, tfibp = ModNextFib (tfibp, maxrow)) X { X if (~(((LSFlags & WILDPATH) != 0) && (tfibp->fe_Fib->fib_DirEntryType > 0))) X { X tlen = strlen (tfibp->fe_Fib->fib_FileName); X if (tlen > padtab[colcnt]) X padtab[colcnt] = tlen; X } X } X X /* If this is the first row, calc actual maxcol/maxrow for this dfcount */ X if (rowcnt == 0) X { X maxcol = colcnt; X maxrow = dfcount / maxcol; X if ((dfcount % maxcol) != 0) /* Round up if non-integral */ X maxrow++; X } X } X X /* Calculate actual total width by adding up width of all columns */ X for (colcnt = totlen = 0; (colcnt + 1) < maxcol; colcnt++) X { X totlen += (LONG)padtab[colcnt] + 2; X#ifdef DEBUGSLD X asprintf(workstr, "padtab[%ld]=%ld\n", colcnt, (LONG)padtab[colcnt]); WSTR(workstr); X#endif X } X totlen += (LONG)padtab[colcnt]; X#ifdef DEBUGSLD X asprintf(workstr, "padtab[%ld]=%ld\n", colcnt, (LONG)padtab[colcnt]); WSTR(workstr); X asprintf(workstr, "totlen %ld\n", totlen); WSTR(workstr); X#endif X X /* if More than one column and X * total width of all columns is greater > our window width, X * then decrease number of display columns X */ X if ((maxcol > 1) && (totlen > CurWinCols)) X { X maxcol--; X#ifdef DEBUGSLD X asprintf(workstr, "new maxcol:%ld\n", maxcol); WSTR(workstr); X#endif X } X else X break; X } X#ifdef DEBUGSLD X asprintf(workstr, "adjusted: maxrow:%ld maxcol:%ld (winwidth:%ld totlen:%ld)\n", maxrow, maxcol, CurWinCols, totlen); WSTR(workstr); X#endif X X } X else X { X X if ((LSFlags & ADDDIRSLASH) != 0) X maxnamlen += 1; X X for (dfcount = 0, hfibp = (struct FibEntry *)fibheadp->lh_Head; X hfibp->fe_Node.mln_Succ != 0; X hfibp = (struct FibEntry *)hfibp->fe_Node.mln_Succ) X { X if ((LSFlags & ADDDIRSLASH) != 0) X if (hfibp->fe_Fib->fib_DirEntryType > 0) X (VOID) strcat (hfibp->fe_Fib->fib_FileName, SlashStr); X else X (VOID) strcat (hfibp->fe_Fib->fib_FileName, " "); X dfcount++; X if (((LSFlags & WILDPATH) != 0) && (hfibp->fe_Fib->fib_DirEntryType > 0)) X dfcount--; X } X X if ((CurWinCols <= maxnamlen) || ((LSFlags & ONECOLFORMAT) != 0)) X maxcol = 1; X else X maxcol = CurWinCols / (maxnamlen + minpad); X maxrow = dfcount / maxcol; X if ((dfcount % maxcol) != 0) X maxrow++; X memset(padtab, 0, PADTABSIZE); X for (colcnt = 0; colcnt < maxcol; colcnt++) X padtab[colcnt] = maxnamlen; X } X X/* Calc number of pages */ X maxwinrow = CurWinRows - 1; /* was -3 in v3.1 */ X if (maxwinrow <= 0) X maxwinrow = 1; X pagecnt = 1; X maxpage = maxrow / maxwinrow; X if ((maxrow % maxwinrow) != 0) X maxpage++; X X/* Do actual output scan */ X for (rowcnt = 0, currow = maxwinrow, hfibp = (struct FibEntry *)fibheadp->lh_Head; X (LSFlags & BREAKFLAG) == 0 && rowcnt < maxrow && hfibp->fe_Node.mln_Succ != 0; X TestBreak(), rowcnt++, currow++, hfibp = (struct FibEntry *)hfibp->fe_Node.mln_Succ) X { X if ((maxpage > 1) && (currow == maxwinrow)) X { X currow = 0; X if ((LSFlags & CONSOLE) != 0) X { X PagePrompt (pagecnt, maxpage); X if ((LSFlags & BREAKFLAG) != 0) X break; X } X pagecnt++; X } X X for (colcnt = 0, tfibp = hfibp; X colcnt < maxcol && tfibp->fe_Node.mln_Succ != 0; X colcnt++) X { X if (tfibp->fe_Fib->fib_DirEntryType < 0) X { X /* Print a file entry */ X (VOID) stpcpy (workstr, tfibp->fe_Fib->fib_FileName); X wlen = strlen (workstr); X } X else X { X /* Print a directory entry */ X workstr[0] = 0; X wlen = 0; X X if ((LSFlags & WILDPATH) == 0) X { X wlen = strlen (tfibp->fe_Fib->fib_FileName); X if ((LSFlags & CONSOLE) != 0) X (VOID) strcat (workstr, penstr3); X (VOID) strcat (workstr, tfibp->fe_Fib->fib_FileName); X if ((LSFlags & CONSOLE) != 0) X (VOID) strcat (workstr, penstr0); X } X } X X /* Move along list to the next entry, mod maxcol, print this entry */ X tfibp = ModNextFib (tfibp, maxrow); X X /* If this is not the last column, pad with spaces till we get to next column */ X if ((colcnt + 1) < maxcol && tfibp->fe_Node.mln_Succ != 0) X { X for (i = (LONG)padtab[colcnt] - 1 + minpad, j = strlen (workstr); i >= wlen; i--, j++) X workstr[j] = ' '; X workstr[j] = 0; X } X /* Output the final entry */ X WSTR(workstr); X } X X /* Filled this row, start next down */ X WCHR(NLine); X } X SetConPen(penstr2); /* Turn cursor back on */ X} X X X/* -------------------------------------------------------------------- */ XBYTE *GetDecNum (cp, spccnt) X BYTE *cp; X LONG *spccnt; X{ X for (*spccnt = 0; *cp >= '0' && *cp <= '9'; cp++) X { X *spccnt = *spccnt * 10 + (LONG)*cp - '0'; X } X return (cp); X} X X X/* -------------------------------------------------------------------- */ XVOID ParseFormatOpts (fib) X struct FileInfoBlock *fib; X{ X BYTE *cp1, *cp2, *reps; X BYTE *pathend, *thenamestr; X LONG i, spccnt; X X i = strlen (curpath); X pathend = curpath + i; X if (i > 1 && *(curpath + i - 1) != ':') X { X *(curpath + i) = '/'; X i++; X *(curpath + i) = 0; X } X thenamestr = curpath + strlen(curpath); X cp2 = thenamestr; X if (fib->fib_DirEntryType > 0 && (LSFlags & CONSOLE) != 0) X cp2 = stpcpy (cp2, penstr3); X cp2 = stpcpy (cp2, fib->fib_FileName); X if (fib->fib_DirEntryType > 0 && (LSFlags & CONSOLE) != 0) X (VOID) stpcpy (cp2, penstr0); X X for (cp1 = workstr, cp2 = thefmtstr; *cp2 != 0; cp2++) X { X if (*cp2 != '%' && *cp2 != '\\') X *cp1++ = *cp2; X else X { X if (*cp2 == '%') X { X cp2++; X cp2 = GetDecNum (cp2, &spccnt); X if (spccnt > 99) X { X spccnt = 99; X } X X switch (*cp2) X { X case 'p': X reps = theprotstr; X break; X case 'd': X reps = thedatestr; X break; X case 't': X reps = thetimestr; X break; X case 'b': X reps = theblksstr; X break; X case 's': X reps = thesizestr; X break; X case 'n': X if (fib->fib_DirEntryType > 0 && (LSFlags & CONSOLE) != 0 && spccnt > 0) X spccnt += 7; X if ((LSFlags & FULLPATHNAMES) != 0) X reps = curpath; X else X reps = thenamestr; X break; X case '%': X *cp1++ = '%'; X *cp1++ = 0; X default: X reps = NULLSTR; X } X for (i = strlen(reps); i < spccnt; i++) X *cp1++ = ' '; X cp1 = stpcpy (cp1, reps); X } X else X { X cp2++; X switch (*cp2) X { X case 'n': X *cp1++ = '\n'; X break; X case 't': X *cp1++ = '\t'; X break; X case '\\': X *cp1++ = '\\'; X break; X } X *cp1 = 0; X } X } X } X WSTR(workstr); X X if ((LSFlags & NOTEFLAG) != 0 && fib->fib_Comment[0] != 0) X { X SetConPen(penstr3); X (VOID)asprintf(workstr, "/* %s */\n", fib->fib_Comment); X WSTR (workstr); X SetConPen(penstr0); X } X *pathend = 0; X} X X X/* -------------------------------------------------------------------- X * Verbosely list a particular FibEntry X * -------------------------------------------------------------------- */ XVOID LListEntry (fib) X struct FileInfoBlock *fib; X{ X LONG i; X LONG pmodes; X X pmodes = fib->fib_Protection & 0xff; X (VOID)stpcpy (theprotstr, "chsparw7d"); X theprotstr[7] = exbit; X for (i = 3; i >= 0; i--) X { X if ((pmodes & (1 << i)) != 0) X theprotstr[8 - i] = '-'; X if ((pmodes & (1 << (i + 4))) == 0) X theprotstr[4 - i] = '-'; X } X X if (fib->fib_Comment[0] == 0) X theprotstr[0] = '-'; X X FibFileDate(&fib->fib_Date, thedatestr, thetimestr); X X if (fib->fib_DirEntryType > 0) X { X if ((LSFlagsX & DATABLKSONLY) != 0) X stpcpy(theblksstr, "0"); X else X stpcpy(theblksstr, "1"); X stpcpy (thesizestr, "Dir"); X } X else X { X asprintf(theblksstr, LongFmtStr, blkalloc(fib)); X asprintf(thesizestr, LongFmtStr, fib->fib_Size); X } X ParseFormatOpts(fib); X} X X X/* -------------------------------------------------------------------- X * List a directory in a verbose informative manner X * -------------------------------------------------------------------- */ XVOID LListDir (fibheadp) X struct List *fibheadp; X{ X struct FibEntry *tfibp; X X SetConPen(penstr1); X X totblocks = totbytes = 0; X for (tfibp = (struct FibEntry *)fibheadp->lh_Head; X tfibp->fe_Node.mln_Succ != 0; X tfibp = (struct FibEntry *)tfibp->fe_Node.mln_Succ) X { X TestBreak(); X if ((LSFlags & BREAKFLAG) != 0) X return; X X if ((tfibp->fe_Fib->fib_DirEntryType > 0) && ((LSFlags & WILDPATH) != 0)) X { X ; /* seems to be a Lattice v5.04a bug ... negating the test and putting the "else" here doesn't work */ X } X else X { X if ((LSFlags & OLDLONGFORMAT) != 0) X LListEntry (tfibp->fe_Fib); X else X llistentry (tfibp->fe_Fib); X X totblocks += blkalloc(tfibp->fe_Fib); X totbytes += tfibp->fe_Fib->fib_Size; X } X } X X if ((LSFlags & (BREAKFLAG | NODIRTOTAL)) == 0) X { X if ((LSFlags & WILDPATH) == 0) X { X if ((dircount + filecount) > 1) X { X asprintf(workstr, totalfmtstr, dircount, filecount, totblocks, totbytes); X WSTR(workstr); X } X } X else X { X if (filecount > 1) X { X asprintf(workstr, filefmtstr, filecount, totblocks, totbytes); X WSTR(workstr); X } X } X } X SetConPen(penstr2); X} X X X/* -------------------------------------------------------------------- */ XLONG CmpDateBounds (tdate) X struct DateStamp *tdate; X{ X if ((LSFlags & SHOWNEWERTHAN) != 0) X { X if (CompareDateStamps(&thenewdate, tdate) >= 0) X return (0L); X } X if ((LSFlags & SHOWOLDERTHAN) != 0) X { X if (CompareDateStamps(tdate, &theolddate) >= 0) X return (0L); X } X return (1L); X} X X X/* -------------------------------------------------------------------- X * Free up memory allocated to a linked list of FibEntrys X * -------------------------------------------------------------------- */ XVOID FreeAllFibs (fibheadp) X struct List *fibheadp; X{ X struct FibEntry *tfibp; X X if (fibheadp != 0) X { X while (fibheadp->lh_Head->ln_Succ != 0) X { X tfibp = (struct FibEntry *)RemTail(fibheadp); X myfree(tfibp); X } X X /* Now free the MinList itself */ X myfree(fibheadp); X } X} X X X/* -------------------------------------------------------------------- X * Allocate and fill a linked list of FileInfoBlocks X * -------------------------------------------------------------------- */ Xstruct List *GetDir (lockp, fibp) X struct FileLock *lockp; X struct FileInfoBlock *fibp; X{ X BYTE *thepat; /* Pattern pointer to dir or file pattern */ X LONG dfcount; X LONG matchstat; /* Result of wildmatch() */ X LONG nextstat; /* Status of ExNext() */ X LONG tempnamlen; /* Compare length for strings */ X LONG tmpflags; X struct List *fibhead; /* Temp list of Fibs created */ X struct List *dirhead; /* Temp list of dirs if SHOWDIRS == 0 */ X X maxnamlen = dfcount = dircount = filecount = 0L; X X/* Initialize an exec list of nodes, zero entries */ X if ((fibhead = myalloc ((LONG)sizeof(struct MinList))) == 0) X return (0L); X NewList (fibhead); X X/* Allocate an separate list for directories that don't match specs */ X if ((dirhead = myalloc((LONG)sizeof(struct MinList))) == 0) X goto BADALLOC; X NewList (dirhead); X X do X { X TestBreak (); X if ((LSFlags & BREAKFLAG) != 0) X goto GOODRET; X X /* If we got something */ X if ((nextstat = ExNext ((BPTR)lockp, fibp)) != 0) X { X /* If the entry is wanted bump count of files or directories */ X if (CmpDateBounds (&fibp->fib_Date) != 0) X { X if (fibp->fib_DirEntryType > 0) /* It's a directory */ X thepat = theDirPat; X else X thepat = theFilePat; X X matchstat = wildmatch (fibp->fib_FileName, thepat); X X if ((LSFlags & MATCHINFOFILES) == 0 && matchstat != 0) X { X tmpflags = LSFlags; X LSFlags |= IGNORECASEWILD; X matchstat = wildmatch (fibp->fib_FileName, "*.info") ^ 1; X LSFlags = tmpflags; X } X if ((LSFlags & MATCHDOTFILES) == 0 && matchstat != 0) X matchstat = wildmatch (fibp->fib_FileName, ".*") ^ 1; X if ((LSFlags & ANTIMATCH) != 0 && matchstat != 0) X matchstat = wildmatch (fibp->fib_FileName, theAntiPat) ^ 1; X if ((fibp->fib_Protection & FIBF_HIDDEN) != 0) X matchstat = (LSFlags & SHOWHIDDEN) ? 1 : 0; X X if (matchstat == 0) /* No match? Then move on */ X continue; X X dfcount++; /* we found something of interest */ X X if (fibp->fib_DirEntryType > 0) /* It's a directory */ X { X if (FillFibEntry (dirhead, fibp) == 0) X goto BADALLOC; X if ((LSFlags & SHOWDIRS) != 0) X { X dircount++; gdircount++; gitemcnt++; X X if ((LSFlagsX & DATABLKSONLY) == 0) X gtotblocks++; X } X else X continue; X } X else /* It's a file entry */ X { X if ((LSFlags & SHOWFILES) != 0) X { X filecount++; gfilecount++; gitemcnt++; X fixNumBlocks(lockp, fibp); X gtotblocks += blkalloc(fibp); X gtotbytes += fibp->fib_Size; X } X else /* Don't want this file, move on to next entry */ X continue; X } X X /* See if this is the longest filename for later use in listing */ X tempnamlen = strlen (fibp->fib_FileName); X if (tempnamlen > maxnamlen) X { X if (fibp->fib_DirEntryType < 0) X { X maxnamlen = tempnamlen; X } X else if ((LSFlags & WILDPATH) == 0) X maxnamlen = tempnamlen; X } X X /* Allocate another FibEntry, put the info inside */ X if (FillFibEntry (fibhead, fibp) == 0) X goto BADALLOC; X } X } X } while (nextstat != 0); X X/* No entries found? print message and return FALSE */ X if ((dircount + filecount) == 0) X { X if ((LSFlags & NOHEADERS) == 0) X { X if ((dfcount != 0) || ((LSFlags & WILDPATH) != 0)) X WSTR("No match.\n"); X else X { X LSFlagsX |= EMPTYDIRFLAG; X X if ((LSFlags & LONGLIST) != 0) X WSTR("total 0\n"); X } X } X } X else X { X if ((LSFlags & (SHOWDIRS | SHOWFILES)) != 0) X { X if ((LSFlags & LONGLIST) == 0) /* Short listing wanted */ X { X SListDir (fibhead); X gentrycnt++; X } X else /* Full listing */ X LListDir (fibhead); X X if ((dircount + filecount) > 0) gentrycnt++; X } X } END_OF_FILE if test 45212 -ne `wc -c <'src/ls.c.aa'`; then echo shar: \"'src/ls.c.aa'\" unpacked with wrong size! fi # end of 'src/ls.c.aa' fi echo shar: End of archive 4 \(of 4\). cp /dev/null ark4isdone MISSING="" for I in 1 2 3 4 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 4 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Mail submissions (sources or binaries) to <amiga@cs.odu.edu>. Mail comments to the moderator at <amiga-request@cs.odu.edu>. Post requests for sources, and general discussion to comp.sys.amiga.