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.

1134 lines
25 KiB

  1. /*++
  2. Copyright (c) 1988-1999 Microsoft Corporation
  3. Module Name:
  4. console.c
  5. Abstract:
  6. Support for video output and input
  7. --*/
  8. #include "cmd.h"
  9. //
  10. // Externals for message buffer translation
  11. //
  12. extern unsigned msglen;
  13. extern CPINFO CurrentCPInfo;
  14. #ifdef FE_SB
  15. extern UINT CurrentCP;
  16. #endif /* FE_SB */
  17. VOID SetColRow( PSCREEN );
  18. ULONG GetNumRows( PSCREEN, PTCHAR );
  19. TCHAR chLF = NLN;
  20. VOID
  21. DisableProcessedOutput(
  22. IN PSCREEN pscr
  23. )
  24. {
  25. if (pscr->hndScreen)
  26. SetConsoleMode(pscr->hndScreen, ENABLE_WRAP_AT_EOL_OUTPUT);
  27. }
  28. VOID
  29. EnableProcessedOutput(
  30. IN PSCREEN pscr
  31. )
  32. {
  33. ResetConsoleMode();
  34. }
  35. STATUS
  36. OpenScreen(
  37. OUT PSCREEN *pscreen
  38. )
  39. /*++
  40. Routine Description:
  41. Allocates and initializes a data structure for screen I/O buffering.
  42. Arguments:
  43. crow - max rows on screen
  44. ccol - max column on screen
  45. ccolTab - spaces to insert for each tab call. This does not
  46. expand tabs in the character stream but is used with the
  47. WriteTab call.
  48. cbMaxBuff - Max. size of a line on screen
  49. Return Value:
  50. pscreen - pointer to screen buffer, used in later calls.
  51. Return: SUCCESS - allocated and inited buffer.
  52. If failure to allocate an abort is executed and return to outer
  53. level of interpreter is executed.
  54. --*/
  55. {
  56. PSCREEN pscr;
  57. CONSOLE_SCREEN_BUFFER_INFO ConInfo;
  58. ULONG cbMaxBuff;
  59. pscr = (PSCREEN)gmkstr(sizeof(SCREEN));
  60. pscr->hndScreen = NULL;
  61. if (FileIsDevice(STDOUT)) {
  62. pscr->hndScreen = CRTTONT(STDOUT);
  63. if (!GetConsoleScreenBufferInfo(pscr->hndScreen,&ConInfo)) {
  64. // must be a device but not console (maybe NUL)
  65. pscr->hndScreen = NULL;
  66. }
  67. }
  68. if (GetConsoleScreenBufferInfo( pscr->hndScreen, &ConInfo)) {
  69. cbMaxBuff = (ConInfo.dwSize.X + _tcslen(CrLf)) < MAXCBMSGBUFFER ? MAXCBMSGBUFFER : (ConInfo.dwSize.X + _tcslen(CrLf));
  70. } else {
  71. cbMaxBuff = MAXCBMSGBUFFER + _tcslen(CrLf);
  72. }
  73. //
  74. // allocate enough to hold a buffer plus line termination.
  75. //
  76. pscr->pbBuffer = (PTCHAR)gmkstr(cbMaxBuff*sizeof(TCHAR));
  77. pscr->cbMaxBuffer = cbMaxBuff;
  78. pscr->ccolTab = 0;
  79. pscr->crow = pscr->ccol = 0;
  80. pscr->crowPause = 0;
  81. SetColRow(pscr);
  82. *pscreen = pscr;
  83. return( SUCCESS );
  84. }
  85. STATUS
  86. WriteString(
  87. IN PSCREEN pscr,
  88. IN PTCHAR pszString
  89. )
  90. /*++
  91. Routine Description:
  92. Write a zero terminated string to pscr buffer
  93. Arguments:
  94. pscr - buffer into which to write.
  95. pszString - String to copy
  96. Return Value:
  97. Return: SUCCESS - enough spaced existed in buffer for line.
  98. FAILURE
  99. --*/
  100. {
  101. return( WriteFmtString(pscr, TEXT("%s"), (PVOID)pszString ) );
  102. }
  103. STATUS
  104. WriteMsgString(
  105. IN PSCREEN pscr,
  106. IN ULONG MsgNum,
  107. IN ULONG NumOfArgs,
  108. ...
  109. )
  110. /*++
  111. Routine Description:
  112. Retrieve a message number and format with supplied arguments.
  113. Arguments:
  114. pscr - buffer into which to write.
  115. MsgNum - message number to retrieve
  116. NumOfArgs - no. of arguments suppling data.
  117. ... - pointers to zero terminated strings as data.
  118. Return Value:
  119. Return: SUCCESS
  120. FAILURE - could not find any message including msg not found
  121. message.
  122. --*/
  123. {
  124. PTCHAR pszMsg = NULL;
  125. ULONG cbMsg;
  126. CHAR numbuf[ 32 ];
  127. #ifdef UNICODE
  128. TCHAR wnumbuf[ 32 ];
  129. #endif
  130. PTCHAR Inserts[ 2 ];
  131. STATUS rc;
  132. va_list arglist;
  133. va_start(arglist, NumOfArgs);
  134. cbMsg = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE
  135. | FORMAT_MESSAGE_FROM_SYSTEM
  136. | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  137. NULL, // lpSource
  138. MsgNum, // dwMessageId
  139. 0, // dwLanguageId
  140. (LPTSTR)&pszMsg, // lpBuffer
  141. 10, // nSize
  142. &arglist // Arguments
  143. );
  144. va_end(arglist);
  145. if (cbMsg == 0) {
  146. _ultoa( MsgNum, numbuf, 16 );
  147. #ifdef UNICODE
  148. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, numbuf, -1, wnumbuf, 32);
  149. Inserts[ 0 ]= wnumbuf;
  150. #else
  151. Inserts[ 0 ]= numbuf;
  152. #endif
  153. Inserts[ 1 ]= (MsgNum >= MSG_FIRST_CMD_MSG_ID ? TEXT("Application") : TEXT("System"));
  154. cbMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
  155. | FORMAT_MESSAGE_ARGUMENT_ARRAY
  156. | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  157. NULL,
  158. ERROR_MR_MID_NOT_FOUND,
  159. 0,
  160. (LPTSTR)&pszMsg,
  161. 10,
  162. (va_list *)Inserts
  163. );
  164. }
  165. if (cbMsg) {
  166. rc = WriteString(pscr, pszMsg);
  167. //
  168. // Flush out buffer if there is an eol. If not then we
  169. // are printing part of a larger message
  170. //
  171. if (GetNumRows(pscr, pscr->pbBuffer) ) {
  172. WriteFlush(pscr);
  173. }
  174. LocalFree( pszMsg );
  175. return( SUCCESS );
  176. } else {
  177. return( FAILURE );
  178. }
  179. }
  180. STATUS
  181. WriteFmtString(
  182. IN PSCREEN pscr,
  183. IN PTCHAR pszFmt,
  184. IN PVOID pszString
  185. )
  186. /*++
  187. Routine Description:
  188. Write a zero terminated string to pscr
  189. Note:
  190. Do not use Msgs with this call. Use only internal Fmt strings
  191. Use WriteMsgString for all system messages. It does not check for
  192. CrLf at end of string to keep row count but WriteMsgString does
  193. Arguments:
  194. pscr - buffer into which to write.
  195. pszFmt - format to apply.
  196. pszString - String to copy
  197. Return Value:
  198. Return: SUCCESS
  199. FAILURE
  200. --*/
  201. {
  202. ULONG cbString;
  203. TCHAR szString[MAXCBLINEBUFFER];
  204. //
  205. // Assume that the format overhead is small so this is a fair estimate
  206. // of the target size.
  207. //
  208. cbString = _sntprintf(szString, MAXCBLINEBUFFER, pszFmt, pszString);
  209. //
  210. // If string can not fit on line then flush out the buffer and reset
  211. // to beginning of line.
  212. //
  213. //
  214. // Check that string can fit in buffer
  215. //
  216. if ((pscr->ccol + cbString) < pscr->cbMaxBuffer) {
  217. mystrcat(pscr->pbBuffer, szString);
  218. pscr->ccol += cbString;
  219. return( SUCCESS );
  220. } else {
  221. //
  222. // String will not fit
  223. //
  224. return( FAILURE );
  225. }
  226. }
  227. STATUS
  228. WriteEol(
  229. IN PSCREEN pscr
  230. )
  231. /*++
  232. Routine Description:
  233. Flush current buffer to screen and write a <cr>
  234. Arguments:
  235. pscr - buffer to write to console.
  236. Return Value:
  237. Return: SUCCESS
  238. FAILURE
  239. --*/
  240. {
  241. ULONG cbWritten;
  242. //
  243. // Check if have to wait for user to hit a key before printing rest of
  244. // line.
  245. CheckPause( pscr );
  246. //
  247. // If we do not write all that we wanted then there must have been some error
  248. //
  249. if (FileIsConsole(STDOUT)) {
  250. PTCHAR s, s1, LastChar;
  251. BOOL b;
  252. s = pscr->pbBuffer;
  253. LastChar = s + pscr->ccol;
  254. //
  255. // s is the next character to output
  256. // n is the number of chars to output.
  257. //
  258. // Due to the vagaries of console character translation, we must output
  259. // all but a small set of UNICODE characters in the "normal" processed
  260. // output fashion. However, for:
  261. //
  262. // 0x2022
  263. //
  264. // we must revert to unprocessed output. So, we scan forward until we
  265. // find the end of string (or the special characters) display them in
  266. // processed form and then handle the special characters in their own way.
  267. //
  268. #define IsSpecialChar(c) ((c) == 0x2022)
  269. while (s < LastChar) {
  270. //
  271. // Skip across a group of contiguous normal chars
  272. //
  273. s1 = s;
  274. while (s1 < LastChar && !IsSpecialChar( *s1 )) {
  275. s1++;
  276. }
  277. //
  278. // If we have any chars to output then do so with normal processing
  279. //
  280. if (s1 != s) {
  281. b = WriteConsole( CRTTONT( STDOUT ), s, (ULONG)(s1 - s), &cbWritten, NULL );
  282. if (!b || cbWritten != (ULONG)(s1 - s)) {
  283. goto err_out_eol;
  284. }
  285. s = s1;
  286. }
  287. //
  288. // Skip across a group of contiguous special chars
  289. //
  290. while (s1 < LastChar && IsSpecialChar( *s1 )) {
  291. s1++;
  292. }
  293. //
  294. // If we have any special chars, output without processing
  295. //
  296. if (s1 != s) {
  297. DisableProcessedOutput( pscr );
  298. b = WriteConsole( CRTTONT( STDOUT ), s, (ULONG)(s1 - s), &cbWritten, NULL);
  299. EnableProcessedOutput(pscr);
  300. if (!b || cbWritten != (ULONG)(s1 - s)) {
  301. goto err_out_eol;
  302. }
  303. s = s1;
  304. }
  305. }
  306. #undef IsSpecialChar
  307. }
  308. else if (MyWriteFile(STDOUT,
  309. pscr->pbBuffer, pscr->ccol*sizeof(TCHAR),
  310. (LPDWORD)&cbWritten) == 0 ||
  311. cbWritten != pscr->ccol*sizeof(TCHAR)) {
  312. err_out_eol:
  313. if (FileIsDevice(STDOUT)) {
  314. //
  315. // If writing to a device then it must have been write fault
  316. // against the device.
  317. //
  318. #if DBG
  319. fprintf(stderr, "WriteFlush - WriteConsole error %d, tried to write %d, did %d\n", GetLastError(), pscr->ccol, cbWritten);
  320. #endif
  321. PutStdErr(ERROR_WRITE_FAULT, NOARGS) ;
  322. } else if (!FileIsPipe(STDOUT)) {
  323. //
  324. // If not a device (file) but not a pipe then the disk is
  325. // considered full.
  326. //
  327. #if DBG
  328. fprintf(stderr, "WriteFlush - WriteFile error %d, tried to write %d, did %d\n", GetLastError(), pscr->ccol*sizeof(TCHAR), cbWritten);
  329. #endif
  330. PutStdErr(ERROR_DISK_FULL, NOARGS) ;
  331. }
  332. //
  333. // if it was was a pipe do not continue to print out to pipe since it
  334. // has probably gone away. This is pretty serious so blow us out
  335. // to the outer loop.
  336. //
  337. // We do not print an error message since this could be normal
  338. // termination of the other end of the pipe. If it was command that
  339. // blew away we would have had an error message already
  340. //
  341. Abort();
  342. }
  343. if (FileIsConsole(STDOUT))
  344. WriteConsole(CRTTONT(STDOUT), CrLf, mystrlen(CrLf), &cbWritten, NULL);
  345. else
  346. MyWriteFile(STDOUT, CrLf, mystrlen(CrLf)*sizeof(TCHAR),
  347. (LPDWORD)&cbWritten);
  348. //
  349. // remember that crow is the number of rows printed
  350. // since the last screen full. Not the current row position
  351. //
  352. //
  353. // Computed the number of lines printed.
  354. //
  355. pscr->crow += GetNumRows( pscr, pscr->pbBuffer );
  356. pscr->crow += 1;
  357. //
  358. // Check if have to wait for user to hit a key before printing rest of
  359. // line.
  360. CheckPause( pscr );
  361. if (pscr->crow > pscr->crowMax) {
  362. pscr->crow = 0;
  363. }
  364. pscr->pbBuffer[0] = 0;
  365. pscr->ccol = 0;
  366. DEBUG((ICGRP, CONLVL, "Console: end row = %d\n", pscr->crow)) ;
  367. return(SUCCESS);
  368. }
  369. VOID
  370. CheckPause(
  371. IN PSCREEN pscr
  372. )
  373. /*++
  374. Routine Description:
  375. Pause. Execution of screen is full, waiting for the user to type a key.
  376. Arguments:
  377. pscr - buffer holding row information
  378. Return Value:
  379. none
  380. --*/
  381. {
  382. DEBUG((ICGRP, CONLVL, "CheckPause: Pause Count %d, Row Count %d",
  383. pscr->crowPause, pscr->crow)) ;
  384. if (pscr->crowPause) {
  385. if (pscr->crow >= pscr->crowPause) {
  386. ePause((struct cmdnode *)0);
  387. pscr->crow = 0;
  388. SetColRow( pscr );
  389. SetPause(pscr, pscr->crowMax - 1);
  390. }
  391. }
  392. }
  393. VOID
  394. SetTab(
  395. IN PSCREEN pscr,
  396. IN ULONG ccol
  397. )
  398. /*++
  399. Routine Description:
  400. Set the current tab spacing.
  401. Arguments:
  402. pscr - screen info.
  403. ccol - tab spacing
  404. Return Value:
  405. none
  406. --*/
  407. {
  408. pscr->ccolTabMax = pscr->ccolMax;
  409. if (ccol) {
  410. //
  411. // divide the screen up into tab fields, then do
  412. // not allow tabbing into past last field. This
  413. // insures that all name of ccol size can fit on
  414. // screen
  415. //
  416. pscr->ccolTabMax = (pscr->ccolMax / ccol) * ccol;
  417. }
  418. pscr->ccolTab = ccol;
  419. }
  420. STATUS
  421. WriteTab(
  422. IN PSCREEN pscr
  423. )
  424. /*++
  425. Routine Description:
  426. Fills the buffer with spaces up to the next tab position
  427. Arguments:
  428. pscr - screen info.
  429. ccol - tab spacing
  430. Return Value:
  431. none
  432. --*/
  433. {
  434. ULONG ccolBlanks;
  435. #ifdef FE_SB
  436. ULONG ccolActual;
  437. #endif /* not Japan */
  438. //
  439. // Check that we have a non-zero tab spacing.
  440. //
  441. if ( pscr->ccolTab ) {
  442. //
  443. // Compute the number of spaces we will have to write.
  444. //
  445. #ifdef FE_SB
  446. if (IsDBCSCodePage())
  447. ccolActual = SizeOfHalfWidthString(pscr->pbBuffer);
  448. else
  449. ccolActual = pscr->ccol;
  450. ccolBlanks = pscr->ccolTab - (ccolActual % pscr->ccolTab);
  451. #else
  452. ccolBlanks = pscr->ccolTab - (pscr->ccol % pscr->ccolTab);
  453. #endif
  454. //
  455. // check if the tab will fit on the screen
  456. //
  457. #ifdef FE_SB
  458. if ((ccolBlanks + ccolActual) < pscr->ccolTabMax) {
  459. #else
  460. if ((ccolBlanks + pscr->ccol) < pscr->ccolTabMax) {
  461. #endif
  462. mytcsnset(pscr->pbBuffer + pscr->ccol, SPACE, ccolBlanks);
  463. pscr->ccol += ccolBlanks;
  464. pscr->pbBuffer[pscr->ccol] = NULLC;
  465. return( SUCCESS );
  466. } else {
  467. //
  468. // It could not so outpt <cr> and move to
  469. // next line
  470. //
  471. return(WriteEol(pscr));
  472. }
  473. }
  474. return( SUCCESS );
  475. }
  476. VOID
  477. FillToCol (
  478. IN PSCREEN pscr,
  479. IN ULONG ccol
  480. )
  481. /*++
  482. Routine Description:
  483. Fills the buffer with spaces up ccol
  484. Arguments:
  485. pscr - screen info.
  486. ccol - column to fill to.
  487. Return Value:
  488. none
  489. --*/
  490. {
  491. #ifdef FE_SB
  492. ULONG ccolActual;
  493. ULONG cb;
  494. BOOL fDBCS;
  495. if ( fDBCS = IsDBCSCodePage())
  496. ccolActual = SizeOfHalfWidthString(pscr->pbBuffer);
  497. else
  498. ccolActual = pscr->ccol;
  499. #endif
  500. #ifdef FE_SB
  501. cb = _tcslen(pscr->pbBuffer);
  502. if (ccolActual >= ccol) {
  503. if (fDBCS)
  504. ccol = cb - (ccolActual - ccol);
  505. #else
  506. if (pscr->ccol >= ccol) {
  507. #endif
  508. //
  509. // If we are there or past it then truncate current line
  510. // and return.
  511. //
  512. pscr->pbBuffer[ccol] = NULLC;
  513. pscr->ccol = ccol;
  514. return;
  515. }
  516. //
  517. // Only fill to column width of buffer
  518. //
  519. #ifdef FE_SB
  520. mytcsnset(pscr->pbBuffer + cb, SPACE, ccol - ccolActual);
  521. if (fDBCS)
  522. ccol = cb + ccol - ccolActual;
  523. #else
  524. mytcsnset(pscr->pbBuffer + pscr->ccol, SPACE, ccol - pscr->ccol);
  525. #endif
  526. pscr->ccol = ccol;
  527. pscr->pbBuffer[ccol] = NULLC;
  528. }
  529. STATUS
  530. WriteFlush(
  531. IN PSCREEN pscr
  532. )
  533. /*++
  534. Routine Description:
  535. Write what ever is currently on the buffer to the screen. No EOF is
  536. printed.
  537. Arguments:
  538. pscr - screen info.
  539. Return Value:
  540. Will abort on write error.
  541. SUCCESS
  542. --*/
  543. {
  544. DWORD cb;
  545. //
  546. // If there is something in the buffer flush it out
  547. //
  548. if (pscr->ccol) {
  549. if (FileIsConsole(STDOUT)) {
  550. ULONG cbWritten;
  551. PTCHAR s, s1, LastChar;
  552. BOOL b;
  553. s = pscr->pbBuffer;
  554. LastChar = s + pscr->ccol;
  555. //
  556. // s is the next character to output
  557. // n is the number of chars to output.
  558. //
  559. // Due to the vagaries of console character translation, we must output
  560. // all but a small set of UNICODE characters in the "normal" processed
  561. // output fashion. However, for:
  562. //
  563. // 0x2022
  564. //
  565. // we must revert to unprocessed output. So, we scan forward until we
  566. // find the end of string (or the special characters) display them in
  567. // processed form and then handle the special characters in their own way.
  568. //
  569. #define IsSpecialChar(c) ((c) == 0x2022)
  570. while (s < LastChar) {
  571. //
  572. // Skip across a group of contiguous normal chars
  573. //
  574. s1 = s;
  575. while (s1 < LastChar && !IsSpecialChar( *s1 )) {
  576. s1++;
  577. }
  578. //
  579. // If we have any chars to output then do so with normal processing
  580. //
  581. if (s1 != s) {
  582. b = WriteConsole( CRTTONT( STDOUT ), s, (ULONG)(s1 - s), &cbWritten, NULL );
  583. if (!b || cbWritten != (ULONG)(s1 - s)) {
  584. goto err_out_flush;
  585. }
  586. s = s1;
  587. }
  588. //
  589. // Skip across a group of contiguous special chars
  590. //
  591. while (s1 < LastChar && IsSpecialChar( *s1 )) {
  592. s1++;
  593. }
  594. //
  595. // If we have any special chars, output without processing
  596. //
  597. if (s1 != s) {
  598. DisableProcessedOutput( pscr );
  599. b = WriteConsole( CRTTONT( STDOUT ), s, (ULONG)(s1 - s), &cbWritten, NULL);
  600. EnableProcessedOutput(pscr);
  601. if (!b || cbWritten != (ULONG)(s1 - s)) {
  602. goto err_out_flush;
  603. }
  604. s = s1;
  605. }
  606. }
  607. #undef IsSpecialChar
  608. }
  609. else if (MyWriteFile(STDOUT,
  610. pscr->pbBuffer, pscr->ccol*sizeof(TCHAR), &cb) == 0 ||
  611. cb < pscr->ccol*sizeof(TCHAR)) {
  612. err_out_flush:
  613. if (FileIsDevice(STDOUT)) {
  614. PutStdErr(ERROR_WRITE_FAULT, NOARGS) ;
  615. } else if (!FileIsPipe(STDOUT)) {
  616. PutStdErr(ERROR_DISK_FULL, NOARGS) ;
  617. }
  618. //
  619. // if it was was a pipe do not continue to print out to pipe since it
  620. // has probably gone away.
  621. Abort();
  622. }
  623. }
  624. pscr->crow += GetNumRows(pscr, pscr->pbBuffer);
  625. pscr->pbBuffer[0] = 0;
  626. pscr->ccol = 0;
  627. return(SUCCESS);
  628. }
  629. STATUS
  630. WriteFlushAndEol(
  631. IN PSCREEN pscr
  632. )
  633. /*++
  634. Routine Description:
  635. Write Flush with eof.
  636. Arguments:
  637. pscr - screen info.
  638. Return Value:
  639. Will abort on write error.
  640. SUCCESS
  641. --*/
  642. {
  643. STATUS rc = SUCCESS;
  644. //
  645. // Check if there is something on the line to print.
  646. //
  647. if (pscr->ccol) {
  648. rc = WriteEol(pscr);
  649. }
  650. return( rc );
  651. }
  652. void
  653. SetColRow(
  654. IN PSCREEN pscr
  655. )
  656. {
  657. CONSOLE_SCREEN_BUFFER_INFO ConInfo;
  658. ULONG crowMax, ccolMax;
  659. crowMax = 25;
  660. ccolMax = 80;
  661. if (pscr->hndScreen) {
  662. //
  663. // On open we checked if this was a valid screen handle so this
  664. // cannot fail for any meaning full reason. If we do fail then
  665. // just leave it at the default.
  666. //
  667. if (GetConsoleScreenBufferInfo( pscr->hndScreen, &ConInfo)) {
  668. //
  669. // The console size we use is the screen buffer size not the
  670. // windows size itself. The window is a frame upon the screen
  671. // buffer and we should always write to the screen buffer and
  672. // format based upon that information
  673. //
  674. ccolMax = ConInfo.dwSize.X;
  675. crowMax = ConInfo.srWindow.Bottom - ConInfo.srWindow.Top + 1;
  676. }
  677. }
  678. pscr->crowMax = crowMax;
  679. pscr->ccolMax = ccolMax;
  680. }
  681. ULONG
  682. GetNumRows(
  683. IN PSCREEN pscr,
  684. IN PTCHAR pbBuffer
  685. )
  686. {
  687. PTCHAR szLFLast, szLFCur;
  688. ULONG crow, cb;
  689. szLFLast = pbBuffer;
  690. crow = 0;
  691. while ( szLFCur = mystrchr(szLFLast, chLF) ) {
  692. cb = (ULONG)(szLFCur - szLFLast);
  693. while ( cb > pscr->ccolMax ) {
  694. cb -= pscr->ccolMax;
  695. crow++;
  696. }
  697. crow++;
  698. szLFLast = szLFCur + 1;
  699. }
  700. //
  701. // if there were no LF's in the line then crow would be
  702. // 0. Count the number of lines the console will output in
  703. // wrapping
  704. //
  705. if (crow == 0) {
  706. crow = (pscr->ccol / pscr->ccolMax);
  707. }
  708. DEBUG((ICGRP, CONLVL, "Console: Num of rows counted = %d", crow)) ;
  709. //
  710. // a 0 returns means that there would not be a LF printed or
  711. // a wrap done.
  712. //
  713. return( crow );
  714. }
  715. #if defined(FE_SB)
  716. BOOLEAN
  717. IsDBCSCodePage()
  718. {
  719. switch (CurrentCP) {
  720. case 932:
  721. case 936:
  722. case 949:
  723. case 950:
  724. return TRUE;
  725. break;
  726. default:
  727. return FALSE;
  728. break;
  729. }
  730. }
  731. /***************************************************************************\
  732. * BOOL IsFullWidth(TCHAR wch)
  733. *
  734. * Determine if the given Unicode char is fullwidth or not.
  735. *
  736. * History:
  737. * 04-08-92 ShunK Created.
  738. * 07-11-95 FloydR Modified to be Japanese aware, when enabled for
  739. * other DBCS languages. Note that we could build
  740. * KOREA/TAIWAN/PRC w/o this code, but we like single
  741. * binary solutions.
  742. * Oct-06-1996 KazuM Not use RtlUnicodeToMultiByteSize and WideCharToMultiByte
  743. * Because 950 only defined 13500 chars,
  744. * and unicode defined almost 18000 chars.
  745. * So there are almost 4000 chars can not be mapped to big5 code.
  746. \***************************************************************************/
  747. BOOL IsFullWidth(TCHAR wch)
  748. {
  749. #ifdef UNICODE
  750. /* Assert CP == 932/936/949/950 */
  751. if (CurrentCPInfo.MaxCharSize == 1)
  752. return FALSE;
  753. if (0x20 <= wch && wch <= 0x7e)
  754. /* ASCII */
  755. return FALSE;
  756. else if (0x3000 <= wch && wch <= 0x3036)
  757. /* CJK Symbols and Punctuation */
  758. return TRUE;
  759. else if (0x3041 <= wch && wch <= 0x3094)
  760. /* Hiragana */
  761. return TRUE;
  762. else if (0x30a1 <= wch && wch <= 0x30f6)
  763. /* Katakana */
  764. return TRUE;
  765. else if (0x3105 <= wch && wch <= 0x312c)
  766. /* Bopomofo */
  767. return TRUE;
  768. else if (0x3131 <= wch && wch <= 0x318e)
  769. /* Hangul Elements */
  770. return TRUE;
  771. else if (0x3200 <= wch && wch <= 0x32ff)
  772. /* Enclosed CJK Letters and Ideographics */
  773. return TRUE;
  774. else if (0x3300 <= wch && wch <= 0x33fe)
  775. /* CJK Squared Words and Abbreviations */
  776. return TRUE;
  777. else if (0xac00 <= wch && wch <= 0xd7a3)
  778. /* Korean Hangul Syllables */
  779. return TRUE;
  780. else if (0xe000 <= wch && wch <= 0xf8ff)
  781. /* EUDC */
  782. return TRUE;
  783. else if (0xff01 <= wch && wch <= 0xff5e)
  784. /* Fullwidth ASCII variants */
  785. return TRUE;
  786. else if (0xff61 <= wch && wch <= 0xff9f)
  787. /* Halfwidth Katakana variants */
  788. return FALSE;
  789. else if ( (0xffa0 <= wch && wch <= 0xffbe) ||
  790. (0xffc2 <= wch && wch <= 0xffc7) ||
  791. (0xffca <= wch && wch <= 0xffcf) ||
  792. (0xffd2 <= wch && wch <= 0xffd7) ||
  793. (0xffda <= wch && wch <= 0xffdc) )
  794. /* Halfwidth Hangule variants */
  795. return FALSE;
  796. else if (0xffe0 <= wch && wch <= 0xffe6)
  797. /* Fullwidth symbol variants */
  798. return TRUE;
  799. else if (0x4e00 <= wch && wch <= 0x9fa5)
  800. /* CJK Ideographic */
  801. return TRUE;
  802. else if (0xf900 <= wch && wch <= 0xfa2d)
  803. /* CJK Compatibility Ideographs */
  804. return TRUE;
  805. else if (0xfe30 <= wch && wch <= 0xfe4f) {
  806. /* CJK Compatibility Forms */
  807. return TRUE;
  808. }
  809. else
  810. /* Unknown character */
  811. return FALSE;
  812. #else
  813. if (IsDBCSLeadByteEx(CurrentCP, wch))
  814. return TRUE;
  815. else
  816. return FALSE;
  817. #endif
  818. }
  819. /***************************************************************************\
  820. * BOOL SizeOfHalfWidthString(PWCHAR pwch)
  821. *
  822. * Determine size of the given Unicode string, adjusting for half-width chars.
  823. *
  824. * History:
  825. * 08-08-93 FloydR Created.
  826. \***************************************************************************/
  827. int SizeOfHalfWidthString(TCHAR *pwch)
  828. {
  829. int c=0;
  830. if (IsDBCSCodePage())
  831. {
  832. while (*pwch) {
  833. if (IsFullWidth(*pwch))
  834. c += 2;
  835. else
  836. c++;
  837. pwch++;
  838. }
  839. return c;
  840. }
  841. else
  842. return _tcslen(pwch);
  843. }
  844. #endif