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.

1144 lines
24 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. BOOL CrLfWritten=FALSE;
  242. ULONG cbWritten;
  243. //
  244. // Check if have to wait for user to hit a key before printing rest of
  245. // line.
  246. CheckPause( pscr );
  247. if ((pscr->ccol + mystrlen(CrLf)) >= pscr->cbMaxBuffer) {
  248. pscr->ccol += _stprintf(pscr->pbBuffer + pscr->ccol, TEXT("%s"), CrLf);
  249. CrLfWritten=TRUE;
  250. }
  251. //
  252. // If we do not write all that we wanted then there must have been some error
  253. //
  254. if (FileIsConsole(STDOUT)) {
  255. ULONG cbWritten;
  256. PTCHAR s, s1, LastChar;
  257. BOOL b;
  258. s = pscr->pbBuffer;
  259. LastChar = s + pscr->ccol;
  260. //
  261. // s is the next character to output
  262. // n is the number of chars to output.
  263. //
  264. // Due to the vagaries of console character translation, we must output
  265. // all but a small set of UNICODE characters in the "normal" processed
  266. // output fashion. However, for:
  267. //
  268. // 0x2022
  269. //
  270. // we must revert to unprocessed output. So, we scan forward until we
  271. // find the end of string (or the special characters) display them in
  272. // processed form and then handle the special characters in their own way.
  273. //
  274. #define IsSpecialChar(c) ((c) == 0x2022)
  275. while (s < LastChar) {
  276. //
  277. // Skip across a group of contiguous normal chars
  278. //
  279. s1 = s;
  280. while (s1 < LastChar && !IsSpecialChar( *s1 )) {
  281. s1++;
  282. }
  283. //
  284. // If we have any chars to output then do so with normal processing
  285. //
  286. if (s1 != s) {
  287. b = WriteConsole( CRTTONT( STDOUT ), s, (ULONG)(s1 - s), &cbWritten, NULL );
  288. if (!b || cbWritten != (ULONG)(s1 - s)) {
  289. goto err_out_eol;
  290. }
  291. s = s1;
  292. }
  293. //
  294. // Skip across a group of contiguous special chars
  295. //
  296. while (s1 < LastChar && IsSpecialChar( *s1 )) {
  297. s1++;
  298. }
  299. //
  300. // If we have any special chars, output without processing
  301. //
  302. if (s1 != s) {
  303. DisableProcessedOutput( pscr );
  304. b = WriteConsole( CRTTONT( STDOUT ), s, (ULONG)(s1 - s), &cbWritten, NULL);
  305. EnableProcessedOutput(pscr);
  306. if (!b || cbWritten != (ULONG)(s1 - s)) {
  307. goto err_out_eol;
  308. }
  309. s = s1;
  310. }
  311. }
  312. #undef IsSpecialChar
  313. }
  314. else if (MyWriteFile(STDOUT,
  315. pscr->pbBuffer, pscr->ccol*sizeof(TCHAR),
  316. (LPDWORD)&cbWritten) == 0 ||
  317. cbWritten != pscr->ccol*sizeof(TCHAR)) {
  318. err_out_eol:
  319. if (FileIsDevice(STDOUT)) {
  320. //
  321. // If writing to a device then it must have been write fault
  322. // against the device.
  323. //
  324. #if DBG
  325. fprintf(stderr, "WriteFlush - WriteConsole error %d, tried to write %d, did %d\n", GetLastError(), pscr->ccol, cbWritten);
  326. #endif
  327. PutStdErr(ERROR_WRITE_FAULT, NOARGS) ;
  328. } else if (!FileIsPipe(STDOUT)) {
  329. //
  330. // If not a device (file) but not a pipe then the disk is
  331. // considered full.
  332. //
  333. #if DBG
  334. fprintf(stderr, "WriteFlush - WriteFile error %d, tried to write %d, did %d\n", GetLastError(), pscr->ccol*sizeof(TCHAR), cbWritten);
  335. #endif
  336. PutStdErr(ERROR_DISK_FULL, NOARGS) ;
  337. }
  338. //
  339. // if it was was a pipe do not continue to print out to pipe since it
  340. // has probably gone away. This is pretty serious so blow us out
  341. // to the outer loop.
  342. //
  343. // We do not print an error message since this could be normal
  344. // termination of the other end of the pipe. If it was command that
  345. // blew away we would have had an error message already
  346. //
  347. Abort();
  348. }
  349. if (!CrLfWritten) {
  350. if (FileIsConsole(STDOUT))
  351. WriteConsole(CRTTONT(STDOUT), CrLf, mystrlen(CrLf), &cbWritten, NULL);
  352. else
  353. MyWriteFile(STDOUT, CrLf, mystrlen(CrLf)*sizeof(TCHAR),
  354. (LPDWORD)&cbWritten);
  355. }
  356. //
  357. // remember that crow is the number of rows printed
  358. // since the last screen full. Not the current row position
  359. //
  360. //
  361. // Computed the number of lines printed.
  362. //
  363. pscr->crow += GetNumRows( pscr, pscr->pbBuffer );
  364. if (!CrLfWritten) {
  365. pscr->crow += 1;
  366. }
  367. //
  368. // Check if have to wait for user to hit a key before printing rest of
  369. // line.
  370. CheckPause( pscr );
  371. if (pscr->crow > pscr->crowMax) {
  372. pscr->crow = 0;
  373. }
  374. pscr->pbBuffer[0] = 0;
  375. pscr->ccol = 0;
  376. DEBUG((ICGRP, CONLVL, "Console: end row = %d\n", pscr->crow)) ;
  377. return(SUCCESS);
  378. }
  379. VOID
  380. CheckPause(
  381. IN PSCREEN pscr
  382. )
  383. /*++
  384. Routine Description:
  385. Pause. Execution of screen is full, waiting for the user to type a key.
  386. Arguments:
  387. pscr - buffer holding row information
  388. Return Value:
  389. none
  390. --*/
  391. {
  392. DEBUG((ICGRP, CONLVL, "CheckPause: Pause Count %d, Row Count %d",
  393. pscr->crowPause, pscr->crow)) ;
  394. if (pscr->crowPause) {
  395. if (pscr->crow >= pscr->crowPause) {
  396. ePause((struct cmdnode *)0);
  397. pscr->crow = 0;
  398. SetColRow( pscr );
  399. SetPause(pscr, pscr->crowMax - 1);
  400. }
  401. }
  402. }
  403. VOID
  404. SetTab(
  405. IN PSCREEN pscr,
  406. IN ULONG ccol
  407. )
  408. /*++
  409. Routine Description:
  410. Set the current tab spacing.
  411. Arguments:
  412. pscr - screen info.
  413. ccol - tab spacing
  414. Return Value:
  415. none
  416. --*/
  417. {
  418. pscr->ccolTabMax = pscr->ccolMax;
  419. if (ccol) {
  420. //
  421. // divide the screen up into tab fields, then do
  422. // not allow tabbing into past last field. This
  423. // insures that all name of ccol size can fit on
  424. // screen
  425. //
  426. pscr->ccolTabMax = (pscr->ccolMax / ccol) * ccol;
  427. }
  428. pscr->ccolTab = ccol;
  429. }
  430. STATUS
  431. WriteTab(
  432. IN PSCREEN pscr
  433. )
  434. /*++
  435. Routine Description:
  436. Fills the buffer with spaces up to the next tab position
  437. Arguments:
  438. pscr - screen info.
  439. ccol - tab spacing
  440. Return Value:
  441. none
  442. --*/
  443. {
  444. ULONG ccolBlanks;
  445. #ifdef FE_SB
  446. ULONG ccolActual;
  447. #endif /* not Japan */
  448. //
  449. // Check that we have a non-zero tab spacing.
  450. //
  451. if ( pscr->ccolTab ) {
  452. //
  453. // Compute the number of spaces we will have to write.
  454. //
  455. #ifdef FE_SB
  456. if (IsDBCSCodePage())
  457. ccolActual = SizeOfHalfWidthString(pscr->pbBuffer);
  458. else
  459. ccolActual = pscr->ccol;
  460. ccolBlanks = pscr->ccolTab - (ccolActual % pscr->ccolTab);
  461. #else
  462. ccolBlanks = pscr->ccolTab - (pscr->ccol % pscr->ccolTab);
  463. #endif
  464. //
  465. // check if the tab will fit on the screen
  466. //
  467. #ifdef FE_SB
  468. if ((ccolBlanks + ccolActual) < pscr->ccolTabMax) {
  469. #else
  470. if ((ccolBlanks + pscr->ccol) < pscr->ccolTabMax) {
  471. #endif
  472. mytcsnset(pscr->pbBuffer + pscr->ccol, SPACE, ccolBlanks);
  473. pscr->ccol += ccolBlanks;
  474. pscr->pbBuffer[pscr->ccol] = NULLC;
  475. return( SUCCESS );
  476. } else {
  477. //
  478. // It could not so outpt <cr> and move to
  479. // next line
  480. //
  481. return(WriteEol(pscr));
  482. }
  483. }
  484. return( SUCCESS );
  485. }
  486. VOID
  487. FillToCol (
  488. IN PSCREEN pscr,
  489. IN ULONG ccol
  490. )
  491. /*++
  492. Routine Description:
  493. Fills the buffer with spaces up ccol
  494. Arguments:
  495. pscr - screen info.
  496. ccol - column to fill to.
  497. Return Value:
  498. none
  499. --*/
  500. {
  501. #ifdef FE_SB
  502. ULONG ccolActual;
  503. ULONG cb;
  504. BOOL fDBCS;
  505. if ( fDBCS = IsDBCSCodePage())
  506. ccolActual = SizeOfHalfWidthString(pscr->pbBuffer);
  507. else
  508. ccolActual = pscr->ccol;
  509. #endif
  510. #ifdef FE_SB
  511. cb = _tcslen(pscr->pbBuffer);
  512. if (ccolActual >= ccol) {
  513. if (fDBCS)
  514. ccol = cb - (ccolActual - ccol);
  515. #else
  516. if (pscr->ccol >= ccol) {
  517. #endif
  518. //
  519. // If we are there or past it then truncate current line
  520. // and return.
  521. //
  522. pscr->pbBuffer[ccol] = NULLC;
  523. pscr->ccol = ccol;
  524. return;
  525. }
  526. //
  527. // Only fill to column width of buffer
  528. //
  529. #ifdef FE_SB
  530. mytcsnset(pscr->pbBuffer + cb, SPACE, ccol - ccolActual);
  531. if (fDBCS)
  532. ccol = cb + ccol - ccolActual;
  533. #else
  534. mytcsnset(pscr->pbBuffer + pscr->ccol, SPACE, ccol - pscr->ccol);
  535. #endif
  536. pscr->ccol = ccol;
  537. pscr->pbBuffer[ccol] = NULLC;
  538. }
  539. STATUS
  540. WriteFlush(
  541. IN PSCREEN pscr
  542. )
  543. /*++
  544. Routine Description:
  545. Write what ever is currently on the buffer to the screen. No EOF is
  546. printed.
  547. Arguments:
  548. pscr - screen info.
  549. Return Value:
  550. Will abort on write error.
  551. SUCCESS
  552. --*/
  553. {
  554. DWORD cb;
  555. //
  556. // If there is something in the buffer flush it out
  557. //
  558. if (pscr->ccol) {
  559. if (FileIsConsole(STDOUT)) {
  560. ULONG cbWritten;
  561. PTCHAR s, s1, LastChar;
  562. BOOL b;
  563. s = pscr->pbBuffer;
  564. LastChar = s + pscr->ccol;
  565. //
  566. // s is the next character to output
  567. // n is the number of chars to output.
  568. //
  569. // Due to the vagaries of console character translation, we must output
  570. // all but a small set of UNICODE characters in the "normal" processed
  571. // output fashion. However, for:
  572. //
  573. // 0x2022
  574. //
  575. // we must revert to unprocessed output. So, we scan forward until we
  576. // find the end of string (or the special characters) display them in
  577. // processed form and then handle the special characters in their own way.
  578. //
  579. #define IsSpecialChar(c) ((c) == 0x2022)
  580. while (s < LastChar) {
  581. //
  582. // Skip across a group of contiguous normal chars
  583. //
  584. s1 = s;
  585. while (s1 < LastChar && !IsSpecialChar( *s1 )) {
  586. s1++;
  587. }
  588. //
  589. // If we have any chars to output then do so with normal processing
  590. //
  591. if (s1 != s) {
  592. b = WriteConsole( CRTTONT( STDOUT ), s, (ULONG)(s1 - s), &cbWritten, NULL );
  593. if (!b || cbWritten != (ULONG)(s1 - s)) {
  594. goto err_out_flush;
  595. }
  596. s = s1;
  597. }
  598. //
  599. // Skip across a group of contiguous special chars
  600. //
  601. while (s1 < LastChar && IsSpecialChar( *s1 )) {
  602. s1++;
  603. }
  604. //
  605. // If we have any special chars, output without processing
  606. //
  607. if (s1 != s) {
  608. DisableProcessedOutput( pscr );
  609. b = WriteConsole( CRTTONT( STDOUT ), s, (ULONG)(s1 - s), &cbWritten, NULL);
  610. EnableProcessedOutput(pscr);
  611. if (!b || cbWritten != (ULONG)(s1 - s)) {
  612. goto err_out_flush;
  613. }
  614. s = s1;
  615. }
  616. }
  617. #undef IsSpecialChar
  618. }
  619. else if (MyWriteFile(STDOUT,
  620. pscr->pbBuffer, pscr->ccol*sizeof(TCHAR), &cb) == 0 ||
  621. cb < pscr->ccol*sizeof(TCHAR)) {
  622. err_out_flush:
  623. if (FileIsDevice(STDOUT)) {
  624. PutStdErr(ERROR_WRITE_FAULT, NOARGS) ;
  625. } else if (!FileIsPipe(STDOUT)) {
  626. PutStdErr(ERROR_DISK_FULL, NOARGS) ;
  627. }
  628. //
  629. // if it was was a pipe do not continue to print out to pipe since it
  630. // has probably gone away.
  631. Abort();
  632. }
  633. }
  634. pscr->crow += GetNumRows(pscr, pscr->pbBuffer);
  635. pscr->pbBuffer[0] = 0;
  636. pscr->ccol = 0;
  637. return(SUCCESS);
  638. }
  639. STATUS
  640. WriteFlushAndEol(
  641. IN PSCREEN pscr
  642. )
  643. /*++
  644. Routine Description:
  645. Write Flush with eof.
  646. Arguments:
  647. pscr - screen info.
  648. Return Value:
  649. Will abort on write error.
  650. SUCCESS
  651. --*/
  652. {
  653. STATUS rc = SUCCESS;
  654. //
  655. // Check if there is something on the line to print.
  656. //
  657. if (pscr->ccol) {
  658. rc = WriteEol(pscr);
  659. }
  660. return( rc );
  661. }
  662. void
  663. SetColRow(
  664. IN PSCREEN pscr
  665. )
  666. {
  667. CONSOLE_SCREEN_BUFFER_INFO ConInfo;
  668. ULONG crowMax, ccolMax;
  669. crowMax = 25;
  670. ccolMax = 80;
  671. if (pscr->hndScreen) {
  672. //
  673. // On open we checked if this was a valid screen handle so this
  674. // cannot fail for any meaning full reason. If we do fail then
  675. // just leave it at the default.
  676. //
  677. if (GetConsoleScreenBufferInfo( pscr->hndScreen, &ConInfo)) {
  678. //
  679. // The console size we use is the screen buffer size not the
  680. // windows size itself. The window is a frame upon the screen
  681. // buffer and we should always write to the screen buffer and
  682. // format based upon that information
  683. //
  684. ccolMax = ConInfo.dwSize.X;
  685. crowMax = ConInfo.srWindow.Bottom - ConInfo.srWindow.Top + 1;
  686. }
  687. }
  688. pscr->crowMax = crowMax;
  689. pscr->ccolMax = ccolMax;
  690. }
  691. ULONG
  692. GetNumRows(
  693. IN PSCREEN pscr,
  694. IN PTCHAR pbBuffer
  695. )
  696. {
  697. PTCHAR szLFLast, szLFCur;
  698. ULONG crow, cb;
  699. szLFLast = pbBuffer;
  700. crow = 0;
  701. while ( szLFCur = mystrchr(szLFLast, chLF) ) {
  702. cb = (ULONG)(szLFCur - szLFLast);
  703. while ( cb > pscr->ccolMax ) {
  704. cb -= pscr->ccolMax;
  705. crow++;
  706. }
  707. crow++;
  708. szLFLast = szLFCur + 1;
  709. }
  710. //
  711. // if there were no LF's in the line then crow would be
  712. // 0. Count the number of lines the console will output in
  713. // wrapping
  714. //
  715. if (crow == 0) {
  716. crow = (pscr->ccol / pscr->ccolMax);
  717. }
  718. DEBUG((ICGRP, CONLVL, "Console: Num of rows counted = %d", crow)) ;
  719. //
  720. // a 0 returns means that there would not be a LF printed or
  721. // a wrap done.
  722. //
  723. return( crow );
  724. }
  725. #if defined(FE_SB)
  726. BOOLEAN
  727. IsDBCSCodePage()
  728. {
  729. switch (CurrentCP) {
  730. case 932:
  731. case 936:
  732. case 949:
  733. case 950:
  734. return TRUE;
  735. break;
  736. default:
  737. return FALSE;
  738. break;
  739. }
  740. }
  741. /***************************************************************************\
  742. * BOOL IsFullWidth(TCHAR wch)
  743. *
  744. * Determine if the given Unicode char is fullwidth or not.
  745. *
  746. * History:
  747. * 04-08-92 ShunK Created.
  748. * 07-11-95 FloydR Modified to be Japanese aware, when enabled for
  749. * other DBCS languages. Note that we could build
  750. * KOREA/TAIWAN/PRC w/o this code, but we like single
  751. * binary solutions.
  752. * Oct-06-1996 KazuM Not use RtlUnicodeToMultiByteSize and WideCharToMultiByte
  753. * Because 950 only defined 13500 chars,
  754. * and unicode defined almost 18000 chars.
  755. * So there are almost 4000 chars can not be mapped to big5 code.
  756. \***************************************************************************/
  757. BOOL IsFullWidth(TCHAR wch)
  758. {
  759. #ifdef UNICODE
  760. /* Assert CP == 932/936/949/950 */
  761. if (CurrentCPInfo.MaxCharSize == 1)
  762. return FALSE;
  763. if (0x20 <= wch && wch <= 0x7e)
  764. /* ASCII */
  765. return FALSE;
  766. else if (0x3000 <= wch && wch <= 0x3036)
  767. /* CJK Symbols and Punctuation */
  768. return TRUE;
  769. else if (0x3041 <= wch && wch <= 0x3094)
  770. /* Hiragana */
  771. return TRUE;
  772. else if (0x30a1 <= wch && wch <= 0x30f6)
  773. /* Katakana */
  774. return TRUE;
  775. else if (0x3105 <= wch && wch <= 0x312c)
  776. /* Bopomofo */
  777. return TRUE;
  778. else if (0x3131 <= wch && wch <= 0x318e)
  779. /* Hangul Elements */
  780. return TRUE;
  781. else if (0x3200 <= wch && wch <= 0x32ff)
  782. /* Enclosed CJK Letters and Ideographics */
  783. return TRUE;
  784. else if (0x3300 <= wch && wch <= 0x33fe)
  785. /* CJK Squared Words and Abbreviations */
  786. return TRUE;
  787. else if (0xac00 <= wch && wch <= 0xd7a3)
  788. /* Korean Hangul Syllables */
  789. return TRUE;
  790. else if (0xe000 <= wch && wch <= 0xf8ff)
  791. /* EUDC */
  792. return TRUE;
  793. else if (0xff01 <= wch && wch <= 0xff5e)
  794. /* Fullwidth ASCII variants */
  795. return TRUE;
  796. else if (0xff61 <= wch && wch <= 0xff9f)
  797. /* Halfwidth Katakana variants */
  798. return FALSE;
  799. else if ( (0xffa0 <= wch && wch <= 0xffbe) ||
  800. (0xffc2 <= wch && wch <= 0xffc7) ||
  801. (0xffca <= wch && wch <= 0xffcf) ||
  802. (0xffd2 <= wch && wch <= 0xffd7) ||
  803. (0xffda <= wch && wch <= 0xffdc) )
  804. /* Halfwidth Hangule variants */
  805. return FALSE;
  806. else if (0xffe0 <= wch && wch <= 0xffe6)
  807. /* Fullwidth symbol variants */
  808. return TRUE;
  809. else if (0x4e00 <= wch && wch <= 0x9fa5)
  810. /* CJK Ideographic */
  811. return TRUE;
  812. else if (0xf900 <= wch && wch <= 0xfa2d)
  813. /* CJK Compatibility Ideographs */
  814. return TRUE;
  815. else if (0xfe30 <= wch && wch <= 0xfe4f) {
  816. /* CJK Compatibility Forms */
  817. return TRUE;
  818. }
  819. else
  820. /* Unknown character */
  821. return FALSE;
  822. #else
  823. if (IsDBCSLeadByteEx(CurrentCP, wch))
  824. return TRUE;
  825. else
  826. return FALSE;
  827. #endif
  828. }
  829. /***************************************************************************\
  830. * BOOL SizeOfHalfWidthString(PWCHAR pwch)
  831. *
  832. * Determine size of the given Unicode string, adjusting for half-width chars.
  833. *
  834. * History:
  835. * 08-08-93 FloydR Created.
  836. \***************************************************************************/
  837. int SizeOfHalfWidthString(TCHAR *pwch)
  838. {
  839. int c=0;
  840. if (IsDBCSCodePage())
  841. {
  842. while (*pwch) {
  843. if (IsFullWidth(*pwch))
  844. c += 2;
  845. else
  846. c++;
  847. pwch++;
  848. }
  849. return c;
  850. }
  851. else
  852. return _tcslen(pwch);
  853. }
  854. #endif