home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / h / hpack78s.zip / io / display.c next >
C/C++ Source or Header  |  1992-09-21  |  13KB  |  482 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                            HPACK Multi-System Archiver                        *
  4. *                            ===========================                        *
  5. *                                                                            *
  6. *                         Output Intercept Handling Routines                    *
  7. *                            DISPLAY.C  Updated 25/10/91                        *
  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  Peter C.Gutmann.  All rights reserved            *
  15. *                                                                            *
  16. ****************************************************************************/
  17.  
  18. #include <string.h>
  19. #include "defs.h"
  20. #include "frontend.h"
  21. #include "hpacklib.h"
  22.  
  23. /* Maximum possible screen width */
  24.  
  25. #define MAX_WIDTH    150
  26.  
  27. #if defined( __MSDOS__ ) && !defined( GUI )
  28.  
  29. /* Prototypes for functions in BIOSCALL.ASM */
  30.  
  31. BYTE getAttribute( void );
  32. void writeChar( const char ch, const BYTE attribute );
  33.  
  34. /* Text mode information */
  35.  
  36. #define NORMAL_ATTR        0x07    /* Normal text */
  37. #define BLINK_MASK        0x80    /* Mask for blink bit */
  38. #define INTENSITY_MASK    0x08    /* Mask for intensity bit */
  39.  
  40. #endif /* __MSDOS__ && !GUI */
  41.  
  42. /* Command settings */
  43.  
  44. BOOLEAN doJustify, doCenter;
  45. int leftMargin, rightMargin, tempIndent;
  46.  
  47. /* Internal status info */
  48.  
  49. #ifndef GUI
  50.   int lineNo;
  51. #endif /* !GUI */
  52. int outPos, outWords;
  53. char outBuffer[ MAX_WIDTH ];    /* Max possible screen width */
  54. BOOLEAN breakFollows;
  55. #if defined( __MSDOS__ ) && !defined( GUI )
  56.   BYTE outAttrBuffer[ MAX_WIDTH ];
  57.   BYTE attribute;
  58.   BOOLEAN putSpace;                /* Whether there is a space queued */
  59. #endif /* __MSDOS__ && !GUI */
  60.  
  61. /* Prototypes for various functions */
  62.  
  63. static void putWord( char *word, int length );
  64.  
  65. /* Get an optional numeric parameter */
  66.  
  67. static void getParam( char *str, int *theValue, const int defaultValue, \
  68.                      const int minValue, const int maxValue )
  69.     {
  70.     char ch;
  71.     int value = 0;
  72.     BOOLEAN sign = FALSE, absolute = TRUE;
  73.  
  74.     /* Skip whitespace */
  75.     while( ( ch = *str ) == ' ' || ch == '\t' )
  76.         str++;
  77.  
  78.     /* Check for sign */
  79.     if( ( ch = *str ) == '-' || ch == '+' )
  80.         {
  81.         str++;
  82.         absolute = FALSE;    /* This is a delta not an absolute value */
  83.         sign = ch - '+';    /* sign = ~( ch - '+' + 1 ); value *= sign */
  84.         }
  85.  
  86.     /* Get digit */
  87.     while( *str > '0' && *str < '9' )
  88.         value = ( value * 10 ) + ( *str++ - '0' );
  89.  
  90.     /* Adjust sign */
  91.     if( sign )
  92.         value = -value;
  93.  
  94.     /* Do range check */
  95.     if( value )
  96.         if( absolute )
  97.             *theValue = value;
  98.         else
  99.             *theValue += value;
  100.     else
  101.         *theValue = defaultValue;
  102.     if( *theValue < minValue )
  103.         *theValue = minValue;
  104.     if( *theValue > maxValue )
  105.         *theValue = maxValue;
  106.     }
  107.  
  108. /* Force a line break */
  109.  
  110. static void doBreak( void )
  111.     {
  112.     BOOLEAN justifyValue = doJustify;
  113.  
  114.     doJustify = FALSE;        /* Make sure we don't justify half-full line */
  115.     putWord( "", rightMargin );
  116.     doJustify = justifyValue;
  117.     outPos = leftMargin + tempIndent;
  118.     tempIndent = 0;
  119.     }
  120.  
  121. /* Process a formatting command.  Note that we can't do an immediate break in
  122.    some cases when the command has an implied .br since it may be followed
  123.    by further implied-.br commands, so we set the breakFollows flag which
  124.    forces a break when we next output text */
  125.  
  126. #ifdef BIG_ENDIAN
  127.   #define BOLDFACE        0x626F        /* 'bo' */
  128.   #define PAGE_BREAK    0x6270        /* 'bp' */
  129.   #define LINE_BREAK    0x6272        /* 'br' */
  130.   #define CENTER        0x6365        /* 'ce' */
  131.   #define FILL            0x6669        /* 'fi' */
  132.   #define FLASH            0x666C        /* 'fl' */
  133.   #define INDENT        0x6E6E        /* 'in' */
  134.   #define ITALIC        0x6974        /* 'it' */
  135.   #define INVERSE        0x6976        /* 'iv' */
  136.   #define NOFILL        0x6E66        /* 'nf' */
  137.   #define NORMAL        0x6E6F        /* 'no' */
  138.   #define RIGHT_MARGIN    0x726D        /* 'rm' */
  139.   #define TEMP_INDENT    0x7469        /* 'ti' */
  140. #else
  141.   #define BOLDFACE        0x6F62        /* 'bo' */
  142.   #define PAGE_BREAK    0x7062        /* 'bp' */
  143.   #define LINE_BREAK    0x7262        /* 'br' */
  144.   #define CENTER        0x6563        /* 'ce' */
  145.   #define FILL            0x6966        /* 'fi' */
  146.   #define FLASH            0x6C66        /* 'fl' */
  147.   #define INDENT        0x6E6E        /* 'in' */
  148.   #define ITALIC        0x7469        /* 'it' */
  149.   #define INVERSE        0x7669        /* 'iv' */
  150.   #define NOFILL        0x666E        /* 'nf' */
  151.   #define NORMAL        0x6F6E        /* 'no' */
  152.   #define RIGHT_MARGIN    0x6D72        /* 'rm' */
  153.   #define TEMP_INDENT    0x6974        /* 'ti' */
  154. #endif /* BIG_ENDIAN */
  155.  
  156. static void processCommand( char *command )
  157.     {
  158.     int commandVal = *( ( int * ) command );
  159.  
  160.     switch( commandVal )
  161.         {
  162. #if defined( __MSDOS__ ) && !defined( GUI )
  163.         case BOLDFACE:
  164.             /* Boldface text */
  165.             attribute |= INTENSITY_MASK;
  166.             break;
  167. #endif /* __MSDOS__ && !GUI */
  168.  
  169.         case PAGE_BREAK:
  170.             /* Page break */
  171.             doBreak();
  172. #ifndef GUI
  173.             while( lineNo )
  174.                 /* Print lots of blank lines */
  175.                 doBreak();
  176. #endif /* !GUI */
  177.  
  178.         case LINE_BREAK:
  179.             /* Line break */
  180.             doBreak();
  181.             break;
  182.  
  183.         case CENTER:
  184.             /* Center text */
  185.             doBreak();
  186.             doCenter = TRUE;
  187.             break;
  188.  
  189.         case FILL:
  190.             /* Justify text */
  191.             breakFollows = doJustify = TRUE;
  192.             break;
  193.  
  194. #if defined( __MSDOS__ ) && !defined( GUI )
  195.         case FLASH:
  196.             /* Flashing text */
  197.             attribute |= BLINK_MASK;
  198.             break;
  199. #endif /* __MSDOS__ && !GUI */
  200.  
  201.         case INDENT:
  202.             /* Set left margin */
  203.             breakFollows = TRUE;
  204.             getParam( command + 2, &leftMargin, 0, -leftMargin, rightMargin );
  205.             break;
  206.  
  207. #if defined( __MSDOS__ ) && !defined( GUI )
  208.         case ITALIC:
  209.             /* Italic text */
  210.             attribute |= INTENSITY_MASK;    /* Treat as italic text */
  211.             break;
  212.  
  213.         case INVERSE:
  214.             /* Inverse text */
  215.             attribute = ( attribute & 0x88 ) | ( ( attribute & 0x70 ) >> 4 ) | \
  216.                                                ( ( attribute & 0x07 ) << 4 );
  217.             break;
  218. #endif /* __MSDOS__ && !GUI */
  219.  
  220.         case NOFILL:
  221.             /* Don't justify text */
  222.             breakFollows = TRUE;
  223.             doJustify = FALSE;
  224.             break;
  225.  
  226. #if defined( __MSDOS__ ) && !defined( GUI )
  227.         case NORMAL:
  228.             /* Normal text mode */
  229.             attribute = NORMAL_ATTR;
  230.             break;
  231. #endif /* __MSDOS__ && !GUI */
  232.  
  233.         case RIGHT_MARGIN:
  234.             /* Set right margin */
  235.             breakFollows = TRUE;
  236.             rightMargin = screenWidth - rightMargin;
  237.             getParam( command + 2, &rightMargin, 0, 0, screenWidth - leftMargin - 1 );
  238.             rightMargin = screenWidth - rightMargin;
  239.             break;
  240.  
  241.         case TEMP_INDENT:
  242.             /* Temporary indent */
  243.             breakFollows = TRUE;
  244.             getParam( command + 2, &tempIndent, -leftMargin, -leftMargin, rightMargin );
  245.             break;
  246.  
  247.         }
  248.     }
  249.  
  250. /* Output a word with all sorts of fancy formatting */
  251.  
  252. static void putWord( char *word, int length )
  253.     {
  254.     int noBlanks, i;
  255.     static BOOLEAN forwards = TRUE;
  256.  
  257.     /* See if there is a break in the pipeline */
  258.     if( breakFollows )
  259.         {
  260.         breakFollows = FALSE;
  261.         doBreak();
  262.         }
  263.  
  264. #if defined( __MSDOS__ ) && !defined( GUI )
  265.     /* Add a space if there's one queued.  We couldn't output this earlier
  266.        since there may have been an attribute change since then */
  267.     if( putSpace )
  268.         {
  269.         putSpace = FALSE;
  270.         outBuffer[ outPos++ ] = ' ';
  271.         outAttrBuffer[ outPos - 1 ] = attribute;
  272.         }
  273. #endif /* __MSDOS__ && !GUI */
  274.  
  275.     /* Check whether line is full */
  276.     if( outPos + length >= rightMargin )
  277.         {
  278.         outBuffer[ outPos ] = '\0';
  279.  
  280.         /* Delete trailing blank */
  281.         if( outBuffer[ outPos - 1 ] == ' ' )
  282.             outBuffer[ --outPos ] = '\0';
  283.  
  284.         /* Check for special text formatting */
  285.         if( doCenter )
  286.             {
  287.             /* Pad out line with spaces to center text */
  288.             for( i = 0; outBuffer[ i ] == ' '; i++ );
  289.             noBlanks = ( ( rightMargin - leftMargin ) - strlen( outBuffer + i ) ) >> 1;
  290.             while( noBlanks-- )
  291. #ifdef GUI
  292.                 putchar( ' ' );
  293. #else
  294.                 hputchar( ' ' );
  295. #endif /* GUI */
  296.             doCenter = FALSE;
  297.             }
  298.         else
  299.             if( doJustify && outPos < rightMargin )
  300.                 {
  301.                 /* Spread out the words on this line.  Note the use of
  302.                    memmove() instead of strcpy() since the source and
  303.                    destination strings overlap */
  304.                 noBlanks = ( rightMargin - outPos );
  305.                 while( noBlanks )
  306.                     {
  307.                     if( forwards )
  308.                         {
  309.                         /* Starting from the beginning of the line, insert
  310.                            an extra space where there is already one */
  311.                         for( i = leftMargin + 1; i <= rightMargin; i++ )
  312.                             if( outBuffer[ i ] == ' ' )
  313.                                 {
  314.                                 memmove( outBuffer + i + 1, outBuffer + i, rightMargin - i );
  315. #if defined( __MSDOS__ ) && !defined( GUI )
  316.                                 memmove( outAttrBuffer + i + 1, outAttrBuffer + i, rightMargin - i );
  317. #endif /* __MSDOS__ && !GUI */
  318.                                 noBlanks--;
  319.                                 i++;    /* Skip new blank */
  320.                                 if( !noBlanks )
  321.                                     break;
  322.                                 }
  323.                         }
  324.                     else
  325.                         /* Starting from the end of the line, insert an extra
  326.                            space where there is already one */
  327.                         for( i = outPos - 1; i > leftMargin; i-- )
  328.                             if( outBuffer[ i ] == ' ' )
  329.                                 {
  330.                                 memmove( outBuffer + i + 1, outBuffer + i, rightMargin - i );
  331. #if defined( __MSDOS__ ) && !defined( GUI )
  332.                                 memmove( outAttrBuffer + i + 1, outAttrBuffer + i, rightMargin - i );
  333. #endif /* __MSDOS__ && !GUI */
  334.                                 noBlanks--;
  335.                                 i--;    /* Skip new blank */
  336.                                 if( !noBlanks )
  337.                                     break;
  338.                                 }
  339.  
  340.                     /* Reverse direction for next round */
  341.                     forwards = !forwards;
  342.                     }
  343.                 }
  344.         outBuffer[ screenWidth + 1 ] = '\0'; /* Make sure we never overrun screen */
  345. #if defined( __MSDOS__ ) && !defined( GUI )
  346.         noBlanks = strlen( outBuffer );
  347.         for( i = 0; i < noBlanks; i++ )
  348.             writeChar( outBuffer[ i ], outAttrBuffer[ i ] );
  349.         if( noBlanks <= screenWidth )
  350.             hputchar( '\n' );
  351. #else
  352.   #ifdef GUI
  353.         printf( "%s\n", outBuffer );
  354.   #else
  355.         if( strlen( outBuffer ) == screenWidth + 1 )
  356.             hprintf( "%s", outBuffer );    /* Line = screen width, no need for NL */
  357.         else
  358.             hprintf( "%s\n", outBuffer );
  359.   #endif /* GUI */
  360. #endif /* __MSDOS__ && !GUI */
  361.  
  362.         /* Indent next line of text */
  363.         memset( outBuffer, ' ', leftMargin + tempIndent );
  364. #if defined( __MSDOS__ ) && !defined( GUI )
  365.         memset( outAttrBuffer, NORMAL_ATTR, leftMargin + tempIndent );
  366. #endif /* __MSDOS__ && !GUI */
  367.         outPos = leftMargin + tempIndent;
  368.         outWords = 0;
  369.  
  370. #ifndef GUI
  371.         /* Handle page breaks */
  372.         lineNo++;
  373.         if( lineNo >= screenHeight - 1 )
  374.             {
  375.             hgetch();
  376.             lineNo = 0;
  377.             }
  378. #endif /* GUI */
  379.         }
  380.     strncpy( outBuffer + outPos, word, length );
  381. #if defined( __MSDOS__ ) && !defined( GUI )
  382.     memset( outAttrBuffer + outPos, attribute, length );
  383. #endif /* __MSDOS__ && !GUI */
  384.     outPos += length;
  385.     if( outPos < rightMargin )
  386. #if defined( __MSDOS__ ) && !defined( GUI )
  387.         if( attribute != NORMAL_ATTR )
  388.             /* We can't add the space now since the attribute may change by
  389.                the time it is due to be inserted, so we queue it for later
  390.                insertion */
  391.             putSpace = TRUE;
  392.         else
  393.             {
  394.             outBuffer[ outPos++ ] = ' ';
  395.             outAttrBuffer[ outPos - 1 ] = attribute;
  396.             }
  397. #else
  398.         outBuffer[ outPos++ ] = ' ';
  399. #endif /* __MSDOS__ && !GUI */
  400.     outWords++;
  401.     }
  402.  
  403. /****************************************************************************
  404. *                                                                            *
  405. *                        Formatted Output Driver Code                        *
  406. *                                                                            *
  407. ****************************************************************************/
  408.  
  409. int lineBufCount;
  410. char lineBuffer[ MAX_WIDTH ];
  411. BOOLEAN wasNewline;
  412.  
  413. /* Initialise the format routines */
  414.  
  415. void initOutFormatText( void )
  416.     {
  417.     /* Set up defaults */
  418.     doJustify = FALSE;
  419.     doCenter = FALSE;
  420.     leftMargin = 0;
  421.     rightMargin = screenWidth;
  422.  
  423.     /* Set up internal status info */
  424. #ifndef GUI
  425.     lineNo = 0;
  426. #endif /* !GUI */
  427.     outPos = 0;
  428.     tempIndent = 0;
  429.     lineBufCount = 0;
  430.     wasNewline = TRUE;    /* At start we've just 'seen' a newline */
  431.     breakFollows = FALSE;
  432. #if defined( __MSDOS__ ) && !defined( GUI )
  433.     attribute = getAttribute();
  434.     putSpace = FALSE;
  435. #endif /* __MSDOS__ && !GUI */
  436.     }
  437.  
  438. /* Output a char via the format routines */
  439.  
  440. void outFormatChar( char ch )
  441.     {
  442.     /* Put a word in the line buffer */
  443.     if( ch != '\r' && ch != '\n' && ch != 0x1A && \
  444.         ( ( wasNewline && *lineBuffer == '.' ) || ( ch != ' ' && ch != '\t' ) ) )
  445.         {
  446.         if( ch >= ' ' && ch <= '~' )
  447.             lineBuffer[ lineBufCount++ ] = ch;
  448.  
  449.         /* Force line break if line is overly long */
  450.         if( leftMargin + tempIndent + lineBufCount > rightMargin )
  451.             goto lineBreak;
  452.         }
  453.     else
  454.         {
  455. lineBreak:
  456.         lineBuffer[ lineBufCount ] = '\0';
  457.  
  458.         /* Process the data in the lineBuffer */
  459.         if( wasNewline && *lineBuffer == '.' )
  460.             processCommand( lineBuffer + 1 );
  461.         else
  462.             if( lineBufCount )
  463.                 putWord( lineBuffer, lineBufCount );
  464.         lineBufCount = 0;
  465.  
  466.         /* Keep track of whether we've just seen a newline, after which
  467.            dotcommands are valid */
  468.         if( wasNewline )
  469.             wasNewline = FALSE;
  470.         if( ch == '\r' || ch == '\n' || ch == 0x1A )
  471.             wasNewline = TRUE;
  472.         }
  473.     }
  474.  
  475. /* Shutdown function for formatted text output */
  476.  
  477. void endOutFormatText( void )
  478.     {
  479.     /* Flush last line of text */
  480.     putWord( "", rightMargin );
  481.     }
  482.