Leaked source code of windows server 2003
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.

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