home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 1 / FFMCD01.bin / bbs / libdisks / d700t799 / disk767.lha / File / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-21  |  10.3 KB  |  582 lines

  1.  
  2. #define VERSION "V1.2"
  3. /*
  4.  * file  - a Unix-like utility to determine the type of a file
  5.  *
  6.  * Copyright 1989 Edwin Hoogerbeets
  7.  *
  8.  * This code is freely redistributable as long as no charge other than
  9.  * reasonable copying fees is levied for it.
  10.  *
  11.  *
  12.  * Usage: file [-h | -v] file [file ...]
  13.  *
  14.  */
  15.  
  16. /*
  17.  * Enhanced and converted to compile under SAS/C 6.0  by :-
  18.  *
  19.  * gduncan@philips.philips.oz.au
  20.  *
  21.  * Changes:-
  22.  *
  23.  * lharc/lz files recognised ( -lh5- )
  24.  * GIF format recognised
  25.  * -h option added
  26.  * test logic improved a bit
  27.  *
  28.  * N.B. this source file formatted with GNU indent , option -gnu
  29.  */
  30.  
  31.  
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <dos.h>
  35. #include <ctype.h>
  36. #include <exec/types.h>
  37. #include <string.h>
  38. #include <exec/memory.h>
  39. #include <libraries/dosextens.h>
  40. #include <proto/dos.h>
  41. #include <proto/exec.h>
  42. #include <clib/dos_protos.h>
  43. #include <math.h>
  44.  
  45.  
  46. typedef struct FileLock FILELOCK;
  47. typedef struct FileInfoBlock FILEINFOBLOCK;
  48.  
  49. typedef struct
  50. {
  51.   int length;
  52.   char *name;
  53.   char *pattern;
  54. } PATTERN;
  55.  
  56. typedef struct
  57. {
  58.   int offset;
  59.   int length;
  60.   char *name;
  61.   char *pattern;
  62. } BPATTERN;
  63.  
  64. #undef  FALSE
  65. #undef TRUE
  66. typedef enum
  67. {
  68.   FALSE = 0, TRUE
  69. } BOOLEAN;
  70.  
  71. #include "file_protos.h"
  72.  
  73. #define FIBSIZE (long) sizeof(struct FileInfoBlock)
  74. #define toint(a) (int)((a) - '0')
  75. #define BLOCKSIZE 512
  76.  
  77. /***** #define BLOCKSIZE 484L              /* almost size of one disk block */
  78.  
  79.  
  80. /* for binary files that start with a magic number */
  81.  
  82. BPATTERN bmagic[] =
  83. {
  84.   0, 4, "Amiga load file", "\x00\x00\x03\xf3",
  85.   0, 4, "Amiga object file", "\x00\x00\x03\xe7",
  86.   0, 2, "Amiga run-time library", "\xec\x62",
  87.  
  88.   0, 2, "Manx 3.6 run-time library", "\x61\x6a",
  89.   0, 2, "Manx 3.6 object file", "\x41\x4a",
  90.   0, 2, "Manx 3.4 object file", "\x6a\x67",
  91.  
  92.   0, 27, "TeX device independent output file",
  93.   "\xf7\x02\x01\x83\x92\xc0"
  94.   "\x1c\x3b\x00\x00\x00\x00"
  95.   "\x03\xe8\x1b\x20\x54\x65"
  96.   "\x58\x20\x6f\x75\x74\x70"
  97.   "\x75\x74\x20",
  98.  
  99.   0, 2, "Amiga icon .info file", "\xe3\x10",
  100.   0, 4, "Amiga .info file", "\xf3\x4c\x00\x12",
  101.   0, 2, "Amiga .font file", "\x0f\x00",
  102.  
  103.   0, 2, "SEA ARC compressed archive", "\x1a\x08",
  104.  
  105.   2, 5, "lharc archive (lh0 - uncompressed)", "-lh0-",
  106.   2, 5, "lharc archive (lh1 compression)", "-lh1-",
  107.   2, 5, "lz  archive (lh5 compression)", "-lh5-",
  108.   0, 3, "GIF file", "GIF",
  109.   NULL, NULL, NULL, NULL,
  110. };
  111.  
  112. /*
  113.  * for ascii files that start with a magic token
  114.  */
  115. PATTERN amagic[] =
  116. {
  117.   2, "UNIX sh script file", "#!",
  118.   4, "AmigaDos execute script file", ".key",
  119.   4, "AmigaDos execute script file", ".bra",
  120.   4, "AmigaDos execute script file", ".ket",
  121.   NULL, NULL, NULL,
  122. };
  123.  
  124. /*
  125.  *    patterns to search for in ascii files
  126.  */
  127.  
  128. PATTERN asearch[] =
  129. {
  130.  
  131.   14, "LaTeX source code", "\\documentstyle",
  132.   6, "TeX source code", "\n\\",
  133.  
  134.   2, "C++ source code", "//",
  135.   2, "C++ source code", "::",
  136.   8, "C++ source code", "iostream.h ",
  137.   5, "C++ source code", "public:",
  138.  
  139.   2, "C source code", "/*",
  140.   2, "C source code", "{\n",
  141.   8, "C source code", "\ntypedef",
  142.   4, "C source code", "int ",
  143.   5, "C source code", "\n#inc",
  144.   5, "C source code", "\n#def",
  145.  
  146.   5, "68K ASM source", "\tjsr",    /* common instrs    */
  147.   3, "68K ASM source", "\tlea",
  148.   6, "68K ASM source", "move.l",
  149.  
  150.   2, "PASCAL source code", ":=",
  151.  
  152.   21, "Modula II source code", "IMPLEMENTATION MODULE",
  153.   17, "Modula II source code", "DEFINITION MODULE",
  154.  
  155.   1, "yacc input file", "\n%TOKEN",
  156.   1, "yacc or lex input file", "\n%%",
  157.  
  158.   1, "shell commands", "\nalias",
  159.   1, "shell commands", "\nAlias",
  160.   1, "shell commands", "\nset",
  161.  
  162.   1, "commands text", "\nrun",
  163.   1, "commands text", "\nRun",
  164.   1, "uuencoded file", "\nbegin ",
  165.   NULL, NULL, NULL,
  166. };
  167.  
  168. PATTERN IFFforms[] =
  169. {
  170.   4, "IFF interleave bit map file", "ILBM",
  171.   4, "IFF Amiga compressed bit map files", "ACBM",
  172.   4, "IFF anim format file", "ANIM",
  173.   4, "IFF instrument file", "8SVX",
  174.   4, "IFF simple music file", "SMUS",
  175.   NULL, NULL, NULL,
  176. };
  177.  
  178. PATTERN compress =
  179. {
  180.   2, "block compressed %d bit code data", "\x1f\x9d",
  181. };
  182.  
  183. PATTERN zoo =
  184. {
  185.   4, "Zoo archive", "ZOO ",
  186. };
  187.  
  188.  
  189. /**************************************************************************
  190.  *
  191.  *    main ()
  192.  *
  193.  */
  194.  
  195. main (int argc, char **argv)
  196.  
  197. {
  198.   int j;
  199.   char *myname;
  200.   char *q = argv[0];
  201.  
  202.   if (argc <= 1)
  203.     {
  204.       usage (q);
  205.       exit (0);
  206.     }
  207.   myname = basename (q);
  208.  
  209.   /*
  210.    *    loop through the file list, checking type
  211.    */
  212.   for (j = 1; j < argc; j++)
  213.     {
  214.       filetype (myname, argv[j]);
  215.     }
  216. }
  217.  
  218. /**************************************************************************
  219.  *
  220.  *    type()
  221.  *
  222.  */
  223.  
  224. void
  225. type (char *ty, char *name)
  226. {
  227.   printf ("%-25s %s\n", name, ty);
  228. }
  229.  
  230. /**************************************************************************
  231.  *
  232.  *    memncmp()
  233.  *
  234.  */
  235.  
  236. int
  237. memncmp (char *a, char *b, int length)
  238. {
  239.   int j;
  240.  
  241.   for (j = 0; j < length; j++)
  242.     {
  243.       if (a[j] != b[j])
  244.     {
  245.       return (a[j] > b[j] ? -1 : 1);
  246.     }
  247.     }
  248.  
  249.   return (0);
  250. }
  251.  
  252. /**************************************************************************
  253.  *
  254.  *    strrpbrk
  255.  *
  256.  */
  257.  
  258. char *
  259. strrpbrk (char *str, char *charset)
  260. {
  261.   char *temp;
  262.   extern char *strchr ();
  263.  
  264.   temp = str + strlen (str) - 1;
  265.  
  266.   while (temp != (str - 1) && !strchr (charset, *temp))
  267.     --temp;
  268.  
  269.   return ((temp != (str - 1)) ? temp : NULL);
  270. }
  271.  
  272. /**************************************************************************
  273.  *
  274.  *    basename ()
  275.  *
  276.  */
  277.  
  278. char *
  279. basename (char *buf)
  280. {
  281.   char *foo = strrpbrk (buf, ":/");
  282.  
  283.   return (foo ? (foo + 1) : buf);
  284. }
  285.  
  286. /**************************************************************************
  287.  *
  288.  *    filetype()
  289.  *
  290.  * find whether file is directory or real file
  291.  *
  292.  */
  293.  
  294. void
  295. filetype (char *myname, char *filename)
  296. {
  297.   BPTR lock;
  298.   FILEINFOBLOCK *fib;
  299.  
  300.   if (lock = Lock (filename, ACCESS_READ))
  301.     {
  302.       if (fib = (FILEINFOBLOCK *) AllocMem (FIBSIZE, MEMF_CLEAR))
  303.     {
  304.       Examine (lock, fib);
  305.  
  306.       dofile (myname, filename, fib);
  307.  
  308.       UnLock (lock);
  309.       FreeMem (fib, FIBSIZE);
  310.  
  311.     }
  312.       else
  313.     {
  314.       UnLock (lock);
  315.       fprintf (stderr, "%s: not enough memory!\n", myname, filename);
  316.       exit (-1);
  317.     }
  318.     }
  319.   else
  320.     {
  321.       fprintf (stderr, "%s: could not access file %s\n", myname, filename);
  322.     }
  323. }
  324.  
  325. /**************************************************************************
  326.  *
  327.  *    dofile()
  328.  *
  329.  */
  330.  
  331. /* find what type of file filename is */
  332.  
  333. void
  334. dofile (char *myname, char *filename, FILEINFOBLOCK * fib)
  335. {
  336.   char *f = &fib->fib_FileName[0];
  337.  
  338.   if (fib->fib_DirEntryType > 0)
  339.     {
  340.       type ("directory", f);
  341.     }
  342.   else if (fib->fib_Size == 0)
  343.     {
  344.       type ("empty", f);
  345.     }
  346.   else
  347.     {
  348.       char *buf;
  349.       long filehandle;
  350.  
  351.       if (!(filehandle = Open (filename, MODE_OLDFILE)))
  352.     {
  353.       fprintf (stderr, "%s: could not open file %s\n", myname, filename);
  354.       return;
  355.     }
  356.  
  357.       if (!(buf = (char *) AllocMem (BLOCKSIZE + 1, MEMF_PUBLIC)))
  358.     {
  359.       fprintf (stderr, "%s: not enough memory\n", myname);
  360.       Close (filehandle);
  361.       return;
  362.     }
  363.  
  364.       if (!Read (filehandle, buf, BLOCKSIZE))
  365.     {
  366.       fprintf (stderr, "%s: read error on file %s\n", myname, f);
  367.       FreeMem (buf, BLOCKSIZE + 1);
  368.       Close (filehandle);
  369.       return;
  370.     }
  371.  
  372.       matchtype (myname, buf, f, fib);
  373.  
  374.       Close (filehandle);
  375.       FreeMem (buf, BLOCKSIZE + 1);
  376.     }
  377. }
  378.  
  379. /**************************************************************************
  380.  *
  381.  *    istextfile()
  382.  *
  383.  */
  384.  
  385.  
  386. BOOLEAN
  387. istextfile (UBYTE * buf, int len)
  388. {
  389.   int j;
  390.   int bad_cnt = 0;
  391.  
  392.   for (j = 0; j < (len - 1); j++, buf++)
  393.     {
  394.       if (*buf == 0xA9)
  395.     continue;        /* Copyright */
  396.  
  397.       if (isascii (*buf) == FALSE)
  398.     {
  399.       return (FALSE);
  400.     }
  401.       else
  402.     {
  403.       switch (*buf)
  404.         {
  405.         case '\n':
  406.         case '\r':
  407.         case '\f':
  408.         case '\t':
  409.         case '\b':
  410.         case '\0':
  411.  
  412.           break;
  413.  
  414.         default:
  415.           if (isprint (*buf))
  416.         break;
  417.           else
  418.         ++bad_cnt;
  419.           break;
  420.         }
  421.     }
  422.     }
  423.   if (bad_cnt)
  424.     return (FALSE);
  425.   else
  426.     return (TRUE);
  427. }
  428.  
  429. /**************************************************************************
  430.  *
  431.  *    matchtype()
  432.  *
  433.  */
  434.  
  435. void
  436. matchtype (char *myname, char *buf, char *file, FILEINFOBLOCK * fib)
  437. {
  438.   int j;
  439.   int len = (fib->fib_Size < BLOCKSIZE) ? fib->fib_Size : BLOCKSIZE;
  440.  
  441.   /*
  442.    * check magic strings (charas which start a line)
  443.    */
  444.  
  445.   j = 0;
  446.   while (amagic[j].length)
  447.     {
  448.       if (!memncmp (amagic[j].pattern, buf, amagic[j].length))
  449.     {
  450.       type (amagic[j].name, file);
  451.       return;
  452.     }
  453.       ++j;
  454.     }
  455.  
  456.   /*
  457.    *    see if a text file, or not
  458.    */
  459.   if (istextfile (buf, len) == TRUE)
  460.     {
  461.       /*
  462.        * check for tell-tale strings; this is rough and ready!
  463.        */
  464.  
  465.       j = 0;
  466.  
  467.       while (asearch[j].length)
  468.     {
  469.       if (search (asearch[j].pattern, buf, len) == TRUE)
  470.         {
  471.           type (asearch[j].name, file);
  472.           return;
  473.         }
  474.       ++j;
  475.     }
  476.  
  477.       j = 0;
  478.  
  479.       /* check script bit */
  480.       if (fib->fib_Protection & (1 << 6))
  481.     {
  482.       type ("AmigaDos script file", file);
  483.       return;
  484.     }
  485.  
  486.       type ("text", file);
  487.     }
  488.   else
  489.     /* deemed not an ASCII text file */
  490.     {
  491.       j = 0;
  492.  
  493.       /* check magic numbers */
  494.       while (bmagic[j].length)
  495.     {
  496.       if (!memncmp (bmagic[j].pattern, buf + bmagic[j].offset, bmagic[j].length))
  497.         {
  498.           type (bmagic[j].name, file);
  499.           return;
  500.         }
  501.       ++j;
  502.     }
  503.  
  504.       /* check for IFF forms -- assume FORM is first header block */
  505.       if (!memncmp ("FORM", buf, 4))
  506.     {
  507.       char buffer[40];
  508.  
  509.       j = 0;
  510.       buffer[0] = '\0';
  511.  
  512.       while (IFFforms[j].length)
  513.         {
  514.           if (!memncmp (IFFforms[j].pattern, &buf[8], IFFforms[j].length))
  515.         {
  516.           type (IFFforms[j].name, file);
  517.           return;
  518.         }
  519.           ++j;
  520.         }
  521.       sprintf (buffer, "IFF form %c%c%c%c", buf[8], buf[9], buf[10], buf[11]);
  522.       type (buffer, file);
  523.       return;
  524.     }
  525.  
  526.       if (!memncmp (compress.pattern, buf, compress.length))
  527.     {
  528.       char buffer[40];
  529.  
  530.       sprintf (buffer, compress.name, buf[2] & 0x0f);
  531.       type (buffer, file);
  532.       return;
  533.     }
  534.  
  535.       if (!memncmp (zoo.pattern, buf, zoo.length))
  536.     {
  537.  
  538.       /* make a string out of ZOO x.xx Archive\0 to print out */
  539.       buf[16] = '\0';
  540.  
  541.       type (buf, file);
  542.       return;
  543.     }
  544.  
  545.       type ("binary file  ?", file);
  546.     }
  547. }
  548.  
  549. /**************************************************************************
  550.  *
  551.  *    search ()
  552.  *
  553.  */
  554.  
  555. BOOLEAN
  556. search (char *pat, char *text, int len)
  557. {
  558.   int j = 0;
  559.   int patlen = strlen (pat);
  560.  
  561.   while (memncmp (pat, &text[j], patlen) && (j < len))
  562.     {
  563.       j++;
  564.     }
  565.  
  566.   return (j < len ? TRUE : FALSE);
  567. }
  568.  
  569. /**************************************************************************
  570.  *
  571.  *    usage
  572.  *
  573.  */
  574.  
  575. void
  576. usage (char *name)
  577. {
  578.   fprintf (stderr, "%s  : Compiled under SAS/C 6.0 on %s\n",
  579.        VERSION, __DATE__);
  580.   fprintf (stderr, "usage: %s  file [file...]\n", name);
  581. }
  582.