home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / C++-7 / DISK4 / SAMPLES / PWBEXTEN / TEXT.C$ / TEXT
Encoding:
Text File  |  1992-01-15  |  41.7 KB  |  1,376 lines

  1. /* TEXT.C - Text processing extension
  2.  *
  3.  * Copyright (C) Microsoft Corp. 1991-1992
  4.  * All Rights Reserved
  5.  *
  6.  * Demonstrates the following extension functions:
  7.  *
  8.  *  atou           BadArg        DelLine            DoMessage
  9.  *  DoMessageBox   DoStatusBox   FileNameToHandle   FindSwitch
  10.  *  GetLine        MoveCur       PutLine            ReadChar
  11.  *  SetKey
  12.  *
  13.  * Switches:
  14.  *  J2Space:no  - Boolean; Justify with two spaces after periods (.)
  15.  *  MapA:       - (see WhenLoaded for default value)
  16.  *  MapB:       - (see WhenLoaded for default value)
  17.  *                Character maps for MapA2B and MapB2A
  18.  *
  19.  * Functions:
  20.  *  Ucase   :ALT+U        - Uppercase
  21.  *  Lcase   :ALT+L        - Lowercase
  22.  *  Tcase   :ALT+X        - Toggle case
  23.  *  MapB2A  :SHIFT+CTRL+U - Map B's to A's
  24.  *  MapA2B  :SHIFT+CTRL+L - Map A's to B's
  25.  *  MapSwap :SHIFT+CTRL+X - Exchange characters between maps (toggle)
  26.  *  Justify :ALT+J        - Justify text
  27.  *  Center  :ALT+C        - Center text
  28.  *  Makebox :NUM/         - Draw a box
  29.  *  Goto    :ALT+G        - Goto a specific line/column
  30.  *  OkCancel:(unassigned) - Message box with replies OK or Cancel
  31.  *  YesNo   :(unassigned) - Message box with replies Yes or No
  32.  */
  33.  
  34. /*  Turn off common warnings for benign extension constructs */
  35. #pragma warning( disable:4001 )  //Allow single-line comments
  36. #pragma warning( disable:4100 )  //Allow unused arguments
  37.  
  38. //#include <stdlib.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include <ext.h>
  42.  
  43. //
  44. //  Prototypes
  45. //
  46. void _cdecl EXTERNAL WhenLoaded( void );
  47. PWBFUNC Ucase   ( unsigned argData, ARG _far *pArg, flagType fMeta );
  48. PWBFUNC Lcase   ( unsigned argData, ARG _far *pArg, flagType fMeta );
  49. PWBFUNC Tcase   ( unsigned argData, ARG _far *pArg, flagType fMeta );
  50. PWBFUNC MapA2B  ( unsigned argData, ARG _far *pArg, flagType fMeta );
  51. PWBFUNC MapB2A  ( unsigned argData, ARG _far *pArg, flagType fMeta );
  52. PWBFUNC MapSwap ( unsigned argData, ARG _far *pArg, flagType fMeta );
  53.  
  54. PWBFUNC Justify ( unsigned argData, ARG _far *pArg, flagType fMeta );
  55. PWBFUNC Center  ( unsigned argData, ARG _far *pArg, flagType fMeta );
  56. PWBFUNC MakeBox ( unsigned argData, ARG _far *pArg, flagType fMeta );
  57. PWBFUNC Goto    ( unsigned argData, ARG _far *pArg, flagType fMeta );
  58. PWBFUNC OkCancel( unsigned argData, ARG _far *pArg, flagType fMeta );
  59. PWBFUNC YesNo   ( unsigned argData, ARG _far *pArg, flagType fMeta );
  60.  
  61. //
  62. //  SWI_EXTTEXT functions to set/query MapA and MapB switches
  63. //
  64. char _far * _pascal EXTERNAL DoMapA( char _far *pszVal, flagType fQuery );
  65. char _far * _pascal EXTERNAL DoMapB( char _far *pszVal, flagType fQuery );
  66.  
  67. //
  68. //  Internal functions for this extension
  69. //
  70. char _far *ParseString( char _far * Dest, char _far * Src );
  71. char _far *SetMap( char *pszMap, char *pszSwi, char _far *pszVal, char chMap );
  72. int     HexDigit( int ch );
  73. char    *Swi2Map( char * pszMap, char *pszSwi );
  74. void    DoGenMap( char *pchChar, int Action );
  75. PWBFUNC MapChars( ARG _far *pArg, int fAction, int fCase );
  76. void EXTERNAL DumpLine( char _far *, PFILE, COL, COL, LINE, char _far *, int );
  77. int     NextLine( char _far *, PFILE, LINE, LINE, char _far * );
  78. void    GetMinLine( LINE y, COL xMin, char *pch, PFILE pFile );
  79. LINE    GetXY( char *pchVal, LINE current );
  80.  
  81. //
  82. //  Constants
  83. //
  84.  
  85. //  Column 'infinity'
  86. #define MAXCOL 32765
  87.  
  88. //
  89. //  Global variables for switches - initialized to default values,
  90. //  but switch overrides.
  91. //
  92. flagType J2Space = FALSE;
  93.  
  94. //
  95. //  Switches initialized by WhenLoaded()
  96. //
  97. char achSwiA[BUFLEN];  //value of CharMapA switch
  98. char achSwiB[BUFLEN];  //value of CharMapB switch
  99. char achMapA[BUFLEN];  //translation map A
  100. char achMapB[BUFLEN];  //translation map B
  101.  
  102. enum eMappings { UPPER, LOWER, TOGGLE };
  103.  
  104. enum eCorners { NW, EW, NE, SW, SE, NS, WW, EE, NN, SS, CE };
  105. char *achBox[] =
  106. {
  107.     "┌─┐└┘│├┤┬┴┼",
  108.     "╔═╗╚╝║╠╣╦╩╬",
  109.     "╒═╕╘╛│╞╡╤╧╪",
  110.     "╓─╖╙╜║╟╢╥╨╫",
  111.     "+-+++|+++++",
  112.     "=====|=====",
  113.     "░░░░░░░░░░░",
  114.     "▒▒▒▒▒▒▒▒▒▒▒",
  115.     "▓▓▓▓▓▓▓▓▓▓▓",
  116.     "███████████",
  117.     "■■■■■■■■■■■",
  118.     "???????????"   //buffer for any other char
  119. };
  120. #define LENBOXCHARS 11  //number of characters in an achBox entry
  121.  
  122. char achBoxMenu[] =
  123.     "Key(Box):0(┼)1(╬)2(╪)3(╫)4(+)5(=)6(░)7(▒)8(▓)9(█)A(■)?(?)";
  124. char achMenuChar[] = "0123456789A";
  125.  
  126.  
  127.  
  128. //  Ucase
  129. //  Convert argument to upper case
  130. //
  131. PWBFUNC Ucase( unsigned argData, ARG _far *pArg, flagType fMeta )
  132. {
  133.     return MapChars( pArg, UPPER, TRUE );
  134. }
  135.  
  136. //  Lcase
  137. //  Convert argument to lower case.
  138. //
  139. PWBFUNC Lcase( unsigned argData, ARG _far *pArg, flagType fMeta )
  140. {
  141.     return MapChars( pArg, LOWER, TRUE );
  142. }
  143.  
  144. //  Tcase
  145. //  Toggle case of argument
  146. //
  147. PWBFUNC Tcase( unsigned argData, ARG _far *pArg, flagType fMeta )
  148. {
  149.     return MapChars( pArg, TOGGLE, TRUE );
  150. }
  151.  
  152. //
  153. //  Map characters between the maps specified by the MapA and MapB
  154. //  switches
  155. //
  156.  
  157. //  MapA2B
  158. //  Map char in MapA to corresponding char in MapB
  159. //
  160. PWBFUNC MapA2B( unsigned argData, ARG _far *pArg, flagType fMeta )
  161. {
  162.     return MapChars( pArg, UPPER, FALSE );
  163. }
  164.  
  165. //  MapB2A
  166. //  Map char in MapB to corresponding char in MapA
  167. //
  168. PWBFUNC MapB2A( unsigned argData, ARG _far *pArg, flagType fMeta )
  169. {
  170.     return MapChars( pArg, UPPER, FALSE );
  171. }
  172.  
  173. //  MapSwap
  174. //  Swap chars between maps
  175. //
  176. PWBFUNC MapSwap( unsigned argData, ARG _far *pArg, flagType fMeta )
  177. {
  178.     return MapChars( pArg, TOGGLE, FALSE );
  179. }
  180.  
  181. //  Swi2Map
  182. //  Convert switch to character map
  183. //
  184. char *Swi2Map( char * pszMap, char *pszSwi )
  185. {
  186.     if( ParseString( pszMap, pszSwi ) == NULL )
  187.         return NULL;
  188.     farmemset( pszMap + farstrlen(pszMap),
  189.             *(pszMap + farstrlen(pszMap) -1 ),
  190.             BUFLEN - farstrlen(pszMap) -1 );
  191.     pszMap[BUFLEN-1] = '\0';
  192.     return pszMap;
  193.  
  194. }//  Swi2Map
  195.  
  196.  
  197. //  DoGenMap
  198. //  Perform a general mapping of *pchChar
  199. //
  200. //  Action specifies the direction of mapping:
  201. //
  202. //      TOGGLE  bidirectional: A's go to B's and B's go to A's
  203. //      UPPER   A's go to B's
  204. //      LOWER   B's go to A's
  205. //
  206. void DoGenMap( char *pchChar, int Action )
  207. {
  208.     char *pchScan;
  209.  
  210.     switch( Action )
  211.     {
  212.     case TOGGLE:
  213.         if( (pchScan = strchr( achMapB, *pchChar )) != NULL )
  214.         {
  215.             *pchChar = achMapA[pchScan - achMapB];
  216.             break;
  217.         }
  218.         //else fall-through to UPPER case
  219.  
  220.     case UPPER:
  221.         if( (pchScan = strchr( achMapA, *pchChar )) != NULL )
  222.             *pchChar = achMapB[pchScan - achMapA];
  223.         break;
  224.  
  225.     case LOWER:
  226.         if( (pchScan = strchr( achMapB, *pchChar )) != NULL )
  227.             *pchChar = achMapA[pchScan - achMapB];
  228.         break;
  229.     }
  230.  
  231. }//  DoGenMap
  232.  
  233.  
  234.  
  235. //  MapChars
  236. //  Map characters
  237. //
  238. PWBFUNC MapChars
  239.     (
  240.     ARG _far *pArg, //Argument record from PWB
  241.     int fAction,    //Direction of mapping: UPPER, LOWER, or TOGGLE
  242.     int fCase       //Case mapping (TRUE) or general mapping (FALSE)
  243.     )
  244. {
  245.     PFILE   pFile;
  246.     COL     xStart = 0;
  247.     COL     xEnd   = 0;
  248.     COL     xTemp  = 0;
  249.     LINE    yStart = 0;
  250.     LINE    yEnd   = 0;
  251.     int     i      = 0;
  252.     char    buf[BUFLEN];
  253.  
  254.     if( (pFile = FileNameToHandle( "", "" )) == PNULL )
  255.         return FALSE;               //No file
  256.  
  257.     //  Handle strictly vertical BOXARG: treat it as a LINEARG.
  258.     if( pArg->argType == BOXARG &&
  259.         (pArg->arg.boxarg.xLeft == pArg->arg.boxarg.xRight) )
  260.         pArg->argType = LINEARG;
  261.  
  262.     switch( pArg->argType )
  263.     {
  264.         case NOARG:                 //Switch case at cursor
  265.             xStart = xEnd = pArg->arg.noarg.x;
  266.             yStart = yEnd = pArg->arg.noarg.y;
  267.             MoveCur( xStart + 1, yStart );
  268.             break;
  269.  
  270.         case NULLARG:               //One arg: switch case to end of word
  271.             if( pArg->arg.nullarg.cArg == 1 )
  272.             {
  273.                 xStart = pArg->arg.nullarg.x;
  274.                 yStart = pArg->arg.nullarg.y;
  275.                 fExecute( "pword" );
  276.                 GetCursor( &xEnd, &yEnd );
  277.                 if( yEnd > yStart )
  278.                 {
  279.                     --yEnd;
  280.                     xEnd = MAXCOL;
  281.                 }
  282.                 else
  283.                     xEnd--;
  284.                 break;
  285.             }
  286.             else
  287.             {                       //Two args: switch case to end of line
  288.                 xStart = pArg->arg.nullarg.x;
  289.                 xEnd = MAXCOL;
  290.                 yStart = yEnd = pArg->arg.nullarg.y;
  291.                 break;
  292.             }
  293.  
  294.  
  295.         case LINEARG:               //Switch case of line range
  296.             xStart = 0;
  297.             xEnd = MAXCOL;
  298.             yStart = pArg->arg.linearg.yStart;
  299.             yEnd = pArg->arg.linearg.yEnd;
  300.             break;
  301.  
  302.         case BOXARG:                //Switch case of box
  303.             xStart = pArg->arg.boxarg.xLeft;
  304.             xEnd   = pArg->arg.boxarg.xRight;
  305.             yStart = pArg->arg.boxarg.yTop;
  306.             yEnd   = pArg->arg.boxarg.yBottom;
  307.             break;
  308.     }
  309.  
  310.     //
  311.     // Get each line. Convert characters from starting to ending column.
  312.     // Put modified line back in file.
  313.     //
  314.     while( yStart <= yEnd )
  315.     {
  316.         i = GetLine( yStart, buf, pFile );
  317.         xTemp = xStart;
  318.         while( (xTemp <= i) && (xTemp <= xEnd) )
  319.         {
  320.             if( fCase )
  321.                 switch( fAction )
  322.                 {
  323.                 case TOGGLE:
  324.                     if( buf[xTemp] >= 'A' && buf[xTemp] <= 'Z' )
  325.                     {
  326.                         buf[xTemp] += 'a' - 'A';   //Convert to lower
  327.                         break;
  328.                     }
  329.                     //else fall through
  330.                 case UPPER:
  331.                     if( buf[xTemp] >= 'a' && buf[xTemp] <= 'z' )
  332.                         buf[xTemp] += 'A' - 'a';   //Convert to upper
  333.                     break;
  334.                 case LOWER:
  335.                     if( buf[xTemp] >= 'A' && buf[xTemp] <= 'Z' )
  336.                         buf[xTemp] += 'a' - 'A';   //Convert to lower
  337.                     break;
  338.                 }
  339.             else
  340.                 DoGenMap( &buf[xTemp], fAction );
  341.             xTemp++;
  342.         }
  343.         PutLine( yStart++, buf, pFile );
  344.     }
  345.  
  346.     return TRUE;
  347.  
  348. }//  MapChars
  349.  
  350.  
  351.  
  352. //  Justify  -   Justify text
  353. //
  354. //  NOARG:       Justify between first nonspace column and rmargin,
  355. //               from the current line to blank line.
  356. //
  357. //  NULLARG:     Justify between current column and rmargin,
  358. //               from the current line to blank line.
  359. //
  360. //  LINEARG:     Justify between column 0 and rmargin,
  361. //               the specified lines.
  362. //
  363. //  STREAMARG:   Justify between specified columns
  364. //               from current line to blank (handled by boxarg).
  365. //
  366. //  BOXARG:      Justify between specified columns
  367. //               the specified rows.
  368. //
  369. //  TEXTARG:     Justify between columns 0 and rmargin,
  370. //               from the current line to a blank line, prepending each
  371. //               line with <textarg>.
  372. //               If the line already begins with <textarg>, only one
  373. //               copy is used.
  374.  
  375. // Terminating line value flags justification to the next blank line
  376. #define fBLANKLINE -1
  377.  
  378. PWBFUNC Justify( unsigned argData, ARG _far *pArg, flagType fMeta )
  379. {
  380.     static char inbuf[512];     //Input buffer
  381.     PFILE       pFile;          //File handle
  382.     char _far   *pText = NULL;  //Pointer to prepending text
  383.     COL         x1 = 0;         //Justify to left column
  384.     COL         x2 = 0;         //Justify to right column
  385.     LINE        y1 = 0;         //Start line
  386.     LINE        y2 = 0;         //End line
  387.     LINE        yOut = 0;       //Output line
  388.     char        buf[BUFLEN];
  389.     int         i = 0;
  390.     PSWI        pswi;
  391.  
  392.     if( (pswi = FindSwitch( "rmargin" )) == NULL )
  393.         return FALSE;                   //No switch
  394.  
  395.     if( (pFile = FileNameToHandle( "", "" )) == PNULL )
  396.         return FALSE;                   //No file
  397.  
  398.     //  Handle strictly vertical BOXARG: treat it as a LINEARG.
  399.     if( pArg->argType == BOXARG &&
  400.         (pArg->arg.boxarg.xLeft == pArg->arg.boxarg.xRight) )
  401.         pArg->argType = LINEARG;
  402.  
  403.     switch( pArg->argType )
  404.     {
  405.     case NOARG:                         //Justify paragraph
  406.         y1 = pArg->arg.noarg.y;         //from current line...
  407.         y2 = fBLANKLINE;                // ...to blank line
  408.         i = GetLine( y1, buf, pFile );
  409.         for( x1 = 0; (buf[x1] == ' ') && (x1 < i); x1++ )
  410.             ;                           //from first nonspace to
  411.         x2 = *(pswi->act.ival);         // ...right margin
  412.         pText = 0;                      //no text to prepend
  413.         break;
  414.  
  415.     case NULLARG:                       //Justify indented
  416.         x1 = pArg->arg.nullarg.x;       //between cur col...
  417.         x2 = *(pswi->act.ival);         // ...and right margin
  418.         y1 = pArg->arg.nullarg.y;       //current line...
  419.         y2 = fBLANKLINE;                // ...to blank line
  420.         pText = 0;                      //no text to prepend
  421.         break;
  422.  
  423.     case LINEARG:                       //Justify line range
  424.         x1 = 0;                         //between cols 0...
  425.         x2 = *(pswi->act.ival);         // ...and right margin
  426.         y1 = pArg->arg.linearg.yStart;  //and range of lines
  427.         y2 = pArg->arg.linearg.yEnd;
  428.         pText = 0;                      //no text to prepend
  429.         break;
  430.  
  431.     case BOXARG:                        //Justify box
  432.         x1 = pArg->arg.boxarg.xLeft;    //from left corner...
  433.         x2 = pArg->arg.boxarg.xRight;   //     ...to right
  434.         y1 = pArg->arg.boxarg.yTop;     //from top...
  435.         y2 = pArg->arg.boxarg.yBottom;  //    ...to bottom
  436.         pText = 0;                      //no text to prepend
  437.         break;
  438.  
  439.     case TEXTARG:                       //Justify & prepend
  440.         x1 = 0;                         //between 0...
  441.         x2 = *(pswi->act.ival);         //   ...and right margin
  442.         y1 = pArg->arg.textarg.y;       //current line...
  443.         y2 = fBLANKLINE;                //    ...to blank line
  444.         pText = pArg->arg.textarg.pText;//text to prepend
  445.         break;
  446.     }
  447.  
  448.     if( y1 == y2 )                      //If same line, then
  449.         y2 = fBLANKLINE;                //justify to blank line
  450.  
  451.     if( x1 == x2 )                      //If same column
  452.         x2 = *(pswi->act.ival);         //then justify to Rmargin
  453.  
  454.     if( x2 < x1 )                       //If backwards
  455.     {
  456.         x1 = 0;                         //revert to default
  457.         x2 = *(pswi->act.ival);
  458.     }
  459.  
  460.     //
  461.     // While we can get data within the specified limits, format each
  462.     // new line and output back to the file.
  463.     //
  464.     inbuf[0] = 0;
  465.     yOut = y1;                                  //line being output
  466.                                                 //while data to get
  467.     while( NextLine( inbuf, pFile, y1, y2, pText ) )
  468.     {
  469.         if( y2 != fBLANKLINE )                  //end moves with deletion
  470.             y2--;
  471.  
  472.         while( farstrlen( inbuf ) > (x2 - x1) )
  473.         {                                       //while data to output
  474.             y1++;                               //line moves with insert
  475.             if( y2 != fBLANKLINE )
  476.                 y2++;
  477.             DumpLine( inbuf, pFile, x1, x2, yOut++, pText, fMeta );
  478.         }
  479.     }
  480.  
  481.     // Dump remaining text
  482.     while( inbuf[0] )
  483.         DumpLine( inbuf, pFile, x1, x2, yOut++, pText, 0 );
  484.  
  485.     // If we were formatting to a blank line, dump out one of those too.
  486.     if( y2 == fBLANKLINE )                      //dump blank line
  487.         DumpLine( "", pFile, x1, x2, yOut++, "", 0 );
  488.  
  489.     return TRUE;
  490.  
  491. }//  Justify
  492.  
  493. //
  494. //  NextLine
  495. //  Get next line from file.
  496. //
  497. //  Like GetLine, except removes leading and trailing spaces.
  498. //
  499. int NextLine(
  500.     char _far  *pBuf,           //Input buffer
  501.     PFILE      pFile,           //File pointer
  502.     LINE       StartLine,       //Line # to read
  503.     LINE       EndLine,         //Line # to stop at
  504.     char _far  *pPrefix         //Prefix to strip (NULL if none)
  505.     )
  506. {
  507.     char _far  *pchScan;        //Scanning pointer
  508.     char _far  *pchPoke;        //Copying pointer
  509.     int        Ret;             //Return value
  510.     char       achWork[512];    //Working buffer
  511.     int        cbPrefix = 0;    //Length of prefix
  512.  
  513.     achWork[0] = 0;
  514.     Ret = 0;
  515.     if( (EndLine == -1) || (StartLine <= EndLine) )
  516.     {
  517.         Ret = GetLine( StartLine, achWork, pFile ); //Get a line
  518.         DelLine( pFile, StartLine, StartLine );     //Remove it
  519.     }
  520.  
  521.     //If there was data, strip prefix (if any) and leading spaces in
  522.     //new input line.
  523.     if( Ret )
  524.     {
  525.         if( pPrefix )
  526.         {
  527.             cbPrefix = farstrlen(pPrefix);
  528.             if( farstrncmp( pPrefix, achWork, cbPrefix ) )
  529.                 pchScan = achWork;
  530.             else
  531.                 pchScan = achWork + cbPrefix;
  532.         }
  533.         else
  534.             pchScan = achWork;
  535.         while( *pchScan == ' ' )
  536.             pchScan++;                              //Skip leading spaces
  537.  
  538.         // If existing buffer is non-empty, append a space and set
  539.         // pointer to end.
  540.         //
  541.         pchPoke = pBuf;
  542.         if( *pchPoke )                              //If non-null string
  543.         {
  544.             pchPoke += farstrlen( pchPoke );        //point to null
  545.             *pchPoke++ = ' ';                       //append space
  546.             if( J2Space && (*(pchPoke - 2) == '.') )//If period...
  547.                 *pchPoke++ = ' ';                   //append another
  548.         }
  549.  
  550.         // Append new line, but compress multiple spaces into one.
  551.         while( *pchScan )                           //Copy line over
  552.         {
  553.             if( J2Space & (*pchScan == '.') )       //If period...
  554.             {
  555.                 if( *(pchScan + 1) == ' ' )         // ...space
  556.                 {
  557.                     *pchPoke++ = *pchScan++;        //Copy period
  558.                     *pchPoke++ = *pchScan;          //Copy space
  559.                 }
  560.             }
  561.             if( (*pchPoke++ = *pchScan++) == ' ' )  //Copy a char
  562.             {
  563.                 while( *pchScan == ' ' )
  564.                     pchScan++;                      //Skip multiple spaces
  565.             }
  566.         }
  567.         while( *(pchPoke-1) == ' ' )                //Remove trailing spaces
  568.             pchPoke--;
  569.         *pchPoke = 0;
  570.  
  571.         if( pPrefix )
  572.             return( farstrlen(pBuf) - cbPrefix );
  573.  
  574.     }
  575.     return Ret;
  576.  
  577. }// NextLine
  578.  
  579. //  DumpLine
  580. //  Dump one line of text to the file.
  581. //  Prepend any required text or spaces, and perform word break/cut at
  582. //  right hand column.
  583.  
  584. void EXPORT DumpLine(
  585.     char _far *pBuf,    //Data to output
  586.     PFILE     pFile,    //File to output to
  587.     COL       x1,       //Left-hand column
  588.     COL       x2,       //Right-hand column
  589.     LINE      yOut,     //Line to output to
  590.     char _far *pText,   //Text to prepend
  591.     int       fFlush    //Flush both sides
  592.     )
  593. {
  594.     int  i;
  595.     char _far *pchScan;
  596.     char _far *pchPoke;
  597.     char achWork[512];  //Working buffer
  598.     char achFlush[512]; //Working buffer
  599.  
  600.     //  Start by prepending any text or padding to the left margin
  601.     //
  602.     achWork[0] = 0;                             //Start with null
  603.     if( pText )                                 //If prefix
  604.     {
  605.         farstrcpy( achWork, pText );            //copy prefix
  606.         x1 = farstrlen( pText );                //set left margin at prefix
  607.     }
  608.     else
  609.     {
  610.         farmemset( achWork, ' ', x1 );             //pad with spaces
  611.         achWork[x1] = '\0';
  612.     }
  613.     farstrcat( achWork, pBuf );
  614.  
  615.     //
  616.     //  Starting at the right column, scan back for a space to break at.
  617.     //  If one is not found before the left hand column, then break at
  618.     //  the right hand column. Copy any leftover line back to the
  619.     //  passed-in buffer.
  620.  
  621.     *pBuf = 0;                                  //Empty input buffer
  622.     if( farstrlen( achWork ) > x2 )             //If we need to cut
  623.     {
  624.         pchScan = &achWork[x2];                 //Point at potential cut
  625.         while( (pchScan > achWork + x1) && (*pchScan != ' ') )
  626.             pchScan--;                          //Back up to space
  627.  
  628.         if( pchScan <= achWork + x1 )           //If no space found
  629.         {
  630.             farstrcpy( pBuf, &achWork[x2] );    //copy remainder
  631.             achWork[x2] = 0;                    //terminate this line
  632.             fFlush = FALSE;                     //suppress right-justify
  633.         }
  634.         else
  635.         {
  636.             *pchScan = 0;                       //terminate this line
  637.             while( *++pchScan == ' ' )          //skip leading spaces
  638.                 ;
  639.             farstrcpy( pBuf, pchScan );         //copy remainder
  640.         }
  641.     }
  642.  
  643.  
  644.     // This code is invoked when the user wants to justify both right
  645.     // and left sides of his text. We determine how many spaces we need
  646.     // to add, and scan through and add one space to each run of spaces
  647.     // until we've added enough.
  648.  
  649.     if( fFlush )                                    //right justify
  650.     {
  651.         while( (i = x2 - farstrlen(achWork)) > 0 )  //count of spaces to add
  652.         {
  653.             farstrncpy( achFlush, achWork, x1 );    //start with prefix
  654.             pchScan = achWork  + x1;                //skip fixed part
  655.             pchPoke = achFlush + x1;
  656.             while( *pchScan )                       //while data to copy
  657.             {
  658.                 if( (*pchScan == ' ') && i )        //time to insert a space
  659.                 {
  660.                     i--;
  661.                     *pchPoke++ = ' ';               //insert space
  662.                     while( *pchScan == ' ' )
  663.                         *pchPoke++ = *pchScan++;    //copy spaces
  664.                 }
  665.                 if( *pchScan )
  666.                     *pchPoke++ = *pchScan++;        //copy next char
  667.             }
  668.             *pchPoke = 0;
  669.             farstrcpy( achWork, achFlush );         //copy back
  670.         }
  671.     }
  672.  
  673.     // Create new line and put it out.
  674.     CopyLine( PNULL, pFile, yOut, yOut, yOut );
  675.     PutLine( yOut, achWork, pFile );
  676.  
  677. }//  DumpLine
  678.  
  679.  
  680. //  Center - Center text
  681. //
  682.  
  683. PWBFUNC Center( unsigned int argData, ARG _far *pArg, flagType fMeta )
  684. {
  685.     PFILE pFile;
  686.     LINE  yStart = 0;
  687.     LINE  yEnd   = 0;
  688.     COL   xStart = 0;
  689.     COL   xStartThisLine= 0;
  690.     COL   xEnd   = 0;
  691.     COL   xMidField = 0;
  692.     COL   xMidText  = 0;
  693.     COL   xLen      = 0;
  694.     char  *pBuf;
  695.     char  buf[BUFLEN];
  696.     PSWI  pswi;
  697.  
  698.     pswi = FindSwitch( "rmargin" );
  699.     xEnd = *(pswi->act.ival);
  700.  
  701.     if( (pFile = FileNameToHandle( "", "" )) == PNULL )
  702.         return FALSE;               //No file
  703.  
  704.     //  Handle strictly vertical BOXARG: treat it as a LINEARG.
  705.     if( pArg->argType == BOXARG &&
  706.         (pArg->arg.boxarg.xLeft == pArg->arg.boxarg.xRight) )
  707.         pArg->argType = LINEARG;
  708.  
  709.     switch( pArg->argType )
  710.     {
  711.     // If the user has the cursor on a line with nothing marked and asks
  712.     // to center, center that line only.
  713.  
  714.     case NOARG:
  715.         yStart = yEnd = pArg->arg.noarg.y;
  716.         break;
  717.  
  718.     // If the user has marked one or more lines, and asks to center,
  719.     // center the range of lines that are marked.
  720.  
  721.     case LINEARG:
  722.         yStart = pArg->arg.linearg.yStart;
  723.         yEnd   = pArg->arg.linearg.yEnd;
  724.         break;
  725.  
  726.     // If the user has block-marked one or more lines, Center the range
  727.     // of lines within the block. Note that the block marks only the
  728.     // field to center in, not the text to be centered.
  729.  
  730.     case BOXARG:
  731.         yStart = pArg->arg.boxarg.yTop;
  732.         yEnd   = pArg->arg.boxarg.yBottom;
  733.         xStart = pArg->arg.boxarg.xLeft;
  734.         xEnd   = pArg->arg.boxarg.xRight;
  735.         break;
  736.  
  737.     }
  738.  
  739.     // Loop across the range of lines
  740.     for( ; yStart <= yEnd; yStart++ )
  741.     {
  742.         xLen = GetLine( yStart, buf, pFile );
  743.  
  744.         // Don't perform any action on zero-length lines
  745.         if( xLen > 0 )
  746.         {
  747.             // Scan for the first non-whitespace character
  748.             pBuf = buf + strspn( buf, " \t" );
  749.  
  750.             xLen = farstrlen( pBuf );
  751.             xMidField = xStart + ((xEnd - xStart) / 2);
  752.             xMidText = xLen / 2;
  753.             xStartThisLine = xMidField - xMidText;
  754.             xStartThisLine = (xStartThisLine > 0) ? xStartThisLine : 0;
  755.  
  756.             // Move the text to the correct place on the line
  757.             memmove( buf + xStartThisLine, pBuf, xLen + 1 );
  758.  
  759.             // Blank fill the area in front of the text
  760.             if( xStartThisLine )
  761.                 farmemset( buf, ' ', xStartThisLine );
  762.  
  763.             // Put the line back
  764.             PutLine( yStart, buf, pFile );
  765.         }
  766.     }
  767.  
  768.     return TRUE;
  769. }//  Center
  770.  
  771.  
  772. //  MakeBox
  773. //  Draw a box
  774. //
  775. PWBFUNC MakeBox( unsigned argData, ARG _far *pArg, flagType fMeta )
  776. {
  777.     PFILE    pFile;
  778.     COL      xStart;
  779.     COL      xEnd;
  780.     COL      xTemp;
  781.     LINE     yStart;
  782.     LINE     yEnd;
  783.     LINE     yTemp;
  784.     char     buf[BUFLEN];
  785.     char     *pchBox;
  786.     unsigned i;
  787.     unsigned ch;
  788.     unsigned fBox;
  789.  
  790.     if( (pFile = FileNameToHandle( "", "" )) == PNULL )
  791.         return FALSE;           //No file
  792.  
  793.     DoMessage( achBoxMenu );
  794.     ch = (int)ReadChar() & 0x00ff;
  795.     DoMessage( NULL );  //restore message line
  796.  
  797.     if( ch == 27 )      //ESC => cancel
  798.         return FALSE;
  799.  
  800.     if( (pchBox = strchr( achMenuChar, toupper( ch ) )) == NULL )
  801.     {
  802.         // Character not in menu, so use it as the drawing character
  803.         i = sizeof (achMenuChar) - 1;
  804.         farmemset( achBox[i], ch, LENBOXCHARS );
  805.     }
  806.     else
  807.         i = pchBox - achMenuChar;
  808.  
  809.     pchBox = achBox[i];
  810.  
  811.     //  Handle strictly vertical BOXARG: treat it as a LINEARG.
  812.     if( pArg->argType == BOXARG &&
  813.         (pArg->arg.boxarg.xLeft == pArg->arg.boxarg.xRight) )
  814.         pArg->argType = LINEARG;
  815.  
  816.     switch( pArg->argType )
  817.     {
  818.         case NOARG:
  819.             xStart = pArg->arg.noarg.x;
  820.             yStart = pArg->arg.noarg.y;
  821.             GetMinLine( yStart, xStart, buf, pFile );
  822.             buf[xStart] = pchBox[CE];
  823.             PutLine( yStart, buf, pFile );
  824.             MoveCur( xStart + 1, yStart );
  825.             break;
  826.  
  827.         case BOXARG:
  828.             fBox   = (pArg->arg.boxarg.cArg == 1) ? TRUE : FALSE;
  829.             xStart = xTemp = pArg->arg.boxarg.xLeft;
  830.             xEnd   = pArg->arg.boxarg.xRight;
  831.             yStart = yTemp = pArg->arg.boxarg.yTop;
  832.             yEnd   = pArg->arg.boxarg.yBottom;
  833.  
  834.  
  835.             if( xStart == xEnd+1 || xStart == xEnd-1 ) //Vertical line.
  836.             {
  837.                 GetMinLine( yTemp, xTemp, buf, pFile );
  838.                 if( (buf[xTemp] == pchBox[EW]) && fBox )
  839.                     buf[xTemp] = pchBox[NN];
  840.                 else
  841.                     buf[xTemp] = pchBox[NS];
  842.                 PutLine( yTemp++, buf, pFile );
  843.  
  844.                 while( yTemp < yEnd )
  845.                 {
  846.                     GetMinLine( yTemp, xTemp, buf, pFile );
  847.                     buf[xTemp] = pchBox[NS];
  848.                     PutLine( yTemp++, buf, pFile );
  849.                 }
  850.  
  851.                 GetMinLine( yTemp, xTemp, buf, pFile );
  852.                 if( (buf[xTemp] == pchBox[EW]) && fBox )
  853.                     buf[xTemp] = pchBox[SS];
  854.                 else
  855.                     buf[xTemp] = pchBox[NS];
  856.                 PutLine( yTemp, buf, pFile );
  857.             }
  858.             else if( yStart == yEnd )       //Horizontal line.
  859.             {
  860.                 GetMinLine( yStart, xEnd, buf, pFile );
  861.                 if( (buf[xTemp] == pchBox[NS]) && fBox )
  862.                     buf[xTemp++] = pchBox[WW];
  863.                 else
  864.                     buf[xTemp++] = pchBox[EW];
  865.  
  866.                 while( xTemp < xEnd )
  867.                     buf[xTemp++] = pchBox[EW];
  868.  
  869.                 if( (buf[xTemp] == pchBox[NS]) && fBox )
  870.                     buf[xTemp++] = pchBox[EE];
  871.                 else
  872.                     buf[xTemp++] = pchBox[EW];
  873.                 PutLine( yStart, buf, pFile );
  874.             }
  875.             else    //Box.
  876.             {
  877.                 GetMinLine( yTemp, xEnd, buf, pFile );
  878.                 buf[xTemp++] = pchBox[NW];
  879.                 while( xTemp < xEnd )
  880.                     buf[xTemp++] = pchBox[EW];
  881.                 buf[xTemp++] = pchBox[NE];
  882.                 PutLine( yTemp++, buf, pFile );
  883.  
  884.                 while( yTemp < yEnd )
  885.                 {
  886.                     xTemp = xStart;
  887.                     GetMinLine( yTemp, xEnd, buf, pFile );
  888.                     buf[xTemp++] = pchBox[NS];
  889.                     while( xTemp < xEnd )
  890.                     {
  891.                         if( pArg->arg.boxarg.cArg > 1 )
  892.                             buf[xTemp++] = pchBox[CE];
  893.                         else
  894.                             xTemp++;
  895.                     }
  896.                     buf[xTemp] = pchBox[NS];
  897.                     PutLine( yTemp++, buf, pFile );
  898.                 }
  899.  
  900.                 xTemp = xStart;
  901.                 GetMinLine( yTemp, xEnd, buf, pFile );
  902.                 buf[xTemp++] = pchBox[SW];
  903.                 while( xTemp < xEnd )
  904.                     buf[xTemp++] = pchBox[EW];
  905.                 buf[xTemp] = pchBox[SE];
  906.                 PutLine( yTemp, buf, pFile );
  907.             }
  908.             break;
  909.  
  910.         default:
  911.             break;
  912.     }
  913.  
  914.     DoMessage( NULL );  //restore message line
  915.     return TRUE;
  916. }//  MakeBox
  917.  
  918.  
  919. //  GetMinLine
  920. //  Get the specified line, blank-padded on the right to fill
  921. //  the minimum width.
  922. //
  923. //  Used by MakeBox
  924. //
  925. void GetMinLine( LINE y, COL xMin, char *pch, PFILE pFile )
  926. {
  927.     COL x;
  928.  
  929.     x = GetLine( y, pch, pFile );
  930.     if( x <= xMin )
  931.     {
  932.         while( x <= xMin )
  933.             pch[x++] = ' ';
  934.         pch[x] = '\0';
  935.     }
  936. }//  GetMinLine
  937.  
  938.  
  939. //  GetXY
  940. //  Parse relative or absolute coordinate from string.
  941. //
  942. //  If the string is not numeric or the name of a numeric switch, return
  943. //  the current location.
  944. //
  945. //  Used by Goto.
  946. //
  947. LINE GetXY( char *pchVal, LINE current )
  948. {
  949.     LINE t;
  950.     PSWI pswi;
  951.  
  952.     if( pchVal == NULL )
  953.         return current;
  954.  
  955.     if( (t = atou( pchVal )) == 0 )     //Number?
  956.     {                                   //Not a number or 0
  957.         // Numeric switch?
  958.         if( isalpha( *pchVal ) &&
  959.             ((pswi = FindSwitch( pchVal )) != NULL) &&
  960.             ((pswi->type & 0xff) == SWI_NUMERIC) )  //mask radix in high byte
  961.         {
  962.             t = *(pswi->act.ival);
  963.             t--;
  964.         }
  965.         else                            //not a numeric switch
  966.             return current;             //return current location
  967.     }
  968.     else                                //Number
  969.     {
  970.         if( (*pchVal == '+') || (*pchVal == '-') )
  971.             t += current;   //Relative
  972.         else
  973.             t--;            //Absolute:convert 1-based to internal 0-based
  974.     }
  975.  
  976.     return t;
  977.  
  978. }//  GetXY
  979.  
  980. //  Goto
  981. //  Go to the indicated line:column
  982. //
  983. //  TEXTARG
  984. //  syntax: [lead]...[[+|-]line][sep...[+|-]column]
  985. //
  986. //  <lead>  One of [ (<[{] or tab
  987. //
  988. //  <sep>   One of [ .,/;:\|=_] or tab
  989. //
  990. //  +|-     Specifies a location relative to the current position
  991. //
  992. //  If <line> is omitted, move to <column> on the same line
  993. //
  994. //  If no <column>, keep same column
  995. //
  996. //  <line> and <column> can be specified by a numeric switch which gives
  997. //  an absolute coordinate.
  998. //
  999. //  Returns:
  1000. //      TRUE : Cursor moved
  1001. //      FALSE: Cursor not moved or bad argument.
  1002. //
  1003. PWBFUNC Goto( unsigned argData, ARG _far *pArg, flagType fMeta )
  1004. {
  1005.     char achSkip[] = " \t(<[{";         //Leading characters
  1006.     char achSep[]  = " \t.,/;:\\|=_";
  1007.     char *pszLine;
  1008.     char *pszCol;
  1009.     COL  x;
  1010.     LINE y;
  1011.  
  1012.     if( pArg->argType == TEXTARG || pArg->argType == BOXSTR )
  1013.     {
  1014.  
  1015.         pszLine = pArg->arg.textarg.pText;
  1016.  
  1017.         // Find line number (if any)
  1018.         pszLine += strspn( pszLine, achSkip );
  1019.         y = GetXY( pszLine, pArg->arg.textarg.y );
  1020.  
  1021.         // Find column number (if any)
  1022.         if( (pszLine = strpbrk( pszLine, achSep )) != NULL )
  1023.         {
  1024.             pszCol = pszLine + strspn( pszLine, achSep );
  1025.             x = (COL)GetXY( pszCol, (LINE)pArg->arg.textarg.x );
  1026.         }
  1027.         else
  1028.             x = pArg->arg.textarg.x;
  1029.  
  1030.         if( x == pArg->arg.textarg.x && y == pArg->arg.textarg.y )
  1031.             return FALSE;   //no movement
  1032.  
  1033.         MoveCur( x, y );
  1034.         return TRUE;
  1035.     }
  1036.     else
  1037.     {
  1038.         BadArg();
  1039.         return FALSE;
  1040.     }
  1041.  
  1042. }//  Goto
  1043.  
  1044.  
  1045. //  SetMap
  1046. //  Set Charmap switches
  1047. //
  1048. char _far *SetMap
  1049.     (
  1050.     char *pszMap,       //Map buffer to set
  1051.     char *pszSwi,       //CharMap<x> switch
  1052.     char _far *pszVal,  //Value to set switch to
  1053.     char chMap          //Letter <x> for error message
  1054.     )
  1055. {
  1056.     static char achErrMsg[] = "MapX: Error in string format.";
  1057.  
  1058.     if( Swi2Map( pszMap, pszVal ) == NULL )    //Syntax error
  1059.     {
  1060.         Swi2Map( pszMap, achSwiA );            //restore map
  1061.         achErrMsg[3] = chMap;
  1062.         return (char _far *)achErrMsg;
  1063.     }
  1064.  
  1065.     farstrcpy( pszSwi, pszVal );              //set switch value
  1066.     return NULL;
  1067. }//  SetMap
  1068.  
  1069.  
  1070. //  DoMapA
  1071. //  Set or query the CharMapA switch
  1072. //
  1073. char _far * _pascal EXTERNAL DoMapA( char _far *pszVal, flagType fQuery )
  1074. {
  1075.     if( fQuery )
  1076.         return (char _far *)achSwiA;
  1077.     else
  1078.         return SetMap( achMapA, achSwiA, pszVal, 'A' );
  1079. }//  DoMapA
  1080.  
  1081.  
  1082.  
  1083. //  DoMapB
  1084. //  Set or query the CharMapB switch
  1085. //
  1086. char _far * _pascal EXTERNAL DoMapB( char _far *pszVal, flagType fQuery )
  1087. {
  1088.     if( fQuery )
  1089.         return (char _far *)achSwiB;
  1090.     else
  1091.         return SetMap( achMapB, achSwiB, pszVal, 'B' );
  1092. }//  DoMapB
  1093.  
  1094.  
  1095. //  HexDigit
  1096. //  Convert hex digit ch to it's numeric value
  1097. //
  1098. //  Used by ParseString
  1099. //
  1100. int HexDigit( int ch )
  1101. {
  1102.     if( isdigit( ch ) )
  1103.         return ch - '0';
  1104.  
  1105.     ch = tolower(ch);
  1106.     if( ch >= 'a' && ch <= 'f' )
  1107.         return (ch - 'a') + 10;
  1108.     else
  1109.         return 0; //silently ignore out of range chars
  1110.  
  1111. }//  HexDigit
  1112.  
  1113.  
  1114. //  ParseString
  1115. //  Copy quoted string in Src to Dest, translating escape sequences.
  1116. //
  1117. //  Hex sequences use 'classic' C syntax, not ANSI (always two hex digits).
  1118. //
  1119. //  Returns:
  1120. //      Pointer to char past end of parsed string
  1121. //      NULL if no quoted string found or syntax error
  1122. //
  1123. //  Assumes:
  1124. //      Destination contains enough space for result.
  1125. //      Octal and Hex sequences are properly formed
  1126.  
  1127. #define CHFNULL (char _far *)NULL
  1128.  
  1129. //  Check for unexpected null character
  1130. #define NULLCHECK if( *Src == '\0' ) return CHFNULL
  1131.  
  1132. //  Beware of aliasing: Src may also be Dest
  1133. #pragma optimize( "a", off)
  1134.  
  1135. char _far * ParseString( char _far * Dest, char _far * Src )
  1136. {
  1137.  
  1138.     while( *Src && *Src++ != '"' )  //scan for starting quote
  1139.         ;
  1140.     NULLCHECK;
  1141.     while( *Src && *Src != '"' )    //up to end or quote
  1142.     {
  1143.         if( *Src == '\\' )
  1144.         {
  1145.             switch( *++Src )
  1146.             {
  1147.             case '\0': return NULL; //error: escaped end-of-string
  1148.  
  1149.             //  Escape codes
  1150.             case 'a' :
  1151.                 *Dest++ = '\a' ;    //alert (bell)
  1152.                 Src++;
  1153.                 break;
  1154.  
  1155.             case 'b' :
  1156.                 *Dest++ = '\b' ;    //backspace
  1157.                 Src++;
  1158.                 break;
  1159.  
  1160.             case 'f' :
  1161.                 *Dest++ = '\f' ;    //formfeed
  1162.                 Src++;
  1163.                 break;
  1164.  
  1165.             case 'n' :
  1166.                 *Dest++ = '\n' ;    //linefeed
  1167.                 Src++;
  1168.                 break;
  1169.  
  1170.             case 'r' :
  1171.                 *Dest++ = '\r' ;    //carriage return
  1172.                 Src++;
  1173.                 break;
  1174.  
  1175.             case 't' :
  1176.                 *Dest++ = '\t' ;    //tab
  1177.                 Src++;
  1178.                 break;
  1179.  
  1180.             case 'v' :
  1181.                 *Dest++ = '\v' ;    //vertical tab
  1182.                 Src++;
  1183.                 break;
  1184.  
  1185.             case '\'':
  1186.                 *Dest++ = '\'' ;    //single quotation mark
  1187.                 Src++;
  1188.                 break;
  1189.  
  1190.             case '"' :
  1191.                 *Dest++ = '\"' ;    //double quotation mark
  1192.                 Src++;
  1193.                 break;
  1194.  
  1195.             case '\\':
  1196.                 *Dest++ = '\\' ;    //backslash
  1197.                 Src++;
  1198.                 break;
  1199.  
  1200.             //  Octal
  1201.             case '0':
  1202.             case '1':
  1203.             case '2':
  1204.             case '3':
  1205.             case '4':
  1206.             case '5':
  1207.             case '6':
  1208.             case '7':
  1209.                 *Dest  = (char)((*Src++ - '0') * 64);
  1210.                 NULLCHECK;
  1211.                 if( *Src < '0' || *Src > '7' )
  1212.                     return CHFNULL;
  1213.                 *Dest += (char)((*Src++ - '0') * 8);
  1214.                 NULLCHECK;
  1215.                 if( *Src < '0' || *Src > '7' )
  1216.                     return CHFNULL;
  1217.                 *Dest += (char)(*Src++ - '0');
  1218.                 if( *Src < '0' || *Src > '7' )
  1219.                     return CHFNULL;
  1220.                 Dest++;
  1221.                 break;
  1222.  
  1223.             //  Hexadecimal (K&R C, not ANSI C)
  1224.             case 'x':
  1225.                 Src++;
  1226.                 NULLCHECK;
  1227.                 if( !isxdigit(*Src) )
  1228.                     return CHFNULL;
  1229.                 *Dest  = (char)(HexDigit( *Src++ ) * 16);
  1230.                 NULLCHECK;
  1231.                 if( !isxdigit(*Src) )
  1232.                     return CHFNULL;
  1233.                 *Dest += (char)HexDigit( *Src++ );
  1234.                 Dest++;
  1235.                 break;
  1236.  
  1237.             default:
  1238.                 *Dest++ = *Src++;   //copy anything else
  1239.                 break;
  1240.             }
  1241.         }
  1242.         else
  1243.             *Dest++ = *Src++;   //any other character
  1244.     }
  1245.     *Dest = '\0';
  1246.     return Src;
  1247.  
  1248. }//  ParseString
  1249. #pragma optimize( "", on )
  1250.  
  1251.  
  1252. //  OkCancel
  1253. //
  1254. //  Displays text argument and prompts for OK or Cancel.
  1255. //
  1256. //  Returns: TRUE  user chose OK
  1257. //           FALSE user chose Cancel
  1258. //  Usage:
  1259. //      Like the Prompt function, this function is not useful interactively,
  1260. //      but is nice to have for writing macros.
  1261. //
  1262. //  Example:
  1263. //      Arg "message" OkCancel ->can ... :>can
  1264. //
  1265.  
  1266. PWBFUNC OkCancel( unsigned argData, ARG _far *pArg, flagType fMeta )
  1267. {
  1268.     return (flagType)(DoMessageBox( pArg->arg.textarg.pText, NULL, NULL,
  1269.                                     MBOX_OKCANCEL | MBOX_NOHELP, 0 )
  1270.                       == MBOX_IDOK);
  1271. }// OkCancel
  1272.  
  1273.  
  1274. //  YesNo
  1275. //
  1276. //  Displays text argument and prompts for Yes or No.
  1277. //
  1278. //  Returns: TRUE  user chose Yes
  1279. //           FALSE user chose No or Cancel
  1280. //  Usage:
  1281. //      Like the Prompt function, this function is not useful interactively,
  1282. //      but is nice to have for writing macros.
  1283. //
  1284. //  Example:
  1285. //      Arg "message" YesNo ->no ... :>no
  1286. //
  1287.  
  1288. PWBFUNC YesNo( unsigned argData, ARG _far *pArg, flagType fMeta )
  1289. {
  1290.     return (flagType)(DoMessageBox( pArg->arg.textarg.pText, NULL, NULL,
  1291.                                     MBOX_YESNO | MBOX_NOHELP, 0 )
  1292.                       == MBOX_IDYES);
  1293. }// YesNo
  1294.  
  1295.  
  1296. //-------------------< Standard Extension Information >--------------------
  1297.  
  1298. struct swiDesc swiTable[] =
  1299. {
  1300.     //  Switches for Justify
  1301.     { "J2Space",  toPIF(J2Space), SWI_BOOLEAN },
  1302.  
  1303.     //  Switches for MapChars
  1304.     { "CharMapA", DoMapA,         SWI_EXTTEXT },
  1305.     { "CharMapB", DoMapB,         SWI_EXTTEXT },
  1306.  
  1307.     //  End of table
  1308.     { NULL,       NULL,           0 }
  1309. };
  1310.  
  1311. struct cmdDesc cmdTable[] =
  1312. {
  1313.     {"Ucase",    Ucase,    0, KEEPMETA|NOARG|LINEARG|NULLARG|BOXARG|MODIFIES },
  1314.     {"Lcase",    Lcase,    0, KEEPMETA|NOARG|LINEARG|NULLARG|BOXARG|MODIFIES },
  1315.     {"Tcase",    Tcase,    0, KEEPMETA|NOARG|LINEARG|NULLARG|BOXARG|MODIFIES },
  1316.     {"MapA2B" ,  MapA2B ,  0, KEEPMETA|NOARG|LINEARG|NULLARG|BOXARG|MODIFIES },
  1317.     {"MapB2A" ,  MapB2A ,  0, KEEPMETA|NOARG|LINEARG|NULLARG|BOXARG|MODIFIES },
  1318.     {"MapSwap",  MapSwap,  0, KEEPMETA|NOARG|LINEARG|NULLARG|BOXARG|MODIFIES },
  1319.     {"Justify",  Justify,  0, TEXTARG|NOARG|LINEARG|NULLARG|BOXARG|MODIFIES },
  1320.     {"Center",   Center,   0, NOARG|LINEARG|BOXARG|MODIFIES},
  1321.     {"MakeBox",  MakeBox,  0, NOARG|BOXARG|MODIFIES},
  1322.     {"Goto",     Goto,     0, NULLEOW|TEXTARG|BOXSTR|KEEPMETA|WINDOWFUNC },
  1323.     {"YesNo",    YesNo   , 0, TEXTARG|NOWINDOWS|ICONFOCUS },
  1324.     {"OkCancel", OkCancel, 0, TEXTARG|NOWINDOWS|ICONFOCUS },
  1325.     { NULL, NULL, 0, 0 }
  1326. };
  1327.  
  1328. void _cdecl EXTERNAL WhenLoaded( void )
  1329. {
  1330.     DoStatusBox( "Text Utilities Extension", NULL );
  1331.  
  1332.     SetKey( "Ucase",   "ALT+U" );
  1333.     SetKey( "Lcase",   "ALT+L" );
  1334.     SetKey( "Tcase",   "ALT+X" );
  1335.  
  1336.     SetKey( "MapB2A" , "Shift+Ctrl+U" );
  1337.     SetKey( "MapA2B" , "Shift+Ctrl+L" );
  1338.     SetKey( "MapSwap", "Shift+Ctrl+X" );
  1339.  
  1340.     SetKey( "Justify", "ALT+J" );
  1341.     SetKey( "Center",  "ALT+C" );
  1342.     SetKey( "Makebox", "NUM/"  );
  1343.     SetKey( "Goto",    "ALT+G" );
  1344.  
  1345.     //  Character maps
  1346.     //
  1347.     //  The default mapping is from full PC characters to the plain
  1348.     //  ASCII chars that approximate their meaning or graphic shape.
  1349.     //  This PC/ASCII mapping is only useful in the A->B direction
  1350.     //  because characters in CharMapB are not unique.
  1351.     //
  1352.     //  Toggling works well for mappings that are unique in both maps such
  1353.     //  as the following definitions, which toggle case, including
  1354.     //  international characters:
  1355.     //
  1356.     //  CharMapA:"abcdefghijklmnopqrstuvwxyzçæäåñöüé¿->«≥¢ ⌐÷≡|([{'"
  1357.     //  CharMapB:"ABCDEFGHIJKLMNOPQRSTUVWXYZÇÆÄÅÑÖÜÉ?+<»≤$ ¬∙=&)]}\""
  1358.  
  1359.     farstrcpy( achSwiA,
  1360.                "\"■■\\t\\n  \\r  " "\\x1a" "<"
  1361.                "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▓"
  1362.                "│┼┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█"
  1363.                "µτΦΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■\"" );
  1364.     Swi2Map( achMapA, achSwiA );
  1365.  
  1366.     farstrcpy( achSwiB,
  1367.                "\"..........MF..*><V!PS=V^v><-H^v"
  1368.                "^CueaaaaceeeiiiAaEaaooouuyOUcLYRfaiounNao?....i<>##"
  1369.                "|+++++++|+++++++++-+++++++-+++++++++++++#"
  1370.                "mlPODI.EN=...SS/=d...n2*\"" );
  1371.     Swi2Map( achMapB, achSwiB );
  1372.  
  1373.     DoStatusBox( NULL, NULL );
  1374.     return;
  1375. }
  1376.