Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (02/03/90)
Submitted-by: Eddy Carroll <ECARROLL%vax1.tcd.ie@CUNYVM.CUNY.EDU> Posting-number: Volume 90, Issue 041 Archive-name: util/bbsindex-1.0/part01 BBSindex is a utility for use with the BBS-PC! bulletin board package. It allows you to list the contents of the file database in a wide variety of ways. It has its own script language with 20 commands which allows a wide variety of tasks to be performed. Eddy Carroll ecarroll@vax1.tcd.ie #!/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 1 (of 3)." # Contents: scripts scripts/bbsindex.scr scripts/filenote.scr # scripts/info.scr scripts/move.scr scripts/offline.scr src # src/bbs.h src/bbsindex.h src/checkfiles.c src/expression.c # src/makefile src/sort.c src/system.h src/tiny.a # Wrapped by tadguy@xanth on Fri Feb 2 14:54:35 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test ! -d 'scripts' ; then echo shar: Creating directory \"'scripts'\" mkdir 'scripts' fi if test -f 'scripts/bbsindex.scr' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'scripts/bbsindex.scr'\" else echo shar: Extracting \"'scripts/bbsindex.scr'\" \(2360 characters\) sed "s/^X//" >'scripts/bbsindex.scr' <<'END_OF_FILE' X# X# This script builds sorted file catalogues for the Amiga and IBM X# file areas (i.e. sections 3, 4, 6 and 1), on the Infomatique BBS X# (Phone: Dublin 302970 (+353-1-302970), V21/22bis/23) X# X# The following constants define the output files for the various filelists X# Change them to suit. X XAmigaFiles = "Amiga.Files" XIBMFiles = "IBM.Files" X X# X# This macro outputs the header for a filelist X# Xmacro header # SectionNumber, No. of dirs, SectionName, Filename X select Section = $1 X scan X echo "Sorted list of $3 files - %d %w %t" X echo "" X echo "This file is available in the files section as $4" X echo "Files which are not currently available are marked with a *" X echo "" X echo "Total of %n files in $2 sections, occupying %m Megabytes." X echo "" Xendm X X# X# This macro takes a Section, Directory and title, and produces a list of X# all the files in that section and directory. X# Xmacro sublist # Section, Directory, Title X echo "%{$2. $3}\n%u-" X select Section = $1 AND Directory = $2 X list X echo "" Xendm X X# X# Standard file stuff, the same for everything X# Xnorequest Xcheckfiles Xformat "%15n %w %-6x-%b{B,T}%v{ ,*} %c" Xsort Section, Directory, Name X X# X# List Amiga files X# Xopen $(AmigaFiles) Xheader 3, 14, "Amiga", "AMIGA.FILES" Xsublist 3, 1, "General text files" Xsublist 3, 2, "Technical text files" Xsublist 3, 3, "Archived text files" Xsublist 3, 4, "Games" Xsublist 3, 5, "Screen Hacks" Xsublist 3, 6, "Graphics, sound & demos" Xsublist 3, 7, "Graphics & sound programs" Xsublist 3, 8, "DOS utilities" Xsublist 3, 9, "Programming utilities" Xsublist 3, 10, "Resident utilities " Xsublist 3, 11, "Applications" Xsublist 3, 12, "Comms programs" Xsublist 3, 13, "Miscellaneous" Xsublist 3, 14, "Hardware" X# X# List IBM files X# Xopen $(IBMfiles) Xheader 4, 16, "IBM", "IBM.FILES" Xsublist 4, 1, "General, Miscellaneous" Xsublist 4, 2, "Miscellaneous Text Files" Xsublist 4, 3, "Digestives" Xsublist 4, 4, "DOS File Utilities" Xsublist 4, 5, "Archive Utilities" Xsublist 4, 6, "Pop-Up Utilities" Xsublist 4, 7, "Games & Fun" Xsublist 4, 8, "Graphics Progs" Xsublist 4, 9, "Graphics Images & Viewers" Xsublist 4, 10, "Sound & Music" Xsublist 4, 11, "Source Code & Programming" Xsublist 4, 12, "Viruses" Xsublist 4, 13, "Comms Packages & Utils" Xsublist 4, 14, "Mainstream Applications" Xsublist 4, 15, "Education/Tutorials" Xsublist 4, 16, "Hardware Utils, Performance Tests" END_OF_FILE if test 2360 -ne `wc -c <'scripts/bbsindex.scr'`; then echo shar: \"'scripts/bbsindex.scr'\" unpacked with wrong size! fi # end of 'scripts/bbsindex.scr' fi if test -f 'scripts/filenote.scr' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'scripts/filenote.scr'\" else echo shar: Extracting \"'scripts/filenote.scr'\" \(511 characters\) sed "s/^X//" >'scripts/filenote.scr' <<'END_OF_FILE' X# X# This script generates an AmigaDOS batch file to go through all the X# files on the system and add a filenote to them, giving the following X# information: X# X# (Section, Directory) BBS Filename Uploader File description X# X XOpen "filenote.exec" X Xnorequest Xcheckfiles X Xselect Online X Xformat 'filenote %f "%6{(%s,%r)} %15n %15o %c"' Xecho ";" Xecho "; Batchfile to add comments to all the BBS files in the system Xecho ";" Xlist Xecho ";" Xecho 'echo "Total of %n files successfully filenoted"' Xecho ";" END_OF_FILE if test 511 -ne `wc -c <'scripts/filenote.scr'`; then echo shar: \"'scripts/filenote.scr'\" unpacked with wrong size! fi # end of 'scripts/filenote.scr' fi if test -f 'scripts/info.scr' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'scripts/info.scr'\" else echo shar: Extracting \"'scripts/info.scr'\" \(806 characters\) sed "s/^X//" >'scripts/info.scr' <<'END_OF_FILE' X########################################################################### X# X# This simple script file merely prints all possible information about X# each file in the catalogue. It serves as a good demonstration of how X# to use extended command lines. Practically the whole script is a single X# extended format command! X# X########################################################################### X Xnorequest Xcheckfiles X Xformat "\ XFilename : %n\n\ XUploaded by : %o\n\ XComment : %c\n\ XFiletype : %b{Binary,Text}\n\ XDisk filename : %f\n\ XOrigin : %l{Local, Remote}\n\ XStatus : %i{Online, Offline}\n\ XFile state : %v{Valid, Invalid}\n\ XAccesses : %a\n\ XSection : %s\n\ XDirectory : %r\n\ XUpload date : %w\n\ XFile size : %x\n\ X----------" Xsort name Xlist END_OF_FILE if test 806 -ne `wc -c <'scripts/info.scr'`; then echo shar: \"'scripts/info.scr'\" unpacked with wrong size! fi # end of 'scripts/info.scr' fi if test -f 'scripts/move.scr' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'scripts/move.scr'\" else echo shar: Extracting \"'scripts/move.scr'\" \(1001 characters\) sed "s/^X//" >'scripts/move.scr' <<'END_OF_FILE' X# X# Simple script to generate and execute an AmigaDOS batch file to move X# all the files in a particular section into # a new common directory. X# X X# X# Set the output file, destination directory and section no's appropriately. X# X XOutFile = "Move.exec" XDest = "DH1:Somedirectory" XSection = 3 X X# X# Use the following MV definition if you have a MV that supports moves X# across disk boundaries (such as Edwin Hoogerbeets' excellent one). X# X XMV = "mv %f $(Dest)" X X# X# Use the following MV definition if you want to use plain AmigaDOS X# X X# MV = "copy %f $(Dest)\ndelete $f" X X# X# Now generate the list of files. We sort by directory name to try X# and localise disk access X# X Xformat "$(MV)" XNoRequest XCheckFiles XSelect Online and Section = $(Section) XSort Diskname Xecho ";" Xecho "; BBSindex generated AmigaDOS batch file to move files in" Xecho "; section $(Section) to directory $(Dest)." Xecho ";" Xecho "; Created on %d %w %r" Xecho ";" Xlist Xecho ";" Xecho 'Echo "Total of %n files moved successfully"' Xecho ";" END_OF_FILE if test 1001 -ne `wc -c <'scripts/move.scr'`; then echo shar: \"'scripts/move.scr'\" unpacked with wrong size! fi # end of 'scripts/move.scr' fi if test -f 'scripts/offline.scr' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'scripts/offline.scr'\" else echo shar: Extracting \"'scripts/offline.scr'\" \(847 characters\) sed "s/^X//" >'scripts/offline.scr' <<'END_OF_FILE' X############################################## X# X# This script lists all the files in the X# BBS catalogue that are offline or invalid X# X############################################## X Xnorequest Xcheckfiles Xsort Section, Name Xformat "%s:%15n %-6x-%b{B,T} | %15d\n%28{} | %c" X Xecho "" Xecho "BBS-PC! file report - %d %w %t" Xecho "" X X############################################## X# X# List offline files X# X############################################## X Xselect Offline Xecho "%{Files offline}\n%u-" Xlist Xecho "" Xecho "(Total of %n files offline.)" Xecho "" X X############################################## X# X# List invalid files X# X############################################## X Xselect Online and Invalid Xecho "%{Files online, but possibly corrupt}\n%u-" Xlist Xecho "" Xecho "(Total of %n files possibly corrupt.)" Xecho "" Xecho "" END_OF_FILE if test 847 -ne `wc -c <'scripts/offline.scr'`; then echo shar: \"'scripts/offline.scr'\" unpacked with wrong size! fi # end of 'scripts/offline.scr' fi if test ! -d 'src' ; then echo shar: Creating directory \"'src'\" mkdir 'src' fi if test -f 'src/bbs.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/bbs.h'\" else echo shar: Extracting \"'src/bbs.h'\" \(3354 characters\) sed "s/^X//" >'src/bbs.h' <<'END_OF_FILE' X/* X * Standard BBS-PC! headers (with a few modifications) X * X * Important note: This header file cannot be precompiled with X * Lattice C V5.02, because of a bug which prevents bit fields X * from working properly when they are precompiled. X */ X X/* Official Micro-Systems Software Structures */ X X#define NUM_TERM 10 /* Number of computer types */ X#define NUM_SECT 16 /* Number of section names */ X X#define CAT_LEN 15 /* File catalogue name lengths */ X#define DESC_LEN 40 /* File catalogue desc length */ X#define FNAME_LEN 12 /* File name lengths */ X#define FPATH_LEN 30 /* File name path lengths */ X#define NAME_LEN 24 /* User name length */ X#define PASS_LEN 10 /* User password length */ X#define SECT_LEN 20 /* Section name lengths */ X#define TERM_LEN 15 /* Computer name lengths */ X X/* UDHEAD.DAT record structure */ X X/* Note some new additions to this structure, for internal tracking */ X Xtypedef struct { X BYTE type; X int local:1; /* True if local upload */ X int bin:1; /* True if binary file */ X int valid:1; /* True if valid NEW */ X int online:1; /* True if file online NEW */ X int dirnum:5; /* Real dir num of file NEW */ X int :7; /* Reserved CHANGED */ X char cat_name[CAT_LEN]; /* Catalog filename (key1) */ X UWORD date; /* Upload date serial */ X BYTE dir; /* Dir number (key2 - seg1) */ X BYTE section; /* Section number (key2 - seg2) */ X UWORD accesses; /* Number of accesses */ X LONG length; /* File length */ X char disk_name[FNAME_LEN+1]; /* Disk filename */ X char owner[NAME_LEN+1]; /* Owner's name */ X char desc[DESC_LEN+1]; /* Description text */ X} UDHEAD; X X#define UDSIZE sizeof(UDHEAD) X X X/* Terminal parameters */ X Xtypedef struct { X int linefeed: 1; X int :31; X BYTE nuls; X BYTE protocol; X BYTE align; X BYTE page[2]; X BYTE cls[4]; X BYTE bs[3]; X char name[TERM_LEN+1]; X} TRMNL; X X X/* CFGINFO.DAT record structure */ X Xtypedef struct { X int dir0_ok: 1; /* Directory 0 downloads */ X int by_call: 1; /* Time limit per call */ X short max_msg; /* Maximum messages in system */ X short max_user; /* Maximum users in system */ X short max_log; /* Maximum call log */ X short max_ud; /* Maximum U/D files */ X short reward; /* Upload reward */ X short sleeptime; /* sleep timeout (adjusted) */ X long dummy; /* Reserved */ X BYTE log_p1; /* Log privilege low */ X BYTE log_p2; /* Log privilege high */ X BYTE hi_men; /* Highest menu set */ X BYTE log_type; /* Login method */ X short limit[2]; /* Guest/member time limits */ X short priv[2]; /* Guest/member privileges */ X UWORD rd_acc[2]; /* Guest/member read access */ X UWORD wr_acc[2]; /* Guest/member write access */ X UWORD up_acc[2]; /* Guest/member upload access */ X UWORD dn_acc[2]; /* Guest/member download access */ X BYTE sav_sec[2]; /* Guest/member save section */ X BYTE sec_flg[NUM_SECT]; /* Section flags */ X char sec_name[NUM_SECT] [SECT_LEN+1]; /* Section names */ X char ud_alt[NUM_SECT] [FPATH_LEN+1]; /* Alternate UD paths */ X char syspass[PASS_LEN+1]; /* Sysop password */ X BYTE menu[2]; /* Guest/Member menu sets */ X BYTE align; X long dummy2; X long dummy3; X TRMNL trmnl[NUM_TERM]; /* Terminal parameters */ X} CFGINFO; X X#define CFGSIZE sizeof(CFGINFO) END_OF_FILE if test 3354 -ne `wc -c <'src/bbs.h'`; then echo shar: \"'src/bbs.h'\" unpacked with wrong size! fi # end of 'src/bbs.h' fi if test -f 'src/bbsindex.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/bbsindex.h'\" else echo shar: Extracting \"'src/bbsindex.h'\" \(12473 characters\) sed "s/^X//" >'src/bbsindex.h' <<'END_OF_FILE' X/* X * BBSINDEX.H X * X * All the standard variables and other stuff used by all the modules X * of BBSindex, and standard BBS-PC! headers (with a few modifications). X * X * Important note: This header file cannot be precompiled with X * Lattice C V5.02, because of a bug which prevents bit fields X * from working properly when they are precompiled. X */ X X#include "bbs.h" X X#define TRUE 1 X#define FALSE 0 X X#define BTOK(x) (((x)+1023)>>10) /* Convert file size into K */ X X/* X * Default values for command line parameters and script commands X */ X X#define FORMAT "%15n %w %-6x-%b{B,T} %c\n" X#define UDNAME "UDHEAD.DAT" X#define CFGNAME "CFGINFO.DAT" X#define PROGSCRIPT "BBSCRIPT" X#define DEFSCRIPT "BBSindex.scr" X X/* X * Blocksize determines the largest contiguous memory segment which is X * needed. Larger values give faster processing, but need more continuous X * memory. X */ X X#define BLOCKSIZE 160 /* Number of records/block (~16K) */ X#define MAXOUT 1024 /* The maximum length of an output line */ X#define MAXCOM 1024 /* Maximum size of a single command */ X#define MAXSUB 256 /* Maximum size of a sub format string */ X#define FRAGBLOCK 8192 /* Memory block to allocate in mymalloc */ X#define FRAGTHRESH 200 /* Threshold for mem reqs in mymalloc */ X#define BUFSIZE 8192 /* Maximum size of output buffer */ X#define MAXEXPR 100 /* Max number of items in an expression */ X#define MAXDIRENT 1000 /* Maximum number of unknown dir files */ X#define DIRFRAG 100 /* Number of dir entries/block alloced */ X#define DIRNAMESIZE 80 /* Maximum length of directory name */ X#define MACROLEN 20 /* Maximum length of macro name */ X#define MAXMACRO 50 /* Maximum number of macros allowed */ X#define MAXNEST 10 /* Max number of macro nesting levels */ X#define MAXCONST 20 /* Maximum length of a constant name */ X X/* Note: MAXSUB above is allocated on the stack, so don't make it too big */ X X/* X * This structure is used to build a tree structure representing X * the expression given with the SELECT command. X */ Xstruct expr { X int field; /* Field to test, or boolean operator */ X int op; /* Operator to test against, if any */ X int num; /* First data field */ X char *text; /* Second data field */ X struct expr *left; /* Left subtree */ X struct expr *right; /* Right subtree */ X}; X Xtypedef struct expr EXPR; X X/* X * This structure is used to hold the name of a file found in X * a BBS-PC! file directory during CHECKFILES, which does not X * exist in the BBS-PC! file catalogue. X */ Xtypedef struct { X char name[32]; /* Disk filename */ X short date; /* In BBS-PC! format, max 16 bits */ X short dirnum; /* The directory number it was in */ X long size; /* The size of the file, in bytes */ X} DIRENTRY; X X#define DIRENTRYSIZE sizeof(DIRENTRY) X X/* X * This structure holds the names of files to be "ignored" during a X * CHECKFILES. I.e. they are marked as valid, even if their filesize X * on disk doesn't match that in the file catalogue. This structure X * is built up with the IGNORE command. X */ Xstruct ignore { X struct ignore *next; X char name[CAT_LEN+1]; X}; X Xtypedef struct ignore IGNORE; X X/* X * This structure is used to store macro definitions. Note that X * a single block is used to store both the macro and its definition. X * The structure is dynamically sized at runtime, to fit whatever X * size definition is given. The text[] array (nominally 1) gets X * expanded to hold the definition. X */ Xtypedef struct { X char name[MACROLEN]; /* Name of this macro */ X int size; /* Size of macro text */ X char text[1]; /* Start of macro text */ X} MACRO; X X#define MACROSIZE (sizeof(MACRO) - 1) /* The -1 is for text[1] */ X X/* X * This structure holds a block of parameters for a macro that is X * executing. X */ Xtypedef struct { X int size; /* Size of parameter block */ X char params[1]; /* Start of parameter block */ X} PARAM; X X#define PARAMSIZE (sizeof(PARAM) - 1) /* The -1 is for params[1] */ X X X/* X * This macro checks to make sure that the file database has been X * read in. This is delayed until as late as possible, so that if X * the script file contains errors, the errors will be spotted BEFORE X * the database is read in. The primary goal here is to save the user X * having to wait for 200K or so of database to be read in, just so X * they can see they have an error in their script. Instead, the X * database is only read in when a command cannot execute without X * having access to the files. Such commands are SORT, SCAN, LIST, X * CHECKFILES and FOREIGN. X */ X#define CHECKDATABASE() {if (!readfiles) readdatabase(databasename);} X X/* X * Global variables, accessible to all modules X */ X X#ifdef GLOBAL X#undef GLOBAL X#endif X#ifdef MAIN X#define GLOBAL X#else X#define GLOBAL extern X#endif X XGLOBAL char *script; /* Array for storing the script */ XGLOBAL long scriptsize; /* The size of the current script */ XGLOBAL long scriptpos; /* Position in the current script */ XGLOBAL long linenum; /* Line number in script file */ XGLOBAL char out[MAXOUT]; /* Array for storing the output lines */ XGLOBAL char combuf[MAXCOM]; /* Buffer to hold a single command */ XGLOBAL char formatstring[MAXCOM];/* Used to store the output format string */ XGLOBAL char databasename[256]; /* The name of the BBS-PC! file database */ XGLOBAL char configname[256]; /* The name of the BBS-PC! config file */ XGLOBAL char scriptname[256]; /* The name of the current script file */ XGLOBAL UDHEAD **ptrblock; /* Array of pointers to file records */ XGLOBAL long numrecs; /* The number of file headers read in */ XGLOBAL long compos; /* Position on the current command line */ XGLOBAL long comlen; /* Length of current command line */ XGLOBAL BPTR outfile; /* Output file (Default is stdout) */ XGLOBAL BPTR errorfile; /* Standard error file (screen usually) */ XGLOBAL BPTR dirlock; /* Lock used when scanning directories */ XGLOBAL struct FileInfoBlock *fib;/* Global fib struct on longword boundary */ XGLOBAL int checkfiles; /* TRUE if file directories were scanned */ XGLOBAL int readfiles; /* TRUE if database file has been read in */ XGLOBAL int toscreen; /* TRUE if output is to screen */ XGLOBAL int totalbytes; /* Total number of bytes output so far */ XGLOBAL int totalfiles; /* Total number of files output so far */ XGLOBAL int curbytes; /* Number of bytes output by last LIST/SCAN */ XGLOBAL int curfiles; /* Number of files output by last LIST/SCAN */ XGLOBAL int sorted; /* True if file array has been sorted */ XGLOBAL EXPR tree[MAXEXPR]; /* Array to hold parsed SELECT expression */ XGLOBAL int numdirentries; /* Number of fake directory entries */ XGLOBAL DIRENTRY *direntries[MAXDIRENT];/* Storage for ptrs to dir entries */ XGLOBAL char dirnames[NUM_SECT][DIRNAMESIZE];/* Storage for directory names */ XGLOBAL CFGINFO config[1]; /* BBS-PC! Configuration file structure */ XGLOBAL MACRO *macros[MAXMACRO]; /* Array of ptrs to macro definitions */ XGLOBAL int nummacros; /* Number of macros currently defined */ XGLOBAL PARAM *params[MAXNEST]; /* Array of pointers to macro parameters */ XGLOBAL int nestlevel; /* Current macro nest level */ XGLOBAL int tracemode; /* Trace mode; TRUE if tracing enabled */ XGLOBAL IGNORE *firstignore; /* Pointer to first filename to ignore */ X X/* X * Global functions, accessible everywhere X */ X Xchar *format(); /* Format output string from file header + format spec */ Xchar *echoformat(); /* Formats output string for ECHO command */ Xchar *itoa(); /* Convert integer into ASCII format */ Xchar *getstring(); /* Get next string from command buffer */ Xvoid *mymalloc(); /* Safe memory tracker that handles out of memory */ Xvoid *SafeAllocMem();/* Safe AllocMem that handles out of memory */ Xvoid execscript(); /* Executes all the commands in the current script */ Xvoid Cleanup(); /* Frees resources and exits program */ Xvoid chkabort(); /* Checks for Control-C, and aborts if detected */ Xvoid putstring(); /* Outputs string to standard I/O */ Xvoid flushout(); /* Flushes data buffer to output file */ Xvoid parse(); /* Parse command line and build expression tree */ Xvoid readdatabase();/* Reads in the BBS-PC! UDHEAD.DAT file database */ Xvoid readconfigfile();/* Reads in the BBS-PC! CFGINFO.DAT file */ Xvoid print(); /* Prints a string to stderr */ Xvoid com_select(); /* SELECT, specifies criteria for files to select */ Xvoid com_checkfiles();/* Scans file directories, updating catlague entries */ Xvoid com_sort(); /* Sorts file catalogue into a particular order */ Xvoid com_foreign(); /* Prints a list of all the unknown foreign files */ Xvoid com_norequest();/* Stop AmigaDos from putting up requesters */ Xint match(); /* Returns TRUE if record matches current selection */ Xint scandir(); /* Scans directory for files, returns TRUE if continue */ Xint sortcmp(); /* Internal routine used for sorting files */ X X/* X * print3() X * -------- X * Prints 3 strings to standard error X */ X#define print2(s1,s2) (print(s1), print(s2)) X#define print3(s1,s2,s3) (print(s1), print(s2), print(s3)) X X/* X * The list of identifiers used by SORT and SELECT. X */ X X#define MAXINDEX 16 X X#define I_ANY 0 X#define I_ACCESS 1 X#define I_BINARY 2 X#define I_COMMENT 3 X#define I_DISKNAME 4 X#define I_SECTION 5 X#define I_ONLINE 6 X#define I_LOCAL 7 X#define I_NAME 8 X#define I_OWNER 9 X#define I_PATHNAME 10 X#define I_DIRECTORY 11 X#define I_DISKDIRNUM 12 X#define I_VALID 13 X#define I_DATE 14 X#define I_SIZE 15 X#define I_KSIZE 16 X XGLOBAL struct { X int tag; X char *name; X} indexes[MAXINDEX] X#ifdef MAIN X= { X X{ I_ACCESS, "ACCESS"}, /* Number of times file was accessed */ X{ I_BINARY, "BINARY"}, /* True if Binary, False if text */ X{ I_COMMENT, "COMMENT"}, /* The file comment */ X{ I_DISKNAME, "DISKNAME"}, /* The name of the file on disk */ X{ I_SECTION, "SECTION"}, /* # of the section the file is in */ X{ I_ONLINE, "ONLINE"}, /* True if file online */ X{ I_LOCAL, "LOCAL"}, /* True if file uploaded locally */ X{ I_NAME, "NAME"}, /* The name of the file in the catalog */ X{ I_OWNER, "OWNER"}, /* The name of uploader of the file */ X{ I_PATHNAME, "PATHNAME"}, /* Pathname to file on disk */ X{ I_DIRECTORY, "DIRECTORY"}, /* # of directory file is in */ X{ I_DISKDIRNUM, "DISKDIRNUM"}, /* # of disk directory file is in */ X{ I_VALID, "VALID"}, /* True if file is Valid */ X{ I_DATE, "DATE"}, /* The date the file was uploaded */ X{ I_SIZE, "SIZE"}, /* The size of the file */ X{ I_KSIZE, "KSIZE"} /* The size of the file in K */ X} X#endif X; X XGLOBAL char *months[] X#ifdef MAIN X= { X "xxx", X "Jan", "Feb", "Mar", "Apr", "May", "Jun", X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" X} X#endif X; X X/* X * Special characters that can occur in the script X */ X#define CHAR_TAB '\t' X#define CHAR_SPACE ' ' X#define CHAR_HASH '#' X#define CHAR_NL '\n' X#define CHAR_ESC '\\' X#define CHAR_QUOTE '\'' X#define CHAR_QUOTES '\"' X#define CHAR_SEMI ';' X#define CHAR_COMMA ',' X#define CHAR_EQUALS '=' X#define CHAR_DOLLAR '$' X#define CHAR_NULL '\0' X X#define CHAR_ASCEND '+' X#define CHAR_DESCEND '-' X X/* X * The following symbols are used in the expression tree X */ X X/* X * Boolean operations, which share storage with field selectors X */ X X#define E_AND 30 /* <left> AND <right> */ X#define E_OR 31 /* <left> OR <right> */ X#define E_NOT 32 /* NOT <left> */ X#define E_ALL 33 /* Always true */ X X/* X * Comparison operators, used for comparing record elements X */ X#define E_EQ 34 /* Record == Value */ X#define E_NE 35 /* Record != Value */ X#define E_LT 36 /* Record < Value */ X#define E_GT 37 /* Record > Value */ X#define E_LE 38 /* Record <= Value */ X#define E_GE 39 /* Record >= Value */ X X#define E_OPENPAR 40 /* Open parameter token */ X#define E_CLOSEPAR 41 /* Close parameter token */ X X#define E_NUMBER 42 /* Any numeric value */ X#define E_STRING 43 /* Anything in quotes */ X#define E_END 44 /* End of command line */ X X#define E_TEXT 45 /* File is a text file */ X#define E_REMOTE 46 /* File is a remote file */ X#define E_INVALID 47 /* File is invalid */ X#define E_OFFLINE 48 /* File is offline */ X X X/* X * Wildcard special fields for strings X */ X#define tokentowild(x) ((x)+50) X X#define W_OWNER tokentowild(I_OWNER) X#define W_NAME tokentowild(I_NAME) X#define W_DISKNAME tokentowild(I_DISKNAME) X#define W_COMMENT tokentowild(I_COMMENT) END_OF_FILE if test 12473 -ne `wc -c <'src/bbsindex.h'`; then echo shar: \"'src/bbsindex.h'\" unpacked with wrong size! fi # end of 'src/bbsindex.h' fi if test -f 'src/checkfiles.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/checkfiles.c'\" else echo shar: Extracting \"'src/checkfiles.c'\" \(6592 characters\) sed "s/^X//" >'src/checkfiles.c' <<'END_OF_FILE' X/* X * CHECKFILES.C X * X * This module contains routines to read in the disk directory, search X * the file database for each filename found to see if it matches, etc. X * X */ X X#ifndef LATTICE_50 X#include "system.h" X#endif X#include "bbsindex.h" X X/* X * addunknown() X * ------------ X * Adds a new entry to the list of unknown files found. If necessary, X * more memory will be allocated to hold the new entry. X */ Xint addunknown(name, size, date, dirnum) Xchar *name; Xlong size; Xint date, dirnum; X{ X static DIRENTRY *dirbase, *dir; X X if (numdirentries >= MAXDIRENT) { X scripterror("directory table full. Skipping rest of files\n"); X return (FALSE); X } X if ((numdirentries % DIRFRAG) == 0) /* Allocate new block */ X dirbase = mymalloc(DIRENTRYSIZE * DIRFRAG); X X dir = &dirbase[numdirentries % DIRFRAG]; X X strcpy(dir->name, name); X dir->size = size; X dir->date = date; X dir->dirnum = dirnum; X X direntries[numdirentries++] = dir; X return (TRUE); X} X X/* X * find() X * ------ X * Does a binary search of the file records looking for the specified X * filename. Returns pointer to the file record if found, NULL if not X * found. X */ XUDHEAD *find(name) Xchar *name; X{ X long low = 0, high = numrecs -1; X long mid; X int cmp; X X while (high >= low) { X mid = (low + high) / 2; X cmp = stricmp(ptrblock[mid]->disk_name, name); X if (!cmp && ptrblock[mid]->type == 0) /* Found match */ X return (ptrblock[mid]); X if (cmp > 0) /* Too far ahead, go backwards */ X high = mid-1; X else /* Too far below, go forwards */ X low = mid+1; X } X return (NULL); X} X X/* X * scandir() X * --------- X * Scans directory, adding the files found either to the 'unknown' X * list or updating the pointers in the main file database appropriately. X */ Xint scandir(dirname, dirnum) Xchar *dirname; Xint dirnum; X{ X UDHEAD *f; X struct tm *filedate; X int bbspcdate; X X dirlock = Lock(dirname, ACCESS_READ); X if (dirlock == NULL) { X scripterror("can't find directory "); X print2(dirname, ", skipping\n"); X return (TRUE); X } X X if (!Examine(dirlock, fib)) { X scripterror("can't examine directory "); X print2(dirname, ", skipping\n"); X UnLock(dirlock); X dirlock = NULL; X return (TRUE); X } X X while (ExNext(dirlock, fib)) { X chkabort(); X if (fib->fib_DirEntryType > 0) /* Skip over directories */ X continue; X if (f = find(fib->fib_FileName)) { X f->online = 1; X f->valid = (fib->fib_Size == f->length); X f->dirnum = dirnum; X } else { X /* X * Convert AmigaDOS date (# days since 1/1/78, # mins X * since midnight) into ANSI date (# seconds since 1/1/70) X * then convert that into BBS-PC! format. X */ X long ansidate; X ansidate = (fib->fib_Date.ds_Days + (365 * 8) + 2) * 86400; X filedate = gmtime(&ansidate); X bbspcdate = (((filedate->tm_year * 13) + X (filedate->tm_mon+1)) * 32) + X filedate->tm_mday; X if (!addunknown(fib->fib_FileName, fib->fib_Size, bbspcdate, X dirnum)) { X UnLock(dirlock); X dirlock = NULL; X return (FALSE); X } X X } X } X if (IoErr() != ERROR_NO_MORE_ENTRIES) { X scripterror("error reading directory "); X print2(dirname, ", skipping\n"); X } X UnLock(dirlock); X dirlock = NULL; X return (TRUE); X} X X/* X * diskcmp() X * --------- X * Compares the disk filenames of two file headers, and returns true X * if they are equal. Used by the sort routine in check_files(). X */ Xint diskcmp(f1,f2) XUDHEAD **f1, **f2; X{ X return (stricmp((*f1)->disk_name, (*f2)->disk_name)); X} X X/* X * com_checkfiles() X * ---------------- X * This command scans the file directories specified on the command X * line (or if none, then using those specified in the CFGINFO.DAT X * file). Each file in the catalogue is searched for in the file X * catalogue, and those that are found are marked as "Online"; if X * the disk filesize matches the catalogue filesize, then their X * "valid" flag is also set. Files which are not found are stored X * in a seperate array, which can be printed with the FOREIGN command. X * After this, any other files listed in the IGNORE list are also marked X * as valid. X * X * Note that before the scan, the files are sorted into alphabetical X * order, by diskname, to allow a binary search to be done. Afterwards, X * if this disrupted a previous sorting order, they are sorted back X * to their original state. X */ Xvoid com_checkfiles() X{ X int dirnum; X IGNORE *ig; X UDHEAD *f; X X if (checkfiles) X return; X X CHECKDATABASE(); X qsort(ptrblock, numrecs, sizeof(UDHEAD *), diskcmp); X if (compos >= comlen) { X readconfigfile(); X for (dirnum = 0; dirnum < NUM_SECT && dirnames[dirnum][0]; dirnum++) { X chkabort(); X if (!scandir(dirnames[dirnum], dirnum)) X break; X } X } else { X for (dirnum = 0; dirnum < NUM_SECT; dirnum++) { X if (compos >= comlen) X break; X strcpy(dirnames[dirnum], getstring()); X chkabort(); X if (!scandir(dirnames[dirnum], dirnum)) X break; X } X } X /* X * Now mark any "ignored" files as valid. X */ X for (ig = firstignore; ig; ig = ig->next) { X if (f = find(ig->name)) X f->valid = 1; X } X chkabort(); X if (sorted) X qsort(ptrblock, numrecs, sizeof(UDHEAD *), sortcmp); X checkfiles = TRUE; X} X X/* X * com_foreign() X * ------------- X * This command prints out the list of foreign files, i.e. files X * not in the catalogue, using the format string setup with X * FORMAT. Not all fields are valid. X */ Xvoid com_foreign() X{ X /* X * Standard file header template for foreign files. X * Note file[] is an array, so we can say file->x instead of file.x X */ X static UDHEAD file[1] = {{ X 0, /* Record type (== valid) */ X 1, 1, 1, 1, /* Local, Binary, Valid and Online :-) */ X 0, /* Directory number is set later */ X "", /* Catalogue filename, filled in later */ X 0, /* Date is set later */ X 0, 0, 0, /* Section 0, Directory 0, no accesses */ X 0, /* Length is set later */ X "", /* Disk name is set later */ X "AmigaDos", /* The file owner */ X "Directory = ", /* File comment, set later */ X }}; X X int i; X X if (!checkfiles) { X scripterror("can't do FOREIGN before CHECKFILES\n"); X Cleanup(10); X } X X for (i = 0; i < numdirentries; i++) { X chkabort(); X /* Setup actual file parameters for format() */ X strcpy(file->disk_name, direntries[i]->name); X strncpy(file->cat_name, direntries[i]->name, CAT_LEN); X strncpy(file->desc+12, dirnames[direntries[i]->dirnum], DESC_LEN-12); X file->desc[DESC_LEN] = CHAR_NULL; X file->length = direntries[i]->size; X file->date = direntries[i]->date; X file->dirnum = direntries[i]->dirnum; X format(out, MAXOUT, formatstring, file, checkfiles); X putstring(out); X } X} END_OF_FILE if test 6592 -ne `wc -c <'src/checkfiles.c'`; then echo shar: \"'src/checkfiles.c'\" unpacked with wrong size! fi # end of 'src/checkfiles.c' fi if test -f 'src/expression.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/expression.c'\" else echo shar: Extracting \"'src/expression.c'\" \(11470 characters\) sed "s/^X//" >'src/expression.c' <<'END_OF_FILE' X/* X * EXPRESSION.C X * X * This module contains the routines needed to parse and evaluate an X * expression. This is used while selecting which files to print. X * X * This is the BNF for the set of expressions recognised by the X * database searcher. It doesn't contain any semantic information however. X * X * Expression ::= Boolean | Boolean Operator Expression | ALL X * Operator ::= AND | OR X * Boolean ::= NOT Boolean | X * '(' Expression ')' | X * BoolIdent | X * NumIdent Op Value | X * StringIdent Op String | X * DateIdent Op Date X * Op ::= '<' | '>' | '<=' | '>=' | '=' | '<>' X * BoolIdent ::= BINARY | ONLINE | LOCAL | VALID X * StringIdent ::= COMMENT | DISKNAME | NAME | OWNER | PATHNAME X * NumIdent ::= ACCESS | SECTION | DIRECTORY | DISKDIRNUM | X * SIZE | KSIZE X * DateIdent ::= DATE X * String ::= (Text enclosed in quotes) X * Value ::= (A number) X * Date ::= (A date in the format "dd-mon-yy") X * X */ X X#ifndef LATTICE_50 X#include "system.h" X#endif X X#include "bbsindex.h" X X#define mystrcmp stricmp /* Make match() insensitive to case */ X X/* X * BNF procedures X */ X Xvoid bnf_op(), bnf_date(), bnf_expression(), bnf_boolean(); X X/* X * Global variable(s) X */ X Xstatic int treepos; /* Next free entry in tree array */ Xstatic int curtoken; /* Current token */ Xstatic int curvalue; /* Current number with E_NUMBER */ Xstatic char curstring[MAXCOM]; /* Current string with E_STRING */ X X/* X * Tokens recognised as special in expressions X */ X Xstruct { X int tag; X char *name; X} tokens[] = { X X { E_EQ, "=" }, X { E_NE, "<>" }, X { E_LE, "<=" }, X { E_GE, ">=" }, X { E_LT, "<" }, X { E_GT, ">" }, X { E_AND, "AND" }, X { E_OR, "OR" }, X { E_NOT, "NOT" }, X { E_ALL, "ALL" }, X { E_OPENPAR, "(" }, X { E_CLOSEPAR, ")" }, X { E_TEXT, "TEXT" }, X { E_REMOTE, "REMOTE" }, X { E_INVALID, "INVALID" }, X { E_OFFLINE, "OFFLINE" }, X { NULL, NULL } X}; X X/* X * wild() X * ------ X * This routine does a wildcard match on the two specified strings. X * The first string contains the string to check, and the second string X * containts the wildcard pattern to check against. The special wild X * card characters are '?' which matches any single characters, and X * '*' which matches any number of characters. 0 is returned if the X * the two strings match, else a +ve or -ve number. X * X */ Xint wild(s,w) Xchar *s; Xchar *w; X{ X char *p; X char ch; X X while (*w && *s) { X switch (*w) { X X case '*': X ch = toupper(w[1]); X if (!ch) X return (0); X for (p = s; *p; p++) { X if (toupper(*p) == ch || ch == '?') { X if (!wild(p,w+1)) X return (0); X } X } X return (toupper(*p)-ch); X X case '?': X break; X X default: X if (toupper(*s) != toupper(*w)) X return (toupper(*s)-toupper(*w)); X } X w++; X s++; X } X return (toupper(*s)-toupper(*w)); X} X X X/* X * Dirty great macro to compare two values according to an operator X */ X#define e_cmp(v1,op,v2) \ X switch (op) { \ X case E_EQ: return ((v1) == (v2)); \ X case E_NE: return ((v1) != (v2)); \ X case E_LT: return ((v1) < (v2)); \ X case E_GT: return ((v1) > (v2)); \ X case E_LE: return ((v1) <= (v2)); \ X case E_GE: return ((v1) >= (v2)); \ X } X X#define e_numcmp(n) e_cmp(n, e->op, e->num) X#define e_strcmp(s) e_cmp(mystrcmp(s,e->text), e->op, 0) X#define e_wildcmp(s) e_cmp(wild(s,e->text), e->op, 0) X X/* X * match() X * ------- X * Scans the the parse tree, and returns TRUE if the current X * record matches the criteria in the tree, else FALSE. X * X * Aside: Aren't C macros wonderful? Just think how long this function X * would be if it wasn't for the above e_cmp, e_numcmp and e_strcmp X * macros. X */ Xint match(p, e) XUDHEAD *p; XEXPR *e; X{ X switch (e->field) { X X case E_AND: return (match(p, e->left) && match(p, e->right)); X case E_OR: return (match(p, e->left) || match(p, e->right)); X case E_NOT: return (!match(p, e->left)); X case E_ALL: return (TRUE); X case I_LOCAL: return ((int)p->local); X case I_BINARY: return ((int)p->bin); X case I_VALID: return ((int)p->valid); X case I_ONLINE: return ((int)p->online); X case E_REMOTE: return (!(int)p->local); X case E_TEXT: return (!(int)p->bin); X case E_INVALID: return (!(int)p->valid); X case E_OFFLINE: return (!(int)p->online); X case I_ACCESS: e_numcmp(p->accesses); X case I_DATE: e_numcmp(p->date); X case I_DIRECTORY: e_numcmp(p->dir); X case I_DISKDIRNUM: e_numcmp(p->dirnum); X case I_KSIZE: e_numcmp(BTOK(p->length)); X case I_SECTION: e_numcmp(p->section); X case I_SIZE: e_numcmp(p->length); X case I_DISKNAME: e_strcmp(p->disk_name); X case I_COMMENT: e_strcmp(p->desc); X case I_NAME: e_strcmp(p->cat_name); X case I_OWNER: e_strcmp(p->owner); X case W_DISKNAME: e_wildcmp(p->disk_name); X case W_COMMENT: e_wildcmp(p->desc); X case W_NAME: e_wildcmp(p->cat_name); X case W_OWNER: e_wildcmp(p->owner); X } X} X X/* X * newnode() X * --------- X * This function allocates a new node from the tree array, and returns X * a pointer to it. If overflow occurs, it aborts with an error message. X */ X XEXPR *newnode() X{ X treepos++; X if (treepos >= MAXEXPR) { X scripterror("expression to complex\n"); X Cleanup(10); X } X return (&tree[treepos]); X} X X/* X * readtoken() X * ----------- X * This function reads the next token from the command line, starting X * at position curpos. curtoken is set to the type of token received. X * If it was E_STRING, then curstring points to the string it X * represents (without the quotes). If it was E_NUM, then curvalue X * points to the number represented. If the end of the line is X * reached, E_END is automatically set. X */ X X#define nextch() (ch = combuf[compos++]) X#define ungetnext() (compos--) X Xvoid readtoken() X{ X char *p = curstring, ch; X int i; X X if (compos >= comlen) { X curtoken = E_END; X return; X } X X do { X nextch(); X } while (ch == CHAR_SPACE); X X if (ch == CHAR_QUOTES) { /* Handle string in quotes */ X curtoken = E_STRING; X nextch(); X if (*p == CHAR_NULL) { X curtoken = E_END; X return; X } X do { X *p++ = ch; X nextch(); X } while (ch && ch != CHAR_QUOTES); X *p = CHAR_NULL; X return; X } X X if (isdigit(ch)) { /* Numeric value? */ X curtoken = E_NUMBER; X curvalue = 0; X do { X curvalue = curvalue * 10 + (ch - '0'); X nextch(); X } while (isdigit(ch)); X ungetnext(); X return; X } X X if (isalpha(ch)) { /* Alphabetic identifier? */ X do { X *p++ = ch; X nextch(); X } while (isalpha(ch)); X } else if (ch == CHAR_NULL) { /* At end of line? */ X curtoken = E_END; X return; X } else { /* Must be punctuation */ X do { X *p++ = ch; X nextch(); X } while (ch && !isalpha(ch) && !isdigit(ch) && ch != CHAR_SPACE X && ch != CHAR_QUOTES); X } X *p = CHAR_NULL; X ungetnext(); X X /* Check for character A - F */ X if (curstring[1] == CHAR_NULL) { X switch (curstring[0]) { X case 'A': case 'B': case 'C': X case 'D': case 'E': case 'F': X curvalue = curstring[0] + 10 - 'A'; X curtoken = E_NUMBER; X return; X } X } X X /* Now find token that matches string */ X for (i = 0; i < MAXINDEX; i++) { X if (!strcmp(curstring, indexes[i].name)) { X curtoken = indexes[i].tag; X return; X } X } X for (i = 0; tokens[i].name; i++) { X if (!strcmp(curstring, tokens[i].name)) { X curtoken = tokens[i].tag; X return; X } X } X scripterror("unrecognised symbol '"); X print2(curstring,"' in expression\n"); X Cleanup(10); X} X X X/* X * com_select() X * ------------ X * This command parses the expression in the command buffer starting X * at position compos, and builds an expression tree representing it. X * This tree is stored in tree[], starting at element 0. This expression X * tree is used when match() is called. X */ X Xvoid com_select() X{ X treepos = 0; X readtoken(); X bnf_expression(tree); X} X X/* X * bnf_expression() X * ---------------- X * Parses the BNF line: X * X * Expression ::= Boolean | Boolean Operator Expression | ALL X * X */ Xvoid bnf_expression(e) XEXPR *e; X{ X EXPR dummy; X X if (curtoken == E_ALL) X e->field = E_ALL; X else { X bnf_boolean(&dummy); X if (curtoken == E_AND || curtoken == E_OR) { X e->field = curtoken; X e->left = newnode(); X e->right = newnode(); X *(e->left) = dummy; X readtoken(); X bnf_expression(e->right); X } else X *e = dummy; X } X} X X/* X * bnf_boolean() X * ------------- X * Parses the following BNF line: X * X * Boolean ::= NOT Boolean | X * '(' Expression ')' | X * BoolIdent | X * NumIdent Op Value | X * StringIdent Op String | X * DateIdent Op Date X */ Xvoid bnf_boolean(e) XEXPR *e; X{ X char *p; X X e->field = curtoken; X switch (curtoken) { X X case E_NOT: X e->left = newnode(); X readtoken(); X bnf_boolean(e->left); X break; X X case E_OPENPAR: X readtoken(); X bnf_expression(e); X if (curtoken != E_CLOSEPAR) { X scripterror("missing close parenthesis\n"); X Cleanup(10); X } X readtoken(); X break; X X case I_BINARY: X case I_VALID: X case I_ONLINE: X case I_LOCAL: X case E_TEXT: X case E_INVALID: X case E_OFFLINE: X case E_REMOTE: X readtoken(); X break; X X case I_ACCESS: X case I_SECTION: X case I_DIRECTORY: X case I_DISKDIRNUM: X case I_SIZE: X case I_KSIZE: X readtoken(); X bnf_op(e); X if (curtoken != E_NUMBER) { X scripterror("number expected in expression\n"); X Cleanup(10); X } X e->num = curvalue; X readtoken(); X break; X X case I_COMMENT: X case I_DISKNAME: X case I_NAME: X case I_OWNER: X case I_PATHNAME: X readtoken(); X bnf_op(e); X if (curtoken != E_STRING) { X scripterror("string expected in expression\n"); X Cleanup(10); X } X e->text = mymalloc(strlen(curstring)+1); X strcpy(e->text, curstring); X /* X * Now check the string, and see if it contains any wildcard X * characters. If it does, use operation W_{string} X * instead of E_{string}. If it doesn't, use the standard X * strcmp which is much faster. X */ X for (p = curstring; *p; *p++) { X if (*p == '*' || *p == '?') { X e->field = tokentowild(e->field); X break; X } X } X readtoken(); X break; X X case I_DATE: X readtoken(); X bnf_op(e); X bnf_date(e); X break; X X default: X scripterror("error in expression\n"); X Cleanup(10); X } X} X X/* X * bnf_op X * ------ X * Sets the operation field of the specified expression to the value X * of the next token on the command line. X */ Xvoid bnf_op(e) XEXPR *e; X{ X switch (curtoken) { X case E_EQ: X case E_NE: X case E_LT: X case E_GT: X case E_LE: X case E_GE: X e->op = curtoken; X readtoken(); X break; X X default: X scripterror("expected comparison operator\n"); X Cleanup(10); X } X} X X/* X * bnf_date() X * ----------- X * Reads a date from the command line, validates it, and sets the X * 'num' field in the expression to its numerical value. The date X * is in the format "dd-mon-yy", e.g. "15-Jun-89" X */ Xvoid bnf_date(e) XEXPR *e; X{ X int day, month, year; X X if (curtoken != E_STRING) { X scripterror("expected date string in expression\n"); X Cleanup(10); X } X X if (strlen(curstring) != 9 || X curstring[2] != '-' || curstring[6] != '-') { X scripterror("Invalid date format (should be dd-mon-yy)\n"); X Cleanup(10); X } X X day = atoi(curstring); X year = atoi(curstring+7); X for (month = 0; month < 12 && strnicmp(curstring+3, months[month], 3); X month++) X ; X if ((day < 1 || day > 31) || (month < 1 || month > 12) || X (year < 1 || year > 99)) { X scripterror("Invalid date format (should be dd-mon-yy)\n"); X Cleanup(10); X } X e->num = (((year * 13) + month) << 5) + day; X readtoken(); X} END_OF_FILE if test 11470 -ne `wc -c <'src/expression.c'`; then echo shar: \"'src/expression.c'\" unpacked with wrong size! fi # end of 'src/expression.c' fi if test -f 'src/makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/makefile'\" else echo shar: Extracting \"'src/makefile'\" \(1075 characters\) sed "s/^X//" >'src/makefile' <<'END_OF_FILE' X# X# Lattice LKM makefile, for Lattice C V5.04 X# X# BBSindex (C) Copyright Eddy Carroll, December 1989 X# X X XCFLAGS = -cus -ms -j88i #-D3 XOPT = -O X#BFLAGS = sc sd map ram:map addsym XBFLAGS = sc sd map ram:map nd XASM = lc:asm X#START = lib:catch.o XSTART = tiny.o X X.c.o: X lc $(CFLAGS) $(OPT) -Hsystem.sym $*.c X.a.o: X $(ASM) -isys:include/ -u $*.a X.n.doc: X nro >$*.doc -ms:an $*.n X.h.sym: X copy $*.h to ram:t/dummy.c X lc $(CFLAGS) -ph -o$*.sym ram:t/dummy.c X delete ram:t/dummy.c X X# X# Makefile dependencies X# XOBJS = bbsindex.o checkfiles.o command.o expression.o format.o sort.o X Xall: bbsindex X Xbbsindex: $(OBJS) tiny.o X blink from $(START) $(OBJS) to bbsindex $(BFLAGS) lib lib:lc.lib X Xbbsindex.doc: bbsindex.n X Xsystem.sym: system.h Xbbsindex.o: bbsindex.c system.sym bbsindex.h bbs.h Xcheckfiles.o: checkfiles.c system.sym bbsindex.h bbs.h Xcommand.o: command.c system.sym bbsindex.h bbs.h Xexpression.o: expression.c system.sym bbsindex.h bbs.h Xformat.o: format.c system.sym bbsindex.h bbs.h Xsort.o: sort.c system.sym bbsindex.h bbs.h Xtiny.o: tiny.a END_OF_FILE if test 1075 -ne `wc -c <'src/makefile'`; then echo shar: \"'src/makefile'\" unpacked with wrong size! fi # end of 'src/makefile' fi if test -f 'src/sort.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/sort.c'\" else echo shar: Extracting \"'src/sort.c'\" \(3552 characters\) sed "s/^X//" >'src/sort.c' <<'END_OF_FILE' X/* X * SORT.C X * X * This module contains the sorting routines that read sorting order from X * the command line, and sort the file database according to that order. X * X */ X X#ifndef LATTICE_50 X#include "system.h" X#endif X X#include "bbsindex.h" X X X/* X * Arrays used to determine sorting order for SORT. X */ X Xint i_order[MAXINDEX+1]; Xint i_ascend[MAXINDEX+1]; X X X/* X * sortcmp() X * --------- X * This function is called by qsort. It compares the two specified X * elements, and returns -ve, 0 or +ve to indicate whether the second X * record is greater than, equal or less than the first, using the X * sorting criteria defined in SORT. X */ X X/* X * DOCMP is a macro which sets cmp equal to the value of the enclosed X * expression if i_ascend[i] is true, or the negative of the expression X * if i_ascend is false. X */ X#define DOCMP(x) (cmp = (i_ascend[i] ? (x) : -(x))) Xint sortcmp(ptr1,ptr2) XUDHEAD **ptr1, **ptr2; X{ X UDHEAD *p1 = *ptr1, *p2 = *ptr2; X int i, cmp = 0; X X /* X * Note safety exit - last element of i_order is guaranteed == I_ANY X */ X for (i = 0; !cmp; i++) { X switch (i_order[i]) { X X case I_ANY: return(0); X X case I_ACCESS: DOCMP(p1->accesses - p2->accesses); X break; X case I_BINARY: DOCMP(p2->bin - p1->bin); X break; X case I_COMMENT: DOCMP(stricmp(p1->desc, p2->desc)); X break; X case I_DISKNAME: DOCMP(stricmp(p1->disk_name, p2->disk_name)); X break; X case I_SECTION: DOCMP(p1->section - p2->section); X break; X case I_ONLINE: DOCMP(p2->online - p1->online); X break; X case I_LOCAL: DOCMP(p2->local - p1->local); X break; X case I_NAME: DOCMP(strcmp(p1->cat_name, p2->cat_name)); X break; X case I_OWNER: DOCMP(strcmp(p1->owner, p2->owner)); X break; X case I_PATHNAME: DOCMP(strcmp(dirnames[p1->dirnum], X dirnames[p2->dirnum])); X break; X case I_DIRECTORY: DOCMP(p1->dir - p2->dir); X break; X case I_DISKDIRNUM: DOCMP(p1->dirnum - p2->dirnum); X break; X case I_VALID: DOCMP(p2->valid - p1->valid); X break; X case I_DATE: DOCMP(p1->date - p2->date); X break; X case I_SIZE: DOCMP(p1->length - p2->length); X break; X case I_KSIZE: DOCMP(BTOK(p1->length) - BTOK(p2->length)); X break; X } X } X return (cmp); X} X X X/* X * com_sort() X * ---------- X * This command sorts the file database into order, according to X * the indexes specified. Each index may be optionally followed by X * a + or - to indirect sorting direction (ascending or descending). X * There must be no space between the direction and the +/-. X */ Xvoid com_sort() X{ X char *index, *p; X int i, j; X int ascend; X X CHECKDATABASE(); X X sorted = TRUE; X for (i = 0; i < MAXINDEX && compos < comlen; i++) { X index = getstring(); X p = index + strlen(index) - 1; X X /* X * Now check to see if sorting direction specified, and adjust X * string if it was. Set 'ascend' to TRUE if ascending, X * else FALSE. X */ X ascend = TRUE; X if (*p == CHAR_ASCEND || *p == CHAR_DESCEND) { X if (*p == CHAR_DESCEND) X ascend = FALSE; X *p = CHAR_NULL; X } X X /* X * Now match index, and setup appropriate entry in array X */ X X for (j = 0; j < MAXINDEX && strcmp(index,indexes[j].name); j++) X ; X if (j == MAXINDEX) { X scripterror("unknown index "); X print2(index, "\n"); X Cleanup(10); X } X i_order[i] = indexes[j].tag; X i_ascend[i] = ascend; X } X if (i == 0) { X i_order[i] = I_NAME; X i_ascend[i++] = TRUE; X } X i_order[i] = I_ANY; X X /* Finally, do the sort! */ X qsort(ptrblock, numrecs, sizeof(UDHEAD *), sortcmp); X} END_OF_FILE if test 3552 -ne `wc -c <'src/sort.c'`; then echo shar: \"'src/sort.c'\" unpacked with wrong size! fi # end of 'src/sort.c' fi if test -f 'src/system.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/system.h'\" else echo shar: Extracting \"'src/system.h'\" \(191 characters\) sed "s/^X//" >'src/system.h' <<'END_OF_FILE' X/* Include files for BBSindex */ X X#include <exec/types.h> X#include <proto/dos.h> X#include <proto/exec.h> X#include <proto/intuition.h> X#include <ctype.h> X#include <string.h> X#include <time.h> END_OF_FILE if test 191 -ne `wc -c <'src/system.h'`; then echo shar: \"'src/system.h'\" unpacked with wrong size! fi # end of 'src/system.h' fi if test -f 'src/tiny.a' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/tiny.a'\" else echo shar: Extracting \"'src/tiny.a'\" \(6132 characters\) sed "s/^X//" >'src/tiny.a' <<'END_OF_FILE' X*:ts=8 X**************************************************************************** X* * X* TINY.A (C) Copyright Eddy Carroll 1989 * X* ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * X* * X* Replacement startup code for Lattice C V5.04. Use instead of c.o * X* This has many features stripped out to allow small utilities to have * X* as small a filesize as possible. In particular, don't call any of the * X* stdio functions. * X* * X**************************************************************************** X X INCLUDE "exec/types.i" X INCLUDE "exec/alerts.i" X INCLUDE "exec/nodes.i" X INCLUDE "exec/lists.i" X INCLUDE "exec/ports.i" X INCLUDE "exec/libraries.i" X INCLUDE "exec/tasks.i" X INCLUDE "libraries/dos.i" X INCLUDE "libraries/dosextens.i" X INCLUDE "workbench/startup.i" X INCLUDE "exec/funcdef.i" X INCLUDE "exec/exec_lib.i" X INCLUDE "libraries/dos_lib.i" X XMAXARGS EQU 100 ; Maximum number of command line arguments from CLI XAbsExecBase EQU 4 ; Welcome to the only fixed point in the universe X X* A useful macro to let us call library routines Xcallsys macro X CALLLIB _LVO\1 X endm X X xdef XCEXIT X xdef exit X xref LinkerDB X xref _BSSBAS X xref _BSSLEN X X csect text,0,0,1,2 * xref's after this are 16-bit reloc X xref main * Name of C program to start with. X Xstart: X movem.l d1-d6/a0-a6,-(a7) XREGSIZE EQU (6+7)*4 X lea REGSIZE(a7),A5 * Determine old stack pointer X move.l a0,a2 * Save command pointer X move.l d0,d2 * and command length X lea LinkerDB,a4 * Load base register X X move.l AbsExecBase.W,a6 X move.l a6,SysBase(A4) X move.l a7,_StackPtr(A4) * Save stack ptr X X suba.l a1,a1 X callsys FindTask * Find out our task ID X move.l d0,a3 X X move.l a5,D0 * get top of stack X sub.l 4(a5),D0 * compute bottom X add.l #128,D0 * allow for parms overflow X move.l D0,_base(A4) * save for stack checking X X lea DOSName(A4),A1 X moveq.l #0,D0 X callsys OpenLibrary X move.l D0,DOSBase(A4) X bne getcom XnoDOS: X moveq.l #100,d0 X bra exit2 X X*------ find command name: Xgetcom: X move.l pr_CLI(a3),a0 X add.l a0,a0 X add.l a0,a0 X move.l cli_CommandName(a0),a1 X add.l a1,a1 X add.l a1,a1 X X*------ collect parameters: X move.l d2,d0 * get command line length X moveq.l #0,d1 X move.b (a1)+,d1 X move.l a1,_ProgramName(A4) X add.l d1,d0 * add length of command name X addq.l #1,d0 * allow for space after command X X clr.w -(A7) * set null terminator for command line X addq.l #1,D0 * force to even number of bytes X andi.w #$fffe,D0 * (round up) X sub.l D0,A7 * make room on stack for command line X subq.l #2,D0 X clr.w 0(A7,D0) X X*------ copy command line onto stack X move.l d2,d0 * get command line length X subq.l #1,d0 X add.l d1,d2 X Xcopy_line: X move.b 0(A2,D0.W),0(A7,D2.W) * copy command line to stack X subq.l #1,d2 X dbf d0,copy_line X move.b #' ',0(a7,d2.w) * add space between command and parms X subq.l #1,d2 X Xcopy_cmd: X move.b 0(a1,d2.w),0(a7,d2.w) * copy command name to stack X dbf d2,copy_cmd X move.l a7,a1 * Get pointer to new command line X X sub.l #(MAXARGS*4),a7 * Reserve space for argv[] X move.l a7,a2 * Initialise base into array X move.l a2,a3 * Save base of argv X moveq #0,d2 * Initialise argc X X* X* From here on down, A1 is pointer into command line X* Xbuild_argv: X bsr.s getnext * Read next character from line X bcs.s doquote * If quote, handle X beq.s build_argv * If white space, skip over it X X lea -1(a1),a0 * Get address of this parameter X bsr.s bumpargv * Store it to argv[] array Xbuild_2: X bsr.s getnext * Get next character X bne.s build_2 * If not white space, keep looking X clr.b -1(a1) * Zero-terminate current argument X bra.s build_argv * And go back to get next argument X Xdoquote: X move.l a1,a0 * Get pointer to this argument X bsr.s bumpargv * Output it to argv[] Xquote_2: X bsr.s getnext * Get next character X bcc.s quote_2 * If not quote, keep looking X clr.b -1(a1) * Zero-terminate current argument Xquote_3: X bsr.s getnext * Get next character X bne.s quote_3 * Skip until space reached X beq.s build_argv * Go back and read next argument X Xbumpargv: X move.l a0,(a2)+ * Output ptr to current argument X addq #1,d2 * Increment argc X cmpi #MAXARGS,d2 * Used up all our arguments yet? X bls.s qrts * If not, then return X moveq #110,d0 * Else set return code X bra.s exit2 * And exit X X* X* Reads next character from command line. If zero, never returns, but X* drops into call to main. Else, returns, with C=1 if character is quote, X* Z=1 if character is white space. X* Xgetnext: X move.b (a1)+,d0 * Get character from command line X beq.s get_2 * Exit if end of line X cmp.b #34,d0 * Check if quote X beq.s isquote * X cmp.b #32,d0 * Check if space X beq.s isspace * X cmp.b #9,d0 * Or tab X beq.s isspace * X cmp.b #10,d0 * Or end of line Xisspace: X andi #$1E,ccr * Clear carry flag, retaining Z Xqrts rts X Xisquote: X ori #1,ccr * Set carry flag X andi #$FB,ccr * Clear zero flag X rts * And return X Xget_2: X move.l a3,-(a7) * Push argv onto stack X move.l d2,-(a7) * Push argc onto stack X X lea _BSSBAS,a3 * get base of BSS X moveq #0,d1 X move.l #_BSSLEN,d0 * get length of BSS in longwords X bra.s clr_lp * and clear for length given Xclr_bss move.l d1,(a3)+ Xclr_lp dbf d0,clr_bss X Xdomain: X jsr main(PC) * Call main(argc,argv) X moveq.l #0,d0 * Set successful status X bra.s exit2 X Xexit: X_exit: XXCEXIT: X move.l 4(SP),d0 * Extract return code Xexit2: X move.l d0,-(a7) X move.l AbsExecBase.W,a6 X move.l DOSBase(A4),a1 X callsys CloseLibrary * Close Dos library X X*------ this rts sends us back to DOS: XexitToDOS: X MOVE.L (A7)+,D0 X movea.l _StackPtr(a4),SP * Restore stack ptr X movem.l (a7)+,d1-d6/a0-a6 X rts X X*----------------------------------------------------------------------- X* Global definitions X* X csect __MERGED,1,,2,2 X X xdef NULL,SysBase,LoadAddress,DOSBase X xdef _oserr,_OSERR,_ONBREAK X xdef _ProgramName,_StackPtr,_base X XNULL dc.l 0 X_base dc.l 0 X_oserr equ * X_OSERR dc.l 0 X_ONBREAK dc.l 0 XSysBase dc.l 0 XLoadAddress dc.l 0 X_StackPtr dc.l 0 XDOSBase dc.l 0 X_ProgramName dc.l 0 XDOSName dc.b 'dos.library',0 X X END END_OF_FILE if test 6132 -ne `wc -c <'src/tiny.a'`; then echo shar: \"'src/tiny.a'\" unpacked with wrong size! fi # end of 'src/tiny.a' fi echo shar: End of archive 1 \(of 3\). cp /dev/null ark1isdone MISSING="" for I in 1 2 3 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 3 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 -- Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to: amiga@cs.odu.edu or amiga@xanth.cs.odu.edu ( obsolescent mailers may need this address ) or ...!uunet!xanth!amiga ( very obsolescent mailers need this address ) Comments, questions, and suggestions s should be addressed to ``amiga-request'' (only use ``amiga'' for submissions) at the above addresses.