/* * catoasc.ttp - a program to convert a stdcat.prg file into ascii. * * Copyright (c) 1989 by Bob Silliker * All Rights Reserved * * Permission is granted for * unrestricted non-commercial use * * Usage: * catoasc.ttp catalog_file * * This source is intened to show how to access the information in the * catalog file. This source will work with version 3.X and 4.X files. * There is no gaurantee that this code will work with future versions * of the catalog program (although I will try to maintain compatibility). * The code was written for the Megamax Laser C compiler. With little * modification it should compile using any of the compilers for the ST. * * Make any changes you would like to this code for your own purposes. * * Version 1.0 - created Feb 16, 1989 by Bob Silliker. */ #include #define SIG_STR "STDCAT" /* * Disk structure. Contains information for a disk. */ typedef struct { char volume[14]; /* Volume name. */ long serial; /* Disk serial number. */ long free; /* Number of bytes free. */ long used; /* Number of bytes used. */ int files; /* Number of files on the disk. */ int folders; /* Number of folders on the disk. */ } MDISK; /* * File structure. Contains information for a file or folder. */ typedef struct { char fill; /* Padding character. */ char attr; /* File attributes. */ int time; /* File modification time. */ int date; /* File modification date. */ long size; /* Size of file in bytes. */ char name[14]; /* File name. */ int flag; /* Flag to control directory levels. */ int comment; /* Flag to indicate there is a comment. */ } MFILE; /* * Misc sizes. */ #define COMMENT_SIZE 34 /* Length of a disk or file comment. */ #define MDISK_SIZE sizeof(MDISK) /* Size of a disk structure. */ #define MFILE_SIZE sizeof(MFILE) /* Size of a file structure. */ #define SIG_SIZE 12 /* Length of the signature string. */ /* * Macros for error() */ #define ERR_USAGE 0 /* Program usage error. */ #define ERR_NOTME 1 /* File is not a catalog file. */ #define ERR_READ 2 /* Read error on a file. */ #define ERR_OPEN 3 /* Open error on a file. */ MDISK disk; /* Structure that holds the information for the current disk. */ char disk_comment[COMMENT_SIZE]; /* The current disk comment is stored here. */ char file_comment[COMMENT_SIZE]; /* The current file comment is stored here. */ int files; /* Temporary storage for the # of files on the current disk. */ int folders; /* Temporary storage for the # of folders on the current disk. */ int num_disks; /* Current number of disks read in. Same as the disk number. */ main(argc, argv) int argc; char *argv[]; { int err; FILE *infile, *fopen(); /* * Must have this or there will be terrible confusion when the * form_alerts() are executed. Remove the form_alerts() and you * can remove this. If you do, don't forget to remove the appl_exit() * at all program termination points (there are two one in this routine * and one in error(). */ appl_init(); /* * If you add command line args then change this. */ if(argc != 2) error(ERR_USAGE); /* * Open the input file for reading. The "br" is binary read where * the read routine does what is should do which is to read the * the information read exactly as it is in the file. */ if((infile = fopen(argv[1], "br")) == NULL) error(ERR_OPEN, argv[1]); /* * Read the catalog and report any errors. */ if(err = read_cat(infile)) { if(err == -1) error(ERR_READ, argv[1]); else if(err == -2) error(ERR_NOTME, argv[1]); } fclose(infile); /* * Remove appl_init() and you can remove this. */ appl_exit(); } /* * Read the entire catalog file. * * The caller passes an open FILE pointer. The routine reads disk * structures and disk comments then calls the read_ent() routine to * read the contents of the disk. When the read_ent() routine returns * with a value of 0 the file read pointer points to the next disk * structure in the file. The process is repeated until there is an * error or there is no more information in the file. * * Returns: * 0 - Read catalog ok. * -1 - File read error. * -2 - File not a catalog file. */ int read_cat(fp) FILE *fp; { int size, version3; char sig[SIG_SIZE]; num_disks = 0; /* * Read in catalog signature and check for signature string. * Should be 'STDCAT VX.X' with a NUL termination and an * extra filler byte (to 12 bytes). */ fread(sig, SIG_SIZE, 1, fp); if(ferror(fp)) return(-1); /* * Check to see if the first 6 bytes match. */ if(strncmp(SIG_STR, sig, 6)) return(-2); /* * Check to see if the file is version 3.X. */ if(sig[8] == '3') version3 = 1; else version3 = 0; /* * Read the catalog file while there aren't any errors and * there is more information in the file. */ do { /* * Get the disk label, and sizes. */ if((size = fread(&disk, MDISK_SIZE, 1, fp)) != 1) { /* * Could not read a disk structure. Either there was * an error or it was end of file. EOF returns 0 below. */ if(ferror(fp)) break; else return(0); } /* * Keep track of the current disk number. */ num_disks++; /* * Check to see if the file is a version 3.0 file. This was * when there were no serial numbers in the file. The value * 0x40000000L is a magic number that should never conflict * with a value serial number. If you were to print the * serial number then check to see if the serial number is * this value and don't output anything if it is. */ if(version3) disk.serial = 0x40000000L; /* * Get the disk comment line. */ if(fread(disk_comment, COMMENT_SIZE, 1, fp) != 1) break; /* * Get temporary copies of the file and folder counts. * This will be used to determine when there are no * more files and folders for the current disk. * Passes this point once for each disk. */ files = disk.files; folders = disk.folders; /* * Read the contents of this disk and continue to the next disk * if there are no errors. */ } while(!read_ent(fp, "", "")); /* * There was a file i/o error. */ return(-1); } /* * Read the contents of an entire disk. * * The caller passes an open FILE pointer, a path string, and a folder * string. The path string and folder string are combined to form a * new path that will be passed onto recursive calls. A recursive call * is made when a folder has been encountered. The contents of a * folder is read in, when encountered, before the rest of the * files/folders in the current folder. * * This routine is recursive and uses up about 300 bytes of stack * space per call. * * Returns: * 0 - Read all files at current directory level. * -1 - File read error. */ int read_ent(fp, current_path, folder) FILE *fp; char *current_path, *folder; { char new_path[256]; MFILE file; /* * Build the path. If the folder is zero length then this is the * root level otherwise combine the current path with the new folder. */ if(*folder == '\0') strcpy(new_path, current_path); else sprintf(new_path, "%s\\%s", current_path, folder); /* * While there are more files or folders for the current disk. */ while(folders || files) { /* * Read one file structure. */ if(fread(&file, MFILE_SIZE, 1, fp) != 1) return(-1); /* * Check to see if there should be a comment for the file. */ if(file.comment) { /* * There should be a comment so read one. */ if(fread(file_comment, COMMENT_SIZE, 1, fp) != 1) return(-1); } else { /* * No comment so make sure the string is terminated anyway. */ file_comment[0] = '\0'; } /* * Check to see of the file structure is actually a folder. */ if(file.attr & 0x10) { /* * It is a folder so decrease the folder count for the disk. * Passes this point once for each folder (not file). */ folders--; /* * If there are entries for this folder get them. * The 0x02 bit, when set, indicates an empty folder. */ if(!(file.flag & 0x02)) { /* * Get more the entries for this folder. */ if(read_ent(fp, new_path, file.name)) return(-1); } /* * Check to see if there are more entires. * The 0x01 bit, when set, indicates the * last file/folder in a folder. A break from * this loop causes the routine to return(0). */ if(file.flag & 0x01) break; } else { /* * This is a file structure so output the file info. * Passes this point once for each file (not folder). */ output_file(&file); /* * Decrement the number of files count for the current disk. */ files--; /* * Check to see if there are more entires. * The 0x01 bit, when set, indicates the * last file/folder in a folder. A break from * this loop cause the routine to return(0). */ if(file.flag & 0x01) break; } } return(0); } /* * Output routine. * * Just print the file name padded with spaces to * 14 characters and the disk number. You could add any of the * global variables to the output. You could also store the file * name and other information into an array in memory for sorting * and formating. */ output_file(file) MFILE *file; { /* * This just prints the file name and disk number. You could * easily add printing the file size, date, comment or volume * name instead of disk number or whatever else you would like * associated with each file. */ printf("%-14s %03d\r\n", file->name, num_disks); } /* * Display a form alert and terminate the program with an * exit status of -1. * * The caller passes an error code integer and a pointer to * a NUL terminated character string. The error code determines * the message displayed and the string is used as part of the * error message and is usually a file name. */ error(err, s) int err; char *s; { char *p, temp[128]; char t[30]; switch(err) { case(ERR_USAGE): p = "USAGE ERROR:"; s = "catoasc.ttp catalog_file"; break; case(ERR_NOTME): p = "NOT A CATALOG FILE:"; break; case(ERR_OPEN): p = "OPEN FAILURE:"; break; case(ERR_READ): p = "READ FAILURE:"; break; default: sprintf(t, "UNDEFINED ERROR #%d:", err); p = t; break; } sprintf(temp, "[3][%s| |%.31s][ TOO BAD ]", p, s); form_alert(1, temp); /* * Remove appl_init() in main() and you can remove this. */ appl_exit(); exit(-1); } /* END OF FILE */