home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / PRINTING / PSFIX.ZIP / STRLIB.C < prev    next >
C/C++ Source or Header  |  1991-03-28  |  30KB  |  1,337 lines

  1. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  2. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  3. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  4. /* *                                                                     * */
  5. /* *  strlib.c        library of string-manipulating functions             * */
  6. /* *                                                                     * */
  7. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  8. /* * Marc A. Murison * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  9. /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  10.  
  11. /*
  12.  * This software may be freely distributed under the following conditions:
  13.  *         1. It is distributed in its current form, without alterations.
  14.  *         2. No monetary profit is made, under any circumstances.
  15.  *
  16.  *             Marc A. Murison
  17.  *             Smithsonian Astrophysical Observatory
  18.  *             60 Garden Street, MS 63
  19.  *             Cambridge, MA  02138
  20.  *
  21.  *             (617) 495-7079      murison@cfacx2.harvard.edu
  22.  */
  23.  
  24.  
  25.  
  26. #define  global  extern
  27. #define  STRLIB_C
  28. #define  KEY_CODES
  29. #include "strlib.h"
  30.  
  31.  
  32.  
  33.  
  34. #ifdef __TURBOC__
  35. /*-----------------------------------------------------------------------------
  36.  * text buffer browse utility
  37.  *
  38.  * returns 0 if unable to allocate enough memory for storing current text
  39.  * screen; 1 otherwise
  40.  *---------------------------------------------------------------------------*/
  41. Boolean browse( char *text, char *title )
  42. {
  43.     unsigned    size;
  44.     int            i, top_line, bot_line, nlines;
  45.     Key_Code    key;
  46.     Boolean        start_text, end_text, extended;
  47.     char        *old_screen, *lp_top, *lp_bot, *end_of_text;
  48.     char        *info_bar = "*   Quit: Q Esc   *   "
  49.                             "Up: Enter Up PgUp Home   *   "
  50.                             "Down: Space Dn PgDn End   *";
  51.     enum   colors        text_fg, text_bkg, title_fg, title_bkg, 
  52.                         info_fg, info_bkg;
  53.     struct text_info    current;
  54.  
  55.  
  56. /* assign colors */
  57.     text_fg   = BLACK;
  58.     text_bkg  = LIGHTGRAY;
  59.     title_fg  = WHITE;
  60.     title_bkg = RED;
  61.     info_fg   = WHITE;
  62.     info_bkg  = RED;
  63.  
  64.  
  65. /* save current text screen */
  66.     gettextinfo( ¤t );
  67.     size = ((current.screenheight*current.screenwidth*2) / 1000) * 1024;    
  68.     old_screen = cvector( 0, size-1 );
  69.     if( old_screen == NULL )  return FALSE;
  70.     gettext( 1, 1, current.screenwidth, current.screenheight, old_screen );
  71.  
  72.  
  73. /* find the end of the input text (for use in paging down) */
  74.     end_of_text = text;
  75.     while( *end_of_text )  ++end_of_text;
  76.  
  77.  
  78. /* write the title bar */
  79.     _setcursortype( _NOCURSOR );
  80.     window( 1, 1, current.screenwidth, 1 );
  81.     textcolor( title_fg );
  82.     textbackground( title_bkg );
  83.     clrscr();
  84.     i = 1 + (current.screenwidth - strlen( title )) / 2;
  85.     gotoxy( i, 1 );
  86.     while( *title ) { putchar(*title); ++title; }
  87.  
  88.  
  89. /* write the info bar */
  90.     window( 1, current.screenheight, current.screenwidth, current.screenheight);
  91.     textcolor( info_fg );
  92.     textbackground( info_bkg );
  93.     clrscr();
  94.     i = 1 + (current.screenwidth - strlen( info_bar )) / 2;
  95.     gotoxy( i, 1 );
  96.     while( *info_bar ) { putchar(*info_bar); ++info_bar; }
  97.  
  98.  
  99. /* side borders */
  100.     window( 1, 2, 1, current.screenheight-1 );
  101.     clrscr();
  102.     window( current.screenwidth, 2, 
  103.             current.screenwidth, current.screenheight-1 );
  104.     clrscr();
  105.  
  106.  
  107. /* define new window */
  108.     window( 2, 2, current.screenwidth-1, current.screenheight-1 );
  109.     textcolor( text_fg );
  110.     textbackground( text_bkg );
  111.     clrscr();
  112.     gotoxy( 1, 1 );
  113.     top_line  = 1;
  114.     bot_line  = current.screenheight - 2;
  115.     nlines    = bot_line - top_line + 1;
  116.  
  117.  
  118. /* print the first screenful of text */
  119.     lp_top = text;
  120.     lp_bot = text;
  121.     for( i=0; i < nlines; i++ ) {
  122.         gotoxy( 1, top_line+i );
  123.         cprint_line( OFF, &lp_bot );
  124.     }
  125.     start_text = TRUE;
  126.     if( *lp_bot == NULL )  
  127.         end_text = TRUE;
  128.     else
  129.         end_text = FALSE;
  130.  
  131.  
  132. /* interpret keystrokes */
  133.     extended = ON;
  134.     key      = KEY_CR;                        /* dummy start value */
  135.     while( BROWSE_KEY( extended, key ) ) {
  136.         i = getch();
  137.         if( i == 0 ) { 
  138.             extended = ON;  
  139.             key      = (Key_Code) getch(); 
  140.         } else {
  141.             extended = OFF;
  142.             key      = (Key_Code) i;
  143.         }
  144.  
  145.         /* scroll window up */
  146.         if( (key == KEY_UP  &&  extended)  ||  key == KEY_CR ) {
  147.             if( !start_text ) {
  148.                 /* insert a blank line at the top */
  149.                 gotoxy( 1, top_line );
  150.                 insline();
  151.                 clreol();
  152.  
  153.                 /* point to previous text line */
  154.                 if( !prev_line( &lp_top, text ) )  start_text = TRUE;
  155.  
  156.                 /* print the previous text line */
  157.                 cprint_line( OFF, &lp_top );
  158.                 prev_line( &lp_top, text );            /* but don't advance */
  159.                 end_text = FALSE;
  160.  
  161.                 /* update bottom line pointer */
  162.                 prev_line( &lp_bot, text );
  163.             }
  164.  
  165.         /* scroll window down */
  166.         } else if( (key == KEY_DN  &&  extended)  ||  key == KEY_SP ) {
  167.             if( !end_text ) {
  168.                 /* delete the top line and scroll window contents up */
  169.                 gotoxy( 1, top_line );
  170.                 delline();
  171.  
  172.                 /* print next line of text */
  173.                 gotoxy( 1, bot_line );
  174.                 clreol();
  175.                 cprint_line( OFF, &lp_bot );
  176.                 if( *lp_bot == NULL )  end_text = TRUE;
  177.                 start_text = FALSE;
  178.  
  179.                 /* update top line pointer */
  180.                 next_line( &lp_top );
  181.             }
  182.  
  183.         /* page window up */
  184.         } else if( key == KEY_PGUP  &&  extended ) {
  185.             if( !start_text ) {
  186.                 clrscr();
  187.                 for( i=0; i < nlines; i++ )  prev_line( &lp_top, text );
  188.                 if( lp_top <= text ) {
  189.                     lp_top     = text;
  190.                     start_text = TRUE;
  191.                 } else
  192.                     start_text = FALSE;
  193.                 lp_bot = lp_top;
  194.                 for( i=0; i < nlines; i++ ) {
  195.                     gotoxy( 1, top_line+i );
  196.                     cprint_line( OFF, &lp_bot );
  197.                 }
  198.                 if( lp_bot >= end_of_text )
  199.                     end_text = TRUE;
  200.                 else
  201.                     end_text = FALSE;
  202.             }
  203.  
  204.         /* page window down */
  205.         } else if( key == KEY_PGDN  &&  extended ) {
  206.             if( !end_text ) {
  207.                 clrscr();
  208.                 for( i=0; i < nlines; i++ )  next_line( &lp_bot );
  209.                 if( lp_bot >=  end_of_text ) {
  210.                     lp_top = end_of_text;
  211.                     for( i=0; i < nlines; i++ )  prev_line( &lp_top, text );
  212.                     end_text = TRUE;
  213.                 } else
  214.                     for( i=0; i < nlines; i++ )  next_line( &lp_top );
  215.                 start_text = FALSE;
  216.                 lp_bot     = lp_top;
  217.                 for( i=0; i < nlines; i++ ) {
  218.                     gotoxy( 1, top_line+i );
  219.                     cprint_line( OFF, &lp_bot );
  220.                 }
  221.             }
  222.  
  223.         /* home */
  224.         } else if( key == KEY_HOME  &&  extended ) {
  225.             if( !start_text ) {
  226.                 clrscr();
  227.                 lp_top = text;
  228.                 lp_bot = text;
  229.                 for( i=0; i < nlines; i++ ) {
  230.                     gotoxy( 1, top_line+i );
  231.                     cprint_line( OFF, &lp_bot );
  232.                 }
  233.                 start_text = TRUE;
  234.                 if( *lp_bot == NULL )  
  235.                     end_text = TRUE;
  236.                 else
  237.                     end_text = FALSE;
  238.             }
  239.  
  240.         /* end */
  241.         } else if( key == KEY_END  &&  extended ) {
  242.             if( !end_text ) {
  243.                 clrscr();
  244.                 lp_top = end_of_text;
  245.                 for( i=0; i < nlines; i++ )  prev_line( &lp_top, text );
  246.                 if( lp_top <= text ) {
  247.                     lp_top     = text;
  248.                     start_text = TRUE;
  249.                 }
  250.                 else
  251.                     start_text = FALSE;
  252.                 lp_bot = lp_top;
  253.                 for( i=0; i < nlines; i++ ) {
  254.                     gotoxy( 1, top_line+i );
  255.                     cprint_line( OFF, &lp_bot );
  256.                 }
  257.                 end_text = TRUE;
  258.             }
  259.         }
  260.     }
  261.  
  262.  
  263. /* restore old screen */
  264.     window( 1, 1, current.screenwidth, current.screenheight );
  265.     puttext( 1, 1, current.screenwidth, current.screenheight, old_screen );
  266.     gotoxy( current.curx, current.cury );
  267.     _setcursortype( _NORMALCURSOR );
  268.     
  269.     return TRUE;
  270. }
  271. #endif
  272.  
  273.  
  274.  
  275.  
  276.  
  277.  
  278.  
  279. /*-----------------------------------------------------------------------------
  280.  * Boolean next_line( char **bp )
  281.  *
  282.  * advance buffer pointer to character after next newline character
  283.  *
  284.  * contents of bp updated to new position in buffer, which is the first
  285.  * character after the next newline
  286.  *
  287.  * returns:        1    successful
  288.  *                0    NULL encountered
  289.  *---------------------------------------------------------------------------*/
  290. Boolean next_line( char **bp )
  291. {
  292.     /* go to next newline character */
  293.     if( !end_line( bp ) )  return FALSE;
  294.  
  295.     /* next character after that */
  296.     ++(*bp);
  297.     if( **bp == NULL )
  298.         return FALSE;
  299.     else
  300.         return TRUE;
  301. }
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.  
  309. /*-----------------------------------------------------------------------------
  310.  * Boolean prev_line( char **bp, char *buffer )
  311.  *
  312.  * move buffer pointer to character before previous newline character
  313.  *
  314.  * contents of bp updated to new position in buffer, which is the first
  315.  * character after the newline beginning the previous line
  316.  *
  317.  * returns:        1    successful
  318.  *                0    beginning of buffer encountered
  319.  *---------------------------------------------------------------------------*/
  320. Boolean prev_line( char **bp, char *buffer )
  321. {
  322.  
  323. /* 
  324.  * special case: 
  325.  * if we're sitting on a newline, and the previous 2 chars are newlines, 
  326.  * move to the middle newline 
  327.  */
  328.     if( **bp == NEWLINE  &&  *(*bp-1) == NEWLINE  &&  *(*bp-2) == NEWLINE ) {
  329.         --(*bp);  
  330.         if( *bp <= buffer )  { *bp = buffer;  return FALSE; }
  331.         return TRUE;
  332.     }
  333.  
  334.  
  335. /* 
  336.  * special case:
  337.  * if we're sitting on a newline, and the preceding char is a newline but the
  338.  * next preceding one isn't, move to before the newlines and then to the
  339.  * beginning of that line
  340.  */
  341.     if( **bp == NEWLINE  &&  *(*bp-1) == NEWLINE ) {
  342.         *bp -= 2;
  343.         if( *bp <= buffer )  { *bp = buffer;  return FALSE; }
  344.         if( !beg_line( bp, buffer ) ) {
  345.             if( **bp == NEWLINE ) {            /* 1st char of buffer = '\n' */
  346.                 ++(*bp);
  347.                 return TRUE;
  348.             } else
  349.                 return FALSE;
  350.         }
  351.         ++(*bp);
  352.         return TRUE;
  353.     } 
  354.  
  355.  
  356. /* 
  357.  * normal case:
  358.  */
  359.  
  360. /* move to beginning of current line  */
  361.     if( !beg_line( bp, buffer ) )  return FALSE;
  362.  
  363. /* move to beginning of previous line (1st char after newline) */
  364.     --(*bp);
  365.     if( *bp < buffer )  { *bp = buffer;  return FALSE; }
  366.     if( !beg_line( bp, buffer ) ) {
  367.         if( **bp == NEWLINE ) {            /* 1st char of buffer = '\n' */
  368.             ++(*bp);
  369.             return TRUE;
  370.         } else
  371.             return FALSE;
  372.     }
  373.     ++(*bp);
  374.     return TRUE;
  375. }
  376.  
  377.  
  378.  
  379.  
  380.  
  381.  
  382.  
  383. /*-----------------------------------------------------------------------------
  384.  * Boolean beg_line( char **bp, char *buffer )
  385.  *
  386.  * move buffer pointer to preceding newline character
  387.  *
  388.  * contents of bp updated to new position in buffer, which is the
  389.  * the newline beginning the current line
  390.  *
  391.  * returns:        1    successful
  392.  *                0    beginning of buffer encountered
  393.  *---------------------------------------------------------------------------*/
  394. Boolean beg_line( char **bp, char *buffer )
  395. {
  396.     char    *p;
  397.  
  398.     p = *bp;
  399.     if( p <= buffer )  { *bp = buffer;  return FALSE; }
  400.     while( *p != NEWLINE ) {
  401.         --p;
  402.         if( p <= buffer )  { *bp = buffer;  return FALSE; }
  403.     }
  404.     *bp = p;
  405.     return TRUE;
  406. }
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413.  
  414. /*-----------------------------------------------------------------------------
  415.  * Boolean end_line( char **bp )
  416.  *
  417.  * move buffer pointer to next newline character
  418.  *
  419.  * contents of bp updated to new position in buffer, which is the next
  420.  * newline
  421.  *
  422.  * returns:        1    successful
  423.  *                0    end of buffer (NULL) encountered
  424.  *---------------------------------------------------------------------------*/
  425. Boolean end_line( char **bp )
  426. {
  427.     char    *p;
  428.  
  429.     p = *bp;
  430.     if( *p == NULL )  return FALSE;
  431.     while( *p != NEWLINE ) {
  432.         ++p;
  433.         if( *p == NULL )  { *bp = p;  return FALSE; }
  434.     }
  435.     *bp = p;
  436.     return TRUE;
  437. }
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445. /*-----------------------------------------------------------------------------
  446.  *
  447.  * announce program version and date
  448.  *
  449.  *---------------------------------------------------------------------------*/
  450. void  announce( char *version_string, char *date_string )
  451. {
  452. #ifdef  __MSDOS__
  453.     int        vlength, dlength, i;
  454. #else
  455.     int        vlength, dlength, i, k;
  456. #endif
  457.  
  458.     vlength = strlen( version_string );
  459.     dlength = strlen( date_string );
  460.  
  461. #ifdef __MSDOS__
  462.  
  463.     if( dlength > 0 ) {
  464.         printf( "\n\xc9" );
  465.         for( i=0; i < vlength+4; i++ )  printf( "\xcd" );
  466.         printf( "\xd1" );
  467.         for( i=0; i < dlength+4; i++ )  printf( "\xcd" );
  468.         printf( "\xbb\n\xba  %s  \xb3  %s  \xba",
  469.                 version_string, date_string );
  470.         printf( "\n\xc8" );
  471.         for( i=0; i < vlength+4; i++ )  printf( "\xcd" );
  472.         printf( "\xcf" );
  473.         for( i=0; i < dlength+4; i++ )  printf( "\xcd" );
  474.         printf( "\xbc\n" );
  475.     } else {
  476.         printf( "\n\xc9" );
  477.         for( i=0; i < vlength+4; i++ )  printf( "\xcd" );
  478.         printf( "\xbb\n\xba  %s  \xba", version_string );
  479.         printf( "\n\xc8" );
  480.         for( i=0; i < vlength+4; i++ )  printf( "\xcd" );
  481.         printf( "\xbc\n" );
  482.     }
  483.  
  484. #else
  485.  
  486.     if( dlength > 0 ) {
  487.         k = (dlength+vlength+8+1)/2;
  488.         printf( "\n*" );
  489.         for( i=0; i < k; i++ )  printf( " *" );
  490.         if( IS_EVEN(dlength+vlength) )
  491.             printf( "\n*  %s  *  %s *", version_string, date_string );
  492.         else
  493.             printf( "\n*  %s  *  %s  *", version_string, date_string );
  494.         printf( "\n*" );
  495.         for( i=0; i < k; i++ )  printf( " *" );
  496.         printf( "\n" );
  497.     } else {
  498.         k = (vlength+4+1)/2;
  499.         printf( "\n*" );
  500.         for( i=0; i < k; i++ )  printf( " *" );
  501.         if( IS_EVEN(vlength) )
  502.             printf( "\n*  %s *", version_string );
  503.         else    
  504.             printf( "\n*  %s  *", version_string );
  505.         printf( "\n*" );
  506.         for( i=0; i < k; i++ )  printf( " *" );
  507.         printf( "\n" );
  508.     }
  509.  
  510. #endif
  511.  
  512.     return;
  513. }
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522. /*-----------------------------------------------------------------------------
  523.  *
  524.  * convert string buffer to upper case
  525.  *
  526.  *---------------------------------------------------------------------------*/
  527. char *upcase( char *string )
  528. {
  529.     char *p;
  530.  
  531.     p = string;
  532.     while( *p )  { *p = UPPER( *p );  p++; }
  533.     return string;
  534. }
  535.  
  536.  
  537.  
  538.  
  539.  
  540.  
  541.  
  542. /*-----------------------------------------------------------------------------
  543.  *
  544.  * convert string buffer to lower case
  545.  *
  546.  *---------------------------------------------------------------------------*/
  547. char *dncase( char *string )
  548. {
  549.     char *p;
  550.  
  551.     p = string;
  552.     while( *p )  { *p = LOWER( *p );  p++; }
  553.     return string;
  554. }
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563.  
  564. /*-----------------------------------------------------------------------------
  565.  * char *itoh( int i, char *string )
  566.  *
  567.  * convert an integer to a string of hex characters
  568.  *---------------------------------------------------------------------------*/
  569. char  *itoh( int i, char *string )
  570. {
  571.     int        k;
  572.     int        j;
  573.     char    *p;
  574.  
  575. /* load the character string with hex values */
  576.     p  = string;
  577.     *p = NULL;
  578.     if( i < 0 )  return string;
  579.  
  580.     k = i;
  581.     if( k == 0 ) {
  582.         *p++ = itohc( k );
  583.         *p   = NULL;
  584.     } else {
  585.         while( k > 0 ) {
  586.             j     = k % HEX_RADIX;
  587.             *p++  = itohc( j );
  588.             k    /= HEX_RADIX;
  589.         }
  590.         *p = NULL;
  591.  
  592.         /* mirror flip */
  593.         p = string;
  594.         sflip( p );
  595.     }
  596.  
  597.     return string;
  598. }
  599.  
  600.  
  601.  
  602.  
  603.  
  604.  
  605.  
  606. /*-----------------------------------------------------------------------------
  607.  * char *ltoh( long i, char *string )
  608.  *
  609.  * convert a long integer to a string of hex characters
  610.  *---------------------------------------------------------------------------*/
  611. char  *ltoh( long i, char *string )
  612. {
  613.     long    k;
  614.     int        j;
  615.     char    *p;
  616.  
  617. /* load the character string with hex values */
  618.     p  = string;
  619.     *p = NULL;
  620.     if( i < 0 )  return string;
  621.  
  622.     k = i;
  623.     if( k == 0 ) {
  624.         *p++ = itohc( (int)k );
  625.         *p   = NULL;
  626.     } else {
  627.         while( k > 0 ) {
  628.             j     = (int) (k % HEX_RADIX);
  629.             *p++  = itohc( j );
  630.             k    /= HEX_RADIX;
  631.         }
  632.         *p = NULL;
  633.  
  634.         /* mirror flip */
  635.         p = string;
  636.         sflip( p );
  637.     }
  638.  
  639.     return string;
  640. }
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648. /*-----------------------------------------------------------------------------
  649.  * char itohc( int i )
  650.  *
  651.  * convert an integer in the range 0 <= i <= 15 to a hex character
  652.  *---------------------------------------------------------------------------*/
  653. char  itohc( int i )
  654. {
  655.     char    *p = "0123456789ABCDEF";
  656.  
  657.     if( i < 0  ||  i > 15 )
  658.         return NULL;
  659.     else
  660.         return p[i];
  661. }
  662.  
  663.  
  664.  
  665.  
  666.  
  667.  
  668.  
  669. /*-----------------------------------------------------------------------------
  670.  * char *sflip( char *string )
  671.  *
  672.  * mirror-flip a string of characters
  673.  *---------------------------------------------------------------------------*/
  674. char *sflip( char *string )
  675. {
  676.     char    *p1, *p2;
  677.  
  678. /* point to first and last characters */
  679.     p1 = string;
  680.     while( *p1 )  ++p1;
  681.     p2 = p1 - 1;
  682.     p1 = string;
  683.  
  684. /* swap characters */
  685.     while( p2 > p1 ) {
  686.         SWAP( *p1, *p2 );
  687.         ++p1;
  688.         --p2;
  689.     }
  690.  
  691.     return string;
  692. }
  693.  
  694.  
  695.  
  696.  
  697.  
  698.  
  699.  
  700.  
  701. /*-----------------------------------------------------------------------------
  702.  *
  703.  * left justify a text string
  704.  *
  705.  *---------------------------------------------------------------------------*/
  706. char *ljust( char *string )
  707. {
  708.     char        *sp, *p;
  709.  
  710.     if( *string != BLANK  &&  *string != TAB )  return string;
  711.  
  712. /* skip white */
  713.     sp = string;
  714.     while( *sp == BLANK  ||  *sp == TAB  &&  *sp )  ++sp;
  715.  
  716. /* move */
  717.     p = string;
  718.     while( *sp )  *p++ = *sp++;
  719.     *p = NULL;
  720.  
  721.     return string;
  722. }
  723.  
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730. /*-----------------------------------------------------------------------------
  731.  * struct tab_info expand_tabs( int n, char *in_ptr, char *out_ptr
  732.  *                              long maxchars )
  733.  *
  734.  * Function to expand the tabs in *in_ptr and put the result into
  735.  * *out_ptr. The number of spaces that will be put in place of tabs
  736.  * is n
  737.  *
  738.  * expand_tabs returns the number of tab substitutions performed and the
  739.  * number of spaces inserted. If the output buffer is too small, values
  740.  * of -1 are returned instead
  741.  *---------------------------------------------------------------------------*/
  742. Tab_Info  expand_tabs( int n, char *in_ptr, char *out_ptr, long maxchars )
  743. {
  744.     int            npos = 0;            /* position from beginning of instring */
  745.                                     /*  or from last '\n'                   */
  746.     int            nfill, i;
  747.     long        char_count = 0;
  748.     char        c, *in, *out;
  749.     Tab_Info    count;
  750.  
  751.  
  752.     count.ntabs   = 0;
  753.     count.nspaces = 0;
  754.  
  755.     in  = in_ptr;
  756.     out = out_ptr;
  757.     c   = *in;
  758.     while( c != NULL ) {
  759.         ++npos;
  760.         ++char_count;
  761.         if( char_count > maxchars ) {
  762.             count.ntabs   = -1;
  763.             count.nspaces = -1;
  764.             return count;
  765.         }
  766.  
  767.         if( c == TAB ) {                        /* found a tab */
  768.             ++count.ntabs;
  769.             if( n != 0 ) {                        /* skip if tab = 0 spaces */
  770.  
  771.                 /* spaces to next tab stop */
  772.                 nfill = ( ((npos-1) / n) + 1 ) * n + 1 - npos;
  773.  
  774.                 /* check for possible overflow */
  775.                 char_count += nfill - 1;
  776.                 if( char_count > maxchars ) {
  777.                     count.ntabs   = -1;
  778.                     count.nspaces = -1;
  779.                     return count;
  780.                 }
  781.  
  782.                 c = BLANK;
  783.                 for( i=0; i < nfill; i++)  *out++ = c;
  784.                 npos += nfill - 1;
  785.                 count.nspaces += nfill;
  786.             }
  787.         } else {
  788.             if( c == NEWLINE )  npos = 0;
  789.             *out++ = *in;
  790.         }
  791.         c = *(++in);
  792.     }
  793.     *out = NULL;
  794.  
  795.     return count;
  796. }
  797.  
  798.  
  799.  
  800.  
  801.  
  802.  
  803.  
  804.  
  805.  
  806.  
  807. /*-----------------------------------------------------------------------------
  808.  * Boolean next_word( char **bp, char *word, int *n )
  809.  *
  810.  * retrieve next word from a buffer
  811.  *
  812.  * A word is assumed to consist of sequential alphanumeric characters or
  813.  * an underscore. Anything else is a word delimiter
  814.  *
  815.  * entry:  bp       pointer to the address of the input buffer pointer
  816.  *
  817.  * exit:   word     contents of next word
  818.  *         n        number of characters in word, excluding the NULL
  819.  *         *bp      points to 1st char after word
  820.  *
  821.  * returns:        1    successful
  822.  *                0    NULL encountered
  823.  *---------------------------------------------------------------------------*/
  824. Boolean  next_word( char **bp, char *word, int *n )
  825. {
  826.     char    *wp;
  827.  
  828. /* skip to next word */
  829.     wp = word;
  830.     *n = 0;  *wp = NULL;
  831.     while( !WORD_CHAR( **bp )  &&  **bp )  ++(*bp);
  832.     if( **bp == NULL )  return FALSE;
  833.  
  834. /* transfer a word */
  835.     *n = 1;  *wp++ = **bp;  ++(*bp);        /* 1st character */
  836.     while( WORD_CHAR( **bp ) ) {
  837.         *wp++ = **bp;
  838.         ++(*n);  
  839.         ++(*bp);
  840.     }
  841.     *wp = NULL;
  842.     return TRUE;
  843. }
  844.  
  845.  
  846.  
  847.  
  848.  
  849.  
  850.  
  851.  
  852.  
  853.  
  854. /*-----------------------------------------------------------------------------
  855.  * Boolean next_word_num( char **bp, char *word, int *n )
  856.  *
  857.  * retrieve next word from a buffer (word can also be a number)
  858.  *
  859.  * A word is assumed to consist of sequential alphanumeric characters or
  860.  * any of the following special characters:  .  +  - _
  861.  * Anything else is a word delimiter
  862.  *
  863.  * entry:  bp       pointer to the address of the input buffer pointer
  864.  *
  865.  * exit:   word     contents of next word
  866.  *         n        number of characters in word, excluding the NULL
  867.  *         *bp      points to 1st char after word
  868.  *
  869.  * returns:        1    successful
  870.  *                0    NULL encountered
  871.  *---------------------------------------------------------------------------*/
  872. Boolean  next_word_num( char **bp, char *word, int *n )
  873. {
  874.     char    *wp;
  875.  
  876. /* skip to next word */
  877.     wp = word;
  878.     *n = 0;  *wp = NULL;
  879.     while( !WORD_NUM_CHAR( **bp )  &&  **bp )  ++(*bp);
  880.     if( **bp == NULL )  return FALSE;
  881.  
  882. /* transfer a word */
  883.     *n = 1;  *wp++ = **bp;  ++(*bp);        /* 1st character */
  884.     while( WORD_NUM_CHAR( **bp ) ) {
  885.         *wp++ = **bp;
  886.         ++(*n);  
  887.         ++(*bp);
  888.     }
  889.     *wp = NULL;
  890.     return TRUE;
  891. }
  892.  
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899.  
  900.  
  901. /*-----------------------------------------------------------------------------
  902.  * Boolean is_blank( char *string )
  903.  *
  904.  * test character string for emptiness
  905.  *
  906.  * returns:        1    string is empty or contains only blanks or tabs
  907.  *                0    string is not empty
  908.  *---------------------------------------------------------------------------*/
  909. Boolean  is_blank( char *string )
  910. {
  911.     char    *sp;
  912.  
  913.     sp = string;
  914.     while( *sp ) {
  915.         if( *sp != BLANK  &&  *sp != TAB )  return FALSE;
  916.         ++sp;
  917.     }
  918.  
  919.     return TRUE;
  920. }
  921.  
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928.  
  929. /*-----------------------------------------------------------------------------
  930.  *  Write a message to stdout
  931.  *
  932.  *  The line after the message is cleared
  933.  *  Cursor is left at column
  934.  *  If nextline = TRUE, a linefeed is printed before the message
  935.  *  If lineafter = TRUE, a linefeed is printed after the message
  936.  *
  937.  *---------------------------------------------------------------------------*/
  938. void  print_msg( Boolean nextline, Boolean lineafter, int n, ... )
  939. {
  940.     char            *sp;
  941.     register int    i;
  942.     int                k, length;
  943.     va_list            argp;
  944.     
  945.  
  946.     if( nextline )  putchar( NEWLINE );
  947.  
  948.     length = 0;
  949.     putchar(CR);
  950.     va_start( argp, n );
  951.     for( k=0; k < n; k++ ) {
  952.         sp = va_arg( argp, char * );
  953.         printf( "%s", sp );
  954.         length += strlen(sp);
  955.     }
  956.     va_end(argp);
  957.  
  958.     for( i=0; i < 79 - length; i++ )  putchar(BLANK);
  959.     putchar(CR);
  960.  
  961.     if( lineafter )  putchar( NEWLINE );
  962.     
  963.     fflush( stdout );
  964. }
  965.  
  966.  
  967.  
  968.  
  969.  
  970.  
  971.  
  972.  
  973. /*-----------------------------------------------------------------------------
  974.  * void moreprint( char *string )
  975.  *
  976.  * Function to print the message in *string to the screen, pausing every
  977.  * (TEXT_ROWS - 1) lines (similar to the Unix more utility)
  978.  *
  979.  *---------------------------------------------------------------------------*/
  980. void moreprint( char *string )
  981. {
  982.     register int    i;
  983.     char            c, *strp;
  984. #if __TURBOC__
  985.     char            *msg = "<*>Press any key (q to quit)";
  986. #else
  987.     char            *msg = "<*>Press ENTER to continue (Q ENTER to quit)";
  988. #endif
  989.  
  990.  
  991.     strp = string;
  992.  
  993. #if __TURBOC__
  994.  
  995.     while( *strp ) {
  996.         /* output one screenful of text */
  997.         clrscr();
  998.         for( i = 0;  *strp  &&  i < TEXT_ROWS - 1;  i++ ) 
  999.             print_line( ON, &strp );
  1000.  
  1001.         /* "more" */
  1002.         if( i == TEXT_ROWS - 1 ) {
  1003.             if( *strp == NULL )  putchar( NEWLINE );
  1004.             c = moreprint_pause( msg );
  1005.             if( c == 'q'  ||  c == 'Q' ) {
  1006.                 putchar( NEWLINE );
  1007.                 return;
  1008.             }
  1009.         }
  1010.     }
  1011.  
  1012.     /* final pause */
  1013.     while( i < TEXT_ROWS-1 )  { ++i;  putchar( NEWLINE ); }
  1014.     c = moreprint_pause( msg );
  1015.  
  1016. #else
  1017.  
  1018.     while( *strp ) {
  1019.         /* output one screenful of text */
  1020.         for( i = 0;  *strp  &&  i < TEXT_ROWS - 2;  i++ ) 
  1021.             print_line( ON, &strp );
  1022.  
  1023.         /* "more" */
  1024.         if( i == TEXT_ROWS - 2 ) {
  1025.             if( *strp == NULL )  putchar( NEWLINE );
  1026.             c = moreprint_pause( msg );
  1027.             if( c == 'q'  ||  c == 'Q' ) {
  1028.                 putchar( NEWLINE );
  1029.                 return;
  1030.             }
  1031.         }
  1032.     }
  1033.  
  1034.     /* final pause */
  1035.     while( i < TEXT_ROWS-2 )  { ++i;  putchar( NEWLINE ); }
  1036.     c = moreprint_pause( msg );
  1037.  
  1038. #endif
  1039.  
  1040.  
  1041.     return;
  1042. }
  1043.  
  1044.  
  1045.  
  1046.  
  1047.  
  1048.  
  1049.  
  1050.  
  1051. /*-----------------------------------------------------------------------------
  1052.  * char moreprint_pause( char *msg )
  1053.  *
  1054.  * Function to put a "press any key" message on the screen and wait for
  1055.  * a keypress. Message text is in *msg, and it has to contain an asterisk
  1056.  * if this is being compiled with TURBO C
  1057.  *
  1058.  * This function is designed for use by moreprint
  1059.  *
  1060.  * Returns the first character pressed
  1061.  *---------------------------------------------------------------------------*/
  1062. char  moreprint_pause( char *msg )
  1063. {
  1064.     char    c, *p;
  1065.     int        i1;
  1066.  
  1067.  
  1068.     /* print the "pause" message */
  1069.     p = msg;
  1070.     while( *p ) { putchar(*p); ++p; }
  1071.     putchar( CR );
  1072.  
  1073.  
  1074.     /* wait for a keypress */
  1075.  
  1076. #if __TURBOC__
  1077.  
  1078.     /* blink the asterisk */
  1079.     i1 = (int) ( strchr( msg, '*' ) - msg + 1 );
  1080.     _setcursortype( _NOCURSOR );
  1081.     while( !kbhit() ) {
  1082.         /* off */
  1083.         gotoxy( i1, TEXT_ROWS );
  1084.         putchar( BLANK );
  1085.         delay( 100 );
  1086.  
  1087.         /* on */
  1088.         gotoxy( i1, TEXT_ROWS );
  1089.         putchar( '*' );
  1090.         delay( 100 );
  1091.     }
  1092.  
  1093.     /* erase the "pause" message */
  1094.     p = msg;
  1095.     putchar( CR );
  1096.     while( *p++ )  putchar( BLANK );
  1097.     putchar( CR );
  1098.  
  1099.     /* quit now? */
  1100.     c = (char) getch();
  1101.     while( kbhit() != 0 )  getch();        /* flush extra key hits */
  1102.     _setcursortype( _NORMALCURSOR );
  1103.     if( c == 'q'  ||  c == 'Q' ) {
  1104.         putchar( NEWLINE );
  1105.         return c;
  1106.     }
  1107.  
  1108. #else
  1109.  
  1110.     /* simulate kbhit() */
  1111.     c = getc(stdin);
  1112.  
  1113.     /* erase the "pause" message */
  1114.     p = msg;
  1115.     putchar( CR );
  1116.     while( *p++ )  putchar( BLANK );
  1117.     putchar( BLANK );
  1118.     putchar( CR );
  1119.  
  1120. #endif
  1121.  
  1122.     return c;
  1123. }
  1124.  
  1125.  
  1126.  
  1127.  
  1128.  
  1129.  
  1130.  
  1131. /*-----------------------------------------------------------------------------
  1132.  * void  print_line( int crlf, char **text_ptr )
  1133.  *
  1134.  * print one line of text to the stdout device (including CR+LF if crlf
  1135.  * is ON)
  1136.  *
  1137.  * input:    text_ptr    Pointer to the address of a pointer in the calling
  1138.  *                      program into the text buffer. Output starts from
  1139.  *                        the position in the text buffer pointed to by the
  1140.  *                        contents of text_ptr
  1141.  *
  1142.  * output:    text_ptr    The contents of text_ptr, which in turn is a
  1143.  *                      pointer, is updated to the address of the new
  1144.  *                      position in the text buffer after the line has
  1145.  *                        written. This new position is the byte after a
  1146.  *                        newline has been encountered
  1147.  *---------------------------------------------------------------------------*/
  1148. void  print_line( int crlf, char **text_ptr )
  1149. {
  1150.     char    *p;
  1151.  
  1152.     p = *text_ptr;
  1153.     while( *p != NEWLINE  &&  *p )  putchar( *p++ );
  1154.     if( *p == NEWLINE ) {
  1155.         ++p;
  1156.         if( crlf ) {
  1157.             putchar(CR);
  1158.             putchar(LF);
  1159.         }
  1160.     }
  1161.     *text_ptr = p;
  1162.  
  1163.     return;
  1164. }
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171.  
  1172. #ifdef __TURBOC__
  1173. /*-----------------------------------------------------------------------------
  1174.  *
  1175.  * console version of print_line
  1176.  *
  1177.  *---------------------------------------------------------------------------*/
  1178. void cprint_line( int crlf, char **text_ptr )
  1179. {
  1180.     char    *p;
  1181.  
  1182.     p = *text_ptr;
  1183.     while( *p != NEWLINE  &&  *p )  putch( *p++ );
  1184.     if( *p == NEWLINE ) {
  1185.         ++p;
  1186.         if( crlf ) {
  1187.             putch(CR);
  1188.             putch(LF);
  1189.         }
  1190.     }
  1191.     *text_ptr = p;
  1192.  
  1193.     return;
  1194. }
  1195. #endif
  1196.  
  1197.  
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204.  
  1205. /*-----------------------------------------------------------------------------
  1206.  * void  parse_args( char string[], int *nargs, double args[] )
  1207.  *
  1208.  * Function to parse (double) floating arguments from a null-terminated
  1209.  * string buffer
  1210.  *
  1211.  * entry:    string[]    null-terminated string containing numbers to
  1212.  *                        decode
  1213.  *
  1214.  * exit:    *nargs        number of numbers decoded
  1215.  *            args[]        vector containing decoded (double) floating
  1216.  *                        numbers
  1217.  *
  1218.  * function dependencies:   none
  1219.  * header files:            ctype.h, stdio.h
  1220.  *---------------------------------------------------------------------------*/
  1221. #ifndef NO_FLOAT
  1222.  
  1223. void  parse_args( char string[], int *nargs, double args[] )
  1224. {
  1225.     int      i, j, k, do_flag;
  1226.     char    c, *tmpstr;
  1227.     double    fnum;
  1228.  
  1229.  
  1230.     tmpstr = cvector( 0, 80 );
  1231.  
  1232.     if( *string == NULL )
  1233.         *nargs = 0;
  1234.     else {
  1235.         *nargs = 0;  i = 0;  do_flag = 1;
  1236.         while( string[i] != NULL  &&  do_flag ) {
  1237.             /* skip leading white space */
  1238.             while( isspace( string[i] ) )  i++;
  1239.  
  1240.             /* put number into tmpstr */
  1241.             j = 0;
  1242.             while( string[i] != NULL  &&  !isspace((c = string[i])) ) {
  1243.                 tmpstr[j++] = c;
  1244.                 i++;
  1245.             }
  1246.  
  1247.             /* decode number in tmpstr */
  1248.             if( j > 0 ) {
  1249.                 tmpstr[j] = NULL;
  1250.                 fnum = atof( tmpstr );
  1251.  
  1252.                 /* valid number was returned */
  1253.                 if( fnum != 0.0 ) {
  1254.                     args[*nargs] = fnum;
  1255.                     (*nargs)++;
  1256.  
  1257.                 /* zero returned--check for an actual zero */
  1258.                 } else {
  1259.                     k = 0;
  1260.                     if( (c=tmpstr[k]) == '+'  ||  c == '-' )  k++;
  1261.                     if( (c=tmpstr[k]) != '0' ) {
  1262.                         if( c != '.' )
  1263.                             do_flag = 0;    /* not a number */
  1264.                         else {    /* is a decimal point */
  1265.                             while( (c=tmpstr[++k]) == '0' );
  1266.                             if( c == NULL  ||  isspace(c) ) {
  1267.                                 args[*nargs] = fnum;
  1268.                                 (*nargs)++;
  1269.                             } else {    /* check for e- or d-floating */
  1270.                                 if( c == 'e' || c == 'E' ||
  1271.                                                 c == 'd' || c == 'D' ) {
  1272.                                     args[*nargs] = fnum;
  1273.                                     (*nargs)++;
  1274.                                 } else
  1275.                                     do_flag = 0;    /* not a number */
  1276.  
  1277.                             }    /* e- or d-floating format check */
  1278.  
  1279.                         }    /* is a decimal point */
  1280.  
  1281.                     }    /* 1st char != 0 */
  1282.  
  1283.                     else {    /* 1st char = '0' */
  1284.                         while( (c=tmpstr[++k]) == '0' );
  1285.                         if( c == NULL  ||  isspace(c) ) {
  1286.                             args[*nargs] = fnum;
  1287.                             (*nargs)++;
  1288.                         } else {    /* check for decimal point */
  1289.                             if( c == '.' ) {
  1290.                                 while( (c=tmpstr[++k]) == '0' );
  1291.                                 if( c == NULL  ||  isspace(c) ) {
  1292.                                     args[*nargs] = fnum;
  1293.                                     (*nargs)++;
  1294.                                 } else {    /* check for e- or d-floating */
  1295.                                     if( c == 'e' || c == 'E' ||
  1296.                                                     c == 'd' || c == 'D' ) {
  1297.                                         args[*nargs] = fnum;
  1298.                                         (*nargs)++;
  1299.                                     } else
  1300.                                         do_flag = 0;    /* not a number */
  1301.  
  1302.                                 }    /* e- or d-floating format check */
  1303.  
  1304.                             }    /* is a decimal point */
  1305.                             else {
  1306.                                 if( c == 'e' || c == 'E' ||
  1307.                                                 c == 'd' || c == 'D' ) {
  1308.                                     args[*nargs] = fnum;
  1309.                                     (*nargs)++;
  1310.                                 } else 
  1311.                                     do_flag = 0;    /* not a number */
  1312.  
  1313.                             }    /* not a d.p., e- or d-floating check */
  1314.  
  1315.                         }    /* decimal point check */
  1316.  
  1317.                     }    /* 1st char = '0' */
  1318.  
  1319.                 }    /* check for actual zero */
  1320.  
  1321.             }    /* j > 0  (input string not empty) */
  1322.  
  1323.         }    /* decoding loop */
  1324.  
  1325.     }    /* input string not NULL */
  1326.  
  1327.     free_cvector( tmpstr, 0 );
  1328.     return;
  1329. }
  1330.  
  1331. #endif
  1332.  
  1333.  
  1334.  
  1335.  
  1336.  
  1337.