Pic to Clip
Volume Number: | | 1
|
Issue Number: | | 11
|
Column Tag: | | Pascal Procedures
|
The Amazing Pic to Clip Utility
By Alan Wootton, President, Top-Notch Productions, MacTutor ContributingEditor
Miscellaneous Month
This month there will not be a main topic, instead I have a collection of goodies that I have been saving up. We will talk a little about some books, about the compiler search I am conducting, revisit printing, and cover two more short topics.
Before I begin, I would like to talk a little philosophy. I wish to bare my soul on what Pascal means to me. There has been some talk about "fluff" in this publication, and this makes me wonder about Pascal. Is Pascal a Real Programmers language? Or is Pascal for Quiche Eaters (see Feirstein, B., "Real Men don't Eat Quiche", New York, Pocket Books, 1982.)? It was once thought that Real Programmers used Fortran. Today it would be C (and always assembly). In that perspective Pascal is indeed for Quiche Eaters, and there are undoubtedly millions of Quiche Eating Pascal programmers. Let us not forget however, that the ROM was originally in Pascal, MacPaint still is. These are not programs created by Quiche Eaters. It was a Real Programmer who, in a fit of rebellion, created LinlineF and Generic. It was a Real Programmer who mangled Niklaus Wirth's (the world renown Quiche Eater who created Pascal) specification by allowing for the beautiful expression ptr:=pointer(ord(ptr)+$100). There is hope for Pascal.
Let us review what a high level language is for. In the dawn of time there were only front panels with switches. Later, the Assembler was invented; the idea being to cater to the laziness of Real Programmers. This was acceptable because every conceivable possibility was still available. After that someone noticed that much of a programmers work was making sure that parameters were passed correctly between procedures, and that the stack was not messed up. The high level language was invented to ease the drudgery of these tasks. Now those who used Fortran ,the first HLL, weren't trying to get away from assembler so much as they were being lazy (one of the higher instincts of Real Programmers). And for those things not allowed in the HLL, assembly code could be linked in. All went well, except for the increasing numbers of Quiche Eaters who jumped straight into Fortran, bypassing knowledge of assembly language. Here is where the trouble begins.
By this time programming had become Real Big Business and certain managerial types were troubled over the fact that their Quiche Eating programmers couldn't decipher the strange things the Real Programmers were now doing in Fortran (list processing, records, pointers, string manipulation, etc.). The word was passed around that Fortran must be upgraded to allow for these strange new constructs. Along comes Wirth to save the day, and the Quiche Eaters gain new momentum. What we had now was a deluge of programmers, working in a toy operating system, who had little or no knowledge of how a computer really works. Real Programmers were in danger of becoming extinct. But, let us not forget that the true purpose of a HLL is as a shortcut to machine code for lazy Real Programmers. Eventually, as Pascal became popular extension were made to the language so that Real Programmers could use it. Still, Pascal was increasingly distant from the workings of the maching it ran on (Basic and microcomputers fuel this trend). This accounts for the popularity of Forth, a language that wallows in the chacteristics of its processor and is infinitly extendable and unreadable (perfect for a Real Programmer).
The 68000 changes all this. The 68000 is designed with an instruction set that provides for the efficient implementation of most HLL statements. On the Mac you can trace machine code and see it follow, line by line, the structure of a Pascal program (I do this all the time). At last the Real Programmers have a language that raises laziness to a high art. And MacPascal is at the top of the heap. One jots down the code he (she) wants, and it is immediately checked for syntax, semantic form, and is even emulated to check for logical errors. It can then be automatically and effortlessly converted into machine code. Or can it?
The Real Programmers at Apple are a snotty bunch (supposedly the worst were canned, but I don't believe it). They think that all the Real Programmers in the world work for Apple, or Microsoft, or IBM (blue suits), or NASA (rocket jocks), or the National Security Agency (spooks), and that there is no need to provide a compiler for the Quiche Eating public. You see they all have compilers on their Lisas (so do I, but I hate it). Therefore, Mr. Jobs allowed Apple to shoot itself in the foot and there is still no compiler. Now I will admit that MacPascal is perfect for the Real-Programmer-growing-up and for the Quiche Eaters too. But, the Real Programmers cannot exist for long on MacPascal and UCSD Pascal. They need a native code compiler or they will all switch to the excellent C systems available for the IBM PC (interpreter, preprocessor, compiler, optimiser, runtime profiler, assembler, libraries, source code debuggers, all integrated into one system). It would be a shame if the Mac died for lack of Real Programmers.
For me this is the real purpose of Pascal; a lazy way to write machine code. Like a spelling checker or a business letter generator, Pascal is a way to save time, not an excuse to not learn to spell or write. One can use MacPascal to diddle with the system, knowing full well that his efforts can be smoothly integrated into the natural Mac way of programming. This arguement should explain why an interpreted language, or a psuedo code system won't do. Not to mention the fact that without native code you can never make desk accessories, window definition functions, control definition functions, INIT resources, etc. More importantly, if you compile your procedures into resources (the standard method), you can call them from inside MacPascal. For an example of this see my article on printing (August Vol.1 No.9) where the PDEF resources are called in just this manner. This way when your MacPascal program gets too long you just compile parts of it until it is more managable. If it weren't for MacPascal I would switch to C in a second.
The Great Compiler Hunt
First of all, Apple intends to port the excellent Lisa compiler over to the Mac (without the dumb OS it now uses). The problem is that they don't have the good sense to just do it; they are going to re-write the whole MDS system. I was told it would not see pre-release until December. My personal prediction is that we will all grow old first and then we will have to buy the new Mac and the new hard disk, to the tune of about $5000.
[Note: MacTutor is pushing for a ".REL" file standard that would allow linking of object code files from a variety of programming languages. We are on record as supporting the MDS ".REL" file format as that standard with proposed extensions submitted by Bill Duvall's new linker, which is compatible with the MDS system as well as his own C system. MacFortran from Microsoft is also very close to being compatable with this standard, and hence Bill's new linker. We encourage Apple and other proposed compilers to support the MDS ".REL" file format for object code files so that all languages can be linked with one common linker. We hope that Apple in developing the Lisa compiler for Pascal on the Mac will consider conforming to this standard. What we don't need is for Apple (and others) to give us yet another incompatible object code file format (ie, don't dump the MDS system Apple!) More on this in upcomming issues. -Ed.]
Tom Leonard of TML systems, Melbourne, FL. (a Real Programmer for sure) is writing a Pascal compiler to go with the MDS system (by Bill Duvall, another Real Programmer). It was going to be in beta test by the writing of this article but didn't make it. Next month look for a Desk Accessory in this column. It will be emulated in MacPascal and compiled in TML Pascal. If this comes true we can do great things. He plans to sell it for $49.95 Stay tuned..
I have a beta copy of Rascal by MetaResearch of Portland OR.. This is a very interesting package. They wrote it to do real time I/O and it is great for that. It runs under an application that integrates editor, compiler, linker and runtime package. What you do is write procedures named _Init, _Main, _Mouse, _Key, _Update, _Event, _Menu, _ and _Halt, and the system calls the correct procedure as needed. The code (native 68000 code) is put into the data fork of the object file with a jump table leading to the procedures. Provisions are made to create stand alone applications (with a 19K overhead). If you wrote an application to break the data fork out into resources you could make anything you wanted. The bad news is that it is not quite Pascal. There are no declared types, and other less important parts are not implemented. The upgrade promises to correct some of these, but I haven't seen it (even though they said it would be ready long ago). The other problem is that it is copy protected (although Steve Jasic's NOSY method of getting things onto hard disks works well). You can buy it now for $99.
I heard rumors that Borland, of Turbo Pascal (for the PC) fame, was doing a compiler for the Mac. Where it is, I don't know. The other bad part is that it seems Turbo Pascal is not native 8086 code. I would not count on them producing native 68000 code either. Many of the Amiga announcements promised Pascal from Borland, so we shall soon see.
UCSD has had a Mac compiler for some time. It makes P-code so I don't know how you are supposed to debug it. You can make stand alone applications. But, you can never call procedures in resources from MacPascal with this system. If it weren't so un-Mac-like in style this would be the premier Quiche Eaters system.
Books
I have three interesting new books. Two on MacPascal, one on programming the Mac. The MacPascal books are The MacPascal Book, by Paul Goodman and Alan Zeldin, Brady Communications company, and Macintosh Pascal, by Lowell A. Carmony and Robert L. Holliday, Computer Science Press. Both are mostly about learning Pascal with MacPascal. Both are also filled with excellent examples, something that the MacPascal docs are short on. If you are a Real-Programmer-in-Training you should get one of these and do some of the examples. It is hard for me to do a good review for two reasons: 1- I already know Pascal; 2- I am familiar with the MacPascal system. The true test is whether a beginning Pascal person can get up to speed using only one of these books. I was told by a computer store person that these books would get yanked from circulation because with one of these books and a pirate copy of MacPascal you have no reason to buy the real thing (Apple doesn't like that). If this is true then they are good books indeed (although you should still buy the product, the MacPascal creators deserve the money). See for yourself. If anyone has any experiences, write a review for MacTutor. I'm sure Dave Smith (our illustrious publisher) would be interested. The main differences between them are that The MacPascal book is typeset while Macintosh Pascal is in Geneva 12. The MacPascal Book also has appendices covering useful things including answers to excercises, syntax diagrams, Quickdraw and SANE.
I also have a copy of Macintosh revealed by Stephen Chernicoff, Apple Press, Hayden book company. This is the first true alternative to Inside Macintosh. I'm sure much will be said about this book in these pages. The true test, again, is whether one can learn about the Mac using this book and without Inside Mac. I would guess that it passes. Even if you already have Inside Mac there are interesting things here. Like the formats of all finder related resources for instance. Chernicoff is from Apple so the book is very accurate. I was shocked, though, to see that he forgot the register information for PACK 7, which in his book implies that it is strictly stack based. He says the information is for all languages although the examples are for Lisa Pascal (when is Apple going to finally give up on Lisa Pascal?).
Enough fluff! I have some programs to present.
Printing Revisited
After I wrote the article on printing in August I realised people might just want to make a printout of a large graphic using MacPascal without having to deal with the details of the Printing Manager. The way to do this is to run Pict_to_clip (below), quit MacPascal, start MacDraw, paste, and print.
What Pict_to_clip does is save the quickdraw calls that you make in the form of a 'picture'. Pictures are covered in the MacPascal Appendix on quickdraw so I won't go too deep. All you have to do is OpenPicture, then make some quickdraw calls and then ClosePicture. You may then DrawPicture, if you wish, and when you are done you KillPicture to free the memory used by the handle. Once you have a handle to your picture, you want the program to copy it onto the clipboard. After it is on the clipboard you can paste it in the scrapbook or just go directly to MacDraw and manipulate and print it all you want.
Clipboard is the name of the file that the scrap is saved in on USA Macs. On other Macs it has different names. So what we are really dealing with here is the Scrap Manager. The Scrap Manager has it's own chapter in Inside Mac, so we should all refer there now (even though we'll only use two functions). First we ZeroScrap; very simple. Then we PutScrap using a pointer to the picture, it's length and a longint that is the four ascii chars 'PICT'.
DrawSomething is the procedure that makes the quickdraw calls. The first example is a recursive routine that draws the fractal above. The second draws a sin(x)/x function. If you need to know more about recursion and fractals get one of the books above, both cover the subject. The sin(x)/x function is an excercise for the reader (note that the program draws the picture upside down, why?). The limitations Drawsomething must observe are that if the PICT gets greater than 32K the Mac locks up. Furthermore, if you paste a 30K picture into MacDraw it gets very slow (2 minutes to update the screen). I have made more intricate drawings by using the LaserWriter with the program from August (I must have done something right 'cause it worked). This won't work with the ImageWriter because there is a 32K/page limit on spool files. More after this short program.
Program to put a picture onto the clipboard. DrawSomething procedure could be anything. This example draws the fractal shown above.
program Pict_to_clip;
uses
sane, Quickdraw2;
procedure DrawSomething;
const
stopsize = 4;
procedure SquareTo (xxx : integer);
var
pt : point;
r : rect;
begin
getpen(pt);
if xxx > stopSize then
begin
xxx := xxx div 2;
moveto(pt.h + xxx, pt.v);
SquareTo(xxx);{ upper right sub square }
moveto(pt.h, pt.v + xxx);
SquareTo(xxx);{ lower left sub square }
moveto(pt.h, pt.v);
SquareTo(xxx);{ upper left sub square }
end
else
begin
setrect(R, pt.h, pt.v, pt.h + xxx, pt.v + xxx);
PaintRect(r);
end;
end;
begin { of DrawSomething }
moveto(-256, -256);
SquareTo(512);
end;
procedure main;
var
bigR, normR : rect;
PicH : PicHandle;
length, theType, lll : longint;
begin
setrect(bigR, -1000, -1000, 1000, 1000);
setrect(normR, 0, 0, 250, 250);
clipRect(bigR);
picH := OpenPicture(bigR);{ 2000 by 2000 plotting area }
DrawSomething;
ClosePicture;
DrawPicture(PicH, normR);{ compress 2000^2 into 250^2 }
lll := LinlineF($A9FC);{ _ZeroScrap }
Hlock(PicH);
theType := $50494354;{ 'PICT' }
length := GetHandleSize(PicH);
writeln('length is', length);
lll := LinlineF($A9FE, length, theType, picH^);
{ _PutScrap}
KillPicture(PicH);{ also disposes of handle }
end;
begin
showDrawing;
main;
end.
DrawSomething procedure to produce second drawing shown above. Use this code in Pict_to_clip.
function form (x, y : integer) : integer;
var
d : extended;
y2, x2 : integer;
begin
x2 := x - 257;
y2 := y - 257; { 257, 257 is center
peak }
d := sqrt((x2 * x2) + (y2 * y2)); { d is distance from center}
d := sin(d / 15) * 2000 / d;
form := num2integer(d) + (y div 2) + 50;
end;
procedure DrawSomething;
const
yst = 8;
xst = 4;
var
hi : boolean;
V, x, y : integer;
arr : array[0..2000] of integer;
begin
y := 0;
while y < 512 do
begin
x := xst;
hi := true;{ above last line }
moveto(0, form(0, y));
while x < 512 do
begin
V := form(x, y); { calculate function }
if V < arr[x] then
begin { if new value under previous line
}
moveto(x, V);
hi := false;
end
else
begin { new value above previous line }
if hi then { were above before, no
change }
lineto(x, V)
else { changing from under to above
}
moveto(x, V);
hi := true;
arr[x] := V;
end;
x := x + xst;
end;
y := y + yst;
end;
end;
Random problems
Ed Groth of Scottsdale, Az. brought to my attention a bug in MacPascal. It seems that Quickdraw and SANE both have a random function with the same name! The SANE Random is therefore unavailable. The fix is to wade through the SANE chapter in Inside Mac until you discover that all of SANE is in packages 4 and 5, and that you can call the functions directly. Use the following incantation.
inlineP($A9EC,@x,$20);
{ _elems68K, $20 is Random }
This performs the function x:=random(x); Use any extended type number instead of x in your program.
Arrowheads
I liked Rick Flott's discovery of how to draw arrow heads (Toolbox tips MacTutor Vol.1, No.9) so much that I had to do it myself. For those who can't decipher C, I present my version below. For a complete description of how it works refer to the August issue. To make the drawing above I used Pict_to_clip to make a 200 by 200 picture that I pasted directly into MacWrite. Note that it looks much better here than it does on the screen because of the LaserWriter. If it were a MacPaint cutout instead of a PICT it would look the same as it does on the screen.
Procedure to draw arrow heads. Use this in any program just as you would Lineto. Note: no example of it's usage is included here.
{ ArrowLineto works just like Lineto except }
{ an arrow head is drawn at the point H,V. }
{ The size and width of the arrow head are }
{ determined by the constants. }
procedure ArrowLineto (H, V : integer);
const
Asize = 20;{ angular size of head }
Ah = 10;{ always half of head angle }
aL = 16;{ length of head }
var
startpt : point;
R : rect;
Ang : integer;
begin
setrect(R, H - aL, V - aL, H + aL, V + aL);
getpen(startpt);
PtToAngle(R, startpt, Ang);
lineto(h, v);
paintarc(R, Ang - Ah, Asize);
end;
Out of Memory?
If you are getting the message "not enough memory to continue execution, hiding the program window may help", when you know full well there is plenty of memory, it is because a nonrelocatable block has been allocated on the heap after execution began. Opening windows or dialog boxes is the most common source of this problem. If your final code is to be a desk accessory you will have this same problem with Microsoft products. The solution is to call NewPtr(small amount), open your windows, and then call DisposePtr. This will leave a little space under your window for MacPascal (or Microsoft Chart) to use when it calls the poison function SetPtrSize. If you are an advanced enough user to get this problem then you are advanced enough to know what I mean.
I think this covers it for this month, so, see ya next time. And if you have problems or questions or suggestions then write me care of MacTutor!