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.

1983 lines
59 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. physical.c
  5. Abstract:
  6. Support the following functions related to sending data to the printer
  7. and print head movements, cursor control.
  8. WriteSpoolBuf
  9. WriteAbortBuf
  10. FlushSpoolBuf
  11. WriteChannel
  12. WriteChannelEx
  13. XMoveTo
  14. YMoveTo
  15. Environment:
  16. Windows NT Unidrv driver
  17. Revision History:
  18. 10/14/96 -amandan-
  19. Created
  20. --*/
  21. #include "unidrv.h"
  22. static int itoA( LPSTR , int );
  23. INT IGetNumParameter( BYTE *, INT);
  24. BOOL BUniWritePrinter(
  25. IN PDEV* pPDev,
  26. IN LPVOID pBuf,
  27. IN DWORD cbBuf,
  28. OUT LPDWORD pcbWritten);
  29. #define DELTA_X (pPDev->dwFontWidth/2)
  30. #define DELTA_Y (dwMaxLineSpacing /5)
  31. WriteSpoolBuf(
  32. PDEV *pPDev,
  33. BYTE *pbBuf,
  34. INT iCount
  35. )
  36. /*++
  37. Routine Description:
  38. This is an intermediate routine for Unidrv to send characters to
  39. the printer via the spooler. All characters must be sent through
  40. the WriteSpool( ) call. WriteSpoolBuf is internal so that Unidrv
  41. can buffer up short command streams before calling WriteSpool.
  42. This routine also checks for error flags returned from WriteSpool.
  43. Arguments:
  44. pPDev - Pointer to PDEVICE struct
  45. pbBuf - Pointer to buffer containing data to be sent
  46. iCount - Count of number of bytes to send
  47. Return Value:
  48. The number of bytes sent to the printer
  49. --*/
  50. {
  51. DWORD dw;
  52. //
  53. // Check for aborted output
  54. //
  55. if( pPDev->fMode & PF_ABORTED )
  56. return 0;
  57. //
  58. // If the output buffer cannot accomodate the current request,
  59. // flush the content of the buffer first.
  60. //
  61. if( (pPDev->iSpool) && (pPDev->iSpool + iCount > CCHSPOOL ))
  62. {
  63. if( !FlushSpoolBuf( pPDev ) )
  64. {
  65. WriteAbortBuf(pPDev, pPDev->pbOBuf, pPDev->iSpool, 0) ;
  66. pPDev->iSpool = 0;
  67. return 0; // at least send previously cached stuff.
  68. }
  69. }
  70. //
  71. // Check whether request is larger than output buffer, if so, skip buffering
  72. // and write directly to spooler.
  73. //
  74. if( iCount >= CCHSPOOL )
  75. {
  76. if( !BUniWritePrinter( pPDev, pbBuf, iCount, &dw ) )
  77. {
  78. pPDev->iSpool = 0;
  79. pPDev->fMode |= PF_ABORTED;
  80. iCount = 0;
  81. }
  82. }
  83. else
  84. {
  85. //
  86. // buffer up the output
  87. //
  88. if( pPDev->pbOBuf == NULL)
  89. return 0;
  90. CopyMemory( pPDev->pbOBuf + pPDev->iSpool, pbBuf, iCount );
  91. pPDev->iSpool += iCount;
  92. }
  93. return iCount;
  94. }
  95. VOID WriteAbortBuf(
  96. PDEV *pPDev,
  97. BYTE *pbBuf,
  98. INT iCount,
  99. DWORD dwWait
  100. )
  101. {
  102. DWORD dwCount = 0;
  103. HMODULE hInst ;
  104. typedef BOOL (*PFNFLUSHPR)( HANDLE hPrinter,
  105. LPVOID pBuf,
  106. DWORD cbBuf,
  107. LPDWORD pcWritten,
  108. DWORD cSleep) ;
  109. //
  110. // Call FlushPrinter only if there is no plugin hooking WritePrinter .
  111. // One of plug-ins hooks WritePrinter, the plug-in need to call FlushPrinter.
  112. // In that case, UNIDRV should not call FlushPrinter.
  113. //
  114. if( pPDev->fMode & PF_ABORTED &&
  115. !(pPDev->fMode2 & PF2_WRITE_PRINTER_HOOKED))
  116. {
  117. #ifdef WINNT_40
  118. ; // Pretend we flushed
  119. #else
  120. BOOL bRet;
  121. do
  122. {
  123. bRet = FlushPrinter(pPDev->devobj.hPrinter, pbBuf, iCount, &dwCount, dwWait);
  124. pbBuf += dwCount;
  125. iCount -= dwCount;
  126. } while (bRet && iCount > 0 && dwCount > 0);
  127. #endif
  128. }
  129. }
  130. BOOL
  131. FlushSpoolBuf(
  132. PDEV *pPDev
  133. )
  134. /*++
  135. Routine Description:
  136. This function flush our internal buffer.
  137. Arguments:
  138. pPDev - Pointer to PDEVICE struct
  139. Return Value:
  140. TRUE if successful , otherwise FALSE
  141. --*/
  142. {
  143. DWORD dwCount;
  144. //
  145. // Check for aborted output
  146. //
  147. if( pPDev->fMode & PF_ABORTED )
  148. return 0;
  149. //
  150. // Write the data out
  151. //
  152. if( pPDev->iSpool )
  153. {
  154. if ( !BUniWritePrinter(pPDev, pPDev->pbOBuf, pPDev->iSpool, &dwCount) )
  155. {
  156. pPDev->fMode |= PF_ABORTED;
  157. return FALSE;
  158. }
  159. pPDev->iSpool = 0;
  160. }
  161. return TRUE;
  162. }
  163. INT
  164. XMoveTo(
  165. PDEV *pPDev,
  166. INT iXIn,
  167. INT fFlag
  168. )
  169. /*++
  170. Routine Description:
  171. This function is called to change the X position.
  172. Arguments:
  173. pPDev - Pointer to PDEVICE struct
  174. iXIn - Number of units to move in X direction
  175. fFlag - Specifies the different X move operations
  176. Return Value:
  177. The difference between requested and actual value sent to the device
  178. --*/
  179. {
  180. int iX, iFineValue, iDiff = 0;
  181. GPDDRIVERINFO *pDrvInfo = pPDev->pDriverInfo;
  182. int iScale;
  183. //
  184. // If the position is given in graphics units, convert to master units
  185. //
  186. // ptGrxScale has been adjusted to suit the current orientation.
  187. //
  188. if (pPDev->pOrientation && pPDev->pOrientation->dwRotationAngle != ROTATE_NONE &&
  189. pPDev->pGlobals->bRotateCoordinate == FALSE)
  190. iScale = pPDev->ptGrxScale.y;
  191. else
  192. iScale = pPDev->ptGrxScale.x;
  193. if ( fFlag & MV_GRAPHICS )
  194. {
  195. iXIn = (iXIn * iScale);
  196. }
  197. //
  198. // Since our print origin may not correspond with the printer's,
  199. // there are times when we need to adjust the value passed in to
  200. // match the desired location on the page.
  201. //
  202. iX = iXIn;
  203. //
  204. // Basically, only adjust if we are doing absolute move
  205. //
  206. if ( !(fFlag & (MV_RELATIVE | MV_PHYSICAL)) )
  207. iX += pPDev->sf.ptPrintOffsetM.x;
  208. //
  209. // If it's a relative move, update iX (iX will be the absolute position)
  210. // to reflect the current cursor position
  211. //
  212. if ( fFlag & MV_RELATIVE )
  213. iX += pPDev->ctl.ptCursor.x;
  214. //By definition a negative absolute move relative to Imageable origin
  215. //is not allowed. But the MV_FORCE_CR flag bypasses this check.
  216. if(!(fFlag & MV_FORCE_CR) && (iX - pPDev->sf.ptPrintOffsetM.x < 0))
  217. iX = pPDev->sf.ptPrintOffsetM.x ;
  218. //
  219. // Update, only update our current cursor position and return
  220. // Do nothing if the XMoveTo cmd is called to move to the current position.
  221. //
  222. if ( fFlag & MV_UPDATE )
  223. {
  224. pPDev->ctl.ptAbsolutePos.x = pPDev->ctl.ptCursor.x = iX;
  225. return 0;
  226. }
  227. if( fFlag & MV_SENDXMOVECMD )
  228. pPDev->ctl.dwMode |= MODE_CURSOR_X_UNINITIALIZED;
  229. if (!(pPDev->ctl.dwMode & MODE_CURSOR_X_UNINITIALIZED) && pPDev->ctl.ptCursor.x == iX )
  230. return 0;
  231. //
  232. // If iX is zero and pGlobals->cxaftercr does not have
  233. // CXCR_AT_GRXDATA_ORIGIN set, then we send CR and reset our
  234. // cursor position to 0, which is the printable x origin
  235. //
  236. if (iX == 0 && (pPDev->pGlobals->cxaftercr == CXCR_AT_CURSOR_X_ORIGIN ||
  237. pPDev->sf.ptPrintOffsetM.x == 0))
  238. {
  239. pPDev->ctl.ptAbsolutePos.x = pPDev->ctl.ptCursor.x = 0;
  240. WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_CARRIAGERETURN));
  241. pPDev->ctl.dwMode &= ~MODE_CURSOR_X_UNINITIALIZED;
  242. return 0;
  243. }
  244. //
  245. // Check whether we any X move cmd, PF_NO_XMOVE_CMD is set if we did
  246. // not see any relative or absolute x move cmds
  247. //
  248. if( pPDev->fMode & PF_NO_XMOVE_CMD)
  249. {
  250. //
  251. // There is no X move command(abs or relative), so we'll have to simulate
  252. // using blanks or null graphics data (0)
  253. //
  254. //
  255. // We assume that when XMoveto is called, the current font is always
  256. // the default font IF the printer has no X movement command.
  257. //
  258. int iRelx = iX - pPDev->ctl.ptCursor.x ;
  259. int iDefWidth;
  260. //
  261. // Convert to Master Units
  262. //
  263. //
  264. // BUG_BUG, Double check that we can use Default Font here when
  265. // we have a custom TTY driver
  266. // seems to work so far.
  267. //
  268. if ( iRelx < 0 && (!pPDev->bTTY || (DWORD)(-iRelx) > DELTA_X ))
  269. {
  270. if (pPDev->pGlobals->cxaftercr == CXCR_AT_CURSOR_X_ORIGIN)
  271. iRelx = iX;
  272. else if (pPDev->pGlobals->cxaftercr == CXCR_AT_PRINTABLE_X_ORIGIN)
  273. {
  274. // printing offset is only available in the callers
  275. // cooridinates so if the move is being performed
  276. // in different coordinates, the offset will be wrong.
  277. ASSERT(!pPDev->pOrientation || pPDev->pOrientation->dwRotationAngle == ROTATE_NONE ||
  278. pPDev->pGlobals->bRotateCoordinate == TRUE) ;
  279. iRelx = iX - pPDev->sf.ptPrintOffsetM.x;
  280. }
  281. WriteChannel( pPDev, COMMANDPTR(pDrvInfo, CMD_CARRIAGERETURN ));
  282. }
  283. //
  284. // Simulate X Move, algorithm is that we always send a blank space
  285. // for every character width, and send graphics null data for
  286. // the remainder, in the case of TTY we skip the remaining graphics that
  287. // cannot be sent within a space character width.
  288. //
  289. iDefWidth = pPDev->dwFontWidth ;
  290. if (iDefWidth)
  291. {
  292. while(iRelx >= iDefWidth)
  293. {
  294. WriteSpoolBuf( pPDev, (LPSTR)" ", 1 );
  295. iRelx -= iDefWidth;
  296. }
  297. }
  298. else
  299. TERSE (("XMoveTo: iDefWidth = 0\n"));
  300. //
  301. // Send the remaining partial space via FineXMoveTo.
  302. //
  303. if (!pPDev->bTTY)
  304. {
  305. iDiff = iRelx;
  306. fFlag |= MV_FINE; // Use graphics mode to reach point
  307. }
  308. }
  309. else
  310. {
  311. DWORD dwTestValue = abs(iX - pPDev->ctl.ptCursor.x);
  312. COMMAND *pCmd;
  313. //
  314. // X movement commmands are available, so use them.
  315. // We need to decide here whether relative or absolute command
  316. // are favored
  317. //
  318. // General assumption: if dwTestValue > dwXMoveThreshold,
  319. // absolute command will be favored
  320. //
  321. //
  322. // BUG_BUG, if we are stripping blanks, we need to check whether
  323. // it's legal to move in Graphics mode. If it's not, we have
  324. // to get out of graphics mode before moving.
  325. // Graphics module is responsible for keeping track
  326. // of these things, and appearently so far, things work, so
  327. // this is neither a bug nor a feature request at this time.
  328. //
  329. if (((pPDev->ctl.dwMode & MODE_CURSOR_X_UNINITIALIZED) ||
  330. ((dwTestValue > pPDev->pGlobals->dwXMoveThreshold ) &&
  331. iX >= 0) ||
  332. !COMMANDPTR(pDrvInfo, CMD_XMOVERELRIGHT)) &&
  333. (pCmd = COMMANDPTR(pDrvInfo, CMD_XMOVEABSOLUTE)) != NULL)
  334. {
  335. //
  336. // if the move units are less than the master units then we need to
  337. // check whether the new position will end up being the same as the
  338. // original position. If so, no point in sending another command.
  339. //
  340. if (!(pPDev->ctl.dwMode & MODE_CURSOR_X_UNINITIALIZED) &&
  341. (pPDev->ptDeviceFac.x > 1) &&
  342. ((iX - (iX % pPDev->ptDeviceFac.x)) == pPDev->ctl.ptCursor.x))
  343. {
  344. iDiff = iX - pPDev->ctl.ptCursor.x;
  345. }
  346. else
  347. {
  348. // check whether the no absolute move left flag is set. If set we need
  349. // to send a CR before doing the absolute move.
  350. //
  351. if (iX < pPDev->ctl.ptCursor.x && pPDev->pGlobals->bAbsXMovesRightOnly)
  352. {
  353. WriteChannel( pPDev, COMMANDPTR(pDrvInfo, CMD_CARRIAGERETURN ));
  354. }
  355. pPDev->ctl.ptAbsolutePos.x = iX;
  356. //
  357. // 3/13/97 ZhanW
  358. // set up DestY as well in case it's needed (ex. FE printers).
  359. // In that case, truncation error (iDiff) is not a concern.
  360. // This is for backward compatibility with FE Win95 and FE NT4
  361. // minidrivers.
  362. //
  363. pPDev->ctl.ptAbsolutePos.y = pPDev->ctl.ptCursor.y;
  364. iDiff = WriteChannelEx(pPDev,
  365. pCmd,
  366. pPDev->ctl.ptAbsolutePos.x,
  367. pPDev->ptDeviceFac.x);
  368. }
  369. }
  370. else
  371. {
  372. //
  373. // Use relative command to send move request
  374. //
  375. INT iRelRightValue = 0;
  376. if( iX < pPDev->ctl.ptCursor.x )
  377. {
  378. //
  379. // Relative move left
  380. //
  381. if (pCmd = COMMANDPTR(pDrvInfo,CMD_XMOVERELLEFT))
  382. {
  383. //
  384. // Optimize to avoid sending 0-move cmd.
  385. //
  386. if ((pPDev->ctl.ptRelativePos.x =
  387. pPDev->ctl.ptCursor.x - iX) < pPDev->ptDeviceFac.x)
  388. iDiff = pPDev->ctl.ptRelativePos.x;
  389. else
  390. iDiff = WriteChannelEx(pPDev,
  391. pCmd,
  392. pPDev->ctl.ptRelativePos.x,
  393. pPDev->ptDeviceFac.x);
  394. iDiff = -iDiff;
  395. }
  396. else
  397. {
  398. //
  399. // No Relative left move cmd, use <CR> to reach start
  400. // Will try to use relative right move cmd to send later
  401. //
  402. WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_CARRIAGERETURN));
  403. if (pPDev->pGlobals->cxaftercr == CXCR_AT_CURSOR_X_ORIGIN)
  404. iRelRightValue = iX;
  405. else if (pPDev->pGlobals->cxaftercr == CXCR_AT_PRINTABLE_X_ORIGIN)
  406. {
  407. // moveto code cannot handle case where printer cannot
  408. // rotate its coordinate system, and we are in landscape mode
  409. // and we are using relative move commands.
  410. ASSERT(!pPDev->pOrientation || pPDev->pOrientation->dwRotationAngle == ROTATE_NONE ||
  411. pPDev->pGlobals->bRotateCoordinate == TRUE) ;
  412. iRelRightValue = iX - pPDev->sf.ptPrintOffsetM.x;
  413. }
  414. }
  415. }
  416. else
  417. {
  418. //
  419. // Relative right move
  420. // UNIITIALZIED is an invalid position, set to zero
  421. //
  422. iRelRightValue = iX - pPDev->ctl.ptCursor.x;
  423. }
  424. if( iRelRightValue > 0 )
  425. {
  426. if (pCmd = COMMANDPTR(pDrvInfo, CMD_XMOVERELRIGHT))
  427. {
  428. //
  429. // optimize to avoid 0-move cmd
  430. //
  431. if ((pPDev->ctl.ptRelativePos.x = iRelRightValue) <
  432. pPDev->ptDeviceFac.x)
  433. iDiff = iRelRightValue;
  434. else
  435. iDiff = WriteChannelEx(pPDev,
  436. pCmd,
  437. pPDev->ctl.ptRelativePos.x,
  438. pPDev->ptDeviceFac.x);
  439. }
  440. else
  441. iDiff = iRelRightValue;
  442. }
  443. }
  444. }
  445. //
  446. // Peform fine move command
  447. //
  448. if ( (fFlag & MV_FINE) && iDiff > 0 )
  449. iDiff = FineXMoveTo( pPDev, iDiff );
  450. //
  451. // Update our current cursor position
  452. //
  453. pPDev->ctl.ptAbsolutePos.x = pPDev->ctl.ptCursor.x = iX - iDiff ;
  454. if( fFlag & MV_GRAPHICS )
  455. {
  456. iDiff = (iDiff / iScale);
  457. }
  458. if (pPDev->fMode & PF_RESELECTFONT_AFTER_XMOVE)
  459. {
  460. VResetFont(pPDev);
  461. }
  462. pPDev->ctl.dwMode &= ~MODE_CURSOR_X_UNINITIALIZED;
  463. return( iDiff);
  464. }
  465. INT
  466. YMoveTo(
  467. PDEV *pPDev,
  468. INT iYIn,
  469. INT fFlag
  470. )
  471. /*++
  472. Routine Description:
  473. This function is called to change the Y position.
  474. Arguments:
  475. pPDev - Pointer to PDEVICE struct
  476. iYIn - Number of units to move in Y direction
  477. fFlag - Specifies the different Y move operations
  478. Return Value:
  479. The difference between requested and actual value sent to the device
  480. --*/
  481. {
  482. INT iY, iDiff = 0;
  483. DWORD dwTestValue;
  484. GPDDRIVERINFO *pDrvInfo = pPDev->pDriverInfo;
  485. COMMAND *pAbsCmd;
  486. INT iScale;
  487. //
  488. // Convert to Master Units if the given units is in Graphics Units
  489. // ptGrxScale has been adjusted to suit the current orientation.
  490. //
  491. if (pPDev->pOrientation && pPDev->pOrientation->dwRotationAngle != ROTATE_NONE &&
  492. pPDev->pGlobals->bRotateCoordinate == FALSE)
  493. iScale = pPDev->ptGrxScale.x;
  494. else
  495. iScale = pPDev->ptGrxScale.y;
  496. if ( fFlag & MV_GRAPHICS )
  497. {
  498. iYIn = (iYIn * iScale);
  499. }
  500. //
  501. // Since our print origin may not correspond with the printer's,
  502. // there are times when we need to adjust the value passed in to
  503. // match the desired location on the page.
  504. //
  505. iY = iYIn;
  506. //
  507. // Basically, only adjust if we are doing absolute move
  508. //
  509. if ( !(fFlag & (MV_RELATIVE | MV_PHYSICAL)) )
  510. iY += pPDev->sf.ptPrintOffsetM.y;
  511. //
  512. // Adjust iY to be the absolute position
  513. //
  514. if( fFlag & MV_RELATIVE )
  515. iY += pPDev->ctl.ptCursor.y;
  516. //
  517. // Update, only update our current cursor position and return
  518. // Do nothing if the YMoveTo cmd is called to move to the current position.
  519. //
  520. if( fFlag & MV_UPDATE )
  521. {
  522. pPDev->ctl.ptAbsolutePos.y = pPDev->ctl.ptCursor.y = iY;
  523. return 0;
  524. }
  525. if( fFlag & MV_SENDYMOVECMD )
  526. pPDev->ctl.dwMode |= MODE_CURSOR_Y_UNINITIALIZED;
  527. if(!(pPDev->ctl.dwMode & MODE_CURSOR_Y_UNINITIALIZED) && pPDev->ctl.ptCursor.y == iY )
  528. return 0;
  529. //
  530. // General assumption: if dwTestValue > dwYMoveThreshold,
  531. // absolute Y move command will be favored. Also, for iY < 0,
  532. // use relative command since some printers like old LaserJet have
  533. // printable area above y=0 accessable only through relative move cmds.
  534. //
  535. //
  536. // BUG_BUG, if we are stripping blanks, we need to check whether
  537. // it's legal to move in Graphics mode. If it's not, we have
  538. // to get out of graphics mode before moving.
  539. // Graphics module is responsible for keeping track
  540. // of these things, and appearently so far, things work, so
  541. // this is neither a bug nor a feature request at this time.
  542. //
  543. dwTestValue = abs(iY - pPDev->ctl.ptCursor.y);
  544. if (((pPDev->ctl.dwMode & MODE_CURSOR_Y_UNINITIALIZED) ||
  545. (dwTestValue > pPDev->pGlobals->dwYMoveThreshold &&
  546. iY >= 0)) &&
  547. (pAbsCmd = COMMANDPTR(pDrvInfo, CMD_YMOVEABSOLUTE)) != NULL)
  548. {
  549. //
  550. // if the move units are less than the master units then we need to
  551. // check whether the new position will end up being the same as the
  552. // original position. If so, no point in sending another command.
  553. //
  554. if (!(pPDev->ctl.dwMode & MODE_CURSOR_Y_UNINITIALIZED) &&
  555. (pPDev->ptDeviceFac.y > 1) &&
  556. ((iY - (iY % pPDev->ptDeviceFac.y)) == pPDev->ctl.ptCursor.y))
  557. {
  558. iDiff = iY - pPDev->ctl.ptCursor.y;
  559. }
  560. else
  561. {
  562. pPDev->ctl.ptAbsolutePos.y = iY;
  563. pPDev->ctl.ptAbsolutePos.x = pPDev->ctl.ptCursor.x;
  564. iDiff = WriteChannelEx(pPDev,
  565. pAbsCmd,
  566. pPDev->ctl.ptAbsolutePos.y,
  567. pPDev->ptDeviceFac.y);
  568. }
  569. }
  570. else
  571. {
  572. DWORD dwSendCRFlags = 0;
  573. //
  574. // FYMOVE_SEND_CR_FIRST indicates that it's required to send a CR
  575. // before each line-spacing command
  576. //
  577. if (pPDev->fYMove & FYMOVE_SEND_CR_FIRST)
  578. {
  579. if ((pPDev->pGlobals->cxaftercr == CXCR_AT_CURSOR_X_ORIGIN))
  580. dwSendCRFlags = MV_PHYSICAL | MV_FORCE_CR;
  581. else
  582. dwSendCRFlags = MV_PHYSICAL;
  583. // in this case CR takes you to Printable origin so
  584. // MV_PHYSICAL flag should not appear.
  585. // This is a bug, but we won't fix it till something
  586. // breaks. Too risky. !!!! Bug_Bug !!!!
  587. }
  588. //
  589. // Use Relative Y-move commands
  590. //
  591. //
  592. // Use line spacing if that is preferred
  593. //
  594. if ( ((pPDev->bTTY) ||
  595. (pPDev->fYMove & FYMOVE_FAVOR_LINEFEEDSPACING &&
  596. pPDev->arCmdTable[CMD_SETLINESPACING] != NULL) ) &&
  597. (iY - pPDev->ctl.ptCursor.y > 0) &&
  598. (pPDev->arCmdTable[CMD_LINEFEED] != NULL)
  599. )
  600. {
  601. INT iLineSpacing;
  602. DWORD dwMaxLineSpacing = pPDev->pGlobals->dwMaxLineSpacing;
  603. if (pPDev->bTTY && (INT)dwTestValue > 0)
  604. { // [Peterwo] here's a hack I tried that ensures that any request for a Y-move results
  605. // in at least one CR being sent. It doesn't work, because bRealrender
  606. // code sends Y move commands of one scanline each, resulting in
  607. // one line feed per scanline.
  608. // if( (INT)dwTestValue < dwMaxLineSpacing)
  609. // dwTestValue = dwMaxLineSpacing;
  610. //
  611. // if you don't send anything, leave diff undisturbed
  612. // so the error can accumulate otherwise many small
  613. // cursor movements will not accumulate to cause one
  614. // occasional actual movement.
  615. //
  616. // For TTY driver we round up the input value one fifth of
  617. // line spacing. This is required for not sending too many
  618. // line feeds for small Y movements.
  619. //
  620. DWORD dwTmpValue;
  621. dwTmpValue = ((dwTestValue + DELTA_Y) / dwMaxLineSpacing) * dwMaxLineSpacing;
  622. if (dwTmpValue)
  623. {
  624. dwTestValue = dwTmpValue ;
  625. }
  626. }
  627. while ( (INT)dwTestValue > 0)
  628. {
  629. if (pPDev->bTTY)
  630. {
  631. iLineSpacing = dwMaxLineSpacing;
  632. if (dwTestValue < (DWORD)iLineSpacing)
  633. {
  634. iDiff = dwTestValue;
  635. break;
  636. }
  637. if ( dwSendCRFlags )
  638. {
  639. XMoveTo( pPDev, 0, dwSendCRFlags );
  640. dwSendCRFlags = 0;
  641. }
  642. }
  643. else
  644. {
  645. iLineSpacing =(INT)(dwTestValue > dwMaxLineSpacing ?
  646. dwMaxLineSpacing : dwTestValue);
  647. //
  648. // new code to handle positioning error when linespacingmoveunit doesn't
  649. // equal master units
  650. if (pPDev->pGlobals->dwLineSpacingMoveUnit > 0)
  651. {
  652. DWORD dwScale = pPDev->pGlobals->ptMasterUnits.y / pPDev->pGlobals->dwLineSpacingMoveUnit;
  653. // optimize to avoid 0-move cmd when move unit is less than master units
  654. //
  655. if (dwTestValue < dwScale)
  656. {
  657. iDiff = dwTestValue;
  658. break;
  659. }
  660. // Modify line spacing to be multiple of moveunit
  661. //
  662. iLineSpacing -= (iLineSpacing % dwScale);
  663. }
  664. if ( dwSendCRFlags )
  665. {
  666. XMoveTo( pPDev, 0, dwSendCRFlags );
  667. dwSendCRFlags = 0;
  668. }
  669. if (pPDev->ctl.lLineSpacing == -1 ||
  670. iLineSpacing != pPDev->ctl.lLineSpacing )
  671. {
  672. pPDev->ctl.lLineSpacing = iLineSpacing;
  673. WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_SETLINESPACING));
  674. }
  675. }
  676. //
  677. // Send the LF
  678. //
  679. WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_LINEFEED));
  680. dwTestValue -= (DWORD)iLineSpacing;
  681. }
  682. }
  683. else
  684. {
  685. //
  686. // Use relative command
  687. //
  688. PCOMMAND pCmd;
  689. if ( iY <= pPDev->ctl.ptCursor.y )
  690. {
  691. //
  692. // If there is no RELATIVE UP cmd, do nothing and return
  693. //
  694. if (pCmd = COMMANDPTR(pDrvInfo, CMD_YMOVERELUP))
  695. {
  696. //
  697. // optimize to avoid 0-move cmd
  698. //
  699. if ((pPDev->ctl.ptRelativePos.y =
  700. pPDev->ctl.ptCursor.y - iY) < pPDev->ptDeviceFac.y)
  701. iDiff = pPDev->ctl.ptRelativePos.y;
  702. else
  703. {
  704. // FYMOVE_SEND_CR_FIRST indicates that it's required to send a CR
  705. // before each line-spacing command
  706. //
  707. if ( dwSendCRFlags )
  708. XMoveTo( pPDev, 0, dwSendCRFlags );
  709. iDiff = WriteChannelEx(pPDev,
  710. pCmd,
  711. pPDev->ctl.ptRelativePos.y,
  712. pPDev->ptDeviceFac.y);
  713. }
  714. iDiff = -iDiff;
  715. }
  716. else
  717. // Do nothing since we can't simulate it
  718. iDiff = (iY - pPDev->ctl.ptCursor.y );
  719. }
  720. else
  721. {
  722. if (pCmd = COMMANDPTR(pDrvInfo, CMD_YMOVERELDOWN))
  723. {
  724. pPDev->ctl.ptRelativePos.y = iY - pPDev->ctl.ptCursor.y;
  725. //
  726. // optimize to avoid 0-move cmd
  727. //
  728. if (pPDev->ctl.ptRelativePos.y < pPDev->ptDeviceFac.y)
  729. iDiff = pPDev->ctl.ptRelativePos.y;
  730. else
  731. {
  732. // FYMOVE_SEND_CR_FIRST indicates that it's required to send a CR
  733. // before each line-spacing command
  734. //
  735. if ( dwSendCRFlags )
  736. XMoveTo( pPDev, 0, dwSendCRFlags );
  737. iDiff = WriteChannelEx(pPDev,
  738. pCmd,
  739. pPDev->ctl.ptRelativePos.y,
  740. pPDev->ptDeviceFac.y);
  741. }
  742. }
  743. else
  744. iDiff = (iY - pPDev->ctl.ptCursor.y );
  745. }
  746. }
  747. }
  748. //
  749. // Update our current cursor position
  750. //
  751. pPDev->ctl.ptAbsolutePos.y = pPDev->ctl.ptCursor.y = iY - iDiff;
  752. if( fFlag & MV_GRAPHICS )
  753. {
  754. iDiff = (iDiff / iScale);
  755. }
  756. pPDev->ctl.dwMode &= ~MODE_CURSOR_Y_UNINITIALIZED;
  757. return (iDiff);
  758. }
  759. INT
  760. FineXMoveTo(
  761. PDEV *pPDev,
  762. INT iX
  763. )
  764. /*++
  765. Routine Description:
  766. This function is called to make microspace justification.
  767. It is only called when the normal x movement commands cannot
  768. move the cursor to the asking position. For example,
  769. resolution is 180 DPI, x move command is 1/120". To move
  770. by 4 pixels in 180 DPI, CM_XM_RIGHT is sent with parameter = 2
  771. (1/120") then one graphics pixel is sent (1/180).
  772. 4/180 = 2/120 + 1/180.
  773. 'iX' is always in MasterUnits.
  774. Arguments:
  775. pPDev - Pointer to PDEVICE struct
  776. iX - Amount to move in Master Units
  777. Return Value:
  778. The difference between the requested move and actual move
  779. --*/
  780. {
  781. INT iDiff;
  782. INT iScale;
  783. //
  784. // Don't do micro justification in graphics mode for device that
  785. // set x position at leftmost position on page after printing a
  786. // block of data OR Y position auto move to next Y row after priting
  787. // block of data.
  788. //
  789. if (pPDev->pGlobals->cxafterblock == CXSBD_AT_CURSOR_X_ORIGIN ||
  790. pPDev->pGlobals->cxafterblock == CXSBD_AT_GRXDATA_ORIGIN ||
  791. pPDev->pGlobals->cyafterblock == CYSBD_AUTO_INCREMENT)
  792. return iX;
  793. //
  794. // Convert Master units to Graphic units
  795. //
  796. // ptGrxScale has been adjusted to suit the current orientation.
  797. //
  798. if (pPDev->pOrientation && pPDev->pOrientation->dwRotationAngle != ROTATE_NONE &&
  799. pPDev->pGlobals->bRotateCoordinate == FALSE)
  800. iScale = pPDev->ptGrxScale.y;
  801. else
  802. iScale = pPDev->ptGrxScale.x;
  803. iDiff = iX % iScale;
  804. iX /= iScale;
  805. if (iX > 0 )
  806. {
  807. INT iMaxBuf, iTmp;
  808. BYTE rgch[ CCHMAXBUF ];
  809. //
  810. // Send the command, to send one block of data to the printer.
  811. // Init the state variable first.
  812. //
  813. //
  814. // BUG_BUG, how does this code work??
  815. // What should we send for CMD_SENDBLOCKDATA?
  816. //
  817. //
  818. // BUG_BUG, May be we should send BEGINGRAPHICS and ENDGRAPHICS later
  819. //
  820. pPDev->dwNumOfDataBytes = iX;
  821. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo, CMD_SENDBLOCKDATA));
  822. iMaxBuf = CCHMAXBUF - (CCHMAXBUF % pPDev->ctl.sBytesPerPinPass);
  823. iX *= pPDev->ctl.sBytesPerPinPass;
  824. //
  825. // Send out null graphics data, zeroes.
  826. //
  827. ZeroMemory( rgch, iX > CCHMAXBUF ? iMaxBuf : iX );
  828. for ( ; iX > 0; iX -= iTmp)
  829. {
  830. iTmp = iX > iMaxBuf ? iMaxBuf : iX;
  831. //
  832. // BUG_BUG, OEMCustomization code might want to hook
  833. // out this graphics move. Make this a bug when
  834. // someone asks for it.
  835. //
  836. WriteSpoolBuf(pPDev, rgch, iTmp);
  837. }
  838. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo, CMD_ENDBLOCKDATA));
  839. return iDiff;
  840. }
  841. return iDiff;
  842. }
  843. INT
  844. WriteChannel(
  845. PDEV *pPDev,
  846. COMMAND *pCmd
  847. )
  848. /*++
  849. Routine Description:
  850. This routine performs the following tasks:
  851. - Parse through the cmd invocation str and build a CMDPARAM struct
  852. for every %dddd encountered.
  853. - Call IProcessTokenStream to calculate the arToken value of the parameter.
  854. - Check for lMin and lMax in PARAMETER struct and send the command
  855. multiple times, if necessary(MaxRepeat was seen).
  856. - Call SendCmd to send the command to the printer.
  857. Arguments:
  858. pPDev - Pointer to PDEVICE struct
  859. pCmd - Pointer to command struct to send, used for sending sequence section cmds
  860. and predefined Unidrv commands
  861. Return Value:
  862. The last value send to the printer
  863. --*/
  864. #define MAX_NUM_PARAMS 16
  865. {
  866. BYTE *pInvocationStr;
  867. CMDPARAM *pCmdParam, *pCmdParamHead;
  868. INT i, iParamCount, iStrCount, iLastValue = 0, iRet;
  869. PARAMETER *pParameter;
  870. BOOL bMaxRepeat = FALSE;
  871. CMDPARAM arCmdParam[MAX_NUM_PARAMS];
  872. if (pCmd == NULL)
  873. {
  874. TERSE(("WriteChannel - Command PTR is NULL.\n"))
  875. return (NOOCD);
  876. }
  877. //
  878. // first check if this command requires callback
  879. //
  880. if (pCmd->dwCmdCallbackID != NO_CALLBACK_ID)
  881. {
  882. PLISTNODE pListNode;
  883. DWORD dwCount = 0; // count of parameters used
  884. DWORD adwParams[MAX_NUM_PARAMS]; // max 16 params for each callback
  885. if (!pPDev->pfnOemCmdCallback)
  886. return (NOOCD);
  887. //
  888. // check if this callback uses any parameters
  889. //
  890. pListNode = LISTNODEPTR(pPDev->pDriverInfo, pCmd->dwStandardVarsList);
  891. while (pListNode)
  892. {
  893. if (dwCount >= MAX_NUM_PARAMS)
  894. {
  895. ASSERTMSG(FALSE,("Command callback exceeds # of parameters limit.\n"));
  896. return (NOOCD);
  897. }
  898. adwParams[dwCount++] = *(pPDev->arStdPtrs[pListNode->dwData]);
  899. if (pListNode->dwNextItem == END_OF_LIST)
  900. break;
  901. else
  902. pListNode = LISTNODEPTR(pPDev->pDriverInfo, pListNode->dwNextItem);
  903. }
  904. FIX_DEVOBJ(pPDev, EP_OEMCommandCallback);
  905. iRet = 0;
  906. if(pPDev->pOemEntry)
  907. {
  908. if(((POEM_PLUGIN_ENTRY)pPDev->pOemEntry)->pIntfOem ) // OEM plug in uses COM and function is implemented.
  909. {
  910. HRESULT hr ;
  911. hr = HComCommandCallback((POEM_PLUGIN_ENTRY)pPDev->pOemEntry,
  912. (PDEVOBJ)pPDev, pCmd->dwCmdCallbackID, dwCount, adwParams, &iRet);
  913. if(SUCCEEDED(hr))
  914. ; // cool !
  915. }
  916. else
  917. {
  918. iRet = (pPDev->pfnOemCmdCallback)((PDEVOBJ)pPDev, pCmd->dwCmdCallbackID,
  919. dwCount, adwParams);
  920. }
  921. }
  922. return iRet ;
  923. }
  924. //
  925. // no cmd callback. Process the string.
  926. //
  927. pInvocationStr = CMDOFFSET_TO_PTR(pPDev, pCmd->strInvocation.loOffset);
  928. iStrCount = pCmd->strInvocation.dwCount;
  929. pCmdParam = pCmdParamHead = arCmdParam;
  930. iParamCount = 0;
  931. //
  932. // Process the parameter from the invocation str.
  933. //
  934. for (i= 0; i < iStrCount; i++)
  935. {
  936. if (pInvocationStr[i] == '%')
  937. {
  938. if (pInvocationStr[i + 1] == '%')
  939. {
  940. //
  941. // Do nothing, just skip %%
  942. //
  943. i += 1;
  944. }
  945. else
  946. {
  947. //
  948. // Build a list of CMDPARAM, one for each %dddd encounter
  949. // in cmd invocation string.
  950. //
  951. BYTE *pCurrent = pInvocationStr + i + 1;
  952. //
  953. // Increment the parameter count
  954. //
  955. iParamCount++;
  956. if (iParamCount > MAX_NUM_PARAMS)
  957. {
  958. ASSERT (iParamCount <= MAX_NUM_PARAMS);
  959. return (NOOCD);
  960. }
  961. //
  962. // Copy the 4 character that represent to parameter index from cmd str
  963. // pInvocationStr + i points to %, pInvocationStr + i + 1 points
  964. // to first digit of param index
  965. //
  966. pParameter = PGetParameter(pPDev, pCurrent);
  967. //
  968. // Initialize CMDPARAM for SendCmd
  969. //
  970. //
  971. // IProcessTokenStream calculate the integer value parameter
  972. // from the token stream in PARAMETER, bMaxRepeat is set
  973. // to TRUE if OP_MAX_REPEAT operator was encountered.
  974. //
  975. pCmdParam->iValue = IProcessTokenStream(pPDev,
  976. &pParameter->arTokens,
  977. &bMaxRepeat);
  978. //
  979. // Save the last value calculated (will only be used by XMoveTo and YMoveTo)
  980. // which assumes there is only one paramter per move command
  981. //
  982. iLastValue = pCmdParam->iValue;
  983. pCmdParam->dwFormat = pParameter->dwFormat;
  984. pCmdParam->dwDigits = pParameter->dwDigits;
  985. pCmdParam->dwFlags = pParameter->dwFlags;
  986. //
  987. // Check for dwFlags PARAM_FLAG_MIN_USED and PARAM_FLAG_MAX_USED
  988. //
  989. if (pCmdParam->dwFlags & PARAM_FLAG_MIN_USED &&
  990. pCmdParam->iValue < pParameter->lMin)
  991. {
  992. pCmdParam->iValue = pParameter->lMin;
  993. }
  994. if (pCmdParam->dwFlags & PARAM_FLAG_MAX_USED &&
  995. !bMaxRepeat &&
  996. pCmdParam->iValue > pParameter->lMax)
  997. {
  998. pCmdParam->iValue = pParameter->lMax;
  999. }
  1000. //
  1001. // Move to next paramter
  1002. //
  1003. pCmdParam++;
  1004. }
  1005. }
  1006. }
  1007. //
  1008. // We are here means have a list of CMD parameter, pointed to by
  1009. // pCmdParamHead, one for each
  1010. // %dddd encountered, in the order they were encountered in invocation string
  1011. //
  1012. // MAJOR ASSUMPTION, GPD specification specifies that
  1013. // only ONE parameter is valid for commands that use OP_MAX_REPEAT operator
  1014. // So assume only one here (pCmdParamHead and pParameter are valid).
  1015. //
  1016. if (bMaxRepeat && pCmdParamHead->dwFlags & PARAM_FLAG_MAX_USED &&
  1017. pCmdParamHead->iValue > pParameter->lMax)
  1018. {
  1019. INT iRemainder, iRepeat;
  1020. ASSERT(iParamCount == 1);
  1021. iRemainder = pCmdParamHead->iValue % pParameter->lMax;
  1022. iRepeat = pCmdParamHead->iValue / pParameter->lMax;
  1023. while (iRepeat--)
  1024. {
  1025. pCmdParamHead->iValue = pParameter->lMax;
  1026. SendCmd(pPDev, pCmd, pCmdParamHead);
  1027. }
  1028. //
  1029. // Send remainder
  1030. //
  1031. if (iRemainder > 0)
  1032. {
  1033. pCmdParamHead->iValue = iRemainder;
  1034. SendCmd(pPDev, pCmd, pCmdParamHead);
  1035. }
  1036. }
  1037. else
  1038. {
  1039. //
  1040. // Send the command to the printer
  1041. // SendCmd will process the command and format the parameters
  1042. // in the order encounter in the invocation string
  1043. //
  1044. SendCmd(pPDev, pCmd, pCmdParamHead);
  1045. }
  1046. return (iLastValue);
  1047. }
  1048. INT
  1049. WriteChannelEx(
  1050. PDEV *pPDev,
  1051. COMMAND *pCmd,
  1052. INT iRequestedValue,
  1053. INT iDeviceScaleFac
  1054. )
  1055. /*++
  1056. Routine Description:
  1057. This routine performs the following tasks:
  1058. - Call WriteChannel to write the command and get the
  1059. value of the last paramter calculated for the cmd.
  1060. - Use device factor to convert device units returned from WriteChannel to
  1061. master units
  1062. - Take the difference between requested and actual value
  1063. Arguments:
  1064. pPDev - Pointer to PDEVICE struct
  1065. pCmd - Pointer to command struct to send, used for sending sequence section cmds
  1066. and predefined Unidrv commands
  1067. iRequestedValue - Value of requested move command in Master units
  1068. iDeviceScaleFac - Scale factor to convert Device units to Master units
  1069. Return Value:
  1070. The difference between actual value and requested value in Master units
  1071. Note:
  1072. This function is only called only by XMoveTo and YMoveTo and assumes
  1073. that all move commands have only one parameter.
  1074. --*/
  1075. {
  1076. INT iActualValue;
  1077. //
  1078. // Get the device unit returned from WriteChannel and convert it
  1079. // to Master units based on the scale factor passed in
  1080. // Scale = Master/Device.
  1081. //
  1082. iActualValue = WriteChannel(pPDev, pCmd);
  1083. iActualValue *= iDeviceScaleFac;
  1084. return (iRequestedValue - iActualValue);
  1085. }
  1086. PPARAMETER
  1087. PGetParameter(
  1088. PDEV *pPDev,
  1089. BYTE *pInvocationStr
  1090. )
  1091. /*++
  1092. Routine Description:
  1093. This routine get the parameter index from pInvocationStr passed in and
  1094. return the PARAMETER struct associated with the index
  1095. Arguments:
  1096. pPDev - Pointer to PDEVICE struct
  1097. pInvocationStr - Pointer Invocation str containing the index
  1098. Return Value:
  1099. Pointer to PARAMETER struct associated with the index specified in
  1100. the invocation string.
  1101. Note:
  1102. Parameter index is the 4 bytes pointed to by pInvocationStr
  1103. --*/
  1104. {
  1105. BYTE arTemp[5];
  1106. INT iParamIndex;
  1107. PARAMETER *pParameter;
  1108. //
  1109. // Copy the 4 character that represent to parameter index from cmd str
  1110. // pInvocationStr
  1111. //
  1112. strncpy(arTemp, pInvocationStr, 4);
  1113. arTemp[4] = '\0';
  1114. iParamIndex = atoi(arTemp);
  1115. pParameter = PARAMETERPTR(pPDev->pDriverInfo, iParamIndex);
  1116. ASSERT(pParameter != NULL);
  1117. return (pParameter);
  1118. }
  1119. VOID
  1120. SendCmd(
  1121. PDEV *pPDev,
  1122. COMMAND *pCmd,
  1123. CMDPARAM *pParam
  1124. )
  1125. /*++
  1126. Routine Description:
  1127. This routine is called by WriteChannel to write one command to the
  1128. printer via. WriteSpoolBuf. WriteChannel passes a pointer to an array
  1129. of CMDPARAM. Each CMDPARAM describes the parameter for each %dddd
  1130. encounter in cmd invocation string (the CMDPARAM is sorted in the order
  1131. encountered).
  1132. Arguments:
  1133. pPDev - Pointer to PDEVICE struct
  1134. pCmd - Pointer to COMMAND struct
  1135. pParam - Pointer to and array CMDPARAM struct, containing everything needed to format
  1136. the parameter
  1137. Return Value:
  1138. None
  1139. --*/
  1140. {
  1141. INT iInput, iOutput; // Used to index through input and output buffers
  1142. BYTE arOutputCmd[CCHMAXBUF]; // Output buffer to send to printer
  1143. PBYTE pInputCmd; // Pointer to Cmd invocation str.
  1144. //
  1145. // Get the command invocation string
  1146. //
  1147. pInputCmd = CMDOFFSET_TO_PTR(pPDev, pCmd->strInvocation.loOffset);
  1148. iOutput = 0;
  1149. //
  1150. // Go through all the bytes in the invocation string and transfer them
  1151. // to the output buffer. Replace %dddd with format value calculated
  1152. // and %% with %.
  1153. //
  1154. for (iInput = 0; iInput < (INT)pCmd->strInvocation.dwCount; iInput++)
  1155. {
  1156. if (pInputCmd[iInput] == '%' )
  1157. {
  1158. if (pInputCmd[iInput + 1] == '%')
  1159. {
  1160. //
  1161. // %% equals '%', skip over marker %%
  1162. //
  1163. arOutputCmd[iOutput++] = '%';
  1164. iInput += 1;
  1165. }
  1166. else
  1167. {
  1168. INT iValue;
  1169. DWORD dwFlags, dwDigits, dwFormat;
  1170. //
  1171. // Skip over the marker % and dddd for %dddd found in invocation str.
  1172. // Skip 4 bytes (%dddd)
  1173. //
  1174. iInput += 4;
  1175. dwDigits = pParam->dwDigits;
  1176. dwFlags = pParam->dwFlags;
  1177. dwFormat = pParam->dwFormat;
  1178. iValue = pParam->iValue;
  1179. pParam++;
  1180. //
  1181. // Format the parameter according the the dwFormat specified in PARAMETER struct
  1182. //
  1183. switch (dwFormat)
  1184. {
  1185. //
  1186. // case 'd': parameter as decimal number
  1187. // case 'D': same as case 'd' with + sign if value > 0
  1188. // case 'c': parameter as a single character
  1189. // case 'C': parameter as character plus '0'
  1190. // case 'f': parameter as decinal number with decimal point inserted
  1191. // before the second digit from the right.
  1192. // case 'l': parameter as word LSB first
  1193. // case 'm': parameter as word MSB first
  1194. // case 'q': parameter as Qume method, 1/48" movements
  1195. // case 'g': parameter as 2 *abs(param) + is_negative(param)
  1196. // case 'n': Canon integer encoding
  1197. // case 'v': NEC VFU encoding
  1198. // case '%': print a %
  1199. case 'D':
  1200. if (iValue > 0)
  1201. arOutputCmd[iOutput++] = '+';
  1202. //
  1203. // Fall through
  1204. //
  1205. case 'd':
  1206. if (dwDigits > 0 && dwFlags & PARAM_FLAG_FIELDWIDTH_USED)
  1207. {
  1208. //
  1209. // Temp call to get the number of digits for the iValue
  1210. //
  1211. int iParamDigit = itoA(arOutputCmd + iOutput, iValue);
  1212. for ( ; iParamDigit < (INT)dwDigits; iParamDigit++)
  1213. {
  1214. //
  1215. // Zero pads
  1216. //
  1217. arOutputCmd[iOutput++] = '0';
  1218. }
  1219. }
  1220. iOutput += itoA( arOutputCmd + iOutput, iValue);
  1221. break;
  1222. case 'C':
  1223. iValue += '0';
  1224. //
  1225. // Fall through
  1226. //
  1227. case 'c':
  1228. arOutputCmd[iOutput++] = (BYTE)iValue;
  1229. break;
  1230. case 'f':
  1231. {
  1232. int x, y, i;
  1233. BYTE arTemp[CCHMAXBUF];
  1234. LPSTR pCurrent = arOutputCmd + iOutput;
  1235. ULONG cchpCurrentLen = 0;
  1236. if ( (LONG)CCHOF(arOutputCmd) - iOutput > 0 )
  1237. {
  1238. cchpCurrentLen = CCHOF(arOutputCmd) - iOutput;
  1239. }
  1240. else
  1241. {
  1242. break;
  1243. }
  1244. x = iValue /100;
  1245. y = iValue % 100;
  1246. iOutput += itoA(pCurrent, x);
  1247. StringCchCatA ( pCurrent, cchpCurrentLen, "."); //strcat(pCurrent, ".");
  1248. i = itoA(arTemp, y);
  1249. //
  1250. // Take care of the case where the mod yields 1 digit, pad a zero
  1251. //
  1252. if (i < 2 )
  1253. {
  1254. StringCchCatA ( pCurrent, cchpCurrentLen, "0"); //strcat(pCurrent, "0");
  1255. }
  1256. StringCchCatA(pCurrent, cchpCurrentLen, arTemp); //strcat(pCurrent, arTemp);
  1257. //
  1258. // Increment iOutput to include the 2 digits after the
  1259. // decimal and the "."
  1260. //
  1261. iOutput += 3;
  1262. }
  1263. break;
  1264. case 'l':
  1265. arOutputCmd[iOutput++] = (BYTE)iValue;
  1266. arOutputCmd[iOutput++] = (BYTE)(iValue >> 8);
  1267. break;
  1268. case 'm':
  1269. arOutputCmd[iOutput++] = (BYTE)(iValue >> 8);
  1270. arOutputCmd[iOutput++] = (BYTE)iValue;
  1271. break;
  1272. case 'q':
  1273. arOutputCmd[ iOutput++ ] = (BYTE)(((iValue >> 8) & 0xf) + '@');
  1274. arOutputCmd[ iOutput++ ] = (BYTE)(((iValue >> 4) & 0xf) + '@');
  1275. arOutputCmd[ iOutput++ ] = (BYTE)((iValue & 0xf) + '@');
  1276. break;
  1277. case 'g':
  1278. {
  1279. if (iValue >= 0)
  1280. iValue = iValue << 1;
  1281. else
  1282. iValue = ((-iValue) << 1) + 1;
  1283. while (iValue >= 64)
  1284. {
  1285. arOutputCmd[iOutput++] = (char)((iValue & 0x003f) + 63);
  1286. iValue >>= 6;
  1287. }
  1288. arOutputCmd[iOutput++] = (char)(iValue + 191);
  1289. }
  1290. break;
  1291. case 'n':
  1292. {
  1293. WORD absParam = (WORD)abs(iValue);
  1294. WORD absTmp;
  1295. if (absParam <= 15)
  1296. {
  1297. arOutputCmd[iOutput++] = 0x20
  1298. | ((iValue >= 0)? 0x10:0)
  1299. | (BYTE)absParam;
  1300. }
  1301. else if (absParam <= 1023)
  1302. {
  1303. arOutputCmd[iOutput++] = 0x40
  1304. | (BYTE)(absParam/16);
  1305. arOutputCmd[iOutput++] = 0x20
  1306. | ((iValue >= 0)? 0x10:0)
  1307. | (BYTE)(absParam % 16);
  1308. }
  1309. else
  1310. {
  1311. arOutputCmd[iOutput++] = 0x40
  1312. | (BYTE)(absParam / 1024);
  1313. absTmp = absParam % 1024;
  1314. arOutputCmd[iOutput++] = 0x40
  1315. | (BYTE)(absTmp / 16);
  1316. arOutputCmd[iOutput++] = 0x20
  1317. | ((iValue >= 0)? 0x10:0)
  1318. | (BYTE)(absTmp % 16);
  1319. }
  1320. }
  1321. break;
  1322. case 'v':
  1323. //
  1324. // NEC VFU(Vertical Format Unit)
  1325. //
  1326. // VFU is a command to specify a paper size
  1327. // (the length of form feed for the NEC 20PL dotmatrix
  1328. // printer.
  1329. //
  1330. // On NEC dotmatrix printer, 1 line is 1/6 inch.
  1331. // If you want to specify N line paper size,
  1332. // you need to send GS, N+1 Data and RS.
  1333. //
  1334. // GS (0x1d)
  1335. // TOF Data (0x41, 0x00)
  1336. // Data (0x40, 0x00)
  1337. // Data (0x40, 0x00)
  1338. // Data (0x40, 0x00)
  1339. // ..
  1340. // ..
  1341. // Data (0x40, 0x00)
  1342. // TOF Data (0x41, 0x00)
  1343. // RS (0x1e)
  1344. //
  1345. arOutputCmd[iOutput++] = 0x1D;
  1346. arOutputCmd[iOutput++] = 0x41;
  1347. arOutputCmd[iOutput++] = 0x00;
  1348. while(--iValue > 0)
  1349. {
  1350. if( iOutput >= CCHMAXBUF - 5)
  1351. {
  1352. WriteSpoolBuf( pPDev, arOutputCmd, iOutput );
  1353. iOutput = 0;
  1354. }
  1355. arOutputCmd[iOutput++] = 0x40;
  1356. arOutputCmd[iOutput++] = 0x00;
  1357. }
  1358. arOutputCmd[iOutput++] = 0x41;
  1359. arOutputCmd[iOutput++] = 0x00;
  1360. arOutputCmd[iOutput++] = 0x1E;
  1361. break;
  1362. default:
  1363. break;
  1364. }
  1365. }
  1366. }
  1367. else
  1368. {
  1369. //
  1370. // Copy the input to output and increment the output count
  1371. //
  1372. arOutputCmd[iOutput++] = pInputCmd[iInput];
  1373. }
  1374. //
  1375. // Write output cmd buffer out to spool buffer in the case
  1376. // where it full or nearly full (2/3 full)
  1377. //
  1378. if( iOutput >= (2 * sizeof( arOutputCmd )) / 3 )
  1379. {
  1380. WriteSpoolBuf( pPDev, arOutputCmd, iOutput );
  1381. iOutput = 0;
  1382. }
  1383. }
  1384. //
  1385. // Write the data to spool buffer
  1386. //
  1387. if ( iOutput > 0 )
  1388. WriteSpoolBuf( pPDev, arOutputCmd, iOutput );
  1389. return;
  1390. }
  1391. INT
  1392. IProcessTokenStream(
  1393. PDEV *pPDev,
  1394. ARRAYREF *pToken ,
  1395. PBOOL pbMaxRepeat
  1396. )
  1397. /*++
  1398. Routine Description:
  1399. This function process a given token stream and calculate the value
  1400. for the command parameter.
  1401. Arguments:
  1402. pPDev - Pointer to PDEVICE
  1403. pToken - Pointer to an array of TOKENSTREAM representing the operands
  1404. and operators for RPN calc. pToken->dwCount is the number of
  1405. TOKENSTREAM in the array. pToken->loOffset is the index
  1406. to the first TOKENSTREAM in the array.
  1407. pbMaxRepeat - Indicates a max repeat operator was seen in token stream
  1408. Return Value:
  1409. The calculated value, always an INT and set pbMaxRepeat TRUE if
  1410. the OP_MAX_REPEAT operator was seen.
  1411. --*/
  1412. {
  1413. INT iRet = 0, sp = 0;
  1414. INT arStack[MAX_STACK_SIZE];
  1415. DWORD dwCount = pToken->dwCount;
  1416. TOKENSTREAM * ptstrToken = TOKENSTREAMPTR(pPDev->pDriverInfo, pToken->loOffset);
  1417. *pbMaxRepeat = FALSE;
  1418. while (dwCount--)
  1419. {
  1420. switch(ptstrToken->eType)
  1421. {
  1422. case OP_INTEGER:
  1423. if (sp >= MAX_STACK_SIZE)
  1424. goto ErrorExit;
  1425. arStack[sp++] = (INT)ptstrToken->dwValue;
  1426. break;
  1427. case OP_VARI_INDEX:
  1428. // dwValue is the index to standard variable list
  1429. if (sp >= MAX_STACK_SIZE)
  1430. goto ErrorExit;
  1431. arStack[sp++] = (INT)*(pPDev->arStdPtrs[ptstrToken->dwValue]);
  1432. break;
  1433. case OP_MIN:
  1434. if (--sp <= 0)
  1435. goto ErrorExit;
  1436. if (arStack[sp-1] > arStack[sp])
  1437. arStack[sp-1] = arStack[sp];
  1438. break;
  1439. case OP_MAX:
  1440. if (--sp <= 0)
  1441. goto ErrorExit;
  1442. if (arStack[sp-1] < arStack[sp])
  1443. arStack[sp-1] = arStack[sp];
  1444. break;
  1445. case OP_ADD:
  1446. if (--sp <= 0)
  1447. goto ErrorExit;
  1448. arStack[sp-1] += arStack[sp];
  1449. break;
  1450. case OP_SUB:
  1451. if (--sp <= 0)
  1452. goto ErrorExit;
  1453. arStack[sp-1] -= arStack[sp];
  1454. break;
  1455. case OP_MULT:
  1456. if (--sp <= 0)
  1457. goto ErrorExit;
  1458. arStack[sp-1] *= arStack[sp];
  1459. break;
  1460. case OP_DIV:
  1461. if (--sp <= 0)
  1462. goto ErrorExit;
  1463. arStack[sp-1] /= arStack[sp];
  1464. break;
  1465. case OP_MOD:
  1466. if (--sp <= 0)
  1467. goto ErrorExit;
  1468. arStack[sp-1] %= arStack[sp];
  1469. break;
  1470. case OP_MAX_REPEAT:
  1471. //
  1472. // If pbMaxRepeat is TRUE, can only send the parameters in
  1473. // increment of lMax repeat value or smaller, set in Parameter list until
  1474. //
  1475. *pbMaxRepeat = TRUE;
  1476. break;
  1477. case OP_HALT:
  1478. if (sp == 0)
  1479. goto ErrorExit;
  1480. iRet = arStack[--sp];
  1481. break;
  1482. default:
  1483. VERBOSE (("IProcessTokenStream - unknown command!"));
  1484. break;
  1485. }
  1486. ptstrToken++;
  1487. }
  1488. return (iRet);
  1489. ErrorExit:
  1490. ERR(("IProcessTokenStream, invalid stack pointer"));
  1491. return 0;
  1492. }
  1493. static int
  1494. itoA( LPSTR buf, INT n )
  1495. {
  1496. int fNeg;
  1497. int i, j;
  1498. if( fNeg = (n < 0) )
  1499. n = -n;
  1500. for( i = 0; n; i++ )
  1501. {
  1502. buf[i] = (char)(n % 10 + '0');
  1503. n /= 10;
  1504. }
  1505. /* n was zero */
  1506. if( i == 0 )
  1507. buf[i++] = '0';
  1508. if( fNeg )
  1509. buf[i++] = '-';
  1510. for( j = 0; j < i / 2; j++ )
  1511. {
  1512. int tmp;
  1513. tmp = buf[j];
  1514. buf[j] = buf[i - j - 1];
  1515. buf[i - j - 1] = (char)tmp;
  1516. }
  1517. buf[i] = '\0';
  1518. return i;
  1519. }
  1520. BOOL
  1521. BUniWritePrinter(
  1522. IN PDEV* pPDev,
  1523. IN LPVOID pBuf,
  1524. IN DWORD cbBuf,
  1525. OUT LPDWORD pcbWritten)
  1526. {
  1527. DWORD dwCount;
  1528. BOOL bReturn = FALSE;
  1529. //
  1530. // Is there any plug-in that hooks WritePrinter?
  1531. // If there is, the plug-in need to take care of all output.
  1532. // Call plug-in's WritePrinter method.
  1533. //
  1534. if(pPDev->pOemEntry && pPDev->fMode2 & PF2_WRITE_PRINTER_HOOKED)
  1535. {
  1536. START_OEMENTRYPOINT_LOOP(pPDev);
  1537. //
  1538. // OEM plug in uses COM and function is implemented.
  1539. //
  1540. if(((POEM_PLUGIN_ENTRY)pPDev->pOemEntry)->pIntfOem )
  1541. {
  1542. //
  1543. // Call only the first available WritePrinter method in
  1544. // multiple plug-ins.
  1545. //
  1546. if (pOemEntry->dwFlags & OEMWRITEPRINTER_HOOKED)
  1547. {
  1548. HRESULT hr;
  1549. //
  1550. // WritePrinter is supported by this plug-in DLL.
  1551. // Plug-in's WritePrinter should not return E_NOTIMPL or
  1552. // E_NOTINTERFACE.
  1553. //
  1554. pPDev->fMode2 |= PF2_CALLING_OEM_WRITE_PRINTER;
  1555. hr = HComWritePrinter((POEM_PLUGIN_ENTRY)pPDev->pOemEntry,
  1556. (PDEVOBJ)pPDev,
  1557. pBuf,
  1558. cbBuf,
  1559. pcbWritten);
  1560. pPDev->fMode2 &= ~PF2_CALLING_OEM_WRITE_PRINTER;
  1561. //
  1562. // If Plug-in's WritePrinter succeeded, return TRUE.
  1563. //
  1564. if(SUCCEEDED(hr))
  1565. {
  1566. //
  1567. // If the method is called and succeeded, return TRUE.
  1568. //
  1569. bReturn = TRUE;
  1570. break;
  1571. }
  1572. else
  1573. {
  1574. //
  1575. // If WritePrinter method failed, break.
  1576. //
  1577. bReturn = FALSE;
  1578. break;
  1579. }
  1580. }
  1581. }
  1582. END_OEMENTRYPOINT_LOOP;
  1583. if (pPDev->pVectorProcs != NULL)
  1584. {
  1585. pPDev->devobj.pdevOEM = pPDev->pVectorPDEV;
  1586. }
  1587. }
  1588. //
  1589. // If there is no WritePrinter hook, call spooler API WritePrinter.
  1590. //
  1591. else
  1592. {
  1593. bReturn = WritePrinter(pPDev->devobj.hPrinter,
  1594. pBuf,
  1595. cbBuf,
  1596. pcbWritten)
  1597. && cbBuf == *pcbWritten;
  1598. }
  1599. return bReturn;
  1600. }