Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1028 lines
20 KiB

  1. /********************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1987-1990 **/
  4. /********************************************************************/
  5. /***
  6. * mutil.c
  7. * Message utility functions used by netcmd
  8. *
  9. * History:
  10. * mm/dd/yy, who, comment
  11. * 06/10/87, andyh, new code
  12. * 04/05/88, andyh, created from util.c
  13. * 10/31/88, erichn, uses OS2.H instead of DOSCALLS
  14. * 01/04/89, erichn, filenames now MAX_PATH_LEN LONG
  15. * 01/30/89, paulc, added GetMessageList
  16. * 05/02/89, erichn, NLS conversion
  17. * 05/11/89, erichn, moved misc stuff into LUI libs
  18. * 06/08/89, erichn, canonicalization sweep
  19. * 01/06/90, thomaspa, fix ReadPass off-by-one pwlen bug
  20. * 03/02/90, thomaspa, add canon flag to ReadPass
  21. * 02/20/91, danhi, change to use lm 16/32 mapping layer
  22. * 03/19/91, robdu, support for lm21 dcr 954, general cleanup
  23. */
  24. /* Include files */
  25. #define INCL_NOCOMMON
  26. #define INCL_DOSFILEMGR
  27. #define INCL_DOSQUEUES
  28. #define INCL_DOSMISC
  29. #define INCL_ERRORS
  30. #include <os2.h>
  31. #include <lmcons.h>
  32. #include <apperr.h>
  33. #include <apperr2.h>
  34. #define INCL_ERROR_H
  35. #include <lmerr.h>
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <lui.h>
  39. #include "netcmds.h"
  40. #include "nettext.h"
  41. #include "msystem.h"
  42. /* Constants */
  43. /* HandType */
  44. #define FILE_HANDLE 0
  45. #define DEVICE_HANDLE 1
  46. #define CHAR_DEV 0x8000
  47. #define FULL_SUPPORT 0x0080
  48. #define STDOUT_DEVICE 0x0002
  49. #define DESIRED_HAND_STATE (CHAR_DEV | FULL_SUPPORT | STDOUT_DEVICE)
  50. /* External variables */
  51. extern int YorN_Switch;
  52. extern CPINFO CurrentCPInfo;
  53. #define MAX_BUF_SIZE 4096
  54. TCHAR ConBuf [MAX_BUF_SIZE];
  55. /* Forward declarations */
  56. DWORD
  57. DosQHandType(
  58. HANDLE hf,
  59. PWORD pus1,
  60. PWORD pus2
  61. );
  62. DWORD
  63. GetPasswdStr(
  64. LPTSTR buf,
  65. DWORD buflen,
  66. PDWORD len
  67. );
  68. /* Static variables */
  69. static DWORD LastError = 0;
  70. static TCHAR MsgBuffer[LITTLE_BUF_SIZE];
  71. /*** InfoSuccess
  72. *
  73. * Just an entrypoint to InfoPrintInsHandle, used to avoid pushing
  74. * the three args in every invocation. And there are a *lot*
  75. * of invocations. Saves code space overall.
  76. */
  77. VOID FASTCALL
  78. InfoSuccess(
  79. VOID
  80. )
  81. {
  82. InfoPrintInsHandle(APE_Success, 0, g_hStdOut);
  83. }
  84. /***
  85. * I n f o P r i n t
  86. *
  87. */
  88. VOID FASTCALL
  89. InfoPrint(
  90. DWORD msg
  91. )
  92. {
  93. InfoPrintInsHandle(msg, 0, g_hStdOut);
  94. }
  95. /***
  96. * I n f o P r i n t I n s
  97. *
  98. */
  99. VOID FASTCALL
  100. InfoPrintIns(
  101. DWORD msg,
  102. DWORD nstrings
  103. )
  104. {
  105. InfoPrintInsHandle(msg, nstrings, g_hStdOut);
  106. }
  107. /***
  108. * I n f o P r i n t I n s T x t
  109. *
  110. * Calls InfoPrintInsHandle with supplementary text
  111. */
  112. void FASTCALL
  113. InfoPrintInsTxt(
  114. DWORD msg,
  115. LPTSTR text
  116. )
  117. {
  118. IStrings[0] = text;
  119. InfoPrintInsHandle(msg, 1, g_hStdOut);
  120. }
  121. /***
  122. * I n f o P r i n t I n s H a n d l e
  123. *
  124. */
  125. void FASTCALL
  126. InfoPrintInsHandle(
  127. DWORD msg,
  128. DWORD nstrings,
  129. HANDLE hdl
  130. )
  131. {
  132. PrintMessage(hdl, MESSAGE_FILENAME, msg, IStrings, nstrings);
  133. }
  134. /***
  135. * P r i n t M e s s a g e
  136. *
  137. */
  138. DWORD FASTCALL
  139. PrintMessage(
  140. HANDLE outFileHandle,
  141. TCHAR *msgFileName,
  142. DWORD msg,
  143. TCHAR *strings[],
  144. DWORD nstrings
  145. )
  146. {
  147. DWORD msg_len;
  148. DWORD result;
  149. result = DosGetMessageW(strings,
  150. nstrings,
  151. MsgBuffer,
  152. LITTLE_BUF_SIZE,
  153. msg,
  154. msgFileName,
  155. &msg_len);
  156. if (result) /* if there was a problem */
  157. { /* change outFile to stderr */
  158. outFileHandle = g_hStdErr;
  159. }
  160. DosPutMessageW(outFileHandle, MsgBuffer, TRUE);
  161. return result;
  162. }
  163. /***
  164. * P r i n t M e s s a g e I f F o u n d
  165. *
  166. */
  167. DWORD FASTCALL
  168. PrintMessageIfFound(
  169. HANDLE outFileHandle,
  170. TCHAR *msgFileName,
  171. DWORD msg,
  172. TCHAR * strings[],
  173. DWORD nstrings
  174. )
  175. {
  176. DWORD msg_len;
  177. DWORD result;
  178. result = DosGetMessageW(strings,
  179. nstrings,
  180. MsgBuffer,
  181. LITTLE_BUF_SIZE,
  182. msg,
  183. msgFileName,
  184. &msg_len);
  185. if (!result) /* if ok, print it else just ignore */
  186. {
  187. DosPutMessageW(outFileHandle, MsgBuffer, TRUE);
  188. }
  189. return result;
  190. }
  191. /***
  192. * E r r o r P r i n t
  193. *
  194. * nstrings ignored for non-NET errors!
  195. *
  196. */
  197. VOID FASTCALL
  198. ErrorPrint(
  199. DWORD err,
  200. DWORD nstrings
  201. )
  202. {
  203. TCHAR buf[17];
  204. DWORD oserr = 0;
  205. LastError = err; /* if > NERR_BASE,NetcmdExit() prints a "more help" msg */
  206. if (err < NERR_BASE || err > MAX_LANMAN_MESSAGE_ID)
  207. {
  208. IStrings[0] = _ultow(err, buf, 10);
  209. nstrings = 1;
  210. oserr = err;
  211. err = APE_OS2Error;
  212. }
  213. {
  214. DWORD msg_len;
  215. DosGetMessageW(IStrings,
  216. nstrings,
  217. MsgBuffer,
  218. LITTLE_BUF_SIZE,
  219. err,
  220. MESSAGE_FILENAME,
  221. &msg_len);
  222. DosPutMessageW(g_hStdErr, MsgBuffer, TRUE);
  223. if (!oserr)
  224. {
  225. return;
  226. }
  227. DosGetMessageW(StarStrings,
  228. 9,
  229. MsgBuffer,
  230. LITTLE_BUF_SIZE,
  231. oserr,
  232. OS2MSG_FILENAME,
  233. &msg_len);
  234. DosPutMessageW(g_hStdErr, MsgBuffer, TRUE);
  235. }
  236. }
  237. /***
  238. * E m p t y E x i t
  239. *
  240. * Prints a message and exits.
  241. * Called when a list is empty.
  242. */
  243. VOID FASTCALL
  244. EmptyExit(
  245. VOID
  246. )
  247. {
  248. InfoPrint(APE_EmptyList);
  249. NetcmdExit(0);
  250. }
  251. /***
  252. * E r r o r E x i t
  253. *
  254. * Calls ErrorPrint and exit for a given LANMAN error.
  255. */
  256. VOID FASTCALL
  257. ErrorExit(
  258. DWORD err
  259. )
  260. {
  261. ErrorExitIns(err, 0);
  262. }
  263. /***
  264. * E r r o r E x i t I n s
  265. *
  266. * Calls ErrorPrint and exit for a given LANMAN error.
  267. * Uses IStrings.
  268. */
  269. VOID FASTCALL
  270. ErrorExitIns(
  271. DWORD err,
  272. DWORD nstrings
  273. )
  274. {
  275. ErrorPrint(err, nstrings);
  276. NetcmdExit(2);
  277. }
  278. /***
  279. * E r r o r E x i t I n s T x t
  280. *
  281. */
  282. VOID FASTCALL
  283. ErrorExitInsTxt(
  284. DWORD err,
  285. LPTSTR text
  286. )
  287. {
  288. IStrings[0] = text;
  289. ErrorPrint(err, 1);
  290. NetcmdExit(2);
  291. }
  292. /***
  293. * N e t c m d E x i t
  294. *
  295. * Net command exit function. Should always be used instead of exit().
  296. * Under the appropriate circumstances, it prints a "more help available"
  297. * message.
  298. */
  299. VOID FASTCALL
  300. NetcmdExit(
  301. int Status
  302. )
  303. {
  304. TCHAR AsciiLastError[17];
  305. DWORD MsgLen;
  306. if (LastError >= NERR_BASE && LastError <= MAX_LANMAN_MESSAGE_ID)
  307. {
  308. IStrings[0] = _ultow(LastError, AsciiLastError, 10);
  309. if (!DosGetMessageW(IStrings, 1, MsgBuffer, LITTLE_BUF_SIZE,
  310. APE_MoreHelp, MESSAGE_FILENAME, &MsgLen))
  311. {
  312. DosPutMessageW(g_hStdErr, MsgBuffer, TRUE);
  313. }
  314. }
  315. MyExit(Status);
  316. }
  317. /***
  318. * P r i n t L i n e
  319. *
  320. * Prints the header line.
  321. */
  322. VOID FASTCALL
  323. PrintLine(
  324. VOID
  325. )
  326. {
  327. /* The following code is provided in OS-specific versions to reduce */
  328. /* FAPI utilization under DOS. */
  329. USHORT type;
  330. USHORT attrib;
  331. if (DosQHandType((HANDLE) 1, &type, &attrib) ||
  332. type != DEVICE_HANDLE ||
  333. (attrib & DESIRED_HAND_STATE) != DESIRED_HAND_STATE)
  334. {
  335. WriteToCon(MSG_HYPHENS, NULL);
  336. }
  337. else if (LUI_PrintLine())
  338. {
  339. WriteToCon(MSG_HYPHENS, NULL);
  340. }
  341. }
  342. /***
  343. * P r i n t D o t
  344. *
  345. * Prints a dot, typically to indicate "I'm working".
  346. */
  347. VOID FASTCALL
  348. PrintDot(
  349. VOID
  350. )
  351. {
  352. WriteToCon(DOT_STRING, NULL);
  353. }
  354. /***
  355. * P r i n t N L
  356. *
  357. * Prints a newline
  358. */
  359. VOID FASTCALL
  360. PrintNL(
  361. VOID
  362. )
  363. {
  364. WriteToCon(TEXT("\r\n"), NULL);
  365. }
  366. /***
  367. * Y o r N
  368. *
  369. * Gets an answer to a Y/N question
  370. * an nstrings arg would be nice
  371. */
  372. int FASTCALL
  373. YorN(
  374. USHORT prompt,
  375. USHORT def
  376. )
  377. {
  378. DWORD err;
  379. if (YorN_Switch)
  380. {
  381. return(YorN_Switch - 2);
  382. }
  383. err = LUI_YorN(prompt, def);
  384. switch (err) {
  385. case TRUE:
  386. case FALSE:
  387. break;
  388. default:
  389. ErrorExit(err);
  390. break;
  391. }
  392. return err;
  393. }
  394. /***
  395. * ReadPass()
  396. * Reads a users passwd without echo
  397. *
  398. * Args:
  399. * pass - where to put pass
  400. * NOTE: buffer for pass should be passlen+1 in size.
  401. * passlen - max length of password
  402. * confirm - confirm pass if true
  403. * prompt - prompt to print, NULL for default
  404. * nstrings - number of insertion strings in IStrings on entry
  405. * cannon - canonicalize password if true.
  406. *
  407. * Returns:
  408. */
  409. VOID FASTCALL
  410. ReadPass(
  411. TCHAR pass[],
  412. DWORD passlen,
  413. DWORD confirm,
  414. DWORD prompt,
  415. DWORD nstrings,
  416. BOOL canon
  417. )
  418. {
  419. DWORD err;
  420. DWORD len;
  421. TCHAR cpass[PWLEN+1]; /* confirmation passwd */
  422. int count;
  423. passlen++; /* one extra for null terminator */
  424. for (count = LOOP_LIMIT; count; count--)
  425. {
  426. InfoPrintIns((prompt ? prompt : APE_UtilPasswd), nstrings);
  427. if (err = GetPasswdStr(pass, passlen, &len))
  428. {
  429. /* too LONG */
  430. InfoPrint(APE_UtilInvalidPass);
  431. continue;
  432. }
  433. if (canon && (err = LUI_CanonPassword(pass)))
  434. {
  435. /* not good */
  436. InfoPrint(APE_UtilInvalidPass);
  437. continue;
  438. }
  439. if (! confirm)
  440. return;
  441. /* password confirmation */
  442. InfoPrint(APE_UtilConfirm);
  443. if (err = GetPasswdStr(cpass, passlen, &len))
  444. {
  445. /* too LONG */
  446. InfoPrint(APE_UtilInvalidPass);
  447. ClearStringW(cpass) ;
  448. continue;
  449. }
  450. if (canon && (err = LUI_CanonPassword(cpass)))
  451. {
  452. /* not good */
  453. InfoPrint(APE_UtilInvalidPass);
  454. ClearStringW(cpass) ;
  455. continue;
  456. }
  457. if (_tcscmp(pass, cpass))
  458. {
  459. InfoPrint(APE_UtilNomatch);
  460. ClearStringW(cpass) ;
  461. continue;
  462. }
  463. ClearStringW(cpass) ;
  464. return;
  465. }
  466. /***
  467. * Only get here if user blew if LOOP_LIMIT times
  468. */
  469. ErrorExit(APE_NoGoodPass);
  470. }
  471. /***
  472. * PromptForString()
  473. * Prompts the user for a string.
  474. *
  475. * Args:
  476. * msgid - id of prompt message
  477. * buffer - buffer to receive string
  478. * bufsiz - sizeof buffer
  479. *
  480. * Returns:
  481. */
  482. VOID FASTCALL
  483. PromptForString(
  484. DWORD msgid,
  485. LPTSTR buffer,
  486. DWORD bufsiz
  487. )
  488. {
  489. DWORD err;
  490. DWORD len;
  491. TCHAR terminator;
  492. TCHAR szLen[16] ;
  493. InfoPrint(msgid);
  494. while (err = GetString(buffer, bufsiz, &len, &terminator))
  495. {
  496. if (err == NERR_BufTooSmall)
  497. {
  498. InfoPrintInsTxt(APE_StringTooLong, _ultow(bufsiz, szLen, 10));
  499. }
  500. else
  501. {
  502. ErrorExit(err);
  503. }
  504. }
  505. return;
  506. }
  507. /*
  508. ** There is no need to have these functions in the Chinese/Korean
  509. ** cases, as there are no half-width varients used in the console
  510. ** in those languages (at least, let's hope so.) However, in the
  511. ** interests of a single binary, let's put them in with a CP/932 check.
  512. **
  513. ** FloydR 7/10/95
  514. */
  515. /***************************************************************************\
  516. * BOOL IsFullWidth(WCHAR wch)
  517. *
  518. * Determine if the given Unicode char is fullwidth or not.
  519. *
  520. * History:
  521. * 04-08-92 ShunK Created.
  522. \***************************************************************************/
  523. BOOL IsFullWidth(WCHAR wch)
  524. {
  525. /* Assert cp == double byte codepage */
  526. if (wch <= 0x007f || (wch >= 0xff60 && wch <= 0xff9f))
  527. return(FALSE); // Half width.
  528. else if (wch >= 0x300)
  529. return(TRUE); // Full width.
  530. else
  531. return(FALSE); // Half width.
  532. }
  533. /***************************************************************************\
  534. * DWORD SizeOfHalfWidthString(PWCHAR pwch)
  535. *
  536. * Determine width of the given Unicode string in console characters,
  537. * adjusting for half-width chars.
  538. *
  539. * History:
  540. * 08-08-93 FloydR Created.
  541. \***************************************************************************/
  542. DWORD
  543. SizeOfHalfWidthString(
  544. PWCHAR pwch
  545. )
  546. {
  547. DWORD c=0;
  548. DWORD cp;
  549. switch (cp=GetConsoleOutputCP())
  550. {
  551. case 932:
  552. case 936:
  553. case 949:
  554. case 950:
  555. while (*pwch)
  556. {
  557. if (IsFullWidth(*pwch))
  558. {
  559. c += 2;
  560. }
  561. else
  562. {
  563. c++;
  564. }
  565. pwch++;
  566. }
  567. return c;
  568. default:
  569. return wcslen(pwch);
  570. }
  571. }
  572. VOID FASTCALL
  573. GetMessageList(
  574. USHORT usNumMsg,
  575. MESSAGELIST Buffer,
  576. DWORD *pusMaxActLength
  577. )
  578. {
  579. DWORD Err;
  580. DWORD MaxMsgLen = 0;
  581. MESSAGE *pMaxMsg;
  582. MESSAGE *pMsg;
  583. DWORD ThisMsgLen;
  584. #ifdef DEBUG
  585. USHORT MallocBytes = 0;
  586. #endif
  587. pMaxMsg = &Buffer[usNumMsg];
  588. for (pMsg = Buffer; pMsg < pMaxMsg; pMsg++)
  589. pMsg->msg_text = NULL;
  590. for (pMsg = Buffer; pMsg < pMaxMsg; pMsg++)
  591. {
  592. #ifdef DEBUG
  593. WriteToCon(TEXT("GetMessageList(): Reading msgID %u\r\n"),pMsg->msg_number);
  594. #endif
  595. if ((pMsg->msg_text = malloc(MSGLST_MAXLEN)) == NULL)
  596. ErrorExit(ERROR_NOT_ENOUGH_MEMORY);
  597. Err = LUI_GetMsgInsW(NULL, 0, pMsg->msg_text, MSGLST_MAXLEN,
  598. pMsg->msg_number, &ThisMsgLen);
  599. if (Err)
  600. {
  601. ErrorExit(Err);
  602. }
  603. #ifdef DEBUG
  604. MallocBytes += (ThisMsgLen + 1) * sizeof(TCHAR);
  605. #endif
  606. ThisMsgLen = max(ThisMsgLen, SizeOfHalfWidthString(pMsg->msg_text));
  607. if (ThisMsgLen > MaxMsgLen)
  608. MaxMsgLen = ThisMsgLen;
  609. }
  610. *pusMaxActLength = MaxMsgLen;
  611. #ifdef DEBUG
  612. WriteToCon(TEXT("GetMessageList(): NumMsg = %d, MaxActLen=%d, MallocBytes = %d\r\n"),
  613. usNumMsg, MaxMsgLen, MallocBytes);
  614. #endif
  615. return;
  616. }
  617. VOID FASTCALL
  618. FreeMessageList(
  619. USHORT usNumMsg,
  620. MESSAGELIST MsgList
  621. )
  622. {
  623. USHORT i;
  624. for (i = 0; i < usNumMsg; i++)
  625. {
  626. if (MsgList[i].msg_text != NULL)
  627. {
  628. free(MsgList[i].msg_text);
  629. }
  630. }
  631. return;
  632. }
  633. VOID
  634. WriteToCon(
  635. LPWSTR fmt,
  636. ...
  637. )
  638. {
  639. va_list args;
  640. va_start( args, fmt );
  641. _vsntprintf( ConBuf, MAX_BUF_SIZE, fmt, args );
  642. va_end( args );
  643. DosPutMessageW(g_hStdOut, ConBuf, FALSE);
  644. }
  645. /***************************************************************************\
  646. * PWCHAR PaddedString(DWORD size, PWCHAR pwch)
  647. *
  648. * Realize the string, left aligned and padded on the right to the field
  649. * width/precision specified.
  650. *
  651. * Limitations: This uses a static buffer under the assumption that
  652. * no more than one such string is printed in a single 'printf'.
  653. *
  654. * History:
  655. * 11-03-93 FloydR Created.
  656. \***************************************************************************/
  657. WCHAR PaddingBuffer[MAX_BUF_SIZE];
  658. PWCHAR
  659. PaddedString(
  660. int size,
  661. PWCHAR pwch,
  662. PWCHAR buffer
  663. )
  664. {
  665. int realsize;
  666. int fEllipsis = FALSE;
  667. if (buffer==NULL) buffer = PaddingBuffer;
  668. if (size < 0) {
  669. fEllipsis = TRUE;
  670. size = -size;
  671. }
  672. //
  673. // size is >= 0 at this point
  674. //
  675. realsize = _snwprintf(buffer, MAX_BUF_SIZE, L"%-*.*ws", size, size, pwch);
  676. if (realsize == 0)
  677. {
  678. return NULL;
  679. }
  680. if (SizeOfHalfWidthString(buffer) > (DWORD) size)
  681. {
  682. do
  683. {
  684. buffer[--realsize] = NULLC;
  685. } while (SizeOfHalfWidthString(buffer) > (DWORD) size);
  686. if (fEllipsis && buffer[realsize-1] != L' ')
  687. {
  688. buffer[realsize-1] = L'.';
  689. buffer[realsize-2] = L'.';
  690. buffer[realsize-3] = L'.';
  691. }
  692. }
  693. return buffer;
  694. }
  695. DWORD
  696. DosQHandType(
  697. HANDLE hf,
  698. PWORD pus1,
  699. PWORD pus2
  700. )
  701. {
  702. DWORD dwFileType;
  703. dwFileType = GetFileType(hf);
  704. if (dwFileType == FILE_TYPE_CHAR)
  705. {
  706. *pus1 = DEVICE_HANDLE;
  707. *pus2 = DESIRED_HAND_STATE;
  708. }
  709. else
  710. {
  711. *pus1 = FILE_HANDLE;
  712. }
  713. return(0);
  714. }
  715. /*** GetPasswdStr -- read in password string
  716. *
  717. * DWORD GetPasswdStr(char far *, USHORT);
  718. *
  719. * ENTRY: buf buffer to put string in
  720. * buflen size of buffer
  721. * &len address of USHORT to place length in
  722. *
  723. * RETURNS:
  724. * 0 or NERR_BufTooSmall if user typed too much. Buffer
  725. * contents are only valid on 0 return.
  726. *
  727. * History:
  728. * who when what
  729. * erichn 5/10/89 initial code
  730. * dannygl 5/28/89 modified DBCS usage
  731. * erichn 7/04/89 handles backspaces
  732. * danhi 4/16/91 32 bit version for NT
  733. */
  734. #define CR 0xD
  735. #define BACKSPACE 0x8
  736. DWORD
  737. GetPasswdStr(
  738. LPTSTR buf,
  739. DWORD buflen,
  740. PDWORD len
  741. )
  742. {
  743. TCHAR ch;
  744. TCHAR *bufPtr = buf;
  745. DWORD c;
  746. int err;
  747. int mode;
  748. buflen -= 1; /* make space for null terminator */
  749. *len = 0; /* GP fault probe (a la API's) */
  750. //
  751. // Init mode in case GetConsoleMode() fails
  752. //
  753. mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT |
  754. ENABLE_MOUSE_INPUT;
  755. GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
  756. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
  757. (~(ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT)) & mode);
  758. while (TRUE)
  759. {
  760. err = ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &ch, 1, &c, 0);
  761. if (!err || c != 1)
  762. {
  763. ch = 0xffff;
  764. }
  765. if ((ch == CR) || (ch == 0xffff)) /* end of the line */
  766. {
  767. break;
  768. }
  769. if (ch == BACKSPACE) /* back up one or two */
  770. {
  771. /*
  772. * IF bufPtr == buf then the next two lines are
  773. * a no op.
  774. */
  775. if (bufPtr != buf)
  776. {
  777. bufPtr--;
  778. (*len)--;
  779. }
  780. }
  781. else
  782. {
  783. *bufPtr = ch;
  784. if (*len < buflen)
  785. bufPtr++ ; /* don't overflow buf */
  786. (*len)++; /* always increment len */
  787. }
  788. }
  789. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode);
  790. *bufPtr = NULLC; /* null terminate the string */
  791. putchar(NEWLINE);
  792. return ((*len <= buflen) ? 0 : NERR_BufTooSmall);
  793. }
  794. /*** GetString -- read in string with echo
  795. *
  796. * DWORD GetString(char far *, USHORT, USHORT far *, char far *);
  797. *
  798. * ENTRY: buf buffer to put string in
  799. * buflen size of buffer
  800. * &len address of USHORT to place length in
  801. * &terminator holds the char used to terminate the string
  802. *
  803. * RETURNS:
  804. * 0 or NERR_BufTooSmall if user typed too much. Buffer
  805. * contents are only valid on 0 return. Len is ALWAYS valid.
  806. *
  807. * OTHER EFFECTS:
  808. * len is set to hold number of bytes typed, regardless of
  809. * buffer length. Terminator (Arnold) is set to hold the
  810. * terminating character (newline or EOF) that the user typed.
  811. *
  812. * Read in a string a character at a time. Is aware of DBCS.
  813. *
  814. * History:
  815. * who when what
  816. * erichn 5/11/89 initial code
  817. * dannygl 5/28/89 modified DBCS usage
  818. * danhi 3/20/91 ported to 32 bits
  819. */
  820. DWORD
  821. GetString(
  822. LPTSTR buf,
  823. DWORD buflen,
  824. PDWORD len,
  825. LPTSTR terminator
  826. )
  827. {
  828. int c;
  829. int err;
  830. buflen -= 1; /* make space for null terminator */
  831. *len = 0; /* GP fault probe (a la API's) */
  832. while (TRUE)
  833. {
  834. err = ReadConsole(GetStdHandle(STD_INPUT_HANDLE), buf, 1, &c, 0);
  835. if (!err || c != 1)
  836. *buf = 0xffff;
  837. if (*buf == (TCHAR)EOF)
  838. break;
  839. if (*buf == RETURN || *buf == NEWLINE) {
  840. INPUT_RECORD ir;
  841. int cr;
  842. if (PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &cr))
  843. ReadConsole(GetStdHandle(STD_INPUT_HANDLE), buf, 1, &c, 0);
  844. break;
  845. }
  846. buf += (*len < buflen) ? 1 : 0; /* don't overflow buf */
  847. (*len)++; /* always increment len */
  848. }
  849. *terminator = *buf; /* set terminator */
  850. *buf = NULLC; /* null terminate the string */
  851. return ((*len <= buflen) ? 0 : NERR_BufTooSmall);
  852. }