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.

207 lines
8.5 KiB

  1. /***
  2. *cgetws.c - buffered keyboard input
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines _cgetws() - read a string directly from console
  8. *
  9. *Revision History:
  10. * 04-19-00 GB Module created based on cgets.
  11. * 05-17-00 GB Use ERROR_CALL_NOT_IMPLEMENTED for existance of W API
  12. * 04-29-02 GB Added try-finally arounds lock-unlock.
  13. *
  14. *******************************************************************************/
  15. #include <cruntime.h>
  16. #include <oscalls.h>
  17. #include <mtdll.h>
  18. #include <conio.h>
  19. #include <stdlib.h>
  20. #include <internal.h>
  21. #define BUF_MAX_LEN 64
  22. extern intptr_t _coninpfh;
  23. static int bUseW = 2;
  24. /***
  25. *wchar_t *_cgetws(string) - read string from console
  26. *
  27. *Purpose:
  28. * Reads a string from the console via ReadConsoleW on a cooked console
  29. * handle. string[0] must contain the maximum length of the
  30. * string. Returns pointer to str[2].
  31. *
  32. * NOTE: _cgetsw() does NOT check the pushback character buffer (i.e.,
  33. * _chbuf). Thus, _cgetws() will not return any character that is
  34. * pushed back by the _ungetwch() call.
  35. *
  36. *Entry:
  37. * char *string - place to store read string, str[0] = max length.
  38. *
  39. *Exit:
  40. * returns pointer to str[2], where the string starts.
  41. * returns NULL if error occurs
  42. *
  43. *Exceptions:
  44. *
  45. *******************************************************************************/
  46. wchar_t * __cdecl _cgetws (
  47. wchar_t *string
  48. )
  49. {
  50. ULONG oldstate;
  51. ULONG num_read;
  52. wchar_t *result;
  53. string[1] = 0; /* no chars read yet */
  54. result = &string[2];
  55. /*
  56. * _coninpfh, the handle to the console input, is created the first
  57. * time that either _getch() or _cgets() or _kbhit() is called.
  58. */
  59. _mlock(_CONIO_LOCK); /* lock the console */
  60. __TRY
  61. if ( _coninpfh == -2 )
  62. __initconin();
  63. if ( _coninpfh == -1 ) {
  64. result=NULL;
  65. } else {
  66. GetConsoleMode( (HANDLE)_coninpfh, &oldstate );
  67. SetConsoleMode( (HANDLE)_coninpfh, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT );
  68. // First try usual way just as _cgets
  69. if ( bUseW)
  70. {
  71. if ( !ReadConsoleW( (HANDLE)_coninpfh,
  72. (LPVOID)result,
  73. (unsigned)string[0],
  74. &num_read,
  75. NULL )
  76. )
  77. {
  78. result = NULL;
  79. if ( bUseW == 2 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  80. bUseW = FALSE;
  81. }
  82. else
  83. bUseW = TRUE;
  84. if ( result != NULL ) {
  85. /* set length of string and null terminate it */
  86. if (string[num_read] == L'\r') {
  87. string[1] = (wchar_t)(num_read - 2);
  88. string[num_read] = L'\0';
  89. } else if ( (num_read == (ULONG)string[0]) &&
  90. (string[num_read + 1] == L'\r') ) {
  91. /* special case 1 - \r\n straddles the boundary */
  92. string[1] = (wchar_t)(num_read -1);
  93. string[1 + num_read] = L'\0';
  94. } else if ( (num_read == 1) && (string[2] == L'\n') ) {
  95. /* special case 2 - read a single '\n'*/
  96. string[1] = string[2] = L'\0';
  97. } else {
  98. string[1] = (wchar_t)num_read;
  99. string[2 + num_read] = L'\0';
  100. }
  101. }
  102. }
  103. // If ReadConsoleW is not present, use ReadConsoleA and then convert
  104. // to Wide Char.
  105. if ( !bUseW)
  106. {
  107. static char AStr[BUF_MAX_LEN +1];
  108. static int in_buff = 0, was_buff_full = 0;
  109. unsigned int Copy, Sz, consoleCP;
  110. unsigned int last_read = 0, i;
  111. consoleCP = GetConsoleCP();
  112. do {
  113. if (!in_buff)
  114. {
  115. if ( !ReadConsoleA( (HANDLE)_coninpfh,
  116. (LPVOID)AStr,
  117. BUF_MAX_LEN,
  118. &num_read,
  119. NULL)
  120. )
  121. result = NULL;
  122. if (result != NULL) {
  123. if (AStr[num_read -2] == '\r')
  124. AStr[num_read -2] = '\0';
  125. else if (num_read == sizeof(AStr) &&
  126. AStr[num_read -1] == '\r')
  127. AStr[num_read -1] = '\0';
  128. else if (num_read == 1 && string[0] == '\n')
  129. AStr[0] = '\0';
  130. else
  131. AStr[num_read] = '\0';
  132. }
  133. }
  134. for ( i = 0; AStr[i] != '\0' &&
  135. i < (BUF_MAX_LEN) &&
  136. last_read < (unsigned)string[0]; i += Sz)
  137. {
  138. // Check if this character is lead byte. If yes, the size
  139. // of this character is 2. Else 1.
  140. if ( IsDBCSLeadByteEx( GetConsoleCP(), AStr[i]))
  141. Sz = 2;
  142. else
  143. Sz = 1;
  144. if ( (Copy = MultiByteToWideChar( consoleCP,
  145. MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
  146. &AStr[i],
  147. Sz,
  148. &string[2+last_read],
  149. string[0] - last_read)))
  150. {
  151. last_read += Copy;
  152. }
  153. }
  154. // Check if this conversion was from buffer. If yes, was
  155. // buffer fully filled when it was first read using
  156. // ReadConsoleA. If the buffer not fully filled, we don't need
  157. // to read more from buffer. This is necessary to make it
  158. // behave same as if we are reading using ReadConsoleW.
  159. if ( in_buff && i == strlen(AStr))
  160. {
  161. in_buff = 0;
  162. if ( was_buff_full)
  163. {
  164. was_buff_full = 0;
  165. continue;
  166. }
  167. else
  168. {
  169. break;
  170. }
  171. }
  172. else if ( i < (BUF_MAX_LEN))
  173. break;
  174. } while (last_read < (unsigned)string[0]);
  175. // We save the buffer to be used again.
  176. if ( i < strlen(AStr))
  177. {
  178. in_buff = 1;
  179. if ( strlen(AStr) == (BUF_MAX_LEN))
  180. was_buff_full = 1;
  181. memmove(AStr, &AStr[i], BUF_MAX_LEN +1 - i);
  182. }
  183. string[2+last_read] = '\0';
  184. string[1] = (wchar_t)last_read;
  185. }
  186. SetConsoleMode( (HANDLE)_coninpfh, oldstate );
  187. }
  188. __FINALLY
  189. _munlock(_CONIO_LOCK); /* unlock the console */
  190. __END_TRY_FINALLY
  191. return result;
  192. }