home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 1 / FFMCD01.bin / bbs / libdisks / d700t799 / disk774.lha / ExtraCmds / src / Concat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-05  |  14.4 KB  |  450 lines

  1. /*
  2.  * Concat - concatenate and print files.
  3.  *          AmigaDOS equivalent of UNIX System V cat.
  4.  *
  5.  * Version 37.1 =TP= 28-Jan-92
  6.  *
  7.  * Compile with SAS/C 5.10a and link without startup code:
  8.  *      lc -cqfist -v -b0 -rr -O -ms Concat
  9.  *      blink Concat.o to Concat sd sc
  10.  *      protect Concat +p
  11.  *
  12.  * Copyright (c) 1992 Torsten Poulin
  13.  *
  14.  * Torsten Poulin
  15.  * Banebrinken 99, 2, lejlighed 77
  16.  * DK 2400  København NV
  17.  * DENMARK
  18.  */
  19.  
  20. /****** English:CONCAT ****************************************************
  21. *
  22. *   FORMAT
  23. *       CONCAT [[FROM] <files|patterns>] [TO <name>]
  24. *              [SORT] [QUIET] [VISIBLE [TABS] [EOL]] [UNBUF]
  25. *
  26. *   TEMPLATE
  27. *       FROM/M,TO/K,SORT/S,QUIET/S,VISIBLE/S,TABS/S,EOL/S,UNBUF/S
  28. *
  29. *   PURPOSE
  30. *       To concatenate and print files.
  31. *
  32. *   SPECIFICATION
  33. *       Concat reads each of the specified FROM files and writes it
  34. *       to the destination specified by the TO option.  If no FROM
  35. *       option is given Concat reads from its default input; likewise
  36. *       if no TO option is specified it writes to its default output.
  37. *
  38. *       The following switches apply to Concat.
  39. *
  40. *       SORT    The FROM files are read in alphabetical order.
  41. *               Useful when concatenating files split with Split.
  42. *
  43. *       QUIET   Concat is quiet about non-existent input files.
  44. *
  45. *       VISIBLE Causes non-printing characters (with the exception
  46. *               of tabs and new-lines) to be printed visibly.
  47. *               Control characters are printed as ^X (control-x);
  48. *               the DEL character (hex 0x7d) is printed as ^?.
  49. *               Non-ASCII characters (with the high bit set) are
  50. *               printed as M-x, where x is the character specified
  51. *               by the seven low order bits.
  52. *
  53. *       UNBUF   The output is not buffered. (The default is
  54. *               buffered output.)
  55. *
  56. *       When used with the VISIBLE switch, the following switches
  57. *       may be used.
  58. *
  59. *       TABS    Causes tabs to be printed as ^I's.
  60. *
  61. *       EOL     Causes a $ character to be printed at the end of
  62. *               each line (prior to the new-line).
  63. *
  64. *       The TABS and EOL switches are ignored if the VISIBLE
  65. *       switch is not specified.
  66. *
  67. *   SEE ALSO
  68. *       COPY, JOIN, MORE, SPLIT, TYPE
  69. *
  70. ***************************************************************************
  71. *
  72. */
  73. /****** dansk:CONCAT ******************************************************
  74. *
  75. *   FORMAT
  76. *       CONCAT [[FROM] <filer|mønstre>] [TO <navn>]
  77. *              [SORT] [QUIET] [VISIBLE [TABS] [EOL]] [UNBUF]
  78. *
  79. *   SKABELON
  80. *       FROM/M,TO/K,SORT/S,QUIET/S,VISIBLE/S,TABS/S,EOL/S,UNBUF/S
  81. *
  82. *   FORMÅL
  83. *       At sammenkæde og udskrive filer.
  84. *
  85. *   SPECIFIKATION
  86. *       Concat læser hver af de med FROM angivne filer og skriver
  87. *       dem til destinationen angivet af TO.  Hvis der ikke er
  88. *       angivet nogen FROM-filer, læser Concat fra sit standard-
  89. *       input.  Ligeledes skriver den til sit standardoutput hvis
  90. *       der ikke er angivet en destination med TO.
  91. *
  92. *       Følgende kontakter kan bruges med Concat:
  93. *
  94. *       SORT    FROM-filerne læses i alfabetisk orden.  Nyttigt
  95. *               ved sammenkædning af filer splittet med SPLIT.
  96. *
  97. *       QUIET   Concat tier stille om ikke-eksisterende filer.
  98. *
  99. *       VISIBLE Usynlige tegn (med undtagelse af tabulerings- og
  100. *               ny-linjetegn) bliver udskrevet synligt.
  101. *               Styretegn udskrives som ^X (kontrol-x). 
  102. *               Slettetegnet (heksadecimalt 0x7d) udskrives som
  103. *               ^?. Ikke-ASCII-tegn (med mest betydende bit sat)
  104. *               udskrives som M-x, hvor x er tegnet givet ved de
  105. *               syv mindst betydende bit.
  106. *
  107. *       UNBUF   Uddata bliver ikke bufferet. (Standard er bufferet
  108. *               uddata.)
  109. *
  110. *       Når kontakten VISIBLE er angivet kan følgende kontakter
  111. *       bruges:
  112. *
  113. *       TABS    Tabuleringstegn udskrives som ^I'er.
  114. *
  115. *       EOL     Et $-tegn udskrives i slutningen af hver linje (før
  116. *               ny-linjetegnet).
  117. *
  118. *       Kontakterne TABS og EOL bliver ignoreret hvis kontakten
  119. *       VISIBLE ikke er angivet.
  120. *
  121. *   SE OGSÅ
  122. *       COPY, JOIN, MORE, SPLIT, TYPE
  123. *
  124. ***************************************************************************
  125. *
  126. */
  127.  
  128.  
  129. #include <exec/types.h>
  130. #include <exec/memory.h>
  131. #include <dos/dos.h>
  132. #include <dos/dosasl.h>
  133. #include <clib/dos_protos.h>
  134. #include <clib/exec_protos.h>
  135. #include <clib/intuition_protos.h>
  136. #include <stdio.h>
  137. #include <string.h>
  138.  
  139. #ifdef __SASC
  140. #include <pragmas/dos_pragmas.h>
  141. #include <pragmas/exec_pragmas.h>
  142. #include <pragmas/intuition_pragmas.h>
  143. #pragma libcall UtilityBase Stricmp A2 9802
  144. #endif
  145.  
  146. /* my include files are for early V36, so ... */
  147. LONG Stricmp(char *, char *);
  148.  
  149. /* !!! Assumption: DOS used to be in BCPL, so max length is 256(?) */
  150. #define MAXNAMELEN 256L
  151.  
  152. #define TEMPLATE "FROM/M,TO/K,SORT/S,QUIET/S,VISIBLE/S,TABS/S,EOL/S,UNBUF/S"
  153. #define OPT_FROM    0
  154. #define OPT_TO      1
  155. #define OPT_SORT    2
  156. #define OPT_QUIET   3
  157. #define OPT_VISIBLE 4
  158. #define OPT_TABS    5
  159. #define OPT_EOL     6
  160. #define OPT_UNBUF   7
  161.  
  162.  
  163. static VOID myFPutC(struct DosLibrary *, BPTR, LONG, BOOL);
  164. static LONG doConcat(struct Library *, struct DosLibrary *,
  165.                      BPTR, BPTR, BOOL, BOOL, BOOL, BOOL);
  166.  
  167. typedef struct nameList {
  168.   struct nameList *next;
  169.   UBYTE *name;
  170. } nameList;
  171.  
  172. char const *blurp = "\0$VER: Concat 37.1 (28.1.92) ©1992 Torsten Poulin";
  173.  
  174.  
  175. LONG entrypoint(VOID)
  176. {
  177.     struct Library       *SysBase;
  178.     struct DosBase       *DOSBase;
  179.     struct IntuitionBase *IntuitionBase;
  180.     struct Library       *UtilityBase;
  181.     struct RDArgs        *args;
  182.     struct AnchorPath    *ap;
  183.     struct Remember      *rememberkey;
  184.     nameList             *list, *p;
  185.     LONG                 arg[8];
  186.     LONG                 rc = RETURN_OK;
  187.     UBYTE                **fromfiles;
  188.     ULONG                i;
  189.     BPTR                 in, out;
  190.         
  191.     SysBase = *(struct Library **) 4L;
  192.     if(!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
  193.         goto noDOS;
  194.     if(!(IntuitionBase = (struct IntuitionBase *)
  195.                         OpenLibrary("intuition.library", 33L)))
  196.         goto noIntuition;
  197.     if(!(UtilityBase = OpenLibrary("utility.library", 37L)))
  198.         goto noUtility;
  199.     
  200.     arg[OPT_FROM]    = arg[OPT_TO]   = arg[OPT_SORT] = arg[OPT_QUIET] =
  201.     arg[OPT_VISIBLE] = arg[OPT_TABS] = arg[OPT_EOL]  = arg[OPT_UNBUF] = 0L;
  202.  
  203.     if(args = ReadArgs(TEMPLATE, arg, NULL))
  204.     {
  205.         out = NULL;
  206.         if(arg[OPT_TO] && !(out = Open((UBYTE *) arg[OPT_TO], MODE_NEWFILE)))
  207.         {
  208.             LONG err = IoErr();
  209.             PutStr("Concat can't open ");
  210.             PrintFault(err, (UBYTE *) arg[OPT_TO]);
  211.             rc = RETURN_ERROR;
  212.             goto exitProgram;
  213.         }
  214.  
  215.         if(arg[OPT_FROM])
  216.         {
  217.             rememberkey = NULL;
  218.             list = NULL;
  219.  
  220.             fromfiles = (UBYTE **) arg[OPT_FROM];
  221.             for(i = 0; fromfiles[i]; i++)
  222.             {
  223.                 UBYTE *dummy;
  224.                 LONG  IsWild;
  225.             
  226.                 if(!(ap = (struct AnchorPath *)
  227.                         AllocRemember(&rememberkey,
  228.                                       sizeof(struct AnchorPath) + MAXNAMELEN,
  229.                                       MEMF_PUBLIC | MEMF_CLEAR)))
  230.                 {
  231.                     PrintFault(ERROR_NO_FREE_STORE, "Concat");
  232.                     rc = RETURN_FAIL;
  233.                     goto exitProgram;
  234.                 }
  235.  
  236.                 ap->ap_Strlen = MAXNAMELEN;
  237.  
  238.                 /* Kludge to determine if it's pattern */
  239.                 if(!(dummy = AllocMem(2 * strlen(fromfiles[i]) + 2,
  240.                                       MEMF_PUBLIC)))
  241.                 {
  242.                     PrintFault(ERROR_NO_FREE_STORE, "Concat");
  243.                     rc = RETURN_FAIL;
  244.                     goto exitProgram;
  245.                 }
  246.                 IsWild = ParsePattern(fromfiles[i], dummy,
  247.                                       2 * strlen(fromfiles[i]) + 2);
  248.                 FreeMem(dummy, 2 * strlen(fromfiles[i]) + 2);
  249.                 if(IsWild == -1)
  250.                 {
  251.                     LONG err = IoErr();;
  252.                     PrintFault(err, "Concat");
  253.                     rc = RETURN_FAIL;
  254.                     goto exitProgram;
  255.                 }
  256.                 
  257.                 if(!IsWild || MatchFirst(fromfiles[i], ap) == 0)
  258.                     do
  259.                     {
  260.                         nameList *newnode, *p;
  261.                         UBYTE    *insertname;
  262.                     
  263. /*
  264.                         if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  265.                         {
  266.                             PrintFault(ERROR_BREAK, NULL);
  267.                             rc = RETURN_WARN;
  268.                             if(IsWild)
  269.                                 MatchEnd(ap);
  270.                             goto exitProgram;
  271.                         }
  272. */
  273.  
  274.                         if(IsWild)
  275.                         {
  276.                             insertname = ap->ap_Buf;
  277.                             if(ap->ap_Info.fib_DirEntryType > 0)
  278.                                 continue;
  279.                         }
  280.                         else
  281.                             insertname = fromfiles[i];
  282.  
  283.                         /* File names are stored in an ordered linked list
  284.                          * unless arg[OPT_SORT] is FALSE in which case
  285.                          * they are inserted at the end of the list.
  286.                          */
  287.                 
  288.                         if(!(newnode = (nameList *)
  289.                                 AllocRemember(&rememberkey, sizeof(nameList),
  290.                                               MEMF_PUBLIC)))
  291.                         {
  292.                             PrintFault(ERROR_NO_FREE_STORE, "Concat");
  293.                             rc = RETURN_FAIL;
  294.                             goto noMemory1;
  295.                         }
  296.                         if(!(newnode->name = (UBYTE *)
  297.                                 AllocRemember(&rememberkey,
  298.                                     strlen(insertname) + sizeof(UBYTE),
  299.                                     MEMF_PUBLIC)))
  300.                         {
  301.                             PrintFault(ERROR_NO_FREE_STORE, "Concat");
  302.                             rc = RETURN_FAIL;
  303.                             goto noMemory1;
  304.                         }
  305.                         strcpy(newnode->name, insertname);
  306.                         newnode->next = NULL;
  307.  
  308.                         if(list == NULL)    /* insert into empty list */
  309.                             list = newnode;
  310.                         else
  311.                         {
  312.                             /* inserting into nonempty list */
  313.                             p = list;
  314.  
  315.                             if(Stricmp(insertname, p->name) < 0
  316.                                && arg[OPT_SORT])
  317.                             {
  318.                                 /* insert before first node */
  319.                             newnode->next = list;
  320.                             list = newnode;
  321.                             }
  322.                             else
  323.                             {
  324.                                 /* general case */
  325.                             for(; p->next; p = p->next)
  326.                                 if(Stricmp(insertname, p->next->name) < 0
  327.                                    && arg[OPT_SORT])
  328.                                     break;
  329.                             newnode->next = p->next;
  330.                             p->next = newnode;
  331.                             }
  332.                         }
  333.                     } while(IsWild == 1 && MatchNext(ap) == 0);
  334.  noMemory1:
  335.                 if(IsWild)
  336.                     MatchEnd(ap);
  337.             }
  338.  
  339.             /* Output by running through list of file names */
  340.             for(p = list; p; p = p->next)
  341.             {
  342.                 if(in = Open(p->name, MODE_OLDFILE))
  343.                 {
  344.                     rc = doConcat(SysBase, DOSBase,
  345.                                   in, arg[OPT_TO] ? out : Output(),
  346.                                   arg[OPT_VISIBLE], arg[OPT_TABS],
  347.                                   arg[OPT_EOL], arg[OPT_UNBUF]);
  348.                     Close(in);
  349.                     if(rc != 0)
  350.                         break;
  351.                 }
  352.                 else
  353.                 {
  354.                     LONG err = IoErr();
  355.                     if(!arg[OPT_QUIET])
  356.                     {
  357.                         PutStr("Concat can't open ");
  358.                         PrintFault(err, p->name);
  359.                     }
  360.                 }
  361.             }
  362.             FreeRemember(&rememberkey, TRUE);
  363.         }
  364.         else
  365.         {
  366.             /* Reading from default input */
  367.             rc = doConcat(SysBase, DOSBase,
  368.                           Input(), arg[OPT_TO] ? out : Output(),
  369.                           arg[OPT_VISIBLE], arg[OPT_TABS],
  370.                           arg[OPT_EOL], arg[OPT_UNBUF]);
  371.         }
  372.  exitProgram:
  373.         if(out)
  374.             Close(out);
  375.         FreeArgs(args);
  376.     }
  377.     else
  378.     {
  379.         LONG err = IoErr();
  380.         PrintFault(err, "Concat");
  381.         rc = RETURN_ERROR;
  382.     }
  383.                 
  384.     CloseLibrary(UtilityBase);
  385.  noUtility:
  386.     CloseLibrary((struct Library *) IntuitionBase);
  387.  noIntuition:
  388.     CloseLibrary((struct DosBase *) DOSBase);
  389.  noDOS:
  390.     return rc;
  391.  
  392.     /*
  393.      * Yes, I KNOW this function is  t o o  l o n g
  394.      * and contains far too many goto's  ;-)
  395.      */
  396. }
  397.  
  398.  
  399.  
  400. static LONG doConcat(struct Library *SysBase, struct DosLibrary *DOSBase,
  401.                      BPTR in, BPTR out,
  402.                      BOOL visible, BOOL tabs, BOOL eol, BOOL unbuf)
  403. {
  404.     register UBYTE breakcheck = 0;
  405.     LONG c;
  406.     
  407.     while((c = FGetC(in)) != -1)
  408.     {
  409.         if(visible)
  410.         {
  411.             if(eol && c == '\n')
  412.                 myFPutC(DOSBase, out, '$', unbuf);
  413.             else if(tabs && c == '\t')
  414.             {
  415.                 myFPutC(DOSBase, out, '^', unbuf);
  416.                 c = 'I';
  417.             }
  418.             else if(c >= 0x80)
  419.             {
  420.                 myFPutC(DOSBase, out, 'M', unbuf);
  421.                 myFPutC(DOSBase, out, '-', unbuf);
  422.                 c &= 0x7f;
  423.             }
  424.             if((c < ' ' && c != '\t' && c != '\n') || c == 0x7F)
  425.             {
  426.                 myFPutC(DOSBase, out, '^', unbuf);
  427.                 if(c == 0x7F)
  428.                     c = '?';
  429.                 else
  430.                     c += 'A' - 1;
  431.             }
  432.         }
  433.         myFPutC(DOSBase, out, c, unbuf);
  434.         if(!(breakcheck -= 8) && SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  435.         {
  436.             PrintFault(ERROR_BREAK, NULL);
  437.             return RETURN_WARN;
  438.         }
  439.     }
  440.     return 0L;
  441. }
  442.  
  443.  
  444. static VOID myFPutC(struct DosLibrary *DOSBase, BPTR out, LONG c, BOOL nobuf)
  445. {
  446.     if(nobuf)
  447.         Flush(out);
  448.     FPutC(out, c);
  449. }
  450.