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.

1178 lines
31 KiB

  1. /*
  2. * Windows Calendar
  3. * Copyright (c) 1985 by Microsoft Corporation, all rights reserved.
  4. * Written by Mark L. Chamberlin, consultant to Microsoft.
  5. *
  6. */
  7. /*
  8. *****
  9. ***** calprint.c
  10. *****
  11. */
  12. #include "cal.h"
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <time.h>
  16. int TranslateString(CHAR *);
  17. CHAR * APIENTRY PFileInPath(CHAR *sz);
  18. VOID APIENTRY DestroyAbortWnd(VOID);
  19. /* We'll dynamically allocate this */
  20. HANDLE hHeadFoot=NULL;
  21. LPSTR szHeadFoot;
  22. SHORT xCharPage, dyHeadFoot;
  23. int dyTop,dyBottom,dxLeft ,dxRight;
  24. int CharPrintWidth, CharPrintHeight;
  25. HDC vhDCPrint;
  26. BOOL vfAbortPrint;
  27. HWND vhwndAbortPrint;
  28. INT vcyPrintLineToLine;
  29. INT xPrintRes, yPrintRes, xPixInch, yPixInch;
  30. INT hChars;
  31. INT vclnPage;
  32. INT nSpace;
  33. INT vclnPrinted;
  34. INT vclnDate;
  35. INT vlnFooter; /* footer line */
  36. INT vlnBottom; /* last line of calendar text */
  37. INT vlnTop; /* first line of calendar text */
  38. BOOL vfPrint;
  39. CHAR szCurDateBuf[9]; /* buffer containing date string for header/footer */
  40. CHAR *szcurDptr = szCurDateBuf;
  41. INT iCurDateLength ;
  42. DOSDATE CurDD;
  43. CHAR *vpchPrintBuf;
  44. #define CLNHEADING 1
  45. #define CLNAFTERHEADING 1
  46. #define CLNAFTERAPPOINTMENTS 1
  47. #define CLNBETWEENDATES 2
  48. /* 1 - blank or asterisk for alarm
  49. 1 - blank
  50. CCHTIMESZ - appointment time (includes 0 terminator, which is used
  51. to hold a blank here)
  52. CCHQDMAX - room for a maximum length appointment description
  53. 1 - room for the 0 terminator
  54. The print buffer is also used for outputting the heading, so it
  55. must be long enough for that too. To make sure this is the case,
  56. add in CCHDATEDISP.
  57. */
  58. #define CCHPRINTBUF (1 + 1 + CCHTIMESZ + CCHQDMAX + 1 + CCHDATEDISP)
  59. /* Format of a printed date:
  60. if not at top of page, CLNBETWEENDATES blank lines
  61. Heading (e.g., Thursday, July 11, 1985)
  62. CLNAFTERHEADING blank lines
  63. Appointments (e.g., * 10:00 Call Tandy to report progress (asterisk
  64. indicates alarm set)
  65. CLNAFTERAPPOINTMENTS blank lines
  66. notes
  67. */
  68. /**** FnPrint ****/
  69. INT_PTR CALLBACK FnPrint (
  70. HWND hwnd,
  71. UINT message,
  72. WPARAM wParam,
  73. LPARAM lParam)
  74. {
  75. CHAR szFromDate [CCHDASHDATE];
  76. switch (message)
  77. {
  78. case WM_INITDIALOG:
  79. /* Remember the window handle of the dialog for AlertBox. */
  80. vhwndDialog = hwnd;
  81. GetDashDateSel (szFromDate);
  82. SetDlgItemText (hwnd, IDCN_FROMDATE, szFromDate);
  83. return (TRUE);
  84. case WM_COMMAND:
  85. switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  86. case IDOK:
  87. GetRangeOfDates (hwnd);
  88. /* line added to fix keyboard hanging when Calendar
  89. is run under ver3.0 rel 1.11 */
  90. CalSetFocus (GetDlgItem(hwnd, IDCN_FROMDATE));
  91. break;
  92. case IDCANCEL:
  93. EndDialog (hwnd, FALSE);
  94. break;
  95. }
  96. return (TRUE);
  97. }
  98. /* Tell Windows we did not process the message. */
  99. return (FALSE);
  100. }
  101. /**** Print */
  102. VOID FAR APIENTRY Print ()
  103. {
  104. TEXTMETRIC Metrics;
  105. WORD idrFree;
  106. INT itdd;
  107. DD *pdd;
  108. DT dt;
  109. DL dl;
  110. WORD idr;
  111. CHAR rgchPrintBuf [CCHPRINTBUF];
  112. INT iDateLen;
  113. INT iHeight;
  114. INT iWidth;
  115. /* Note - there is no need to force edits to be recorded here.
  116. We got here after the Print dialog, which took over the focus
  117. and therefore has recorded the edits. We are not going to
  118. modify the current DR, so we do not need to set the focus
  119. to NULL (as we sometimes do to prevent recording data into
  120. the wrong DR).
  121. */
  122. if (BeginPrint () < 0)
  123. {
  124. /* Unable to get print DC - display error and give up. */
  125. CalPrintAlert(SP_ERROR);
  126. return;
  127. }
  128. /* Determine the number of lines per page. */
  129. GetTextMetrics (vhDCPrint, &Metrics);
  130. CharPrintHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
  131. CharPrintWidth = (Metrics.tmAveCharWidth + Metrics.tmMaxCharWidth)/2; /* character width */
  132. xPrintRes = GetDeviceCaps(vhDCPrint, HORZRES);
  133. yPrintRes = GetDeviceCaps(vhDCPrint, VERTRES);
  134. xPixInch = GetDeviceCaps(vhDCPrint, LOGPIXELSX);
  135. yPixInch = GetDeviceCaps(vhDCPrint, LOGPIXELSY);
  136. dyHeadFoot = yPixInch / 2; /* 1/2 an inch */
  137. dyTop = atopix(chPageText[4], yPixInch);
  138. dyBottom = atopix(chPageText[5], yPixInch);
  139. dxLeft = atopix(chPageText[2], xPixInch);
  140. dxRight = atopix(chPageText[3], xPixInch);
  141. /* There's some recalculating here entirely unneeded. The call to
  142. GetDeviceCaps for hChars isn't needed since xPrintRes already has
  143. that value. CharPrintHeight already has the value desired for
  144. vcyPrintLineToLine. (I'd pull one of them out entirely, but that
  145. requres a lot of code review without the time.) The call to
  146. GetDeviceCaps for vlnFooter isn't needed since yPrintRes already
  147. has that value. 21 Sept 1989 Clark Cyr */
  148. #if 0
  149. hChars=GetDeviceCaps(vhDCPrint, HORZRES)/Metrics.tmAveCharWidth;
  150. vcyPrintLineToLine = Metrics.tmHeight + Metrics.tmExternalLeading;
  151. vlnFooter = GetDeviceCaps(vhDCPrint, VERTRES) / vcyPrintLineToLine - 1;
  152. #endif
  153. hChars = xPrintRes / Metrics.tmAveCharWidth;
  154. vlnFooter = yPrintRes / (vcyPrintLineToLine = CharPrintHeight) - 1;
  155. MGetTextExtent(vhDCPrint, " ", 1, &iHeight, &iWidth);
  156. nSpace = iWidth;
  157. viLeftMarginLen =dxLeft/nSpace;
  158. viRightMarginLen=dxRight/nSpace;
  159. viTopMarginLen =dyTop/vcyPrintLineToLine;
  160. viBotMarginLen =dyBottom/vcyPrintLineToLine;
  161. /* Number of characters between margins */
  162. xCharPage=(xPrintRes/CharPrintWidth)-viLeftMarginLen-viRightMarginLen;
  163. /* Allocate memory for the header.footer string. Will allow any size
  164. * of paper and still have enough for the string.
  165. */
  166. hHeadFoot=GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (DWORD)xCharPage+2);
  167. if (!hHeadFoot)
  168. {
  169. /* Tell user that there's not memory to do this... */
  170. CalPrintAlert(SP_OUTOFMEMORY);
  171. return;
  172. }
  173. /* Change 2 to 3. Leave room for footer itself. 21 Sept 1989 Clark Cyr */
  174. vclnPage = vlnFooter - 3;
  175. vlnTop = viTopMarginLen;
  176. vlnBottom = vclnPage - viBotMarginLen;
  177. CurDD.dayofweek = 0xff;
  178. CurDD.year = vd3Cur.wYear + 1980;
  179. CurDD.month = vd3Cur.wMonth + 1;
  180. CurDD.day = vd3Cur.wDay + 1;
  181. iDateLen = GetDateString(&CurDD, szCurDateBuf, GDS_LONG|GDS_DAYOFWEEK);
  182. *(szcurDptr + iDateLen) = '\0';
  183. /* Find a free DR in case we need to read from the disk. */
  184. idrFree = IdrFree ();
  185. /* Say we are at the top of the page. */
  186. /* vclnPrinted = 0; */
  187. /* print out header string */
  188. viCurrentPage = 1;
  189. vpchPrintBuf = rgchPrintBuf;
  190. PrintHeaderFooter(TRUE);
  191. vclnPrinted = vlnTop;
  192. for (itdd = vitddFirst; !vfAbortPrint && itdd < vitddMax; itdd++)
  193. {
  194. pdd = TddLock () + itdd;
  195. dt = pdd -> dt;
  196. dl = pdd -> dl;
  197. idr = pdd -> idr;
  198. TddUnlock ();
  199. if (idr == IDRNIL)
  200. {
  201. /* The date is not in memory, see if it's on disk. */
  202. if (dl == DLNIL)
  203. {
  204. /*
  205. Not on disk either - this is an empty DD. Skip
  206. over this date.
  207. */
  208. continue;
  209. }
  210. /* Read the date from disk into the free DR. */
  211. ReadTempDr (idr = idrFree, dl);
  212. }
  213. /* Calculate how many lines are needed to print this date. */
  214. if (!PrintDate (idr, dt, FALSE))
  215. return;
  216. if (vclnDate == 0)
  217. {
  218. /* There's nothing to print in this date (must just
  219. be special times without alarms or text and no notes).
  220. */
  221. continue;
  222. }
  223. /* Change 0 to vlnTop + 2. 21 Sept 1989 Clark Cyr */
  224. if (vclnPrinted > vlnTop + 2)
  225. {
  226. /* Not at top of page - see if this entire date will fit
  227. on the remainder of this page. If it won't fit, start
  228. a new page.
  229. */
  230. /* print out the footer if bottom of page is reached */
  231. if (vclnPrinted + vclnDate > vlnBottom ){
  232. PrintHeaderFooter( FALSE );
  233. if (!NewPage ())
  234. return;
  235. viCurrentPage++;
  236. /* print out the header on top of new page */
  237. PrintHeaderFooter( TRUE );
  238. vclnPrinted = vlnTop;
  239. }
  240. }
  241. /* Print the schedule for the date. */
  242. if (!PrintDate (idr, dt, TRUE))
  243. return;
  244. }
  245. /* print out the footer if bottom of page is reached */
  246. if (vclnPrinted < vlnFooter - 3)
  247. PrintHeaderFooter(FALSE);
  248. if (NewPage ())
  249. EndPrint ();
  250. GlobalFree(hHeadFoot);
  251. hHeadFoot=NULL;
  252. }
  253. /*
  254. * convert floating point strings (like 2.75 1.5 2) into number of pixels
  255. * given the number of pixels per inch
  256. */
  257. INT atopix(CHAR *ptr, INT pix_per_in)
  258. {
  259. CHAR *dot_ptr;
  260. CHAR sz[20];
  261. INT decimal;
  262. lstrcpy(sz, ptr);
  263. dot_ptr = strchr(sz, szDec[0]);
  264. if (dot_ptr)
  265. {
  266. *dot_ptr++ = 0; /* terminate the inches */
  267. if (*(dot_ptr + 1) == 0)
  268. {
  269. *(dot_ptr + 1) = '0'; /* convert decimal part to hundredths */
  270. *(dot_ptr + 2) = 0;
  271. }
  272. decimal = ((INT)atol(dot_ptr) * pix_per_in) / 100; /* first part */
  273. }
  274. else
  275. decimal = 0; /* there is not fraction part */
  276. return ((INT)atol(sz) * pix_per_in) + decimal; /* second part */
  277. }
  278. /**** PrintDate - Print the specified date. If fPrint == FALSE then
  279. don't actually print - just set up vclnDate with the number of
  280. lines required to print the date.
  281. */
  282. BOOL APIENTRY PrintDate (
  283. INT idr,
  284. DT dt,
  285. BOOL fPrint)
  286. {
  287. CHAR rgchPrintBuf [CCHPRINTBUF];
  288. CHAR szTemp[CCHPRINTBUF];
  289. DR *pdr;
  290. register PQR pqr;
  291. PQR pqrMax;
  292. CHAR *pchTemp;
  293. register CHAR *pchSrc;
  294. CHAR *pchDest;
  295. CHAR c;
  296. BOOL fSameLine;
  297. INT cchTime, i, nx;
  298. BOOL fFirstLine;
  299. BOOL fFirstPM;
  300. /* Set up global print flag for routines to be called. */
  301. vfPrint = fPrint;
  302. /* Set up a global pointer to the print buffer. */
  303. vpchPrintBuf = rgchPrintBuf;
  304. /* Initialize the count of lines required to print this date. */
  305. vclnDate = 0;
  306. pdr = PdrLock (idr);
  307. fFirstLine = TRUE;
  308. fFirstPM = TRUE;
  309. for (pqrMax = (PQR)((BYTE UNALIGNED*)(pqr = (PQR)PbTqrFromPdr(pdr)) +
  310. pdr->cbTqr); pqr<pqrMax; pqr = (PQR)((BYTE UNALIGNED*)pqr + pqr->cb))
  311. {
  312. /* Don't print special times that don't have an alarm
  313. or an appointment description.
  314. */
  315. if (pqr -> fAlarm || pqr -> cb != CBQRHEAD)
  316. {
  317. if (!PrintHeading (dt))
  318. goto error0;
  319. FillBuf (vpchPrintBuf, CCHPRINTBUF, ' ');
  320. if (pqr -> fAlarm)
  321. *(vpchPrintBuf+viLeftMarginLen) = '*';
  322. cchTime = GetTimeSz (pqr -> tm, vpchPrintBuf + viLeftMarginLen + 2);
  323. /* Print am/pm strings only for first line printed and noon */
  324. if (!(fFirstLine || ((fFirstPM && pqr->tm >= TMNOON))))
  325. FillBuf (vpchPrintBuf+viLeftMarginLen+5+2, cchTime-5, ' ');
  326. FillBuf (vpchPrintBuf, viLeftMarginLen, ' '); /* pad margin space
  327. with blanks */
  328. pchTemp = vpchPrintBuf + viLeftMarginLen + cchTime+2;
  329. *pchTemp++ = ' ';
  330. *pchTemp = '\0';
  331. if (pqr -> cb > CBQRHEAD)
  332. lstrcpy (pchTemp, (CHAR *)((BYTE *)pqr + CBQRHEAD));
  333. CheckMarg:
  334. if (lstrlen(vpchPrintBuf) > (hChars-viRightMarginLen))
  335. {
  336. lstrcpy(szTemp, vpchPrintBuf+hChars-viRightMarginLen);
  337. vpchPrintBuf[hChars-viRightMarginLen]=0;
  338. if (!PrintLine ())
  339. goto error0;
  340. /* CHeck for one space at the beginning and strip if needed */
  341. nx=0;
  342. if (szTemp[0]==' ' && szTemp[1]!=' ')
  343. nx=1;
  344. /* Note that 11 = strlen[* + Time + AM/PM + Space] */
  345. FillBuf (vpchPrintBuf, viLeftMarginLen+11-nx, ' ');
  346. vpchPrintBuf[viLeftMarginLen+11-nx]=0;
  347. lstrcat(vpchPrintBuf, szTemp);
  348. goto CheckMarg;
  349. }
  350. if (!PrintLine ())
  351. goto error0;
  352. fFirstLine = FALSE;
  353. if (pqr->tm >= TMNOON)
  354. fFirstPM = FALSE;
  355. }
  356. }
  357. if (pdr -> cbNotes != 0)
  358. {
  359. if (vclnDate != 0)
  360. {
  361. if (!PrintBlankLn (CLNAFTERAPPOINTMENTS))
  362. goto error0;
  363. }
  364. else
  365. if (!PrintHeading (dt))
  366. goto error0;
  367. /* The notes are split into lines as follows:
  368. '\0' terminates a line and terminates the notes.
  369. <CR,LF> is a hard line break (user typed Enter key).
  370. <CR,CR,LF> is a soft line break (caused by word wrap).
  371. In order to do something reasonable no matter what is seen,
  372. this code skips an abitrary number of CRs followed by an
  373. arbitrary number of LFs.
  374. */
  375. pchSrc = (CHAR *)((BYTE *)pdr + CBDRHEAD);
  376. while (*pchSrc != '\0')
  377. {
  378. pchDest = rgchPrintBuf;
  379. fSameLine = TRUE;
  380. i=0; /* fill margin space with blanks */
  381. while (i<viLeftMarginLen)
  382. {
  383. *pchDest++ = ' ';
  384. i++;
  385. }
  386. while (fSameLine)
  387. {
  388. c=*pchSrc;
  389. #ifdef DBCS
  390. if( IsDBCSLeadByte(*pchSrc) )
  391. *pchDest++ = *pchSrc++;
  392. *pchDest++ = *pchSrc++;
  393. #else
  394. *pchDest++ = *pchSrc++;
  395. #endif
  396. if (c=='\r')
  397. {
  398. /* Eat multiple CRs if present. */
  399. while (*pchSrc == '\r')
  400. pchSrc++;
  401. /* Eat line feeds following carriage return if
  402. there are any.
  403. */
  404. while (*pchSrc == '\n')
  405. *pchSrc++;
  406. /* Terminate the line. */
  407. *(pchDest - 1) = 0;
  408. fSameLine = FALSE;
  409. }
  410. else
  411. {
  412. if (c=='\0')
  413. {
  414. /* Backup to point to the 0 so the outer
  415. loop terminates. */
  416. pchSrc--;
  417. fSameLine = FALSE;
  418. }
  419. }
  420. i++;
  421. if ( i >= (hChars - viRightMarginLen))
  422. fSameLine = FALSE;
  423. }
  424. while (*(vpchPrintBuf+viLeftMarginLen)==' ')
  425. vpchPrintBuf++;
  426. if (!PrintLine ())
  427. goto error0;
  428. vpchPrintBuf=rgchPrintBuf;
  429. }
  430. }
  431. DrUnlock (idr);
  432. return TRUE;
  433. error0:
  434. DrUnlock(idr);
  435. return FALSE;
  436. }
  437. /**** PrintHeading - print the heading if it hasn't been printed yet. */
  438. BOOL APIENTRY PrintHeading (DT dt)
  439. {
  440. D3 d3;
  441. if (vclnDate == 0)
  442. {
  443. /* The heading has not yet been printed - print it out
  444. now since we now know that the date is not empty.
  445. */
  446. /* First put out the lines between dates if this date is
  447. not being printed at the top of a page.
  448. */
  449. vclnPrinted++;
  450. /* Convert the date into an ASCII string. */
  451. GetD3FromDt (dt, &d3);
  452. FillBuf (vpchPrintBuf, viLeftMarginLen, ' '); /* pad margin space
  453. with blanks */
  454. GetDateDisp (&d3, vpchPrintBuf + viLeftMarginLen);
  455. if (!PrintLine ())
  456. return FALSE;
  457. if (!PrintBlankLn (CLNAFTERHEADING))
  458. return FALSE;
  459. }
  460. return TRUE;
  461. }
  462. /**** PrintBlankLn */
  463. INT APIENTRY PrintBlankLn (INT cln)
  464. {
  465. *vpchPrintBuf = '\0';
  466. while (cln--)
  467. if (!PrintLine ())
  468. return FALSE;
  469. return TRUE;
  470. }
  471. /**** PrintLine */
  472. BOOL APIENTRY PrintLine ()
  473. {
  474. if (vfPrint)
  475. {
  476. /* print footer if bottom of page is reached */
  477. if (vclnPrinted >= vclnPage)
  478. {
  479. PrintHeaderFooter(FALSE);
  480. if (!NewPage ())
  481. return FALSE;
  482. viCurrentPage++;
  483. PrintHeaderFooter(TRUE); /* print header */
  484. vclnPrinted = vlnTop;
  485. }
  486. TextOut (vhDCPrint, 0, vclnPrinted * vcyPrintLineToLine,
  487. vpchPrintBuf, lstrlen (vpchPrintBuf));
  488. vclnPrinted++;
  489. }
  490. vclnDate++;
  491. return TRUE;
  492. }
  493. /****************************************************************************
  494. *
  495. * BOOL PASCAL PrintHeaderFooter ( hdr )
  496. *
  497. * function : generates and formats the header/footer strings and copies
  498. * them to the print buffer
  499. *
  500. * params : IN hdr : boolean indicating if header(TRUE) or footer(FALSE)
  501. * is to be generated
  502. *
  503. * called by: Print(), PrintLine()
  504. *
  505. * returns : none
  506. *
  507. ***************************************************************************/
  508. BOOL APIENTRY PrintHeaderFooter(BOOL bHeader)
  509. {
  510. CHAR buf[80];
  511. int len;
  512. /* 1-bHeader gives 0 for header, 1 for footer. */
  513. lstrcpy(buf, chPageText[1-bHeader]);
  514. szHeadFoot=GlobalLock(hHeadFoot);
  515. len=TranslateString(buf);
  516. if (*szHeadFoot)
  517. {
  518. if (bHeader)
  519. TextOut(vhDCPrint, dxLeft, dyHeadFoot - CharPrintHeight, szHeadFoot, len);
  520. else
  521. TextOut(vhDCPrint, dxLeft, yPrintRes-CharPrintHeight-dyHeadFoot, szHeadFoot, len);
  522. }
  523. GlobalUnlock(hHeadFoot);
  524. return TRUE;
  525. }
  526. /***************************************************************************
  527. * int TranslateString(char *src)
  528. *
  529. * purpose:
  530. * translate a header/footer strings
  531. *
  532. * supports the following:
  533. *
  534. * && insert a & char
  535. * &f current file name or (untitiled)
  536. * &d date in Day Month Year
  537. * &t time
  538. * &p page number
  539. * &p+num set first page number to num
  540. *
  541. * params:
  542. * IN/OUT src this is the string to translate, gets filled with
  543. * translate string. limited by len chars
  544. * IN len # chars src pts to
  545. *
  546. * used by:
  547. * Header Footer stuff
  548. *
  549. * uses:
  550. * lots of c lib stuff
  551. *
  552. * restrictions:
  553. * this function uses the following global data
  554. *
  555. * iPageNum
  556. * text from main window caption
  557. *
  558. ***************************************************************************/
  559. int TranslateString(CHAR *src)
  560. {
  561. CHAR letters[15];
  562. CHAR chBuff[3][80], buf[80];
  563. CHAR *ptr, *dst=buf, *save_src=src;
  564. INT page;
  565. int nAlign=1, foo, nx,
  566. nIndex[3];
  567. struct tm *newtime;
  568. time_t long_time;
  569. nIndex[0]=0;
  570. nIndex[1]=0;
  571. nIndex[2]=0;
  572. /* Get the time we need in case we use &t. */
  573. time(&long_time);
  574. newtime=localtime(&long_time);
  575. LoadString(vhInstance, IDS_LETTERS, letters, 15);
  576. while (*src) /* look at all of source */
  577. {
  578. while (*src && *src != '&')
  579. {
  580. chBuff[nAlign][nIndex[nAlign]]=*src++;
  581. nIndex[nAlign] += 1;
  582. }
  583. if (*src == '&') /* is it the escape char? */
  584. {
  585. src++;
  586. if (*src == letters[0] || *src == letters[1])
  587. { /* &f file name (no path) */
  588. /* a bit of sleez... get the caption from
  589. * the main window. search for the '-' and
  590. * look two chars beyond, there is the
  591. * file name or (untitiled) (cute hu?)
  592. */
  593. GetWindowText(vhwnd0, buf, 80);
  594. ptr=strchr(buf, '-') + 2;
  595. /* Copy to the currently aligned string. */
  596. lstrcpy((chBuff[nAlign]+nIndex[nAlign]), ptr);
  597. /* Update insertion position. */
  598. nIndex[nAlign] += lstrlen(ptr);
  599. }
  600. else
  601. if (*src == letters[2] || *src == letters[3])
  602. { /* &P or &P+num page */
  603. src++;
  604. page = 0;
  605. if (*src == '+') /* &p+num case */
  606. {
  607. src++;
  608. while (isdigit(*src))
  609. {
  610. /* Convert to int on-the-fly*/
  611. page = (10*page)+(UCHAR)(*src)-48;
  612. src++;
  613. }
  614. }
  615. _itoa(viCurrentPage+page, buf, 10);
  616. lstrcpy((chBuff[nAlign]+nIndex[nAlign]), buf);
  617. nIndex[nAlign] += lstrlen(buf);
  618. src--;
  619. }
  620. else
  621. if (*src == letters[4] || *src == letters[5])
  622. { /* &t time */
  623. ptr = asctime(newtime);
  624. /* extract time */
  625. strncpy(chBuff[nAlign]+nIndex[nAlign], ptr+11, 8);
  626. nIndex[nAlign] += 8;
  627. }
  628. else
  629. if (*src == letters[6] || *src == letters[7])
  630. { /* &d date */
  631. ptr = asctime(newtime);
  632. /* extract day month day */
  633. strncpy(chBuff[nAlign]+nIndex[nAlign], ptr, 11);
  634. nIndex[nAlign] += 11;
  635. /* extract year */
  636. strncpy(chBuff[nAlign]+nIndex[nAlign], ptr+20, 4);
  637. nIndex[nAlign] += 4;
  638. }
  639. else
  640. if (*src == '&')
  641. { /* quote a single & */
  642. chBuff[nAlign][nIndex[nAlign]]='&';
  643. nIndex[nAlign] += 1;
  644. }
  645. else
  646. /* Set the alignment for whichever has last occured. */
  647. if (*src == letters[8] || *src == letters[9])
  648. /* &c center */
  649. nAlign=1;
  650. else
  651. if (*src == letters[10] || *src == letters[11])
  652. /* &r right */
  653. nAlign=2;
  654. else
  655. if (*src == letters[12] || *src == letters[13])
  656. /* &d date */
  657. nAlign=0;
  658. src++;
  659. }
  660. }
  661. /* Make sure all strings are null-terminated. */
  662. for (nAlign=0; nAlign<3; nAlign++)
  663. chBuff[nAlign][nIndex[nAlign]]=0;
  664. /* Initialize Header/Footer string */
  665. for (nx=0; nx<xCharPage; nx++)
  666. *(szHeadFoot+nx)=32;
  667. /* Copy Left aligned text. */
  668. for (nx=0; nx < nIndex[0]; nx++)
  669. *(szHeadFoot+nx)=chBuff[0][nx];
  670. /* Calculate where the centered text should go. */
  671. foo=(xCharPage-nIndex[1])/2;
  672. for (nx=0; nx<nIndex[1]; nx++)
  673. *(szHeadFoot+foo+nx)=(CHAR)chBuff[1][nx];
  674. /* Calculate where the right aligned text should go. */
  675. foo=xCharPage-nIndex[2];
  676. for (nx=0; nx<nIndex[2]; nx++)
  677. *(szHeadFoot+foo+nx)=(CHAR)chBuff[2][nx];
  678. return lstrlen(szHeadFoot);
  679. }
  680. /**** NewPage */
  681. BOOL APIENTRY NewPage ()
  682. {
  683. INT iErr;
  684. if ((iErr = Escape(vhDCPrint, NEWFRAME, 0, NULL, 0)) < 0) {
  685. EndPrint();
  686. CalPrintAlert(iErr);
  687. return FALSE;
  688. }
  689. vclnPrinted = 0;
  690. return TRUE;
  691. }
  692. /**** BeginPrint - code taken from Cardfile - inprint.c - modified
  693. as necessary. Returns 0 if successful, SP_errorcode (which is
  694. < 0 for error.
  695. */
  696. INT APIENTRY BeginPrint ()
  697. {
  698. CHAR rgchWindowText [CCHSZWINDOWTEXTMAX];
  699. INT iErr;
  700. /* If can't create print DC, return FALSE to indicate can't print. */
  701. if (!(vhDCPrint = GetPrinterDC()))
  702. return (SP_ERROR);
  703. /* Show the hour glass cursor. */
  704. HourGlassOn ();
  705. vfAbortPrint = FALSE;
  706. SetAbortProc(vhDCPrint, FnProcAbortPrint);
  707. GetWindowText (vhwnd0, rgchWindowText, CCHSZWINDOWTEXTMAX);
  708. /* Gotta disable the window before doing the start doc so that the user
  709. * can't quickly do multiple prints.
  710. */
  711. EnableWindow (vhwnd0, FALSE);
  712. if ((iErr = Escape(vhDCPrint, STARTDOC, lstrlen((LPSTR)rgchWindowText),
  713. (LPSTR)rgchWindowText, (LPSTR)0)) < 0) {
  714. EnableWindow (vhwnd0, TRUE);
  715. DeleteDC(vhDCPrint);
  716. HourGlassOff();
  717. return iErr;
  718. }
  719. vhwndAbortPrint = CreateDialog(vhInstance, MAKEINTRESOURCE(IDD_ABORTPRINT),
  720. vhwnd0,FnDlgAbortPrint);
  721. return (0);
  722. }
  723. /**** EndPrint - code taken from Cardfile - inprint.c - modified
  724. as necessary.
  725. */
  726. VOID APIENTRY EndPrint ()
  727. {
  728. if (!vfAbortPrint)
  729. Escape(vhDCPrint, ENDDOC, 0, (LPSTR)0, (LPSTR)0);
  730. /* The previous Escape could have changed the value of vfAbortPrint;
  731. * So, this has to be tested again;
  732. * Fix for Bug #6029 --SANKAR-- 11-9-89
  733. */
  734. if(!vfAbortPrint)
  735. DestroyAbortWnd();
  736. DeleteDC (vhDCPrint);
  737. /* The waiting is over. */
  738. HourGlassOff ();
  739. }
  740. /**** FnProcAbortPrint - code taken from Cardfile - inprint.c - modified
  741. as necessary.
  742. */
  743. INT APIENTRY FnProcAbortPrint (
  744. HDC hDC,
  745. INT iReserved)
  746. {
  747. MSG msg;
  748. while (!vfAbortPrint && PeekMessage(&msg, NULL, 0L, 0L, TRUE))
  749. if (vhwndAbortPrint == NULL || !IsDialogMessage(vhwndAbortPrint, &msg))
  750. {
  751. TranslateMessage (&msg);
  752. DispatchMessage (&msg);
  753. }
  754. return (!vfAbortPrint);
  755. }
  756. /**** FnDlgAbortPrint - code taken from Cardfile - inprint.c - modified
  757. as necessary.
  758. */
  759. INT_PTR CALLBACK FnDlgAbortPrint (
  760. HWND hwnd,
  761. UINT msg,
  762. WPARAM wParam,
  763. LPARAM lParam)
  764. {
  765. static HMENU hMenuSys;
  766. switch (msg)
  767. {
  768. case WM_COMMAND:
  769. vfAbortPrint = TRUE;
  770. DestroyAbortWnd();
  771. vhwndAbortPrint = NULL;
  772. return (TRUE);
  773. case WM_INITDIALOG:
  774. hMenuSys = GetSystemMenu (hwnd, FALSE);
  775. SetDlgItemText (hwnd, IDCN_PATH,
  776. (LPSTR)PFileInPath (vszFileSpec));
  777. CalSetFocus (hwnd);
  778. return (TRUE);
  779. case WM_INITMENU:
  780. EnableMenuItem (hMenuSys, SC_CLOSE, MF_GRAYED);
  781. return(TRUE);
  782. }
  783. return(FALSE);
  784. }
  785. /**** Enable Tiled window, THEN destroy dialog window. */
  786. VOID DestroyAbortWnd()
  787. {
  788. EnableWindow (vhwnd0, TRUE);
  789. DestroyWindow (vhwndAbortPrint);
  790. vhwndAbortPrint = NULL;
  791. }
  792. /**** Post printing error message box */
  793. VOID APIENTRY CalPrintAlert(INT iErr)
  794. {
  795. INT iszErr;
  796. /* Map error code to string index */
  797. if (iErr == SP_OUTOFDISK)
  798. iszErr = IDS_NEDSTP;
  799. else if (iErr == SP_OUTOFMEMORY)
  800. iszErr = IDS_NEMTP;
  801. else iszErr = IDS_CANNOTPRINT;
  802. AlertBox (vrgsz[iszErr], PFileInPath (vszFileSpec),
  803. MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
  804. }
  805. /* ** GetPrinterDc()
  806. Get Dc for current device on current output port according to
  807. info in win.ini.
  808. returns
  809. DC if success
  810. NULL if failure
  811. */
  812. HDC APIENTRY GetPrinterDC()
  813. {
  814. extern BOOL bPrinterSetupDone;
  815. LPDEVMODE lpDevMode;
  816. LPDEVNAMES lpDevNames;
  817. if(!bPrinterSetupDone){ /* Retrieve default printer if none selected. */
  818. vPD.Flags = PD_RETURNDEFAULT|PD_PRINTSETUP;
  819. vPD.hDevNames = NULL;
  820. vPD.hDevMode = NULL;
  821. PrintDlg(&vPD);
  822. }
  823. if(!vPD.hDevNames)
  824. return NULL;
  825. lpDevNames = (LPDEVNAMES)GlobalLock(vPD.hDevNames);
  826. if(vPD.hDevMode)
  827. lpDevMode = (LPDEVMODE)GlobalLock(vPD.hDevMode);
  828. else
  829. lpDevMode = NULL;
  830. /* For pre 3.0 Drivers,hDevMode will be null from Commdlg so lpDevMode
  831. * will be NULL after GlobalLock()
  832. */
  833. vPD.hDC = CreateDC((LPSTR)lpDevNames+lpDevNames->wDriverOffset,
  834. (LPSTR)lpDevNames+lpDevNames->wDeviceOffset,
  835. (LPSTR)lpDevNames+lpDevNames->wOutputOffset,
  836. lpDevMode);
  837. GlobalUnlock(vPD.hDevNames);
  838. if (vPD.hDevMode)
  839. GlobalUnlock(vPD.hDevMode);
  840. return vPD.hDC;
  841. }
  842. /****************************************************************************
  843. ** IsDefaultPrinterStillValid()
  844. ** The user might setup the app for a particular printer and a port
  845. ** using the Printer Setup available in the application command menu;
  846. ** But later, he might go to control panel and delete that printer
  847. ** driver altogether or he might connect it to a different port;
  848. ** So, the application must process the WININICHANGE message and at that
  849. ** time, it must check whether the printer setup is still valid or not!
  850. ** This function is used to make that check;
  851. ** The input parameter is a string containing the printer name, driver,
  852. ** port selected by the printer setup; This function checks if the printer
  853. ** name is still present under the [Devices] section of Win.INI and if so,
  854. ** it will check if the port selected is listed among the ports to which
  855. ** this printer is connected; If not, it will automatically select the
  856. ** first port listed as the default port and modify the input "lpszPrinter"
  857. ** string accordingly;
  858. ** If the default printer is not listed in WIN.INI at all, then this
  859. ** function return FALSE;
  860. ** Fix for Bug #5607 -- SANKAR -- 10-30-89
  861. **
  862. ****************************************************************************/
  863. BOOL FAR APIENTRY IsDefaultPrinterStillValid(LPSTR lpszPrinter)
  864. {
  865. CHAR PrinterBuff[128];
  866. CHAR DeviceBuff[128];
  867. LPSTR lpPort; /* Default port name */
  868. LPSTR lpFirstPort = NULL;
  869. LPSTR lpch;
  870. LPSTR lpListedPorts;
  871. /* lpszPrinter contains "PrinterName,DriverName,Port" */
  872. lstrcpy(PrinterBuff, lpszPrinter); /* Make a local copy of the default printer name */
  873. /* Search for the end of printer name */
  874. for(lpch = PrinterBuff; (*lpch)&&(*lpch != ','); lpch = AnsiNext(lpch))
  875. ;
  876. if(*lpch)
  877. *lpch++ = '\0';
  878. /* Skip the Driver name; We do not need it! */
  879. while(*lpch && *lpch <= ' ') /* Skip the blanks preceeding the driver name */
  880. lpch = AnsiNext(lpch);
  881. while(*lpch && *lpch != ',' && *lpch > ' ') /* Search for ',' following driver name */
  882. lpch = AnsiNext(lpch);
  883. while (*lpch && (*lpch <= ' ' || *lpch == ',')) /* Search for begining of port name */
  884. lpch = AnsiNext(lpch);
  885. lpPort = lpch; /* Default port name */
  886. /* Search for the printer name among the [devices] section */
  887. if (!GetProfileString("devices", PrinterBuff, "", DeviceBuff, 128))
  888. return(FALSE); /* Default printer no longer exists */
  889. lpch = DeviceBuff;
  890. /* Skip the Driver filename */
  891. while(*lpch && *lpch != ',')
  892. lpch = AnsiNext(lpch);
  893. while(*lpch)
  894. {
  895. /* Skip all blanks */
  896. while(*lpch && (*lpch <= ' ' || *lpch == ','))
  897. lpch = AnsiNext(lpch);
  898. lpListedPorts = lpch;
  899. if(!lpFirstPort)
  900. lpFirstPort = lpch; /* Save the first port in the list */
  901. /* Search for the end of the Port name */
  902. while(*lpch && *lpch != ',' && *lpch > ' ')
  903. lpch = AnsiNext(lpch);
  904. if(*lpch)
  905. *lpch++ = '\0';
  906. /* Check if the port names are the same */
  907. if(lstrcmp(lpPort, lpListedPorts) == 0)
  908. return(TRUE); /* Default port exists among the listed ones */
  909. }
  910. /* The default port does not exist among the listed ports; So, change
  911. * the default port to the first port in the list;
  912. */
  913. if(*lpFirstPort)
  914. {
  915. /* Search for the end of the printer name */
  916. for (lpch = szPrinter; (*lpch)&&(*lpch != ','); lpch = AnsiNext(lpch))
  917. ;
  918. /* Skip the driver file name */
  919. if(*lpch)
  920. lpch++;
  921. while(*lpch && *lpch != ',')
  922. lpch = AnsiNext(lpch);
  923. if(*lpch)
  924. lpch++;
  925. lstrcpy(lpch, lpFirstPort);
  926. return(TRUE);
  927. }
  928. return(FALSE);
  929. }