home *** CD-ROM | disk | FTP | other *** search
/ synchro.net / synchro.net.tar / synchro.net / main / BBS / ODOORS62.ZIP / ODEdStr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-07  |  40.6 KB  |  1,239 lines

  1. /* OpenDoors Online Software Programming Toolkit
  2.  * (C) Copyright 1991 - 1999 by Brian Pirie.
  3.  *
  4.  * This library is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU Lesser General Public
  6.  * License as published by the Free Software Foundation; either
  7.  * version 2 of the License, or (at your option) any later version.
  8.  *
  9.  * This library is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.  * Lesser General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU Lesser General Public
  15.  * License along with this library; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17.  *
  18.  *
  19.  *        File: ODEdStr.c
  20.  *
  21.  * Description: Implementation of od_edit_str(). This is the advanced line
  22.  *              editing function which requires ANSI or AVATAR graphics.
  23.  *
  24.  *   Revisions: Date          Ver   Who  Change
  25.  *              ---------------------------------------------------------------
  26.  *              Oct 13, 1994  6.00  BP   New file header format.
  27.  *              Dec 09, 1994  6.00  BP   Standardized coding style.
  28.  *              Dec 31, 1994  6.00  BP   Use ODTimerSleep() instead of loop.
  29.  *              Aug 19, 1995  6.00  BP   32-bit portability.
  30.  *              Nov 11, 1995  6.00  BP   Removed register keyword.
  31.  *              Nov 16, 1995  6.00  BP   Removed oddoor.h, added odcore.h.
  32.  *              Nov 17, 1995  6.00  BP   Use new input queue mechanism.
  33.  *              Dec 12, 1995  6.00  BP   Added entry, exit and kernel macros.
  34.  *              Dec 23, 1995  6.00  BP   Added EDIT_FLAG_SHOW_SIZE.
  35.  *              Dec 30, 1995  6.00  BP   Added ODCALL for calling convention.
  36.  *              Jan 04, 1996  6.00  BP   Use od_get_input().
  37.  *              Jan 12, 1996  6.00  BP   Claim exclusive use of arrow keys.
  38.  *              Jan 31, 1996  6.00  BP   Added timeout for od_get_input().
  39.  *              Feb 10, 1996  6.00  BP   Fixed ...SHOW_SIZE /w ...PERMALITERAL.
  40.  *              Feb 13, 1996  6.00  BP   Added od_get_input() flags parameter.
  41.  *              Feb 19, 1996  6.00  BP   Changed version number to 6.00.
  42.  *              Mar 03, 1996  6.10  BP   Begin version 6.10.
  43.  *              Apr 08, 1996  6.10  BP   Make 'C' use word capitalization.
  44.  */
  45.  
  46. #define BUILDING_OPENDOORS
  47.  
  48. #include <ctype.h>
  49. #include <stddef.h>
  50. #include <string.h>
  51.  
  52. #include "OpenDoor.h"
  53. #include "ODCore.h"
  54. #include "ODGen.h"
  55. #include "ODPlat.h"
  56. #include "ODKrnl.h"
  57. #include "ODStat.h"
  58.  
  59.  
  60. /* Current od_edit_str() state and settings. */
  61. static INT anCurrentFormatOffset[80];
  62. static BOOL abCurrentFormatLiteral[80];
  63. static char szCurrentOriginalString[81];
  64. static char *pszCurrentInput;
  65. static char *pszCurrentFormat;
  66. static unsigned char nCurrentStringLength;
  67. static char chCurrentBlank;
  68.  
  69.  
  70. /* Private helper functions used by od_edit_str(). */
  71. static BOOL ODEditIsCharValidForPos(char chEntered, INT nPosition);
  72. static char ODEditAsCharForPos(char chEntered, INT nPosition);
  73. static void ODEditDisplayPermaliteral(WORD nFlags);
  74.  
  75.  
  76. /* ----------------------------------------------------------------------------
  77.  * od_edit_str()
  78.  *
  79.  * Provides more advanced editing capabilities than od_get_str(), requiring
  80.  * ANSI, AVATAR or RIP modes.
  81.  *
  82.  * Parameters: pszInput          - Pointer to string where inputted text is
  83.  *                                 stored.
  84.  *
  85.  *             pszFormat         - Pointer to format string, which specifies
  86.  *                                 the format of inputted text.
  87.  *
  88.  *             nRow              - The row number where the input field should
  89.  *                                 begin.
  90.  *
  91.  *             nColumn           - The column number where the input field
  92.  *                                 should begin.
  93.  *
  94.  *             btNormalColour    - Color of normal text.
  95.  *
  96.  *             btHighlightColour - Color of highlighted text.
  97.  *
  98.  *             chBlank           - Character to display blanks with.
  99.  *
  100.  *             nFlags            - Specifies one or more flags, combined with
  101.  *                                 the bitwise-or operator.
  102.  *
  103.  *     Return: One of a number of possible EDIT_RETURN_ values, which indicate
  104.  *             why the function returned.
  105.  */
  106. ODAPIDEF WORD ODCALL od_edit_str(char *pszInput, char *pszFormat, INT nRow,
  107.    INT nColumn, BYTE btNormalColour, BYTE btHighlightColour,
  108.    char chBlank, WORD nFlags)
  109. {
  110.    char chTemp;
  111.    unsigned int nCount;
  112.    unsigned char chCurrentValue;
  113.    char *pchCurrent;
  114.    unsigned int nCursorPos;
  115.    INT nKeysPressed = 0;
  116.    WORD wToReturn;
  117.    BOOL bInsertMode = TRUE;
  118.    char chAddAtEnd = '\0';
  119.    BOOL bNormal = TRUE;
  120.    tODInputEvent InputEvent;
  121.  
  122.    /* Log function entry if running in trace mode */
  123.    TRACE(TRACE_API, "od_edit_str()");
  124.  
  125.    /* Verify that OpenDoors has been initialized. */
  126.    if(!bODInitialized) od_init();
  127.  
  128.    OD_API_ENTRY();
  129.  
  130.    /* Store pointers to current input string and current format string. */
  131.    pszCurrentInput=(char *)pszInput;
  132.    pszCurrentFormat=(char *)pszFormat;
  133.  
  134.    /* Check that the parameters passed in are valid. */
  135.    if(pszCurrentInput == NULL || pszCurrentFormat == NULL || nRow < 1
  136.       || nColumn < 1)
  137.    {
  138.       od_control.od_error = ERR_PARAMETER;
  139.       OD_API_EXIT();
  140.       return(EDIT_RETURN_ERROR);
  141.    }
  142.  
  143.    /* Initially, the maximum length of input string is 0. */
  144.    nCurrentStringLength = 0;
  145.  
  146.    /* The type that is being examined. */
  147.    chCurrentValue = 0;
  148.  
  149.    /* Counter of position in format string. */
  150.    nCount = 0;
  151.  
  152.    /* Loop until we reach the end fo the format string. */
  153.    for(pchCurrent = pszCurrentFormat; *pchCurrent;)
  154.    {
  155.       /* Get next character from format string. */
  156.       chTemp = *pchCurrent++;
  157.  
  158.       /* If current character is not a literal value. */
  159.       if(chCurrentValue == '\0')
  160.       {
  161.          /* If format string has " or ' characters, then this is the */
  162.          /* beginning of a literal string.                           */
  163.          if(chTemp == 39 || chTemp == 34)
  164.          {
  165.             chCurrentValue = chTemp;
  166.          }
  167.  
  168.          /* If this is not a literal character, and not a space character... */
  169.          else if(chTemp != 32)
  170.          {
  171.             /* Check that we haven't exceeded the maximum allowable string */
  172.             /* length.                                                     */
  173.             if(nCurrentStringLength >= 80)
  174.             {
  175.                od_control.od_error = ERR_PARAMETER;
  176.                OD_API_EXIT();
  177.                return(EDIT_RETURN_ERROR);
  178.             }
  179.  
  180.             /* Record format character's position. */
  181.             anCurrentFormatOffset[nCurrentStringLength] = nCount;
  182.  
  183.             /* Record that this character is not a literal. */
  184.             abCurrentFormatLiteral[nCurrentStringLength] = FALSE;
  185.  
  186.             /* Increment length of input string. */
  187.             ++nCurrentStringLength;
  188.          }
  189.       }
  190.  
  191.       /* If this is a literal character. */
  192.       else
  193.       {
  194.          /* Check for end of literal string. */
  195.          if(chTemp == chCurrentValue)
  196.          {
  197.             /* If found, stop literal string processing */
  198.             chCurrentValue = '\0';
  199.          }
  200.          else
  201.          {
  202.             /* Check that we haven't exceeded the maximum allowable string */
  203.             /* length.                                                     */
  204.             if(nCurrentStringLength >= 80)
  205.             {
  206.                od_control.od_error = ERR_PARAMETER;
  207.                OD_API_EXIT();
  208.                return(EDIT_RETURN_ERROR);
  209.             }
  210.  
  211.             /* Record character's position. */
  212.             anCurrentFormatOffset[nCurrentStringLength] = nCount;
  213.  
  214.             /* Record that character IS a literal value. */
  215.             abCurrentFormatLiteral[nCurrentStringLength] = TRUE;
  216.  
  217.             /* Increment length of input string. */
  218.             ++nCurrentStringLength;
  219.          }
  220.       }
  221.  
  222.       /* Increment format string position. */
  223.       ++nCount;
  224.    }
  225.  
  226.    /* Check that there is at least one character permitted in the input */
  227.    /* string. If not, return with a parameter error.                    */
  228.    if(nCurrentStringLength==0)
  229.    {
  230.       od_control.od_error = ERR_PARAMETER;
  231.       OD_API_EXIT();
  232.       return(EDIT_RETURN_ERROR);
  233.    }
  234.  
  235.    /* If editing an existing string. */
  236.    if(nFlags & EDIT_FLAG_EDIT_STRING)
  237.    {
  238.       /* Check for valid existing input string. */
  239.       if(strlen(pszCurrentInput) > nCurrentStringLength)
  240.       {
  241.          pszCurrentInput[nCurrentStringLength] = '\0';
  242.       }
  243.  
  244.       /* Start with cursor at the end of the string. */
  245.       nCursorPos = strlen(pszCurrentInput);
  246.    }
  247.  
  248.    /* If we are not editing an existing string. */
  249.    else
  250.    {
  251.       /* Blank-out current string contents. */
  252.       pszCurrentInput[0] = '\0';
  253.  
  254.       /* Set cursor to beginning of string. */
  255.       nCursorPos = 0;
  256.    }
  257.  
  258.    /* Store original string, in case user cancels. */
  259.    strcpy(szCurrentOriginalString,pszCurrentInput);
  260.  
  261.    /* Set appropriate text color. */
  262.    od_set_attrib(btHighlightColour);
  263.  
  264.    /* Determine appropriate blank character */
  265.    chCurrentBlank = (nFlags & EDIT_FLAG_PASSWORD_MODE) ? ' ' : chBlank;
  266.  
  267.    /* Turn off insert mode if the strict input or permaliteral flags were */
  268.    /* specified.                                                          */
  269.    if((nFlags & EDIT_FLAG_STRICT_INPUT) || (nFlags & EDIT_FLAG_PERMALITERAL))
  270.    {
  271.       bInsertMode = FALSE;
  272.    }
  273.  
  274.    /* If the no-initial-redraw flag is not set, then do initial redraw. */
  275.    if(!(nFlags & EDIT_FLAG_NO_REDRAW))
  276.    {
  277.       /* Set to redraw position. */
  278.       od_set_cursor(nRow, nColumn);
  279.  
  280.       if(nFlags & EDIT_FLAG_PASSWORD_MODE)
  281.       {
  282.          /* If we are in password mode, then just draw password blanks. */
  283.          od_repeat(chBlank, (BYTE)strlen(pszCurrentInput));
  284.       }
  285.       else
  286.       {
  287.          /* Otherwise, display the actual string. */
  288.          od_disp_str(pszCurrentInput);
  289.       }
  290.  
  291.       if(nFlags & EDIT_FLAG_PERMALITERAL)
  292.       {
  293.          /* If we are in permaliteral mode, then fill the remaining edit */
  294.          /* field with the literal characters.                           */
  295.          ODEditDisplayPermaliteral(nFlags);
  296.       }
  297.       else
  298.       {
  299.          /* Otherwise, fill the remaining edit field with the blank */
  300.          /* character.                                              */
  301.          BYTE btRemaining
  302.             = (BYTE)(nCurrentStringLength - strlen(pszCurrentInput));
  303.          if(!(nFlags & EDIT_FLAG_SHOW_SIZE)) ++btRemaining;
  304.          od_repeat(chCurrentBlank, btRemaining);
  305.       }
  306.    }
  307.  
  308.    /* Claim exclusive use of arrow keys. */
  309.    ODStatStartArrowUse();
  310.  
  311.    /* Set the cursor to appropriate position. */
  312.    od_set_cursor(nRow, nColumn + nCursorPos);
  313.  
  314.    /* Normally, we start the input loop at the keep_going tag. */
  315.    if(bNormal) goto keep_going;
  316.  
  317.    for(;;)
  318.    {
  319.       /* If auto-accept mode has been specified ... */
  320.       if(nFlags & EDIT_FLAG_AUTO_ENTER)
  321.       {
  322.          /* ... then check whether we have reached the end of the string. */
  323.          if(strlen(pszCurrentInput) == nCurrentStringLength)
  324.          {
  325.             /* Indicate that input has been accepted, rather than cancelled. */
  326.             wToReturn = EDIT_RETURN_ACCEPT;
  327.  
  328.             /* Return the current string to the caller, if it is valid. */
  329.             goto try_to_accept;
  330.          }
  331.       }
  332.  
  333. keep_going:
  334.       /* Check whether we have reached a literal character in permaliteral */
  335.       /* mode. If so, we will move past the permanent literal characters   */
  336.       /* automatically.                                                    */
  337.       if((nFlags & EDIT_FLAG_PERMALITERAL)
  338.          && (nCursorPos < nCurrentStringLength))
  339.       {
  340.          if(abCurrentFormatLiteral[nCursorPos])
  341.          {
  342.             if(nCursorPos < strlen(pszCurrentInput))
  343.             {
  344.                goto pressed_right_arrow;
  345.             }
  346.             chTemp = pszCurrentFormat[anCurrentFormatOffset[nCursorPos]];
  347.             ++nKeysPressed;
  348.             goto try_this_character;
  349.          }
  350.       }
  351.  
  352. get_another_key:
  353.       /* Block, waiting for the next key pressed by the user. */
  354.  
  355.       od_get_input(&InputEvent, OD_NO_TIMEOUT, GETIN_NORMAL);
  356.       
  357.       /* Increment total number of keystrokes. */
  358.       ++nKeysPressed;
  359.  
  360.       if(InputEvent.EventType == EVENT_EXTENDED_KEY)
  361.       {
  362.          switch(InputEvent.chKeyPress)
  363.          {
  364.             case OD_KEY_UP:
  365.             case OD_KEY_SHIFTTAB:
  366.                if(nFlags & EDIT_FLAG_FIELD_MODE)
  367.                {
  368.                   wToReturn = EDIT_RETURN_PREVIOUS;
  369.                   goto try_to_accept;
  370.                }
  371.                break;
  372.  
  373.             case OD_KEY_DOWN:
  374. pressed_down_arrow:
  375.                if(nFlags & EDIT_FLAG_FIELD_MODE)
  376.                {
  377.                   wToReturn = EDIT_RETURN_NEXT;
  378.                   goto try_to_accept;
  379.                }
  380.                break;
  381.  
  382.             case OD_KEY_RIGHT:
  383. pressed_right_arrow:
  384.                /* If we are not at the end of the string. */
  385.                if(nCursorPos < strlen(pszCurrentInput))
  386.                {
  387.                   /* Move input position right. */
  388.                   nCursorPos++;
  389.  
  390.                   /* Move the cursor on screen. */
  391.                   od_set_cursor(nRow, nColumn + nCursorPos);
  392.                }
  393.                if(chAddAtEnd)
  394.                {
  395.                   chAddAtEnd = 0;
  396.                   goto add_another_key;
  397.                }
  398.                break;
  399.  
  400.             case OD_KEY_LEFT:
  401. pressed_left_arrow:
  402.                /* If we are not at the beginning of the string. */
  403.                if(nCursorPos > 0)
  404.                {
  405.                   /* Move input position left. */
  406.                   nCursorPos--;
  407.  
  408.                   /* Move cursor on screen. */
  409.                   od_set_cursor(nRow, nColumn + nCursorPos);
  410.                }
  411.  
  412.                /* If we are moving past a permanent literal character, */
  413.                /* then continue moving further left, if possible.      */
  414.                if((nFlags & EDIT_FLAG_PERMALITERAL)
  415.                   && abCurrentFormatLiteral[nCursorPos] && nCursorPos > 0)
  416.                {
  417.                   goto pressed_left_arrow;
  418.                }
  419.                break;
  420.  
  421.          case OD_KEY_HOME:
  422.             /* If we are not at the beginning of the string. */
  423.             if(nCursorPos != 0)
  424.             {
  425.                /* Move input position to the beginning of the string. */
  426.                nCursorPos = 0;
  427.  
  428.                /* Move the cursor on the screen. */
  429.                od_set_cursor(nRow, nColumn);
  430.             }
  431.             break;
  432.  
  433.          case OD_KEY_END:
  434.             /* If we are not at the end of the string .*/
  435.             if(nCursorPos != strlen(pszCurrentInput))
  436.             {
  437.                /* Set the input position to the end of the string. */
  438.                nCursorPos=strlen(pszCurrentInput);
  439.  
  440.                /* Move cursor on screen. */
  441.                od_set_cursor(nRow,nColumn+nCursorPos);
  442.             }
  443.             break;
  444.  
  445.          case OD_KEY_DELETE:
  446. pressed_delete:
  447.             /* Check whether delete key is permitted at this time. */
  448.             if(!(nFlags & EDIT_FLAG_STRICT_INPUT)
  449.                && nCursorPos < strlen(pszCurrentInput)
  450.                && !(nFlags & EDIT_FLAG_PERMALITERAL))
  451.             {
  452.                /* Move remaining line, if any, to the left */
  453.                chCurrentValue = strlen(pszCurrentInput) - 1;
  454.                for(nCount = nCursorPos; nCount < chCurrentValue; ++nCount)
  455.                {
  456.                   od_putch(
  457.                      pszCurrentInput[nCount] = pszCurrentInput[nCount + 1]);
  458.                }
  459.  
  460.                /* Erase the last character. */
  461.                pszCurrentInput[chCurrentValue] = '\0';  
  462.  
  463.                /* Blank out last character. */
  464.                od_putch(chCurrentBlank);
  465.  
  466.                /* Move the cursor on the screen. */
  467.                od_set_cursor(nRow, nColumn + nCursorPos);
  468.  
  469.                /* Update changes to string. */
  470.                goto check_cursor_char;
  471.             }
  472.             break;
  473.  
  474.          case OD_KEY_INSERT:
  475.             if(!(nFlags & EDIT_FLAG_STRICT_INPUT)
  476.                && !(nFlags & EDIT_FLAG_PERMALITERAL))
  477.             {
  478.                /* Toggle insert setting. */
  479.                bInsertMode = !bInsertMode;
  480.             }
  481.             break;
  482.  
  483.          }
  484.       }
  485.       else if(InputEvent.EventType == EVENT_CHARACTER)
  486.       {
  487.          chTemp = InputEvent.chKeyPress;
  488. try_this_character:
  489.  
  490.          if(chTemp == 27)
  491.          {
  492.             /* If cancel key is allowed ... */
  493.             if(nFlags & EDIT_FLAG_ALLOW_CANCEL)
  494.             {
  495.                /* Reset the input string to the original contents. */
  496.                strcpy(pszCurrentInput, szCurrentOriginalString);
  497.  
  498.                /* Indicate that return reason was due to user cancelling. */
  499.                wToReturn = EDIT_RETURN_CANCEL;
  500.  
  501.                /* Return after redrawing the original string in the input */
  502.                /* field.                                                  */
  503.                goto exit_and_redraw;
  504.             }
  505.          }
  506.  
  507.  
  508.          /* If user pressed [Enter] or [Ctrl]-[Z]. */
  509.          else if(chTemp == 13 || chTemp == 26)
  510.          {
  511.             /* User has accepted input. */
  512.             wToReturn = EDIT_RETURN_ACCEPT;
  513.  
  514.             /* Return if input string is valid. */
  515.             goto try_to_accept;
  516.          }
  517.  
  518.          /* If the backspace key has been pressed. */
  519.          else if(chTemp == 8)
  520.          {
  521.    backspace_again:
  522.             /* If we are not already at the beginning of the string. */
  523.             if(nCursorPos > 0)
  524.             {
  525.                if(nFlags & EDIT_FLAG_PERMALITERAL)
  526.                {
  527.                   for(nCount = 0;nCount < nCursorPos; ++nCount)
  528.                   {
  529.                      if(!abCurrentFormatLiteral[nCount]) goto continue_deletion;
  530.                   }
  531.                   goto get_another_key;
  532.                }
  533.  
  534.    continue_deletion:
  535.                /* If we are at the end of the string. */
  536.                if(nCursorPos == strlen(pszCurrentInput))
  537.                {
  538.                   /* Erase last char in string. */
  539.                   pszCurrentInput[--nCursorPos] = '\0';
  540.  
  541.                   if((nFlags & EDIT_FLAG_PERMALITERAL)
  542.                      && abCurrentFormatLiteral[nCursorPos])
  543.                   {
  544.                      goto backspace_again;
  545.                   }
  546.                   else
  547.                   {
  548.                      /* Move to new cursor pos. */
  549.                      od_set_cursor(nRow,nColumn+nCursorPos);
  550.  
  551.                      /* Blank old character. */
  552.                      od_putch(chCurrentBlank);
  553.  
  554.                      /* Move again to cursor pos. */
  555.                      od_set_cursor(nRow,nColumn+nCursorPos);
  556.                   }
  557.                }
  558.  
  559.                /* If we are in the middle of the string and we are not in */
  560.                /* string input mode.                                      */
  561.                else if(!(nFlags & EDIT_FLAG_STRICT_INPUT)
  562.                   && !(nFlags & EDIT_FLAG_PERMALITERAL))
  563.                {
  564.                   /* Move cursor left. */
  565.                   --nCursorPos;
  566.  
  567.                   /* Move cursor on screen. */
  568.                   od_set_cursor(nRow, nColumn + nCursorPos);
  569.  
  570.                   /* Goto standard delete handler. */
  571.                   goto pressed_delete;
  572.                }
  573.             }
  574.          }
  575.  
  576.          /* If this is a next field request. */
  577.          else if(chTemp == 9)
  578.          {
  579.             /* Goto down arrow handler. */
  580.             goto pressed_down_arrow;
  581.          }
  582.  
  583.          /* If Control-Y. */
  584.          else if(chTemp == 25)
  585.          {
  586.             /* Erase entire contents of line. */
  587.             goto kill_whole_line;
  588.          }
  589.  
  590.          else
  591.          {
  592.             /* If this is the first key pressed, and we are in autodelete mode. */
  593.             if(nKeysPressed == 1 && (nFlags & EDIT_FLAG_AUTO_DELETE))
  594.             {
  595.    kill_whole_line:
  596.                /* If string is not empty. */
  597.                if(strlen(pszCurrentInput) != 0)
  598.                {
  599.                   /* Move to beginning of string. */
  600.                   od_set_cursor(nRow,nColumn);
  601.  
  602.                   /* Blank out the entire string contents. */
  603.                   od_repeat(chCurrentBlank, (BYTE)strlen(pszCurrentInput));
  604.                }
  605.  
  606.                /* Move to new cursor position. */
  607.                od_set_cursor(nRow,nColumn);
  608.  
  609.                /* Update insert position. */
  610.                nCursorPos = 0;
  611.  
  612.                /* Blank out the current string contents. */
  613.                pszCurrentInput[0] = '\0';
  614.             }
  615.  
  616.    add_another_key:
  617.             if(!ODEditIsCharValidForPos(chTemp,nCursorPos))
  618.             {
  619.                /* If character is not a valid input char. */
  620.                if(abCurrentFormatLiteral[nCursorPos])
  621.                {
  622.                   if(nCursorPos < strlen(pszCurrentInput))
  623.                   {
  624.                      if(pszCurrentInput[nCursorPos] == 
  625.                         pszCurrentFormat[anCurrentFormatOffset[nCursorPos]])
  626.                      {
  627.                         chAddAtEnd = chTemp;
  628.                         goto pressed_right_arrow;
  629.                      }
  630.                   }
  631.                   chAddAtEnd = chTemp;
  632.                   chTemp = pszCurrentFormat[anCurrentFormatOffset[nCursorPos]];
  633.                }
  634.                else
  635.                {
  636.                   continue;
  637.                }
  638.             }
  639.  
  640.             /* Convert character to correct value, if applicable. */
  641.             chTemp = ODEditAsCharForPos(chTemp, nCursorPos);
  642.  
  643.             /* If we are at end of string. */
  644.             if(nCursorPos >= strlen(pszCurrentInput))
  645.             {
  646.                /* Reset original cursor position */
  647.                nCursorPos = strlen(pszCurrentInput);
  648.  
  649.                /* If there is room to add a char. */
  650.                if(nCursorPos < nCurrentStringLength)
  651.                {
  652.                   /* If password mode */
  653.                   if(nFlags & EDIT_FLAG_PASSWORD_MODE)
  654.                   {
  655.                      /* Display the password character. */
  656.                      od_putch(chBlank);
  657.                   }
  658.                   /* If not in password mode. */
  659.                   else
  660.                   {
  661.                      /* Display the character. */
  662.                      od_putch(chTemp);
  663.                   }
  664.  
  665.                   /* Store the character. */
  666.                   pszCurrentInput[nCursorPos] = chTemp;
  667.  
  668.                   /* Add a new string terminator. */
  669.                   pszCurrentInput[++nCursorPos] = '\0';
  670.                }
  671.             }
  672.  
  673.             /* If in insert mode, but not at end of string. */
  674.             else if(bInsertMode)
  675.             {
  676.                /* If room in string. */
  677.                if(strlen(pszCurrentInput) < nCurrentStringLength)
  678.                {
  679.                   /* If in password mode. */
  680.                   if(nFlags & EDIT_FLAG_PASSWORD_MODE)
  681.                   {
  682.                      /* Move to end. */
  683.                      od_set_cursor(nRow,nColumn+strlen(pszCurrentInput));
  684.  
  685.                      /* Add another password character. */
  686.                      od_putch(chBlank);
  687.                   }
  688.  
  689.                   /* If not in password mode. */
  690.                   else
  691.                   {
  692.                      /* Display the new character. */
  693.                      od_putch(chTemp);
  694.  
  695.                      /* Loop through rest of string. */
  696.                      for(nCount = nCursorPos; nCount < strlen(pszCurrentInput);
  697.                         ++nCount)
  698.                      {
  699.                         /* Display the next remaining character. */
  700.                         od_putch(pszCurrentInput[nCount]);
  701.                      }
  702.                   }
  703.  
  704.                   pszCurrentInput[(strlen(pszCurrentInput) + 1)] = '\0';
  705.  
  706.                   /* Sift remaining characters forward. */
  707.                   for(nCount = strlen(pszCurrentInput); nCount > nCursorPos;
  708.                      --nCount)
  709.                   {                     
  710.                      pszCurrentInput[nCount] = pszCurrentInput[nCount-1];
  711.                   }
  712.  
  713.                   /* Add new char in space. */
  714.                   pszCurrentInput[nCursorPos++] = chTemp;
  715.  
  716.                   /* Move to new cursor position. */
  717.                   od_set_cursor(nRow, nColumn + nCursorPos);
  718.                }
  719.                else
  720.                {
  721.                   goto get_another_key;
  722.                }
  723.             }
  724.  
  725.             /* If we are in overwrite mode, but not at end of string. */
  726.             else
  727.             {
  728.                /* If password mode. */
  729.                if(nFlags & EDIT_FLAG_PASSWORD_MODE)
  730.                {
  731.                   /* Display the password character. */
  732.                   od_putch(chBlank);
  733.                }
  734.                /* If not in password mode. */
  735.                else
  736.                {
  737.                   /* Display the character. */
  738.                   od_putch(chTemp);
  739.                }
  740.  
  741.                /* Add character to string. */
  742.                pszCurrentInput[nCursorPos++] = chTemp;
  743.             }
  744.  
  745.             /* If not at end of possible string. */
  746.             if(nCursorPos < nCurrentStringLength)
  747.             {
  748.                /* If the next character is literal constant. */
  749.                if(abCurrentFormatLiteral[nCursorPos])
  750.                {
  751.                   chTemp = pszCurrentFormat[anCurrentFormatOffset[nCursorPos]];
  752.                   goto add_another_key;
  753.                }
  754.             }
  755.  
  756.             if(chAddAtEnd)
  757.             {
  758.                chTemp = chAddAtEnd;
  759.                chAddAtEnd = 0;
  760.                goto add_another_key;
  761.             }
  762.  
  763.  
  764.    check_cursor_char:
  765.             /* If there is a character under cursor. */
  766.             if(nCursorPos < strlen(pszCurrentInput))
  767.             {
  768.                /* If character corresponds to the format string. */
  769.                if(ODEditIsCharValidForPos(pszCurrentInput[nCursorPos],
  770.                   nCursorPos))
  771.                {
  772.                   /* Determine correct character for this position. */
  773.                   chTemp = ODEditAsCharForPos(pszCurrentInput[nCursorPos],
  774.                      nCursorPos);
  775.  
  776.                   /* If actual character is not correct. */
  777.                   if(chTemp != pszCurrentInput[nCursorPos])
  778.                   {                        
  779.                      /* Change character to correct value. */
  780.                      pszCurrentInput[nCursorPos] = chTemp;
  781.  
  782.                      /* If password mode. */
  783.                      if(nFlags & EDIT_FLAG_PASSWORD_MODE)
  784.                      {
  785.                         /* Display the password character. */
  786.                         od_putch(chBlank);
  787.                      }
  788.  
  789.                      /* If not in password mode. */
  790.                      else
  791.                      {
  792.                         /* Display the character. */
  793.                         od_putch(chTemp);
  794.                      }
  795.  
  796.                      /* Reset cursor position. */
  797.                      od_set_cursor(nRow, nColumn + nCursorPos);
  798.                   }
  799.                }
  800.             }
  801.          }
  802.       }
  803.    }
  804.  
  805.    /* Accept string if it is valid. */
  806. try_to_accept:
  807.    /* If string must be filled. */
  808.    if(nFlags & EDIT_FLAG_FILL_STRING)
  809.    {
  810.       /* If string is not filled, don't return. */
  811.       if(strlen(pszCurrentInput) != nCurrentStringLength) goto keep_going;
  812.    }
  813.  
  814.    /* Loop through string .... */
  815.    for(nCount = 0; nCount < strlen(pszCurrentInput); ++nCount)
  816.    {
  817.       /* ... testing each character for validity. */
  818.       if(!ODEditIsCharValidForPos(pszCurrentInput[nCount], nCount))
  819.          goto keep_going;
  820.    }
  821.  
  822.    /* Initially, assume that the string has not been changed. */
  823.    chCurrentValue = FALSE;
  824.  
  825.    /* Loop through the string. */
  826.    for(nCount = 0; nCount < strlen(pszCurrentInput); ++nCount)
  827.    {
  828.       /* Find correct value for each character. */
  829.       chTemp = ODEditAsCharForPos(pszCurrentInput[nCount], nCount);
  830.  
  831.       /* If character is not correct. */
  832.       if(chTemp != pszCurrentInput[nCount])           
  833.       {
  834.          /* Change char to correct value */
  835.          pszCurrentInput[nCount] = chTemp;
  836.  
  837.          /* Remember that string has been changed. */
  838.          chCurrentValue = TRUE;
  839.       }
  840.    }
  841.  
  842.    /* If permaliteral mode. */
  843.    if(nFlags & EDIT_FLAG_LEAVE_BLANK)
  844.    {
  845.       /* Count # of literal characters. */
  846.       nCount = 0;
  847.       while(nCount<strlen(pszCurrentInput))
  848.       {
  849.          if(abCurrentFormatLiteral[nCount])
  850.          {
  851.             ++nCount;
  852.          }
  853.          else
  854.          {
  855.             break;
  856.          }
  857.       }
  858.  
  859.       /* If only literals in string. */
  860.       if(strlen(pszCurrentInput) == nCount && nCount > 0)
  861.       {
  862.          /* Then they shouldn't be here. */
  863.          pszCurrentInput[0] = '\0';
  864.          goto exit_and_redraw;
  865.       }
  866.    }
  867.  
  868.    /* Always redraw if string was changed. */
  869.    if(chCurrentValue) goto exit_and_redraw;
  870.  
  871.    /* If no-redraw flag not set. */
  872.    if(!(nFlags & EDIT_FLAG_NO_REDRAW))
  873.    {
  874. exit_and_redraw:
  875.       /* Set appropriate text colour. */
  876.       od_set_attrib(btNormalColour);
  877.  
  878.       /* Set to redraw position. */
  879.       od_set_cursor(nRow,nColumn);
  880.  
  881.       /* If password mode. */
  882.       if(nFlags & EDIT_FLAG_PASSWORD_MODE)
  883.       {
  884.          /* Display blanked-out string. */
  885.          od_repeat(chBlank, (BYTE)strlen(pszCurrentInput));
  886.       }
  887.       else
  888.       {
  889.          /* Display actual string. */
  890.          od_disp_str(pszCurrentInput);
  891.       }
  892.  
  893.       /* If we should keep the background. */
  894.       if(nFlags & EDIT_FLAG_KEEP_BLANK)
  895.       {
  896.          /* Then redraw background. */
  897.          if(nFlags & EDIT_FLAG_PERMALITERAL)
  898.          {
  899.             ODEditDisplayPermaliteral(nFlags);
  900.          }
  901.          else
  902.          {
  903.             od_repeat(chCurrentBlank,
  904.                (BYTE)(nCurrentStringLength - strlen(pszCurrentInput) + 1));
  905.          }
  906.       }
  907.       /* If we should erase the background ... */
  908.       else
  909.       {
  910.          /* ... then do it. */
  911.          od_repeat(' ',
  912.             (BYTE)(nCurrentStringLength - strlen(pszCurrentInput) + 1));
  913.       }
  914.    }
  915.  
  916.    /* Release exclusive use of arrow keys. */
  917.    ODStatEndArrowUse();
  918.  
  919.    /* Return with appropriate return value. */
  920.    OD_API_EXIT();
  921.    return(wToReturn);
  922. }
  923.  
  924.  
  925.  
  926. /* ----------------------------------------------------------------------------
  927.  * ODEditIsCharValidForPos()                           *** PRIVATE FUNCTION ***
  928.  *
  929.  * Determines whether or not the entered character can be accepted as a valid
  930.  * character (after any possible conversion by ODEditAsCharForPos() is applied)
  931.  * for the specified position in the string.
  932.  *
  933.  * Parameters: chEntered   - The character entered by the user.
  934.  *
  935.  *             nPosition   - The position in the string where this character
  936.  *                           would be inserted.
  937.  *
  938.  *     Return: TRUE if this character should be accepted, FALSE if not.
  939.  */
  940. static BOOL ODEditIsCharValidForPos(char chEntered, INT nPosition)
  941. {
  942.    /* If this character is a literal. */
  943.    if(abCurrentFormatLiteral[nPosition])
  944.    {                                     
  945.       /* Check required literal character. */
  946.       if(chEntered != pszCurrentFormat[anCurrentFormatOffset[nPosition]])
  947.       {                                          
  948.          /* If this is not the correct literal character, then do not */
  949.          /* permit it to be entered in this position. */
  950.          return(FALSE);
  951.       }
  952.       return(TRUE);
  953.    }
  954.  
  955.    /* If this position has a corresponding format control character, */
  956.    /* then check that control character. The execution path will     */
  957.    /* continue out of this switch statement (rather than returning   */
  958.    /* to the calling function) if and only if the entered character  */
  959.    /* is valid for the format character specified.                   */
  960.    switch(pszCurrentFormat[anCurrentFormatOffset[nPosition]])
  961.    {
  962.       /* Only numerical characters are to be permitted. */
  963.       case '#':
  964.          if(chEntered < '0' || chEntered > '9') return(FALSE);
  965.          break;
  966.  
  967.       /* Only numerical and space characters are to be permitted. */
  968.       case '%':
  969.          if((chEntered < '0' || chEntered > '9') && chEntered != ' ')
  970.          {
  971.             return(FALSE);
  972.          }
  973.          break;
  974.  
  975.       /* Only floating point number characters are to be permitted. */
  976.       case '9':
  977.          if(chEntered >= '0' && chEntered <= '9') break;
  978.          if(chEntered == '.' || chEntered == '+' || chEntered == '-') break;
  979.          return(FALSE);
  980.  
  981.       /* Only "printable" characters are to be permitted. */
  982.       case '*':
  983.          if(chEntered < 32) return(FALSE);
  984.          break;
  985.  
  986.       /* City name characters are to be permitted. */
  987.       case 'C':
  988.       case 'c':
  989.          if(chEntered >= 'A' && chEntered <= 'Z') break;
  990.          if(chEntered >= 'a' && chEntered <= 'z') break;
  991.          if(chEntered == ' ' || chEntered == ',' || chEntered == '.') break;
  992.          if(chEntered == '*' || chEntered == '?') break;
  993.          return(FALSE);
  994.  
  995.       /* If only alphabetic characters are to be permitted. */
  996.       case 'A':
  997.       case 'a':
  998.       case 'L':
  999.       case 'l':
  1000.       case 'M':
  1001.       case 'm':
  1002.       case 'U':
  1003.       case 'u':
  1004.          if(chEntered>='A' && chEntered<='Z') break;
  1005.          if(chEntered>='a' && chEntered<='z') break;
  1006.          if(chEntered==' ') break;
  1007.          return(FALSE);
  1008.  
  1009.       /* If only date characters are to be permitted. */
  1010.       case 'D':
  1011.       case 'd':
  1012.          if(chEntered>='0' && chEntered<='9') break;
  1013.          if(chEntered=='-' || chEntered=='/') break;
  1014.          return(FALSE);
  1015.  
  1016.       /* If only MS-DOS filename characters are to be permitted. */
  1017.       case 'F':
  1018.       case 'f':
  1019.          if(chEntered >= 'A' && chEntered <= 'Z') break;
  1020.          if(chEntered >= '0' && chEntered <= '9') break;
  1021.          if(chEntered >= 'a' && chEntered <= 'z') break;
  1022.          switch(chEntered)
  1023.          {
  1024.             /* Filename separators. */
  1025.             case ':':
  1026.             case '.':
  1027.             case '\\':
  1028.  
  1029.             /* Wildcard characters. */
  1030.             case '?':
  1031.             case '*':
  1032.  
  1033.             /* Other valid symbols in filenames */
  1034.             case '#':
  1035.             case '$':
  1036.             case '&':
  1037.             case '\'':
  1038.             case '(':
  1039.             case '>':
  1040.             case '-':
  1041.             case '@':
  1042.             case '_':
  1043.             case '!':
  1044.             case '{':
  1045.             case '}':
  1046.             case '~':
  1047.                return(TRUE);
  1048.          }
  1049.  
  1050.          return(FALSE);
  1051.  
  1052.       /* If only hexidecimal characters are to be permitted. */
  1053.       case 'H':
  1054.       case 'h':
  1055.          if(chEntered>='0' && chEntered<='9') break;
  1056.          if(chEntered>='A' && chEntered<='F') break;
  1057.          if(chEntered>='a' && chEntered<='f') break;
  1058.          return(FALSE);
  1059.  
  1060.       /* If only telephone number characters are to be permitted. */
  1061.       case 'T':                                          
  1062.       case 't':
  1063.          if(chEntered >= '0' && chEntered <= '9') break;
  1064.          if(chEntered == '-' || chEntered == '(' || chEntered == ')'
  1065.             || chEntered == ' ' || chEntered == '+')
  1066.          {
  1067.             break;
  1068.          }
  1069.          return(FALSE);
  1070.  
  1071.       /* If filenames with wildcards are to be permitted. */
  1072.       case 'W':
  1073.       case 'w':
  1074.          if(chEntered >= 'A' && chEntered <= 'Z') break;
  1075.          if(chEntered >= 'a' && chEntered <= 'z') break;
  1076.          if(chEntered == ':' || chEntered == '.' || chEntered == '\\'
  1077.             || chEntered == '*' || chEntered == '?')
  1078.          {
  1079.             break;
  1080.          }
  1081.          return(FALSE);
  1082.  
  1083.       /* If alpha-numeric characters are to be permitted. */
  1084.       case 'X':
  1085.       case 'x':
  1086.          if(chEntered >= 'A' && chEntered <= 'Z') break;
  1087.          if(chEntered >= 'a' && chEntered <= 'z') break;
  1088.          if(chEntered >= '0' && chEntered <= '9') break;
  1089.          if(chEntered == ' ') break;
  1090.          return(FALSE);
  1091.  
  1092.       /* If this is a Yes/No field. */
  1093.       case 'Y':
  1094.       case 'y':
  1095.          if(chEntered == 'y' || chEntered == 'n' || chEntered == 'Y'
  1096.             || chEntered == 'N')
  1097.          {
  1098.             break;
  1099.          }
  1100.          return(FALSE);
  1101.    }
  1102.  
  1103.    /* If execution gets to this point, then the character has been approved. */
  1104.    return(TRUE);
  1105. }
  1106.  
  1107.  
  1108.  
  1109. /* ----------------------------------------------------------------------------
  1110.  * ODEditAsCharForPos()                                *** PRIVATE FUNCTION ***
  1111.  *
  1112.  * Converts the character entered by the user to a valid character for this
  1113.  * position in the string. For example, for fields that are set to all
  1114.  * upper case, this function converts the entered characte to its upper case
  1115.  * equivalent.
  1116.  *
  1117.  * Parameters: chEntered   - Character that was entered by the user.
  1118.  *
  1119.  *             nPosition   - Position in the string where the character is to
  1120.  *                           be entered.
  1121.  *
  1122.  *     Return: The actual character to add to the input string at this
  1123.  *             position.
  1124.  */
  1125. static char ODEditAsCharForPos(char chEntered, INT nPosition)
  1126. {
  1127.    /* If this character is a literal. */
  1128.    if(abCurrentFormatLiteral[nPosition])
  1129.    {                                      
  1130.       /* Return the only valid char for this position. */
  1131.       return(pszCurrentFormat[anCurrentFormatOffset[nPosition]]);
  1132.    }
  1133.  
  1134.    /* If this position has a corresponding format control character, */
  1135.    /* then check that control character. */
  1136.    switch(pszCurrentFormat[anCurrentFormatOffset[nPosition]])
  1137.    {
  1138.       /* If Yes/No characters are required. */
  1139.       case 'Y':
  1140.       case 'y':
  1141.          return(toupper(chEntered));
  1142.  
  1143.       /* If filename characters are required. */
  1144.       case 'F':                                       
  1145.       case 'f':
  1146.          return(toupper(chEntered));
  1147.  
  1148.       /* If lower case characters are required. */
  1149.       case 'L':
  1150.       case 'l':
  1151.          return(tolower(chEntered));
  1152.  
  1153.       /* If upper case characters are required. */
  1154.       case 'U':
  1155.       case 'u':
  1156.          return(toupper(chEntered));
  1157.  
  1158.       /* If automatic capitalization is required. */
  1159.       case 'M':
  1160.       case 'm':
  1161.       case 'C':
  1162.       case 'c':
  1163.          /* First character is always upper case. */
  1164.          if(nPosition == 0) return(toupper(chEntered));
  1165.  
  1166.          /* Check for other base cases. */
  1167.          if(abCurrentFormatLiteral[nPosition-1]) return(toupper(chEntered));
  1168.          if(toupper(pszCurrentFormat[anCurrentFormatOffset[nPosition]]) != 'M'
  1169.             && toupper(pszCurrentFormat[anCurrentFormatOffset[nPosition]])
  1170.             != 'C')
  1171.          {
  1172.             return(toupper(chEntered));
  1173.          }
  1174.  
  1175.          /* If previous character is a word delimiter, then this character */
  1176.          /* should be uppper case.                                         */
  1177.          if(pszCurrentInput[nPosition-1] == ' '
  1178.             || pszCurrentInput[nPosition-1] == '.'
  1179.             || pszCurrentInput[nPosition-1] == ','
  1180.             || pszCurrentInput[nPosition-1] == '-')
  1181.          {
  1182.             return(toupper(chEntered));                                             /* Otherwise, this should be lower */
  1183.          }
  1184.  
  1185.          /* Otherwise, this character should be lower-case. */
  1186.          return(tolower(chEntered));
  1187.    }
  1188.  
  1189.    return(chEntered);
  1190. }
  1191.  
  1192.  
  1193. /* ----------------------------------------------------------------------------
  1194.  * ODEditDisplayPermaliteral()                         *** PRIVATE FUNCTION ***
  1195.  *
  1196.  * Displays permaliterals (characters specified in the format string that
  1197.  * should be returned in the input string, but which the user may never
  1198.  * change).
  1199.  *
  1200.  * Parameters: nFlags - Flags parameter that was passed into od_edit_str().
  1201.  *
  1202.  *     Return: void
  1203.  */
  1204. static void ODEditDisplayPermaliteral(WORD nFlags)
  1205. {
  1206.    INT nCount;
  1207.    BYTE btRepeat = 0;
  1208.  
  1209.    for(nCount = strlen(pszCurrentInput); nCount <= nCurrentStringLength;
  1210.       ++nCount)
  1211.    {
  1212.       if(nCount != nCurrentStringLength)
  1213.       {
  1214.          if(abCurrentFormatLiteral[nCount])
  1215.          {
  1216.             if(btRepeat > 0)
  1217.             {
  1218.                od_repeat(chCurrentBlank, btRepeat);
  1219.                btRepeat = 0;
  1220.             }
  1221.             od_putch(pszCurrentFormat[anCurrentFormatOffset[nCount]]);
  1222.          }
  1223.          else
  1224.          {
  1225.             ++btRepeat;
  1226.          }
  1227.       }
  1228.       else
  1229.       {
  1230.          if(!(nFlags & EDIT_FLAG_SHOW_SIZE))
  1231.          {
  1232.             ++btRepeat;
  1233.          }
  1234.       }
  1235.    }
  1236.  
  1237.    if(btRepeat > 0) od_repeat(chCurrentBlank, btRepeat);
  1238. }
  1239.