home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / HPACK78S.ZIP / script.c < prev    next >
C/C++ Source or Header  |  1992-12-03  |  15KB  |  472 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                            HPACK Multi-System Archiver                        *
  4. *                            ===========================                        *
  5. *                                                                            *
  6. *                             Script File Handling Code                        *
  7. *                            SCRIPT.C  Updated 20/07/92                        *
  8. *                                                                            *
  9. * This program is protected by copyright and as such any use or copying of    *
  10. *  this code for your own purposes directly or indirectly is highly uncool    *
  11. *                      and if you do so there will be....trubble.                *
  12. *                 And remember: We know where your kids go to school.            *
  13. *                                                                            *
  14. *        Copyright 1991 - 1992  Peter C.Gutmann.  All rights reserved        *
  15. *                                                                            *
  16. ****************************************************************************/
  17.  
  18. #include <ctype.h>
  19. #include <string.h>
  20. #include <stdio.h>
  21. #ifdef __MAC__
  22.   #include "defs.h"
  23.   #include "choice.h"
  24.   #include "error.h"
  25.   #include "filesys.h"
  26.   #include "flags.h"
  27.   #include "frontend.h"
  28.   #include "hpacklib.h"
  29.   #include "hpaktext.h"
  30.   #include "system.h"
  31.   #include "wildcard.h"
  32.   #include "fastio.h"
  33.   #include "hpackio.h"
  34. #else
  35.   #include "defs.h"
  36.   #include "choice.h"
  37.   #include "error.h"
  38.   #include "filesys.h"
  39.   #include "flags.h"
  40.   #include "frontend.h"
  41.   #include "hpacklib.h"
  42.   #include "system.h"
  43.   #include "wildcard.h"
  44.   #include "io/fastio.h"
  45.   #include "io/hpackio.h"
  46.   #include "language/hpaktext.h"
  47. #endif /* __MAC__ */
  48.  
  49. /****************************************************************************
  50. *                                                                            *
  51. *                        Build/Free List of Files to Handle                    *
  52. *                                                                            *
  53. ****************************************************************************/
  54.  
  55. /* The start of the list of fileSpecs */
  56.  
  57. FILEPATHINFO *filePathListStart = NULL;
  58.  
  59. /* Add a filespec to the list of files to handle */
  60.  
  61. void addFilespec( char *fileSpec )
  62.     {
  63.     FILEPATHINFO *theNode, *prevNode, *newNode;
  64.     FILENAMEINFO *fileNamePtr, *prevFileNamePtr;
  65.     char fileCode[ MATCH_DEST_LEN ], pathCode[ MATCH_DEST_LEN ];
  66.     char pathName[ MAX_PATH ];
  67.     int pathNameEnd, nonMatch, fileCodeLen, pathCodeLen;
  68.     BOOLEAN fileHasWildcards, pathHasWildcards;
  69. #if defined( __AMIGA__ ) || defined( __ARC__ ) || defined( __ATARI__ ) || \
  70.     defined( __MAC__ ) || defined( __MSDOS__ ) || defined( __OS2__ ) || \
  71.     defined( __VMS__ )
  72.     int count;
  73. #endif /* __AMIGA__ || __ARC__ || __ATARI__ || __MAC__ || __MSDOS__ || __OS2__ || __VMS__ */
  74. #if defined( __ARC__ ) || defined( __VMS__ )
  75.     int nodeNameEnd = 0;
  76. #endif /* __ARC__ || __VMS__ */
  77.  
  78.     /* Check the path is of a legal length */
  79.     if( strlen( fileSpec ) > MAX_PATH - 1 )
  80.         error( PATH_s_TOO_LONG, fileSpec );
  81.  
  82.     /* Extract the pathname and convert it into an OS-compatible format */
  83.     pathNameEnd = extractPath( fileSpec, pathName );
  84.  
  85.     /* Compile the file spec.and path spec.into a form acceptable by the
  86.        wildcard-matching finite-state machine */
  87.     fileCodeLen = compileString( fileSpec + pathNameEnd, fileCode );
  88.     pathCodeLen = compileString( pathName, pathCode );
  89.     fileHasWildcards = strHasWildcards( fileSpec + pathNameEnd );
  90.     pathHasWildcards = strHasWildcards( pathName );
  91.  
  92.     /* Complain if it's an external path with wildcards.  This is the case
  93.        for Add and the add portion of an Update */
  94.     if( pathHasWildcards && ( choice == ADD || choice == UPDATE ) )
  95.         error( CANNOT_USE_WILDCARDS_s, pathName );
  96.  
  97.     /* Now sort the file names by path as they are added, in order to make disk
  98.        accesses more efficient.  This can be done by a simple insertion sort
  99.        since there are only a small number of names to sort, and it can be done
  100.        on the fly.  Note that there is one case in which the files won't be
  101.        sorted:  If there drive specs, normal files/paths, and files/paths
  102.        beginning with letters lower than ':' then they will be put before the
  103.        drive specs, with the rest of the normal files/paths being placed
  104.        after the drive specs.  However the occurrence of filenames containing
  105.        these characters is virtually unheard-of so no special actions are
  106.        taken for them */
  107.     theNode = filePathListStart;
  108.     if( filePathListStart == NULL )
  109.         {
  110.         /* Create the initial list node */
  111.         if( ( filePathListStart = newNode = ( FILEPATHINFO * ) hmalloc( sizeof( FILEPATHINFO ) ) ) == NULL )
  112.             error( OUT_OF_MEMORY );
  113.         }
  114.     else
  115.         {
  116.         /* Find the correct position to insert the new pathname */
  117.         prevNode = filePathListStart;
  118.         while( theNode != NULL && ( nonMatch = strcmp( pathName, theNode->filePath ) ) > 0 )
  119.             {
  120.             prevNode = theNode;
  121.             theNode = theNode->next;
  122.             }
  123.  
  124.         /* Don't insert the pathname if it's already in the list */
  125.         if( !nonMatch )
  126.             {
  127.             /* Find the end of the list of fileNames and add a new node */
  128.             for( prevFileNamePtr = fileNamePtr = theNode->fileNames; \
  129.                  fileNamePtr != NULL; prevFileNamePtr = fileNamePtr, \
  130.                  fileNamePtr = fileNamePtr->next )
  131.                 /* Leave now if the fileName is already in the list */
  132.                 if( !strncmp( fileNamePtr->fileName, fileCode, fileCodeLen ) )
  133.                     return;
  134.             fileNamePtr = prevFileNamePtr;
  135.  
  136.             if( ( fileNamePtr->next = ( FILENAMEINFO * ) hmalloc( sizeof( FILENAMEINFO ) ) ) == NULL )
  137.                 error( OUT_OF_MEMORY );
  138.             fileNamePtr = fileNamePtr->next;
  139.             goto nodeExists;
  140.             }
  141.  
  142.         /* Create the new node and link it into the list */
  143.         if( ( newNode = ( FILEPATHINFO * ) hmalloc( sizeof( FILEPATHINFO ) ) ) == NULL )
  144.             error( OUT_OF_MEMORY );
  145.         if( prevNode == filePathListStart )
  146.             {
  147.             /* Insert at start of list */
  148.             filePathListStart = newNode;
  149.             theNode = prevNode;
  150.             }
  151.         else
  152.             /* Insert in middle/end of list */
  153.             prevNode->next = newNode;
  154.         }
  155.  
  156.     newNode->next = theNode;
  157.  
  158.     /* Seperate out the node/path component and make sure we're not trying
  159.        to override an existing base path */
  160. #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
  161.     /* Look for a drive spec in the filename */
  162.     newNode->device = NULL;
  163.     if( ( ( count = ( *pathName && pathName[ 1 ] == ':' ) ? \
  164.                 toupper( *pathName ) : 0 ) && *basePath ) || \
  165.         ( *basePath && basePath[ 1 ] == ':' && basePath[ 2 ] && \
  166.                 *pathName == SLASH ) )
  167.         error( CANNOT_OVERRIDE_BASEPATH, basePath );
  168.  
  169.     /* If there is a drive spec, save it */
  170.     if( count )
  171.         {
  172.         if( ( newNode->device = ( char * ) hmalloc( 3 ) ) == NULL )
  173.             error( OUT_OF_MEMORY );
  174.         newNode->device[ 0 ] = count;
  175.         newNode->device[ 1 ] = ':';
  176.         newNode->device[ 2 ] = '\0';
  177.         }
  178. #elif defined( __AMIGA__ ) || defined( __MAC__ )
  179.     /* Look for a drive spec in the pathname */
  180.     newNode->device = NULL;
  181.     for( count = 0; count < pathNameEnd; count++ )
  182.         if( pathName[ count ] == ':' )
  183.             {
  184.             /* Save the drive spec */
  185.             if( ( newNode->device = ( char * ) hmalloc( count + 2 ) ) == NULL )
  186.                 error( OUT_OF_MEMORY );
  187.             strncpy( newNode->device, pathName, count + 1 );
  188.             newNode->device[ count + 1 ] = '\0';
  189.             break;    /* Exit while loop */
  190.             }
  191.  
  192.     if( *basePath && *pathName == SLASH )
  193.         error( CANNOT_OVERRIDE_BASEPATH, basePath );
  194. #elif defined( __ARC__ )
  195.     /* Look for a node name in the pathname */
  196.     newNode->node = NULL;
  197.     for( count = 1; count < pathNameEnd; count++ )
  198.         if( pathName[ count - 1 ] == ':' && pathName[ count ] == ':' )
  199.             {
  200.             /* Save the node name */
  201.             if( ( newNode->node = ( char * ) hmalloc( count + 2 ) ) == NULL )
  202.                 error( OUT_OF_MEMORY );
  203.             strncpy( newNode->node, pathName, ++count );
  204.             newNode->node[ count ] = '\0';
  205.             nodeNameEnd = count;
  206.             break;    /* Exit while loop */
  207.             }
  208.  
  209.     /* Archimedes drives are handled funny */
  210.     newNode->device = NULL;
  211. #elif defined( __UNIX__ )
  212.     if( *basePath && *pathName == SLASH )
  213.         error( CANNOT_OVERRIDE_BASEPATH, basePath );
  214. #elif defined( __VMS__ )
  215.     /* Look for a node name in the pathname */
  216.     newNode->node = NULL;
  217.     for( count = 1; count < pathNameEnd; count++ )
  218.         if( pathName[ count - 1 ] == ':' && pathName[ count ] == ':' )
  219.             {
  220.             /* Save the node name */
  221.             if( ( newNode->node = ( char * ) hmalloc( count + 2 ) ) == NULL )
  222.                 error( OUT_OF_MEMORY );
  223.             strncpy( newNode->node, pathName, ++count );
  224.             newNode->node[ count ] = '\0';
  225.             nodeNameEnd = count;
  226.             break;    /* Exit while loop */
  227.             }
  228.  
  229.     /* Look for a device name in the pathname */
  230.     newNode->device = NULL;
  231.     for( count = nodeNameEnd; count < pathNameEnd; count++ )
  232.         if( pathName[ count ] == ':' )
  233.             {
  234.             /* Save the device name */
  235.             count -= nodeNameEnd;
  236.             if( ( newNode->device = ( char * ) hmalloc( count + 2 ) ) == NULL )
  237.                 error( OUT_OF_MEMORY );
  238.             strncpy( newNode->device, pathName + nodeNameEnd, ++count );
  239.             newNode->device[ count ] = '\0';
  240.             break;    /* Exit while loop */
  241.             }
  242.  
  243.     if( *basePath && *pathName == SLASH )
  244.         error( CANNOT_OVERRIDE_BASEPATH, basePath );
  245. #endif /* Various OS-specific device handling */
  246.  
  247.     if( ( newNode->filePath = ( char * ) hmalloc( pathCodeLen ) ) == NULL )
  248.         error( OUT_OF_MEMORY );
  249.     memcpy( newNode->filePath, pathCode, pathCodeLen );
  250.     newNode->hasWildcards = pathHasWildcards;
  251.  
  252.     if( ( newNode->fileNames = ( FILENAMEINFO * ) hmalloc( sizeof( FILENAMEINFO ) ) ) == NULL )
  253.         error( OUT_OF_MEMORY );
  254.     fileNamePtr = newNode->fileNames;
  255.  
  256. nodeExists:
  257.     fileNamePtr->next = NULL;
  258.  
  259.     /* Add the compiled filespec to the list of filespecs */
  260.     if( ( fileNamePtr->fileName = ( char * ) hmalloc( fileCodeLen ) ) == NULL )
  261.         error( OUT_OF_MEMORY );
  262.     memcpy( fileNamePtr->fileName, fileCode, fileCodeLen );
  263.     fileNamePtr->hasWildcards = fileHasWildcards;
  264.     }
  265.  
  266. #if !defined( __MSDOS__ ) || defined( GUI )
  267.  
  268. /* Free up the memory used by the list of filespecs.  See the comment in
  269.    freeArchiveNames() for why we use this complex double-stepping way of
  270.    freeing the headers */
  271.  
  272. void freeFilespecs( void )
  273.     {
  274.     FILEPATHINFO *pathHeaderCursor = filePathListStart, *pathHeaderPtr;
  275.     FILENAMEINFO *nameHeaderCursor, *nameHeaderPtr;
  276.  
  277.     /* Free the nodes of the filePath list */
  278.     while( pathHeaderCursor != NULL )
  279.         {
  280.         /* Free the nodes of the fileName list */
  281.         nameHeaderCursor = pathHeaderCursor->fileNames;
  282.         while( nameHeaderCursor != NULL )
  283.             {
  284.             nameHeaderPtr = nameHeaderCursor;
  285.             nameHeaderCursor = nameHeaderCursor->next;
  286.             hfree( nameHeaderPtr->fileName );
  287.             hfree( ( void * ) nameHeaderPtr );    /* ThinkC needs this */
  288.             }
  289.  
  290.         pathHeaderPtr = pathHeaderCursor;
  291.         pathHeaderCursor = pathHeaderCursor->next;
  292.         hfree( pathHeaderPtr->filePath );
  293.         hfree( ( void * ) pathHeaderPtr );        /* ThinkC again */
  294.         }
  295.     }
  296. #endif /* !__MSDOS__ || GUI */
  297.  
  298. /****************************************************************************
  299. *                                                                            *
  300. *                                Process a List-File                            *
  301. *                                                                            *
  302. ****************************************************************************/
  303.  
  304. /* The types of error we check for */
  305.  
  306. enum { NO_ERROR, ILLEGAL_CHAR_ERROR, PATH_ERROR };
  307.  
  308. #define CPM_EOF    0x1A        /* ^Z = CPM EOF char */
  309.  
  310. #define MAX_ERRORS    10        /* Max.no.errors before we give up */
  311.  
  312. void processListFile( const char *listFileName )
  313.     {
  314.     FD listFileFD;
  315.     int ch = 0, theCh;
  316.     int errType, errPos, errCount = 0, line = 1;
  317.     BOOLEAN firstError = TRUE, seenCR = FALSE;
  318. #ifdef GUI
  319.     char string[ 10 ];
  320. #endif /* GUI */
  321.  
  322.     if( ( listFileFD = hopen( listFileName, O_RDONLY | S_DENYWR | A_SEQ ) ) == IO_ERROR )
  323.         {
  324. #ifdef GUI
  325.         alert( ALERT_CANNOT_OPEN_SCRIPTFILE, listFileName );
  326. #else
  327.         hprintf( WARN_CANNOT_OPEN_SCRIPTFILE_s, listFileName );
  328. #endif /* GUI */
  329.         return;
  330.         }
  331. #ifndef GUI
  332.     hprintfs( MESG_PROCESSING_SCRIPTFILE_s, listFileName );
  333. #endif /* !GUI */
  334.     setInputFD( listFileFD );
  335.     resetFastIn();
  336.  
  337.     /* Process each line in the listFile */
  338.     while( ch != FEOF )
  339.         {
  340.         /* If we've just seen a CR and now we see a LF, skip to next line */
  341.         if( ( ch = fgetByte() ) == '\n' && seenCR )
  342.             ch = fgetByte();
  343.         seenCR = FALSE;
  344.  
  345.         /* Skip whitespace */
  346.         while( ( ch == ' ' || ch == '\t' ) && ch != FEOF )
  347.             ch = fgetByte();
  348.  
  349.         /* Get a line into the mrglBuffer */
  350.         mrglBufCount = 0;
  351.         errType = NO_ERROR;
  352.         while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != FEOF )
  353.             {
  354.             /* Check for an illegal char in the data */
  355.             if( ( ch < ' ' || ch > '~' ) && ch != '\r' && ch != '\n' && \
  356.                 ch != CPM_EOF && ch != FEOF )
  357.                 {
  358.                 if( errType == NO_ERROR )
  359.                     /* Save position of first illegal char */
  360.                     errPos = mrglBufCount;
  361.                 errType = ILLEGAL_CHAR_ERROR;
  362.                 }
  363. #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
  364.             if( ch == '\\' )
  365.                 ch = SLASH;        /* Get dir.seperator in correct format */
  366. #endif /* __ATARI__ || __MSDOS__ || __OS2__ */
  367.  
  368.             /* Make sure the path is of the correct length.  Note that the
  369.                code is ordered so that a PATH_ERROR takes precedence over
  370.                an ILLEGAL_CHAR_ERROR */
  371.             if( mrglBufCount > MAX_PATH )
  372.                 errType = PATH_ERROR;
  373.             else
  374.                 mrglBuffer[ mrglBufCount++ ] = ch;
  375.  
  376.             if( ( ch = fgetByte() ) == '#' )
  377.                 {
  378.                 /* Skip comment section and trailing whitespace */
  379.                 while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != FEOF )
  380.                     ch = fgetByte();
  381.                 break;
  382.                 }
  383.             }
  384.  
  385.         /* Remember we've just passed a CR if necessary */
  386.         if( ch == '\r' )
  387.             seenCR = TRUE;
  388.  
  389.         /* Skip trailing whitespace and add der terminador */
  390.         while( mrglBufCount && \
  391.                ( ( theCh = mrglBuffer[ mrglBufCount - 1 ] ) == ' ' || theCh == '\t' ) )
  392.             mrglBufCount--;
  393.         mrglBuffer[ mrglBufCount ] = '\0';
  394.  
  395.         /* Process the line unless its a blank or comment line */
  396.         if( mrglBufCount && *mrglBuffer != '#' )
  397.             {
  398.             /* At the first error we must print a newline to get the text
  399.                away from the HPACK title message unless we've already
  400.                printed one as part of the listFile message */
  401.             if( ( errType != NO_ERROR ) && firstError )
  402.                 {
  403.                 firstError = FALSE;
  404. #ifndef GUI
  405.                 hputchar( '\n' );
  406. #endif /* !GUI */
  407.                 }
  408.  
  409.             switch( errType )
  410.                 {
  411.                 case PATH_ERROR:
  412.                     mrglBuffer[ screenWidth - strlen( MESG_PATH_s__TOO_LONG_LINE_d ) - 3 ] = '\0';
  413.                                 /* Truncate to fit screen size (3 = '%s' + 1) */
  414. #ifdef GUI
  415.                     itoa( line, string, 10 );
  416.                     alert( ALERT_PATH_TOO_LONG_LINE, string );
  417. #else
  418.                     hprintf( MESG_PATH_s__TOO_LONG_LINE_d, mrglBuffer, line );
  419. #endif /* GUI */
  420.                     errCount++;
  421.                     break;
  422.  
  423.                 case ILLEGAL_CHAR_ERROR:
  424. #ifdef GUI
  425.                     itoa( line, string, 10 );
  426.                     alert( ALERT_BAD_CHAR_IN_FILENAME_LINE, string );
  427.                     if( errPos );    /* Get rid of "Not used" warning */
  428. #else
  429.                     hprintf( "> %s\n  ", mrglBuffer );
  430.                     while( errPos-- )
  431.                         hputchar( ' ' );
  432.                     hprintf( MESG_BAD_CHAR_IN_FILENAME_LINE_d, line );
  433. #endif /* GUI */
  434.                     errCount++;
  435.                     break;
  436.  
  437.                 default:
  438.                     addFilespec( ( char * ) mrglBuffer );
  439.                 }
  440.             }
  441.         else
  442.             /* It may be a script language command */
  443.             if( strlen( ( char * ) mrglBuffer ) > 2 && mrglBuffer[ 1 ] != ' ' )
  444.                 {
  445.                 /* At the moment just complain about it */
  446. #ifdef GUI
  447.                 alert( ALERT_UNKNOWN_SCRIPT_COMMAND, ( char * ) mrglBuffer );
  448. #else
  449.                 hprintf( WARN_UNKNOWN_SCRIPT_COMMAND_s, mrglBuffer );
  450. #endif /* GUI */
  451.                 errCount++;
  452.                 }
  453.  
  454.         /* Handle special-case of ^Z if listFile came off an MSDOS system */
  455.         if( ch == CPM_EOF )
  456.             ch = FEOF;
  457.  
  458.         /* Exit if there are too many errors */
  459.         if( errCount >= MAX_ERRORS )
  460.             break;
  461.  
  462.         line++;
  463.         }
  464.     hclose( listFileFD );
  465.  
  466.     /* Exit if there were errors */
  467.     if( errCount )
  468.         error( N_ERRORS_DETECTED_IN_SCRIPTFILE, ( errCount >= MAX_ERRORS ) ? \
  469.                MESG_MAXIMUM_LEVEL_OF : "", errCount );
  470.     }
  471.  
  472.