egv@aicchi.UUCP (Vann) (12/18/86)
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. 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? :wq :quit! -- Eric Geoffrey Vann Analysts International (Chicago Branch) (312) 882-4673 ..!ihnp4!aicchi!egv
egv@aicchi.UUCP (Vann) (12/19/86)
> 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
zen@utcs.UUCP (12/21/86)
In article <878@aicchi.UUCP> egv@aicchi.UUCP (Vann) writes: >> 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 >> -- > Eric Geoffrey Vann > Analysts International (Chicago Branch) > (312) 882-4673 > ..!ihnp4!aicchi!egv Small problem with posting lister! It is NOT PUBLIC DOMAIN!! Read your license agreement. I seriously doubt if it i either legal or ethical to upload the source. Nick Zentena -- Nick Zentena zen@utcs {ihnp4,allegra,seismo} I don't need no stinking signature