Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!rutgers!clyde!cuae2!ihnp4!aicchi!egv From: egv@aicchi.UUCP (Vann) Newsgroups: comp.sys.mac Subject: Re: Print Manager Info Message-ID: <878@aicchi.UUCP> Date: Thu, 18-Dec-86 23:38:51 EST Article-I.D.: aicchi.878 Posted: Thu Dec 18 23:38:51 1986 Date-Received: Sat, 20-Dec-86 00:08:46 EST References: <875@aicchi.UUCP> Organization: Analysts International Corp; Chicago Branch Lines: 704 > I have recently become an owner of Turbo Pascal. Included among the files > for use with the compiler (sample examples of Pascal programming) is one > which generates a listing of a source file. It is entitled Lister.pas. > > I have been in the process of modifying the program to attempt to get it > to do two things: > > (1) Print line numbers (right-justified) for each source line > > (2) Improve the efficiency of the program when printing all or a > portion of a file. > > I have been able to get the line numbers prepended to each line, but the > efficiency problem is still escaping me. Inside Macintosh shows a method > of avoiding the unnecessary looping through all pages of a document when > only a portion is to be printed. (See pgs. II-155,156) But still the > printing seems to be considerably slower than Macintosh applications I > have purchased. > > My question for those of you who know a great deal about this, is whether > there are some tricks that I can perform to speed up the spooling of the > file to the disk. Will any of this be possible in Pascal via existing > Toolbox routines, or are we talking about some work in Assembler, etc? > > I'd be glad to post a summary of any comments I receive. Thanks in advance. > e P.S. For any of you who might have been curious, Turbo Pascal seems to be a > very slick package. From the comments on the net concerning the speed of > LSP and LSC, I should think this package is in the ballpark. But most of all > I liked the documentation. There are some nicely stated insights into the > Macintosh in general, and into the programming of the Mac in specific. Novice > programmers of the Mac will no doubt find this a welcome addition to their > programming arsenal. > > I should wonder if any of you have suggestions for a debugger other than the > MACSBUG debugger that comes with the package? > > > -- > Eric Geoffrey Vann > Analysts International (Chicago Branch) > (312) 882-4673 > ..!ihnp4!aicchi!egv Here is a copy of the source about which I wrote: program Lister; {$B+} { set the bundle bit } {$R-} { turn off range checking } {$I-} { turn off I/O checking } {$U-} { turn off autolink to runtime units } {$T APPLLIST} { Set TYPE and CREATOR } {$R Lister.Rsrc} { Link the resource file } uses PasInOut,Memtypes,QuickDraw,OSIntf,ToolIntf,PackIntf,MacPrint; const MenuCnt = 6; { total # of menus } ApplMenu = 1000; { resource ID of Apple Menu } FileMenu = 1001; { resource ID of File Menu } EditMenu = 1002; { resource ID of Edit Menu } OptnMenu = 1003; { resource ID of Options Menu } FontMenu = 1004; { resource ID for Font Menu } SizeMenu = 1005; { resource ID for Size Menu } AM = 1; { index into MenuList for ApplMenu } FM = 2; { ditto for File Menu } EM = 3; { ditto for Edit Menu } OM = 4; { ditto for Options Menu } TM = 5; { ditto for Font Menu } SM = 6; { ditto for Size Menu } MainID = 1000; { resource ID for Main Window } AboutID = 1000; { resource ID for dialog box } Text1ID = 1000; { resource IDs for 'About...' text } Text2ID = 1001; Text3ID = 1002; MyCursID = 1000; { resource ID for myCursor } MyCursor = 5; { array index for myCursor } LeftMargin = 10; { left margin offset } type CursorList = array[iBeamCursor..myCursor] of CursHandle; var FontName : str255; { text name of selected font } FontNumber : integer; { number of selected font } PrintRecord : THPrint; { ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Here is a description of the THPrint record so that some of the code below makes more sense: TYPE THPrint = ^TPPrint; TPPrint = ^TPrint; TPrint = RECORD iPrVersion: INTEGER; Printing Manager version prInfo : TPrInfo; printer info subrecord rPaper : Rect; paper rectangle prStl : TPrStl; additional device information prInfoPT : TPrInfo; use internally prXInfo : TPrXInfo; additional device information prJob : TPrJob; job subrecord printX : not used Array[1..19] of Integer END; TPrInfo = RECORD iDev : INTEGER; used internally iVRes : INTEGER; vertical resolution of printer iHRes : INTEGER; horizontal resolution of printer rPage : Rect page rectangle END; Rect = RECORD CASE INTEGER OF 0 : (top : INTEGER; left : INTEGER; bottom : INTEGER; right : INTEGER); 1 : (topLeft: Point; botRight: Point) END; VHSelect = (v,h); Point = RECORD CASE INTEGER OF 0 : (v: INTEGER: vertical coordinate h: INTEGER); horizontal coordinate 1 : (vh: ARRAY[VHSelect] OF INTEGER) END; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: } Reply : SFReply; Quit : Boolean; MenuList : array[1..MenuCnt] of MenuHandle; { holds menu info } MainPtr : WindowPtr; { pointer to main window } MainRec : WindowRecord; { holds data for main window } MainPeek : WindowPeek; { pointer to MainRec } ScreenPort : GrafPtr; { pointer to entire screen } FrontWindow : WindowPtr; { pointer to active window } TH,TV : Integer; ScreenArea : Rect; { defines screen dimensions } CursList : CursorList; { used to hold cursor handles } ExpIncludes : Boolean; { global flag for expanding inc } FontItem : integer; { current font menu item number } SizeItem : integer; { global size menu item number } LineSize : Integer; { heigth of a printed line } procedure Debugger; inline $A9FF; procedure PrinterError; var SavePrPort : GrafPtr; ErrorString : str255; begin GetPort(SavePrPort); SetPort(ScreenPort); MoveTo(200,200); NumToString(PrError,ErrorString); ErrorString := 'Printer Error # '+ErrorString; DrawString(ErrorString); SetPort(SavePrPort); end; procedure DoPageSetup; var dummy : boolean; begin dummy := PrValidate(PrintRecord); { validate print information } dummy := PrStlDialog(PrintRecord); { page setup dialog } end; procedure OutputText(TextLine : str255; var OutputLine : integer); var I : integer; CurrentPoint : Point; LineString : Str255; Blanks : Str255; begin NumToString(OutputLine,LineString); Blanks := ''; for I := 1 to 5-Length(LineString) do Blanks := Blanks+Chr(20); TextLine := Blanks+LineString+TextLine; MoveTo(LeftMargin,OutputLine * LineSize); { Moveto X,Y page coordinates... } for I := 1 to Length(TextLine) do begin GetPen(CurrentPoint); { if next character will go off the right side of the page, then go to first print position of the next line } if CurrentPoint.h+CharWidth(TextLine[I]) > PrintRecord^^.prInfo.rPage.right then begin OutputLine := OutputLine + 1; NumToString(OutputLine,LineString); Blanks := ''; for I := 1 to 5-Length(LineString) do Blanks := Blanks+Chr(20); TextLine := Blanks+LineString+TextLine; MoveTo(LeftMargin,OutputLine * LineSize); end; DrawString(TextLine[I]); end; OutputLine := OutputLine+1; end; procedure DoPrintFile; { procedure that prints the file to the printer using the Print Manager macintosh calls } var AString : str255; PrinterPort : TPPrPort; LinesPerPage : Integer; { # of text lines to print on a page } FileFilter : SFTypeList; { file filter type list } f,fi : text; { the text file variables for main and inc } Secs : LongInt; TextLine : str255; { the text line to be printed } topLeft : Point; theErr : OSErr; PrintStatus : TPrStatus; DoneWithFile : Boolean; { main file end of file flag } DoneWithInc : Boolean; { include file end of file flag } myRefNum : Integer; SystemTime : str255; SystemDate : str255; PageWidth : Integer; { # of columns per page } PageHeight : Integer; { # of lines per page } CurrentLine : Integer; { current print line on the page } PageNumber : Integer; { listing page number counter } PageString : str255; HeaderText : str255; { string used to build the listing header } FontName : str255; { text name of selected font } FontNumber : integer; { number of selected font } SizeName : str255; { text name of font size } FontSize : LongInt; { font size value } AfterDigits : integer; FirstNonBlank : Integer; { index for first char of include name } FoundInclude : Integer; { flag for finding $I include directive } EndName : Integer; { index for end of include file name } IncludeFName : str255; { include file name scanned from source } begin topLeft.h := 90; { top left horiz point for Get File dialog } topLeft.v := 80; { top left vert " " " " " } FileFilter[0] := 'TEXT'; { file filter for text files } { Get Font and Size Information } GetItem(MenuList[TM],FontItem,FontName); GetFNum(FontName,FontNumber); GetItem(MenuList[SM],SizeItem,SizeName); AfterDigits := Pos(' ',SizeName); Delete(SizeName,AfterDigits,99); StringToNum(SizeName,FontSize); { get a file to print dialog } { The 2nd paramater in SFGETFILE is no } { longer being used. It was a string that } { could be displayed as a prompt... } SFGetFile(topLeft,'',nil,1,FileFilter,nil,Reply); if Reply.good then { if they selected a file} begin if PrJobDialog(PrintRecord) then { Post the dialog that requests info about} { Quality, Page Range, Number of Copies, &} { Paper Feed... } begin PrinterPort := PrOpenDoc(PrintRecord,nil,nil); { Initializes a printing grafPort for use } { in printing a document, makes it the } { current port, and returns its pointer...} PageNumber := 1; DoneWithFile := False; PageWidth := Round(((PrintRecord^^.prInfo.rPage.right) / (PrintRecord^^.prInfo.iHRes)) * 72) - LeftMargin; PageHeight := Round(((PrintRecord^^.prInfo.rPage.bottom) / (PrintRecord^^.prInfo.iVRes)) * 72); LineSize := FontSize + 4; { line size depends on font size } LinesPerPage := (PageHeight DIV LineSize) - 4; theErr := SetVol(nil,Reply.vRefNum); Reset(f,Reply.fName); { Open file as text using name gotten } { from the SFGetFile subroutine... } GetDateTime(Secs); { get raw values for date and time... } { Convert the raw values into ASCII } { strings for display in header of page } IUDateString(Secs,abbrevDate,SystemDate); IUTimeString(Secs,true,SystemTime); repeat if PrError = noErr then begin PrOpenPage(PrinterPort,nil); { start a new page } if PrError = noErr then begin CurrentLine := 1; TextFont(monaco); { set font for header } TextSize(12); { set text size for header } TextFace([bold]); { set bold for header } NumToString(PageNumber,PageString); HeaderText := 'File: '+Reply.fname+' '+SystemDate+' '; HeaderText := HeaderText+SystemTime+' Page: '+PageString; MoveTo(LeftMargin + (PageWidth DIV 2) - (StringWidth(HeaderText) DIV 2),CurrentLine * LineSize); DrawString(HeaderText); { print header text } CurrentLine := CurrentLine + 2; TextFont(FontNumber); { set selected font } TextSize(FontSize); { set selected font size } TextFace([]); { set plain text type } repeat Readln(f,TextLine); { read text line from file } OutputText(TextLine,CurrentLine); { print it out... } { scan for $I includes - see if expansion is required } if ExpIncludes then begin FoundInclude := Pos('{$I ',TextLine); if FoundInclude > 0 then { found $I - get filename } begin { search for first non blank after $I } FirstNonBlank := FoundInclude+3; repeat FirstNonBlank := FirstNonBlank + 1; until (TextLine[FirstNonBlank] <> ' ') or (FirstNonBlank > length(TextLine)); EndName := FirstNonBlank; repeat EndName := EndName + 1; until (TextLine[EndName] = ' ') or (TextLine[EndName] = '}') or (EndName > length(TextLine)); { get the include file name } IncludeFName := copy(TextLine,FirstNonBlank, EndName-FirstNonBlank); reset(fi,IncludeFName); { open include file } if IOResult = 0 then { if file exists } begin DoneWithInc := false; { process through include file } OutputText('[INCLUDE FILE EXPANSION]',CurrentLine); repeat ReadLn(fi,TextLine); { read include line } OutputText(TextLine,CurrentLine); { output the text } if eof(fi) then { test end of inc } DoneWithInc := true; until DoneWithInc; { until end of inc } close(fi); { close include file } OutputText('[END OF INCLUDE FILE]',CurrentLine); end; end; end; if Eof(f) then { test end of main } DoneWithFile := true; until (CurrentLine > LinesPerPage) or DoneWithFile; end else PrinterError; PrClosePage(PrinterPort); { print the page } end else PrinterError; PageNumber := PageNumber + 1; until (PrError <> noErr) or DoneWithFile; Close(f); PrCloseDoc(PrinterPort); if (PrintRecord^^.prJob.bjDocLoop = bSpoolLoop) AND (PrError = noErr) then PrPicFile(PrintRecord,nil,nil,nil,PrintStatus); if PrError <> noErr then PrinterError; end; end; end; procedure DoExpandIncludes(ItemNum : Integer); { sets/resets check mark and option for exapnding include files } var Ch : char; begin ExpIncludes := not ExpIncludes; { toggle the flag } if ExpIncludes { if flag is True... } then Ch := Chr(CheckMark) { then check item in menu } else Ch := Chr(NoMark); { else clear any checkmark } SetItemMark(MenuList[OM],ItemNum,Ch); { put char by item in menu } end; procedure DoFontMenu(ItemNum : Integer); var ChCheckMark, NoCheckMark : char; begin ChCheckMark := Chr(CheckMark); NoCheckMark := Chr(NoMark); SetItemMark(MenuList[TM],FontItem,NoCheckMark); { turn off prev mark } SetItemMark(MenuList[TM],ItemNum,ChCheckMark); { turn on new mark } FontItem := ItemNum; { update current pos } end; procedure DoSizeMenu(ItemNum : Integer); var ChCheckMark, NoCheckMark : char; begin ChCheckMark := Chr(CheckMark); NoCheckMark := Chr(NoMark); SetItemMark(MenuList[SM],SizeItem,NoCheckMark); { turn off prev mark } SetItemMark(MenuList[SM],ItemNum,ChCheckMark); { turn on new mark } SizeItem := ItemNum; { update current pos } end; procedure DoAbout; var theItem : Integer; AboutPtr : DialogPtr; S1,S2,S3 : StringHandle; begin SetCursor(CursList[myCursor]^^); { set to my cursor } ShowCursor; { and turn it back on } S1 := GetString(Text1ID); { get text from resource file } S2 := GetString(Text2ID); S3 := GetString(Text3ID); ParamText(S1^^,S2^^,S3^^,''); { and set up as parameter text } AboutPtr := getNewDialog(AboutID,NIL,Pointer(-1)); { get dialog box} ModalDialog(NIL,theItem); { put dialog box up; get result } DisposDialog(AboutPtr); { get rid of dialog box } end; { of proc DoAbout } procedure DoDeskAcc(Item : Integer); var SavePort : GrafPtr; RefNum : Integer; DName : String; begin GetPort(SavePort); { save port before starting it } GetItem(MenuList[AM],Item,DName); { get name of desk accessory } refNum := OpenDeskAcc(DName); { and start that sucker up! } SetPort(SavePort); { restore grafport and continue } end; { of proc DoDeskAcc } procedure ProcessMenu(CodeWord : LongInt); var MenuNum : Integer; { Res ID# of the menu Selected } ItemNum : Integer; { The item number in the menu } begin MenuNum := HiWord(CodeWord); { get the menu number } ItemNum := LoWord(CodeWord); { get the item number } if ItemNum > 0 then { ok to handle the menu? } begin case MenuNum of ApplMenu : case ItemNum of 1: DoAbout otherwise DoDeskAcc(ItemNum) end; FileMenu : case ItemNum of 1: DoPageSetup; 2: DoPrintFile; 3: Quit := true; end; EditMenu : if not SystemEdit(ItemNum - 1) then begin end; OptnMenu : case ItemNum of 1 : DoExpandIncludes(ItemNum); { expand includes } end; FontMenu : DoFontMenu(ItemNum); SizeMenu : DoSizeMenu(ItemNum); end; { of case menuNum of } end; { of if CodeWord... } HiliteMenu(0); end; { of process menu } procedure ClearWindow(WPtr : WindowPtr); begin if (WPtr = MainPtr) and (Wptr = FrontWindow ) then begin EraseRect(WPtr^.portRect); { clear rect area of window } end end; { of proc ClearWindow } procedure DoUpdate(Event : EventRecord); var SavePort,theWindow : WindowPtr; begin theWindow := WindowPtr(Event.Message); { find which window } if theWindow = MainPtr then begin { only update ours } SetCursor(CursList[MyCursor]^^); { set my cursor } GetPort(SavePort); { save current grafport } SetPort(theWindow); { set as current port } BeginUpdate(theWindow); { signal start of update} { nothing to do } EndUpdate(theWindow); { signal end of update } SetPort(SavePort); { restore grafport } end end; { of proc DoUpdate } procedure DoActivate(Event : EventRecord); var I : Integer; AFlag : Boolean; theWindow : WindowPtr; begin with Event do begin theWindow := WindowPtr(Message); { get the window } AFlag := Odd(Modifiers); { get activate/deactive } if AFlag then begin { if it's activated... } SetPort(theWindow); { make it the port } FrontWindow := theWindow; { know it's in front } DrawGrowIcon(theWindow); { set size box } end else begin SetPort(ScreenPort); { else reassign port } if theWindow = FrontWindow { if it's in front } then FrontWindow := NIL { ...then forget that } end; end end; { of proc DoActivate } procedure CursorAdjust; var MousePt : Point; begin if MainPtr = FrontWindow then SetCursor(CursList[MyCursor]^^) end; { of proc CursorAdjust } procedure EventHandler; var Event : EventRecord; { Filled by Get next event } windowLoc : integer; { the mouse location } mouseLoc : point; { the area it was in } theWindow : WindowPtr; { Dummy,cause we have no windows} begin repeat { do this until we selected quit} SystemTask; { Take care of desk accessories } CursorAdjust; { update which cursor } if GetNextEvent(everyEvent,Event) then begin case Event.what of { case out on the event type } mouseDown : { we had a mouse-down event } begin mouseLoc := Event.where; { where's the pesky mouse } windowLoc := FindWindow(mouseLoc,theWindow); { find out where } case windowLoc of { now case on the location } inMenuBar : ProcessMenu(MenuSelect(MouseLoc)); { Handle the selection } inSysWindow: SystemClick(Event,theWindow); {It was in a desk acc } end; end; updateEvt : DoUpdate(Event); { window need updating } activateEvt : DoActivate(Event) { window made act/inact } end; end; until Quit; end;{ of Event Handler } procedure Initialize; var Indx : Integer; begin { initialize all the different managers } InitGraf(@thePort); { create a grafport for the screen } MoreMasters; { allocate a block of master Ptr's } MoreMasters; { and another } InitFonts; { start up the font manager } InitWindows; { start up the window manager } InitMenus; { start up the menu manager } TEInit; { start up the text manager for DAs } InitDialogs(NIL); { start up the dialog manager } FlushEvents(EveryEvent,0); { clear events from previous state } { set up printer stuff } PrintRecord := THPrint(NewHandle(SizeOf(TPrint))); { allocate data record from } { applicaton heap to handle printer } { data... } PrintDefault(PrintRecord); { set printer defaults...reads from } { printer resource file the default } { values to be placed in the data } { record allocated above... } HLock(Handle(PrintRecord)); { Prevents the relocatable block } { pointed at by PrintRecord from } { being moved during heap compaction } { get four standard system cursors, } { plus one custom one } for Indx := iBeamCursor to watchCursor do begin CursList[Indx]:=GetCursor(Indx); { read in from system resource } HLock(Handle(CursList[Indx])) { lock the handle down } end; CursList[MyCursor] := GetCursor(MyCursID); { get cursor from resources } HLock(Handle(CursList[MyCursor])); { and lock it down } { set up menus } MenuList[AM] := GetMenu(ApplMenu);{ read menus in from resource fork } { This needs to be done PRIOR to } { bringing in the DA's... } AddResMenu(MenuList[AM],'DRVR'); { pull in all desk accessories from } { resource file on disk } MenuList[FM] := GetMenu(FileMenu);{ All of these menus are read in } MenuList[EM] := GetMenu(EditMenu);{ from the resource file. They are } MenuList[OM] := GetMenu(OptnMenu);{ then inserted into the array } MenuList[TM] := GetMenu(FontMenu);{ MenuList[]...of menu handles } ExpIncludes := False; { set expand includes flag to false } { This flag tells us whether or not } { to try and print the include files } { associated with a given programs } { source listing... } AddResMenu(MenuList[TM],'FONT'); { pull in all fonts } FontItem := 2; { choose second font in list as the } { default font... } DoFontMenu(FontItem); { post the menu of fonts with the } { second one checked... } MenuList[SM] := GetMenu(SizeMenu);{ get font size menu from resource } { file... } SizeItem := 3; { let the 3rd size be checked... } DoSizeMenu(SizeItem); { post menu with size checked... } for Indx := 1 to MenuCnt do { place menus in menu bar } InsertMenu(MenuList[Indx],0); DrawMenuBar; { draw updated menu bar to screen } { set up window stuff } { To use the Window Manager, you must have previously called InitGraf } { to initialize QuickDraw and InitFonts to initialize the Font Mgr... } { The first Window Manager routine to call is the initialization rou- } { tine InitWindows, which draws the desktop and the (empty) menu bar. } { InitWindows initializes the Window Manager, creating the Window } { Manager port. GetWMgrPort returns a pointer to this port... } GetWMgrPort(ScreenPort); { get grafport for all windows } SetPort(ScreenPort); { and keep handy just in case } MainPtr := GetNewWindow(MainID,@MainRec,POINTER(-1)); { get window } SetPort(MainPtr); { set window to current graf port } SelectWindow(MainPtr); { and make window active } FrontWindow := MainPtr; { remember that it's in front } MainPeek := WindowPeek(MainPtr); { get pointer to window record } MainPeek^.windowKind := UserKind; { set window type = user kind (ID=8) } ScreenArea := screenBits.Bounds; { get size of screen (don't assume) } Quit := False; { set program terminator to false } SetCursor(CursList[myCursor]^^); { bring up my cursor } ShowCursor; { turn it back on } end; { of proc Initialize } begin Initialize; { Initialize all of the managers } PrOpen; { open the print manager } if PrError = noErr then { if no error then go handle events } begin EventHandler; { Start handling Events } PrClose; { close the print manager } PrDrvrClose; { close driver opened by PrOpen... } end else { else, print manager error } PrinterError; { display error messageand exit } end. ]End-of-file enountered... -- Eric Geoffrey Vann Analysts International (Chicago Branch) (312) 882-4673 ..!ihnp4!aicchi!egv