ODEdStr.c 39 KB

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