home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / utility / 1b / cat2asc.c next >
Encoding:
C/C++ Source or Header  |  1991-02-27  |  12.1 KB  |  399 lines

  1. /*
  2.  * cat2asc - a program to convert a STDCAT catalog file into ascii.
  3.  *
  4.  *             Copyright (c) 1989 by Bob Silliker
  5.  *                   All Rights Reserved
  6.  *
  7.  *                Permission is granted for
  8.  *              unrestricted non-commercial use
  9.  *
  10.  * Usage:
  11.  *    cat2asc <catalog_file>
  12.  *
  13.  * This source is intended to show how to access the information in the
  14.  * catalog file.  This source will work with version 3.X and 4.X files.
  15.  * There is no guarantee that this code will work with future versions
  16.  * of the catalog program (although I will try to maintain compatibility).
  17.  * The code was written for the Megamax Laser C compiler.  With little
  18.  * modification it should compile using any of the compilers for the ST.
  19.  *
  20.  * Make any changes you would like to this code for your own purposes.
  21.  *
  22.  * Version 1.0 - created Feb 16, 1989 by Bob Silliker.
  23.  * Version 1.1 - August 24, 1990 - Jim Hurley 
  24.  *           (jimh@ultra.com, ...!ames!ultra!jimh)
  25.  *           Changed output line to display more information.
  26.  *           Made some structure changes to access bit-fields.
  27.  *           Added osbind.h include.
  28.  *           Changed name from catoasc to cat2asc.
  29.  *           Many small cosmetic changes.
  30.  */
  31.  
  32. #include <stdio.h>
  33. #include <osbind.h>
  34.  
  35. #define SIG_STR "STDCAT"
  36.  
  37. /* define file attribute bit-format */
  38. typedef union {
  39.         struct {
  40.            unsigned r : 1;          /* read-only           */
  41.            unsigned h : 1;          /* hidden              */
  42.            unsigned s : 1;          /* system              */
  43.            unsigned v : 1;          /* volume              */
  44.            unsigned d : 1;          /* directory           */
  45.            unsigned a : 1;          /* archive             */
  46.            unsigned x : 10;         /* reserved + byte pad */
  47.         } part;
  48.         unsigned int realfattr;     /* file attribute area */
  49. } attrinfo;
  50.  
  51. /*
  52.  * Disk structure.  Contains information for a disk.
  53.  */
  54. typedef struct {
  55.     char volume[14];        /* Volume name.                       */
  56.     long serial;        /* Disk serial number.                */
  57.     long free;            /* Number of bytes free.              */
  58.     long used;            /* Number of bytes used.              */
  59.     int files;            /* Number of files on the disk.       */
  60.     int directories;        /* Number of directories on the disk. */
  61. }   MDISK;
  62.  
  63. /*
  64.  * File structure.  Contains information for a file or directory.
  65.  */
  66. typedef struct {
  67.     attrinfo attr;        /* File attributes.                     */
  68.     timeinfo time;        /* File modification time.              */
  69.     dateinfo date;        /* File modification date.              */
  70.     long size;            /* Size of file in bytes.               */
  71.     char name[14];        /* File name.                           */
  72.     int flag;            /* Flag to control directory levels.    */
  73.     int comment;        /* Flag to indicate there is a comment. */
  74. }   MFILE;
  75.  
  76. /*
  77.  * Misc sizes.
  78.  */
  79. #define COMMENT_SIZE 34             /* Length of a disk or file comment. */
  80. #define MDISK_SIZE sizeof(MDISK) /* Size of a disk structure.         */
  81. #define MFILE_SIZE sizeof(MFILE) /* Size of a file structure.         */
  82. #define SIG_SIZE 12         /* Length of the signature string.   */
  83.  
  84. /*
  85.  * Macros for error()
  86.  */
  87. #define ERR_USAGE  0        /* Program usage error.        */
  88. #define ERR_NOTME  1        /* File is not a catalog file.     */
  89. #define ERR_READ   2        /* Read error on a file.     */
  90. #define ERR_OPEN   3        /* Open error on a file.     */
  91.  
  92. MDISK disk;  /* Structure that holds the information for the current disk. */
  93.  
  94. char disk_comment[COMMENT_SIZE];               /* The current disk comment */
  95. char file_comment[COMMENT_SIZE];               /* The current file comment */
  96.  
  97. int files;       /* Storage for the # of files on the current disk.       */
  98. int directories; /* Storage for the # of directories on the current disk. */
  99. int num_disks;     /* Current number of disks read in.
  100.                     Same as the disk number. */
  101.  
  102.  
  103. main (argc, argv)
  104. int argc;
  105. char *argv[];
  106. {
  107.     int err;
  108.     FILE *infile, *fopen ();
  109.  
  110.  
  111.     /* If you add command line args then change this. */
  112.     if (argc != 2)
  113.     error (ERR_USAGE, "");
  114.  
  115.     /* Open the input file for reading. 
  116.        The "br" is binary read where the read routine does what
  117.          is should do which is to read the the information read
  118.          exactly as it is in the file.
  119.     */
  120.     if ((infile = fopen (argv[1], "br")) == NULL)
  121.     error (ERR_OPEN, argv[1]);
  122.  
  123.     /* Read the catalog and report any errors. */
  124.     if (err = read_cat (infile)) {
  125.     if (err == -1)
  126.         error (ERR_READ, argv[1]);
  127.     else if (err == -2)
  128.         error (ERR_NOTME, argv[1]);
  129.     }
  130.  
  131.     /* normal termination */
  132.     (void) fclose (infile);
  133.     exit(0);
  134. }
  135.  
  136.  
  137. /*
  138.  * Read the entire catalog file.
  139.  *
  140.  * The caller passes an open FILE pointer.  The routine reads disk
  141.  * structures and disk comments then calls the read_ent() routine to
  142.  * read the contents of the disk.  When the read_ent() routine returns
  143.  * with a value of 0 the file read pointer points to the next disk
  144.  * structure in the file.  The process is repeated until there is an
  145.  * error or there is no more information in the file.
  146.  *
  147.  * Returns:
  148.  *     0 - Read catalog ok.
  149.  *    -1 - File read error.
  150.  *    -2 - File not a catalog file.
  151.  */
  152. int
  153. read_cat (fp)
  154. FILE *fp;
  155. {
  156.     int version3;
  157.     char sig[SIG_SIZE];
  158.  
  159.     num_disks = 0;
  160.  
  161.     /* Read in catalog signature and check for signature string.
  162.        Should be 'STDCAT VX.X' with a NUL
  163.           termination and an extra filler byte (to 12 bytes).
  164.     */
  165.     (void) fread (sig, SIG_SIZE, 1, fp);
  166.     if (ferror (fp))
  167.     return (-1);
  168.  
  169.     /* Check to see if the first 6 bytes match. */
  170.     if (strncmp (SIG_STR, sig, 6))
  171.     return (-2);
  172.  
  173.     /* Check to see if the file is version 3.X. */
  174.     if (sig[8] == '3')
  175.     version3 = 1;
  176.     else
  177.     version3 = 0;
  178.  
  179.     /* Read the catalog file while there aren't any errors
  180.           and there is more information in the file.
  181.     */
  182.     do {
  183.  
  184.     /* Get the disk information block. */
  185.     if (fread (&disk, MDISK_SIZE, 1, fp) != 1) {
  186.         /* Could not read a disk structure. 
  187.                Either there was an error or it was end of file.
  188.            EOF returns 0 below.
  189.             */
  190.         if (ferror (fp))
  191.         break;
  192.         else
  193.         return (0);
  194.     }
  195.     /* Keep track of the current disk number. */
  196.     num_disks++;
  197.  
  198.     /* Check to see if the file is a version 3.0 file.
  199.            This was when there were no serial numbers in the file.
  200.            The value 0x40000000L is a magic number that should never
  201.               conflict with a valid serial number.
  202.            If you were to print the serial number then check to see if
  203.           the serial number is this value and don't output
  204.               anything if it is. 
  205.         */
  206.     if (version3)
  207.         disk.serial = 0x40000000L;
  208.  
  209.     /* Get the disk comment line. */
  210.     if (fread (disk_comment, COMMENT_SIZE, 1, fp) != 1)
  211.         break;
  212.  
  213.     /* Get temporary copies of the file and directory counts.
  214.            This will be used to determine when there are no more 
  215.               files and directories for the current disk.
  216.            Passes this point once for each disk. 
  217.         */
  218.     files = disk.files;
  219.     directories = disk.directories;
  220.  
  221.     /* Read the contents of this disk 
  222.              and continue to the next disk if there are no errors.
  223.         */
  224.     } while (!read_ent (fp, "", ""));
  225.  
  226.     /* There was a file i/o error. */
  227.     return (-1);
  228. }
  229.  
  230.  
  231. /*
  232.  * Read the contents of an entire disk.
  233.  *
  234.  * The caller passes an open FILE pointer, a path string, and a directory
  235.  * string.  The path string and directory string are combined to form a
  236.  * new path that will be passed onto recursive calls.  A recursive call
  237.  * is made when a directory has been encountered.  The contents of a
  238.  * directory is read in, when encountered, before the rest of the
  239.  * files/directories in the current directory.
  240.  *
  241.  * This routine is recursive and uses up about 300 bytes of stack
  242.  * space per call.
  243.  *
  244.  * Returns:
  245.  *     0 - Read all files at current directory level.
  246.  *    -1 - File read error.
  247.  */
  248. int
  249. read_ent (fp, current_path, directory)
  250. FILE *fp;
  251. char *current_path, *directory;
  252. {
  253.     char new_path[256];
  254.     MFILE file;
  255.  
  256.     /* Build the path.
  257.        If the directory is zero length then this is the root level
  258.          otherwise combine the current path with the new directory.
  259.     */
  260.     if (*directory == '\0')
  261.     (void) strcpy (new_path, current_path);
  262.     else
  263.     (void) sprintf (new_path, "%s\\%s", current_path, directory);
  264.  
  265.     /* While there are more files or directories for the current disk. */
  266.     while (directories || files) {
  267.     /* Read one file structure. */
  268.     if (fread (&file, MFILE_SIZE, 1, fp) != 1)
  269.         return (-1);
  270.  
  271.     /* Check to see if there should be a comment for the file. */
  272.     if (file.comment) {
  273.         /* There should be a comment so read one. */
  274.         if (fread (file_comment, COMMENT_SIZE, 1, fp) != 1)
  275.         return (-1);
  276.     } else {
  277.         /* No comment so make sure the string is terminated anyway. */
  278.         file_comment[0] = '\0';
  279.     }
  280.  
  281.     /* Check to see of the file structure is actually a directory. */
  282.     if (file.attr.part.d) {
  283.         /* It is a directory so decrease the directory count for the disk.
  284.                Passes this point once for each directory (not file).
  285.             */
  286.         directories--;
  287.  
  288.         /* If there are entries for this directory get them.
  289.                The 0x02 bit, when set, indicates an empty directory.
  290.             */
  291.         if (!(file.flag & 0x02)) {
  292.         /* Get more the entries for this directory. */
  293.         if (read_ent (fp, new_path, file.name))
  294.             return (-1);
  295.         }
  296.         /* Check to see if there are more entires.
  297.                The 0x01 bit, when set, indicates the last
  298.               file/directory in a directory.
  299.                A break from this loop causes the routine to return(0).
  300.             */
  301.         if (file.flag & 0x01)
  302.         break;
  303.     } else {
  304.         /* This is a file structure so output the file info. 
  305.                Passes this point once for each
  306.               file (not directory). 
  307.             */
  308.         output_file (&file, new_path);
  309.  
  310.         /* Decrement the number of files count for the current disk. */
  311.         files--;
  312.  
  313.         /* Check to see if there are more entires.
  314.                The 0x01 bit, when set, indicates the last
  315.               file/directory in a directory.  
  316.                A break from this loop cause the routine to return(0). 
  317.             */
  318.         if (file.flag & 0x01)
  319.         break;
  320.     }
  321.     }
  322.     return (0);
  323. }
  324.  
  325.  
  326. /*
  327.  * Output routine.
  328.  */
  329.  
  330. output_file (file, path)
  331. MFILE *file;
  332. char *path;
  333. {
  334.     char ra, ha, sa, va, da, aa;
  335.  
  336.     /* decipher the file attribute */
  337.     ra = file->attr.part.r ? 'r' : '-';
  338.     ha = file->attr.part.h ? 'h' : '-';
  339.     sa = file->attr.part.s ? 's' : '-';
  340.     va = file->attr.part.v ? 'v' : '-';
  341.     da = file->attr.part.d ? 'd' : '-';
  342.     aa = file->attr.part.a ? 'a' : '-';
  343.  
  344.     /* print the line */
  345.     (void) printf (
  346.   "%-14s %9ld %c%c%c%c%c%c %02d/%02d/%02d %02d:%02d:%02d %-14s %s\n",
  347.   file->name, file->size, aa, da, va, sa, ha, ra,
  348.   file->date.part.year+80, file->date.part.month, file->date.part.day,
  349.   file->time.part.hours, file->time.part.minutes, file->time.part.seconds*2, 
  350.   disk.volume, path );
  351. }
  352.  
  353.  
  354. /*
  355.  * Print error and terminate the program with an
  356.  * exit status of -1.
  357.  *
  358.  * The caller passes an error code integer and a pointer to
  359.  * a NUL terminated character string.  The error code determines
  360.  * the message displayed and the string is used as part of the
  361.  * error message and is usually a file name.
  362.  */
  363. error (err, s)
  364. int err;
  365. char *s;
  366. {
  367.     char *p;
  368.     char temp[128];
  369.     char t[30];
  370.  
  371.     switch (err) {
  372.  
  373.     case (ERR_USAGE):
  374.     p = "USAGE ERROR:";
  375.     s = "cat2asc <catalog_file>";
  376.     break;
  377.     case (ERR_NOTME):
  378.     p = "NOT A CATALOG FILE:";
  379.     break;
  380.     case (ERR_OPEN):
  381.     p = "OPEN FAILURE:";
  382.     break;
  383.     case (ERR_READ):
  384.     p = "READ FAILURE:";
  385.     break;
  386.     default:
  387.     (void) sprintf (t, "UNDEFINED ERROR #%d:", err);
  388.     p = t;
  389.     break;
  390.     }
  391.  
  392.     (void) fprintf (stderr,"\n%s\n%s\n", p, s);
  393.     (void) puts ("Press RETURN...");
  394.     (void) getchar(); 
  395.     exit (-1);
  396. }
  397.  
  398. /* end of file: cat2asc.c */
  399.