/*********************************************************************** Title: AEOPJ2.TXT Created: August 13, 1993 Last Modified: October 16, 1993 Purpose: Second installment of AEO Programmers' Journal Editor: Albert Dayes Legal Notes: Copyright (c) 1993 Subspace Publishers ***********************************************************************/ Publisher = Michael Lindsay [GE: EXPLORER] Managing Editor = Travis Guy [GE: AEO.MAG] Editor = Albert Dayes [GE: AEO.1] [CIS: 70007,3615] Technical Editor = Carl Barron [GE: CBARRON] [CIS: 75066,3204] GFA BASIC columnist = Eric Goodman [GE: AEO.6] OBJECT::ATARI columnist = Warwick Allison [In: warwick@cs.uq.oz.au] 68K columnist = Damien M. Jones [GE: DMJ] Contributing: Laurent Chemla [ In: laurent@brasil.frmug.fr.net] Loic Duval [ CIS: 100015,3044 ] [ GE: ATARI-FRANCE ] [ In: loic@brasil.frmug.fr.net ] Kris Gasteiger [ CIS: 73637,2004 ] Alexandre Lemaresquier [ In: alex@brasil.frmug.fr.net ] Raphael Lemoine [ In: raphael@brasil.frmug.fr.net ] Daniel Verite [ In: daniel@brasil.frmug.fr.net ] Ron Whittam [ GE: R.WHITTAM ] /***********************************************************************/ Table of Contents: * Editorial * Meet the Authors ............. short biographical notes on the authors * What is in this issue of AEO-PJ * A note from the IAAD .............. They want to help Atari Developers * 68K Column ................. Some Assembly Required by Damien M. Jones * C Column ....................... First steps to learning C programming * Advanced Computing ..... Carl Barron explores a practical side to Flex * Hard Core .... Interview with Charles Smeton author of STraight Fax! 2 * Dabbling in PASCAL ......... Kris Gasteiger explains Pascal and Sherry * Practical DSP .................... Programming the 56001 by BrainStorm * LIB [ new file(s) ] ................. X11R5 and GNU CD-ROM disc review * Periodicals ......... The Atari Compendium reviewed by Damien M. Jones * OBJECT::ATARI ............... Warwick Allison examines C++ and GEM VDI * In the Trenches ............ Solving "real-world" programming problems * Language Watch ................... Current versions of developer tools * Bad Example ........................... Do you really want to do that? * On the Networks ...................... Interactive programming on-line * Network Sign-up Information * User View ............................................. by Ron Whittam * Brain Stem rotator ..................... A true programming challenge? * Glossary of Terms * ATARI DEVELOPER INFORMATION ..... Where to get the official Atari Docs * Sources of Information ..................... References for this issue * Post Increment ................... What is coming up in the next issue * LEGAL NOTES ------------------------------------------------------------------------- Editorial: "Real-Time Error Correction & Car Dealers" By: Albert Dayes ------------------------------------------------------------------------- The on-line networks provide users with a amount of interaction. The type of interaction includes writing/reading messages, file transfers and real-time conferences and something more study groups. On Compuserve, programming related study groups were pioneered by Richard Cohen in the Computer Language Forum (GO CLMFORUM) approximately four years ago. Basically the group chooses a programming book and then reads a chapter or two per week. As one completes the chapter one can post his/her comments in the forum. This produces a long running discussion that continues until that particular book is completed. Then another book is chosen and the cycle repeats itself. The current book that is currently being discussed is Code Complete - A practical handbook of software construction by Steve McConnell (publisher: Microsoft Press: ISBN 1-55615-484-4). This would be something very useful to do in the Atari world as well. We could choose a programming book on C for example or use a more Atari platform specific book like C-manship Complete by Clayton Walnum. I am just using C as an example since they could apply to many different languages and/or programming topics. It is also possible that many study groups could run concurrently as well. There are several advantages that I can see currently: A) "Real-Time" Error Correction of each other and the book. B) Discussion of many important side issues in addition to the main topic. C) New ideas/techniques for solving a particular problem. D) Working code fragments (very important). E) Get more people involved in discussing programming in general. And there are many more... Speaking of error correction one thing to always look at when purchasing development tools is how the developer resolves disputes. Its the same thing when one goes to purchase a car or anything else. You are not interested in those who have perfectly working vehicles at all. You are interested in one thing and one thing only. How was the difference of opinion also known as a dispute resolved? Was it resolved constructively? Was it acted upon in good faith? If it's not to the advantage of the car dealer how did he/she handle it? Did any other car owners have similar problems? Were the problems solved? Were they solved to both the car owners' and the car dealer's satisfaction? How does the car dealer talk about other car dealers in the area? Is it positive and constructive? Does it give you the impression that his/her opinion about other car dealers is a honest accessment? If a car dealer has a dispute with another car dealer how was it handled? Are the points of argument legitimate ones? Did both car dealers act in good faith to solve the problem at hand? Was it ever solved? And if it was solved was it done in a positive, constructive and diplomatic manner? These are similar to the type of things I always take careful consideration of when I make a software development tool purchase. On an online service it is much easier to get a very good indication of how disputes are resolved as many of you already know. Many of you have sent e-mail or posted in public forums on the various on-line services on our first issue. EVERY MESSAGE IS GREATLY APPRECIATED so keep sending your questions and comments! Some of you talked about problems with understanding the terms used throughout the first issue as well. The early part of learning programming involves learning new terms and what they mean. This can be very frustrating when one does not understand the meaning of the terms. PLEASE ASK QUESTIONS, send EMail, post in public forums, etc. Some people worry about "stupid" questions.... there is no such thing as a stupid question!!! Every question is useful and helps everyone. Many times the so called "simple" questions are some of the hardest ones to answer. So send EMail, post in public forums and ask questions since discussion of programming related problems will help everyone learn something new. We welcome all feedback both positive and negative so feel free to write anytime. Feedback is not just related to the current issue but anything that one wishes to discuss. Sometimes we can assume that everyone is coming from the same direction but that is not always the case. We want to be sure that you are working on solving your problem (the fun part) and not fighting with the syntax of the programming language. -- Albert CIS: 70007,3615 GE: AEO.1 In: 70007.3615@Compuserve.com /**********************************************************************/ Meet the Authors /**********************************************************************/ Brainstorm is a 4-person company writing development tools, system and DSP programs, as well as high-end algorithm software. They are known for their Atari products such as Adebug/Assemble (an assembly development package including a low and source level debugger), the official Atari DSP Debugger and their JPEG and MPEG decoders. Brainstorm is composed of: Laurent Chemla (communication - hardware link - system development) Alexandre Lemaresquier (manager - GEM development - system development) Raphael Lemoine (graphics programming - DSP programming - system development) Daniel Verite (image recognition - parallel programming - system development) //// Loic Duval Loic is the Product Manager & Developer Support Manager of Atari France. He bought his first ST in September 1985 and was one of the first registered French developers. He joined Atari France in October 1991. Previously he was a journalist at ST Magazine and other French computer magazines then chief editor of Atari Magazine. //// Kris Gasteiger I received my first computer, an Atari 520ST for Christmas of 1986. Before then, I was a mild techno-phobe. The ease of use and programmability caught me, and I've been dabbling ever since. I taught myself ST BASIC, graduated to LDW BASIC, got discouraged by the environment of GFA BASIC, and finally decided I liked ICD/OSS Personal Pascal enough to stop my search for a "decent" programming language. (I'd also over spent my budget on software about then). I may have gone on to learn C, but Personal Pascal seems adequate to my needs. I commented on the lack of information on Pascal programming in this, journal, and was invited to fill that gap. My article(s) will be pointed towards the beginner, with the hope that feedback will help me find a direction for future exploration. I moved to N. Billerica, MA a year ago, quitting my job in a state park in upstate New York to be with my lady. I worked as a temp for a short time, and am currently working full time for a health-care supplier as a packer (big come down in pay, but what the heck, love will mess your mind, no how). //// Damien M. Jones (DMJ) Damien M. Jones started programming on the Atari ST in 1988, before he even owned one. He bought one so he could program in GFA BASIC, and has learned continually over the past five years, learning C, assembly, and various other languages. In the past two years he has written Sound Lab, DMJ GIF, Spc Thumb, ReNameIt! (with Tom Hayslett), and has recently released his first commercial product, View II. His "real" job involves writing C code for Windows, but he still prefers the Atari ST/Falcon line. //// Ron Whittam OCCUPATION: "Computer Operations Technical Support" in a large bank holding company's MAINFRAME COMPUTER CENTER. My job title denotes "computer operations" in deference to "PC/LAN operations". The "technical" refers to ANY technical, hardware, software, or logistics problem encountered. The "support" refers to help and assistance, (this differs depending on the type and extent of the problem). My primary focus is to help the end user communicate with the programmer. I look for possible problems and take steps (or write procedures) to avoid them. When a problem is reported I determine the possible causes (human error, code error, communication error, hardware malfunction, logistic or distribution error, etc.) and then coordinate the resolution. I work with the Bank's customers to insure their data is transmitted to or from the bank properly via modem, data-line, magnetic tape, pc disk media, etc. I also test, evaluate, install, and maintain software; and train the computer operators in its use. My responsibilities include Disaster Contingency and Business Resumption planning. I have no formal Computer training. My training has been "on the job" for the past 6 years. HOME COMPUTERS: I bought a TI-99/4A computer in 1983. I bought my first Atari 1040 ST in 1987 and my second Atari 1040 ST in 1993. I also own an HP CS laptop (NEC-30 CPU) and a Intel386SX IBM clone with a ROM Drive, hand scanner, and sound board. I have installed (and removed) PC-ditto II in the Atari, installed TOS 1.4, installed Xtra-RAM Deluxe (4megs). I enjoy programming (my WINNER11.LZH program was on the STI's August DOM). However my basic use of the ATARI is writing. I use PROTEXT, but plan to buy AW soon. I also use MasterPlan for my financial work. COMMUNITY: I am the president of the "Atari Boise Users Group" and have been for 3 years. We meet monthly. I was an assistant SYSOP on a local BBS until the SYSOP closed the board. I occasionally teach Adult community education classes in DOS, Windows, or LOTUS. I consult, teach and tutor, and offer basic help to anyone who has any type of computer. I have helped media buyers, florists, homemakers, copywriters, advertizing agents, farmers, etc. with their home and business computers. NON-COMPUTER: I have been a pastor (youth director) at Parkview Bible Fellowship for 4 years. I spend a lot of time helping junior and senior high youth. I teach Bible classes and plan activities with the youth. It's fun but it's also rewarding as I help the kids "grow up". MARRIED: Yes. 10 years. (KIDS: No -- PETS: Yes). /**********************************************************************/ What is in this issue of AEO-PJ and new in the Atari market By: Albert Dayes /**********************************************************************/ //// Special Thanks This issue we have a special treat from Atari France and BrainStorm. They will be providing a series of articles on programming the FALCON030's digital signal processor (DSP). Special thanks to Loic Duval of Atari France for initiating and putting this deal together! We also have some special guests and new columnists in this is as well. We would like to thank Kris Gasteiger, Damien M. Jones, Charles Smeton, and Ron Whittam for their contributions to this issue. And of course all our regular writers and columnists deserve credit as well. We regret that Eric Goodman (our GFA BASIC columnist) was not able to complete his article due to some hardware problems. Look for it in the next issue of AEO-PJ. Be sure to send everyone some feedback too! //// Ditch Digging Also this issue will debut a new column called "In the Trenches." The inspiration for this column is from Skin Diver magazine. In Skin Diver magazine they had a diver column that spoke about "stupid" things people did and what they learned from it. One tells of a scuba diver who went into a cave without a light and got lost. Another tells of diving under the ice without a rope to guide his way back. Not all of the stories are this bad but one gets the general idea. This column will not deal specifically with the "stupid" mistakes as such, but with the entire process of problem solving. Solving programming related problems is always a learning experience - and sharing programming experiences is what this is all about. The goal is to have a different programmer/developer write this column for every issue. //// User View? In the last issue some thought that the user view was to discuss User Interfaces (UI). It was not designed to discuss User Interfaces in general or specifically. This entire column is designated for USERS ONLY. Basically it is designed for users to help remind programmers/ developers what they like or do not like in the software they use. Actually it does not have to be software specific it can be on anything computing related. The goal is to have a different person write a column for each issue. //// Library and Periodicals The PERIODICALS section is designed for anyone who wants to write a book, magazine or other programming related periodical review. The LIBRARY is designed for anyone who wants to write a review/report of any new programming tool or programming language library. This can include CLIs, programming editors, c/basic/fortran/pascal libraries, new compilers, new languages, new updated development tools, etc, etc. //// New Products Also there is some interesting new products for Atari Programmers. On the documentation side, there is the new Atari Compendium by SDS. This book is the new Programmers' Reference Guide for Atari computers. It will also be included with Atari's own developer documentation as well. It was reviewed by several at Atari so it should be highly accurate. It covers GEM GUI guidelines, Cookie Jar, GEM/TOS (AES, VDI, XBIOS, GEMDOS, BIOS... and what TOS version supports them), Memory Map (system boot variables; 680x0 exception vectors; auto-vector interrupts; trap, 68881, 68851 exception vectors; MFP, SCC, System vectors; System variables; Processor Save area; System Ram; MMU; Video; DMA, ASCI, SCSI, floppy; PSG; DMA sound; BLiTTER; Keyboard; Midi; etc.), Speedo Fonts, XCONTROL, FALCON030 Digital Signal Processor (DSP)/DMA, Mint/Multi-TOS, error codes, File Formats (GEM, IMG, FNT, RSC), 680x0 cpu, 68881 floating point co-processor, Drag & Drop protocol and more. See the review in this issue for more details. SDS Publishing 996 Redondo Ave #404 Long Beach, CA 90804 USA GE: S.SANDERS2 IN: S.SANDERS2@genie.geis.com Atari Compendium ISBN: 0-9638331-0-3 On the software side is Gribnif's Geneva software. This is a multi-tasking program manager with no limits on desk accessories (which can be loaded or removed dynamically). It allows up to 256 windows open at the same time compared to seven. This multi-tasking is similar to Apple's multi-finder or Microsoft's Windows software. All tasks get equal amount of time, etc. The amount of memory to run Geneva is not that large and works on all Atari machines. Programmers will enjoy the last 50 pages of the manual which is dedicated to programming Geneva. In addition upgrades are planned to make it work with Multi-TOS/MiNT and other multi-tasking kernels. Gribnif Software PO BOX 779 Northampton, MA 01061 USA (413) 247-5620 (voice) (413) 247-5622 (fax) GE: GRIBNIF CIS: 75300,1131 In: 75300,1131@compuserve.com GENEVA v1.x /**********************************************************************/ A message from the IAAD /**********************************************************************/ =-=-=-=-=-=-=-=-=-=-=-=-= Developers, Please Note! =-=-=-=-=-=-=-=-=-=-=-=-= The Independent Association of Atari Developers (IAAD) provides peer support to commercial Atari developers. The IAAD can help you find a shrinkwrap machine, weigh the benefits of different kinds of packaging, reach potential customers, tackle programming dilemmas, locate distributors for your products - in short, our members offer each other information on virtually every aspect of commercial software development and marketing. Membership is open to registered Atari developers who have a commercial product currently shipping or about to launch. To apply, please send a note to PERMIT$ on GEnie. /**********************************************************************/ 68K Column - Some Assembly Required By: Damien M. Jones /**********************************************************************/ An Introduction to 68000 Assembly Language Programming on the ST/TT/Falcon -- Part 1: But I don't WANT to learn assembly! -- Sure you do. 68000 programming isn't like assembly programming for a lot of other chips. You may have heard horror stories about programming in assembly for PCs (or you may have some of your own); I can tell you they're all true. But every Atarian knows how messed up PCs are, right? (smile) Atari made an incredibly good move when they chose the 68000 as the CPU for the ST; unlike the 80x86 series, which by all indications was either designed by an idiot or someone who wanted to make programmers' lives miserable. The 680x0 series was designed intelligently from the start. I could go on for quite some time about the differences between 80x86 and 680x0 processors, but I won't. The practical upshot of all this is that writing for a 680x0 processor is SO much simpler than most other assembly languages, it can be learned very quickly. No horror stories. Just smooth coding. So who should learn assembly? Anyone who: * Wants to write fast subroutines to replace slow ones. * Wants to create very small programs (like AUTO programs). * Wants to do efficient interrupt programming. Of these, the most important is the first one - writing fast subroutines. When I started writing Sound Lab (my digital sample editor) all the sample processing routines were written in GFA BASIC, as was the rest of the program. When it took a couple of minutes to process 500K of data, I decided something had to be done. So I rewrote some of the processing routines in assembly, to see how much of a speed improvement I could get... and I was able to do that same 500K processing job in about two seconds. It wasn't until much later that the other two reasons became more important to me, but they are also valid reasons for using assembly rather than a high-level language. I'll be getting into them later in this series. Still with me? Good. In this article I'll go over some material you'll need to get started with assembly. First I recommend a good assembler/debugger package; I personally use HiSoft's Devpac 3 (available here in the US from Oregon Research Associates). I will try to avoid too much Devpac-specific material here, though. I will assume throughout this series that you already know a high-level language, preferably C or a structured BASIC. I will not be explaining programming in general; I'll be covering assembly programming specifically, and how it differs from high-level language programming. Assembly is NOT a good first language, as it's too easy to get into bad programming habits (like unstructured code). Now, on with the introduction! REGISTERS Inside the 68000 are a number of "registers". These are nothing more than memory locations inside the 68000; because they're inside the CPU, they can be accessed MUCH faster than locations in RAM can. Almost every assembly language instruction will refer to at least one register, so knowing how to use registers is absolutely vital to writing assembly programs. There are sixteen general-purpose registers inside the 68000, divided into two general categories, "address registers" and "data registers". There are eight of each, numbered 0 through 7; registers are named by specifying "a" or "d" and following it with a number, like this: "a0". All of these registers are 32-bit, which means they can contain a number from -2,147,483,648 to 2,147,483,647. More on this in a bit. Address registers are used mainly for memory addresses, and there are some special ways of using them that make them most useful when used in that capacity. Data registers are used for just about everything else, and include special data processing capabilities. Both kinds of registers allow you to do simple math with them (adding and subtracting) so for many things, the decision on whether to use a data or address register is up to you. The large number of registers makes it very convenient to do complicated data manipulations. There are some other registers in the 68000. One of them is the program counter (pc) which tells the CPU where the next instruction is. Another is the stack pointer - although this is really a7. That might be hard to get used to for a while--address register 7 is used by the 68000 as the stack pointer. It's nice, though, because you can do anything with the stack pointer that you can do with any of the other address registers. Most assemblers will allow you to use either "a7" or "sp" to refer to the stack pointer. There are more registers, but they are not important right now. As mentioned above, each register is 32 bits in size, but often you will not want or need to use the entire 32-bit size. Fortunately, you can access (and manipulate) the low 8 or 16 bits of data registers without affecting the rest, and you can also do this with the low 16 bits of address registers as well. Perhaps an example will make this clearer. Let's say you put $12345678 (that's a hexadecimal number) into d0. The entire d0 register can be referred to as d0.l ("l" for Long), so d0.l would be $12345678. d0.w ("w" for Word), which refers to the lower 16 bits of d0, is just $5678. d0.b ("b" for Byte) is just the low 8 bits of d0, so it is just $78. Remember, these are just referring to different parts of the same register. Address registers work similarly, except that you cannot use "b" for address registers. Here's where it gets a bit confusing. The size extensions (.l, .w, and .b) do not normally appear on the registers themselves. They appear on the instructions. I'll explain, as it's time now to talk about the instructions. //// Instructions Most instructions are a three- or four-letter "mnemonic". That just means they're a short bunch of letters that replace a more complete word. For example, "sub" is the instruction for "subtract". In an assembly language program, each instruction is listed on a separate line. At the very beginning of a line there might be a "label"; this is just a name for where that line's instruction is in memory. Usually the label is followed by some space, and then the instruction mnemonic; some more space, and the "source" data for the instruction, a comma, and the "destination". (Some instructions do not need a source or a destination.) More space follows this, and then an optional comment provided by the programmer explains what the instruction does. Here's an example: loop move.l d0,d1 ; Copy d0 into d1. "loop" is the label for this instruction - you'd use this sort of name to indicate the beginning of some sort of loop. Labels are NOT required on every instruction, and you shouldn't put them there unless you need them. Some assemblers require you to put a colon (:) after a label, but many do not. "move.l" is the instruction. "move" is the mnemonic, which in this case means just that - move. It moves data around without changing it, and is probably the most often-used instruction. The ".l" size extension just specifies how much data is to be moved - in this case, "long" data, or 32 bits, the full size of the registers. For several instructions, the size is implied by the instruction itself, so it is often left out. Where a choice of sizes is offered, I will always explicitly show the size, rather than let the assembler provide the default; this makes for clearer code! "d0" is the source of the data. Since the size of the move is .l, the entire contents of d0 (d0.l) will be used. Similarly, "d1" is the destination, and because .l was specified, the entire contents of d1 (d1.l) will be overwritten with new data. The comment, "; Copy d0 into d1.", doesn't seem too helpful. But this statement was taken out of context, so it's hard to decipher meaning from it. Each assembly instruction does just one thing, so it's hard to determine what one instruction, by itself, might be doing. This is why comments are so important - they help the programmer piece together the whole from the parts. There aren't really that many instructions for the 68000; what makes it powerful is that most of those instructions can be used with most of the registers, instead of being limited in arcane and often arbitrary ways. I'll go over most of the important instructions next time, along with addressing modes. SUMMARY This time, I covered the following basic concepts: * Why assembly is useful. * What registers are. * What instructions look like. Next time I'll cover more material, and actually do a "Hello World!" program in assembly. /***********************************************************************/ C Programming Column By: Albert Dayes /***********************************************************************/ In the programming language C, one has a basic building block called a function. With a large group of different functions, one can build programs much faster than having to write the program from scratch each and every time. What is a function? One way to think of a function is like a dam holding back a river which then forms a lake. The function can have outputs which is similar to releasing water from the behind the dam. It can also have inputs which could be one or more rivers coming into the lake. A function can have inputs only, outputs only or inputs and outputs. Below is a simple comparison chart. ================================================================ Nature | C Programming ================================================================ A lake of water behind a dam | Function River(s) going into the lake | input(s) into the function Water released from the dam | output(s) from the function ================================================================ Within the functions themselves are additional building blocks called variables. A variable can be thought of as a cup or glass. Each variable is of a specific type such as int, float, char, etc. This can be thought as a special cup or glass. For example a wine glass, a tea cup, and a coffee mug. ================================================================ Drink Containers | Variable Type ================================================================ wine glass | float (floating point) tea cup | int (integer) coffee mug | char (character) ================================================================ Here is a short example... #include /* AEO-PJ - C program #2 */ <--- a comment statement which is ignored by the C compiler. main() { int tea_cups; <---- declaring a variable : note it's a meaningful variable name tea_cups = 23; <---- assigning a value to the variable printf( "%d", cups ); <--- displaying the contents of the variable to the screen. To do this we call the function printf. The function printf displays formatted output to the screen. In this case it displays a single integer. } /* main() */ After one has written the preceding in a text editor the compiler is run. What does the compiler do? It parses the source file (the code - which is the ASCII file we just saved) and converts it to tokens. Finally it is converted to object code. Then the linker resolves all unresolved references, links in the correct libraries and then the executable program is created. If this does not make sense, we will think of this in a different manner. Suppose that someone writes you a check and then you take the check to the bank to cash or deposit it. You can think of your check as the ASCII source file. The first thing the bank teller does is make sure all of the information on the check is valid. Does the printed amount of the check equal the amount written on the check? +-------------------------------------------------+ | | | $95.00 | | | | Pay to: AEO-Programmers' Journal | | | | Ninety five dollars and xx/100 cents | | | | virtual C++ signature | +-------------------------------------------------+ Yes it does in this case. The bank teller checks for a valid signature on the front and then turns the check over. Oops, you forget to endorse the back of the check. This error is similar to the syntax error that a C compiler gives you when a mistake is found. In the source code above the syntax error would be... printf( "%d", cups ); <--- variable cups is not declared/defined This is true since the variable cups should really be the variable tea_cups. printf( "%d", tea_cups ); So after editing the file, fixing the error, and saving the file its time to recompile the program. This would also be similar to what happens in the bank after you endorse the check and hand it back to the bank teller. Now it is time to resolve unresolved references. Since you want your check to be cashed the teller checks to make sure that there is money in the account. This is just like the linker which searches the libraries looking for references that are not defined in your program. After the bank teller discovers that there is enough money in the account he/she gives you the cash. When the linker is done the executable program will be given to you to run. This is also known as the development cycle (which is as follows EDIT->COMPILE->LINK->RUN ) which repeats itself over and over again. So the final program as it stands... #include main() { int tea_cups; tea_cups = 23; printf( "%d", tea_cups ); } /* main() */ Now to solve other problems between ANSI C and K&R C. We need to define a constant that inform the C compiler to use or not use function prototypes. And how do we do this? We just define it of course #define AEOPJ_ANSI 1 What we just did was the define the constant AEOPJ_ANSI and set its value equal to one. Anything that begins with # is handled very carefully by the C compiler. For example... #include This tells the compiler to include (read the contents of) the file stdio.h into the program. The file stdio means standard input/output in which are defined functions and constants dealing with standard input/output. The #define AEOPJ_ANSI 0 is going to be used as an on/off switch to the C compiler. If the switch is a 1 (ON), ANSI function prototypes will be used. When the switch is a 0 (OFF), K&R style functions will be used. This will allow conditional compiling of our program. Basically it will only compile areas of the source code that are in the "ON" state. There are also #if and #else and #endif which make creating control blocks very simple. #include #define AEOPJ_ANSI 0 #if AEOPJ_ANSI > 0 main(void) #else main() #endif { int tea_cups; tea_cups = 23; printf( "%d", tea_cups ); #if AEOPJ_ANSI > 0 return(0); #endif } /* main() */ This way one can use one source file for both K&R and ANSI C compilers. With this switch at the top of the file one can control many things within the file very easily. This can be used for error control, using different commands dependent on TOS versions, etc. For the C compiler it examines each expression as and if it's TRUE than that block becomes an "ON" block and is compiled. If the expression is FALSE then the C compiler ignores that block of code. #if AEOPJ_ANSI > 0 < do all these commands/instructions > #else < do these alternate commands/instructions > #endif For all of the K&R C compilers... Mark Williams C Heat & Serve C SOBOZON C Megamax C Laser C Hippo C Aztec C #define AEOPJ_ANSI 0 For all of the ANSI C compilers... GNU C Prospero C Pure C Turbo C Lattice C #define AEOPJ_ANSI 1 If one does move source code between different computer platforms one will often find similar type of conditionals in the source code. Such as the following... #ifdef UNIX #endif #ifdef ATARI #endif #ifdef MSDOS #endif #ifdef CRAY #endif The #ifdef is similar to the #if except that the condition is true only if the constant has been defined. So if one created the following definition at the top of the C source file... #define ATARI 1 The C compiler would review each expression below with the following results.... #ifdef UNIX <--- false since UNIX has not been defined #endif #ifdef ATARI <--- true since Atari is defined as 1 < do all these Atari specific commands > #endif #ifdef MSDOS <--- false since MSDOS has not been defined #endif #ifdef CRAY <--- false since CRAY has not been defined #endif This is all for now but next time we will do more with conditional statements in your program (not just for the C compiler), creating your own functions and more on variables. /***********************************************************************/ Advanced Computing By: Carl Barron /************************************************************************/ As promised I am presenting an edited Compuserve (CIS) capture of files to download to a Flash (1.x or II.x) do file generator. The generator will download all the selected files with no human intervention (most of the time). This will speed up your CIS 9600 baud downloads via Flash. The source code includes the standard headers we will use, declares some constants, including the ASCII equivalent of your prompt code for CIS. I then declare some regular expressions by name to make the code more readable. We are looking for specific lines: A) The name of the forum in lower case, followed by a space, tab or newline. B) [number,number] spaces/tabs Lib: number junk. This line will tell us at the third number in which the file is located. C) Starting with a sequence of anything but newlines or slashes, followed by a slash. This is the filename as stored on CIS and is normally in upper case. Upon finding one of the above line types (other lines are ignored, as are errors, by this code), we return what type of line we found and what we found in one of the pointer arguments. Note that YY_DECL is undefined and then defined to be the function heading that we desire. This is a "goodie" of flex, that I believe is not in the parent program lex. Our main function opens the FILE *'s yyin, yyout. If either of these fails we quit with a message, since we do not want to use either of the defaults stdin or stdout. We then go into a loop until yylex returns 0 indicating end of file. In this loop is the switch which is the heart of our do file generator. This switch determines what to do given the return value of our yylex function. There are three cases to consider. If it is a forum line we check to see if it is different from the last line used. If it is different we issue commands to CIS to go to that forum, and reset the old lib to -1 so that the next LIB line will create a set of CIS commands to go to the library. If is a LIB line, to a different library, we create the commands to goto the new library. Finally if it is a FNAME line we issue the commands to download the file from the library. Note again that is not as complicated as it sounds, all the gory details of text analysis are hidden in the flex generated code. After I introduce YACC (Berkeley PD yacc in particular), I will revisit this problem to solve it again. It will use a simpler flex file and a yacc file to do the same thing, a good way to get to see what this really is doing as the yacc version is programmed in a more intuitive manner. /* code for cisdls.l example */ %{ #include #include #undef YY_DECL #define YY_DECL int yylex(int *lib,char **text) #define FORUM 1 #define LIB 2 #define FNAME 3 #define PROMPT '\007' /* MY prompt char. change accordingly.*/ %} forum [a-z]+ num [0-9]+ lib [ \t]+"Lib:"[ \t]* fname [^\n\\]+ %x skip get_number %% ^{forum}/[ \t\n] {*text=strdup(yytext);BEGIN(skip); return FORUM;} ^{fname}/\/ {*text=strdup(yytext);BEGIN(skip); return FNAME;} ^\[{num},{num}\]{lib}/[0-9] BEGIN(get_number); \n /**/ . BEGIN(skip); {num} {*lib=atoi(yytext);BEGIN(skip); return LIB;} .*\n BEGIN(INITIAL); %% static char *forum,*fname; static int lib; void main(int ac,char *av[]) { char *text; int new_lib,c; if((yyin=fopen(av[1],"r"))==NULL) { fprintf(stderr,"Can't open %s\n",av[1]); exit(1); } if((yyout=fopen(av[2],"w"))==NULL) { fprintf(stderr,"Can't create %s\n",av[2]); exit(1); } forum = strdup("?"); /* strdup copies string to */ /* malloced memory */ fname = strdup("?"); lib = -1; while(c=yylex(&new_lib,&text)) switch(c) { case FORUM: if(strcmp(forum,text)!=0) { free(forum); forum = text; lib = -1; fprintf(yyout, "g %s|\n>WA \"%c\"|\n",text,PROMPT); } else free(text); break; case LIB: if(lib!=new_lib) { lib = new_lib; fprintf(yyout, "LIB %d|\n>WA \"%c\"|\n",new_lib,PROMPT); } break; case FNAME: if(strcmp(fname,text)!=0) { free(fname);fname=text; fprintf(yyout, "DOW %s|\n>WA \"omputer:\"|\n%s|\n" ">WA \"%c\"|\n",text,text,PROMPT); } else free(text); } exit(0); } I linked the resulting lexyy.o file with this linker file for LC5: from c.o lexyy.o lib lc.lib to cisdls.ttp A second example is a lot shorter and is a gem based text unformatter. One that will not weld words together like 'thisis' unless they are so welded in the original text. This unformatter will take formatted ASCII text and remove all endlines except at the end of a paragraph. This process makes the importation of text into desktop publishers and word processors easy to handle than the normal ASCII formatted text. All we are doing is looking for a sequence of newlines ignoring the spaces and tabs in between them. If we find such a sequence of only one newline, we replace it with a blank, otherwise we replace it with a pair of newlines. This process removes all blank lines but one between paragraphs. The code is fairly simple but includes two functions I use with a lot of the gem code I write, namely a formatted alert function, and a get complete path name from a file selector. This code does contain a couple of lattice specific functions, but these should be fairly easy to rewrite if you do not have Lattice C, just knowing what they do. It uses standard C function vsprintf() which if you have non-ANSI C compiler you may not have. Fsel_exinput() is used but with Lattice this will work with all versions of TOS. Some other compiler systems may require TOS 1.4 or newer to prevent the computer from crashing! Here is my 'better' unformatter code : /* begin of gemunf.l */ %{ #include #include #include #include #define output(x) (fputc(x,yyout)) %} %% [ \t]*\n([ \t]*\n)+[ \t]* output('\n');output('\n'); [ \t]*\n[ \t]*. output(' '); . ECHO; %% #include void quit(void) /* easier quitting of gem prgs via exit */ { appl_exit(); } char *get_file(char *prompt); int alertf(int,char *,...); void main(void) { char *fname; appl_init(); atexit(quit); /* call appl_exit() just before any exit() call */ if(fname=get_file("formatted file")) { if((yyin=fopen(fname,"r"))==NULL) { alertf(1,"[3][Can't open |%s][ ok ]",fname); exit(EXIT_FAILURE); } if(fname=get_file("Unformatted file")) { if((yyout=fopen(fname,"w"))==NULL) { alertf(1, "[3][Can't create |%s][ ok ]",fname); exit(EXIT_FAILURE); } yylex(); } } exit(EXIT_SUCCESS); } /* formatted alert box ansi style */ int alertf(int n, char *fmt,...) { va_list args; char buf[BUFSIZ]; va_start(args,fmt); vsprintf(buf,fmt,args); va_end(args); return form_alert(1,buf); } /* get full path via fileselector */ char *get_file(char *prompt) { static char path[BUFSIZ] = "", result[BUFSIZ], name[14]; short button; char *p; if(path[0]=='\0') { getcwd(result,BUFSIZ); /* get current dir. */ strmfp(path,result,"*.*"); /* combine path, fname to complete*/ memset(result,0,BUFSIZ); /* clear result */ *name='\0'; } /* OK with LC5 else req. tos>=1.4 */ fsel_exinput(path,name,&button,prompt); if(button!=1 || *name=='\0') /* if cancel or no filename selected*/ return NULL; strcpy(result,path); /* copy path to result; */ p=strrchr(result,'\\'); /* fsel always has at least one \ in path. */ strcpy(p+1,name); /* append filenname to path */ return result; } /* end of gemunf.l */ I linked with the following LC5 linker file: from c.o lexyy.o lib lcg.lib lc.lib to gemunf.prg If you have ANY questions, problems or suggestions, do not forget to contact me. I think we can handle just about any C or tool related question. /***********************************************************************/ HARD CORE - Interview with Charles Smeton By: Albert Dayes /***********************************************************************/ AD: What is your current product for the Atari line of computers? CS: Our current product is STraight FAX! 2 for the Atari ST/STe/Mega ST/Mega STe/ TT030/Falcon030 computers. STraight FAX! 2 has a suggested list price of $109.95 (US). Owners of STraight FAX! 1.xx can upgrade to STraight FAX! 2 for $25.00 (US) or $20.00 (US) if STraight FAX! 1.xx was purchased since June 1, 1993. STraight FAX! 2 is a complete send/receive FAX application that will operate with standard Class 1, Class 2 or SendFAX Modems. We also have available a driver for the Navarone/Canon IX-12 series sheet feed and flat bed scanners that will allow full page scanning from inside of STraight FAX! with these cartridge interfaced scanners for $19.95 (US). AD: When did you decide to write FAX software for that Atari? CS: In early 1990, I purchased a generic model of the Zoom SendFAX Modem for my PC Clone. This FAX Modem is a plain 2400 baud data modem with 4800 baud SendFAX capabilities. This particular modem was an internal PC card model. Upon looking at the FAX Modem and software, I thought that it would be possible to write a program to send FAXes if an external version of this modem was ever released. A few months later, Zoom released external versions of this Send FAX Modem. I purchased one. Before I began a full scale development effort, I did what is known as a "Rapid Prototype" design effort. I needed to prove that I could take a monochrome graphic image and convert it to the CCITT Group 3 format. This required doing some research to obtain the necessary standards that document the data format. Once this step was proven, the next step was to prove that the FAX Modem could be commanded to send the FAX image. Again this required contacting companies to obtain the necessary documentation. Once these two steps had been completed, the next step was to layout the requirements for the program along with its user interface. AD: How long was the design phase before you actually started writing the code? CS: The design phase, including rapid prototype was about 2 months for the original Send FAX software that was released in October of 1990. Many areas of the rapid prototype were reused in the final design and implementation (coding). In April of 1992, STraight FAX! 1.00 was released. STraight FAX! added support for Class 2 FAX Modems to both send and receive FAX documents. Many other enhancements were also added to STraight FAX!, such as scheduling FAX events to occur up to a year in advance and enhanced viewing capabilities. Just as with the Send FAX software, a "Rapid Prototype" phase was necessary to prove that the Class 2 send and receive functions were possible on the ST architecture. However, most of the added features were an evolutionary growth of the original SendFAX software that were added over time based on new operating system features, hardware features, user suggested enhancements and analysis of the FAX software marketplace. Over the 11 months, STraight FAX! was enhanced to support a wider array of Class 2 FAX Modems, additional file support (GEM Metafiles), additional FAX Modem capabilities (Silent Answer and Caller ID), and additional printer drivers (Calligrapher, Speedo GDOS and That's Write 2). In the 6 months prior to its release, STraight FAX! 2 was developed. Again the primary emphasis was on increased support for a wider array of FAX Modems (Class 1), file support (First Word Plus, Word Writer ST & PCX import, PCX & Encapsulated PostScript export and CardFile 4 import into the Phone List) and support for the latest operating system and hardware enhancements (3D user interface, MultiTOS, Speedo GDOS and the Falcon030). STraight FAX! 2 went through extensive beta testing with beta testers in North America and Europe. Many enhancements were suggested by beta testers and users. AD: Any particular problems in the design phase that were a significant obstacle in your work that had to be overcome? CS: Most of the problems that we discovered were related to the fact that not all Class 2 FAX Modems were 100% identical in operation. While Class 1 is an EIA approved specification, Class 2 was not. The Class 2 FAX Modems in used today are based on the initial Class 2 specification that was not approved (due to politics from members of the committees that regulate the FAX Modem standards). This did not stop several companies, such as Rockwell, Sierra, Exar and ZyXEL from releasing FAX Modem chipsets and firmware. This required obtaining various FAX Modems to test and verify the software with. To maintain maximum compatibility, the software polls the FAX Modem for its manufacturer's identification and adjusts as necessary. Other variances between FAX Modems can be tested for with proper AT commands and can also be accounted for. Other problems that had to be overcome were the need for tools to verify the operation of the FAX Modem and FAX software. Normally, an RS-232 monitor device would be used. However, these devices are not inexpensive. The next best thing was to write our own monitoring software that used a Mega STe or TT030 (with multiple serial ports) to monitor in real-time the data that was sent to or received from the FAX Modem and save this data to a log file for a post mortem analysis. This device has proven to be a very useful tool in being able to diagnose differences between FAX Modems. On a smaller level, there were many operating system and hardware related problems to overcome, such as the need for patches to correct Hardware Flow control problems in various TOS versions. Working with Atari Developer support (primarily Mike Fulton), these problems were solved. AD: What programming language is STraight FAX written in? CS: STraight FAX! is written in C with some 680x0 assembly language. Megamax Laser C was used, as it had the best source level debugger at the time. While Laser C has not been updated in a while, the debugger will still operate on the Falcon030 with its 68030 CPU as long as the ST compatible graphic modes are used. Laser C's editor/shell is also not compatible with TOS 2.00 and above, so we use the gulam (UNIX-like) shell with many special script files to streamline operations. Most of the printer drivers and CPU intensive functions in STraight FAX! (image scaling, cleanup, rotate, flip, fax compression/decompression) are written in assembly language for optimum performance. Many of the tools from the Atari developer's package were utilized such as the ALN linker and RCS Resource Construction Set. AD: How long was total development cycle before the first commercial release of your product? CS: It took approximately 5 months from the initial concept to the release of the first SendFAX software in October of 1990. However, the size of the original program pales in comparison to the program today (the original SendFAX software was about 100K for the main program, STraight FAX! 1.00 was about 150K, STraight FAX! 1.07 was about 200K, STraight FAX! 2.00 is about 276K (this does not even take into consideration the additional utilities and printer drivers). AD: Can you so give some general ideas how your program works from a software point of view? Trade secrets are not required. (smile) This can also include general information on how a FAX, FAX modem, and FAX software work too. Hardware and Software overview would also be helpful. CS: In the Send Mode, STraight FAX! allows the user to select one or more files of various types that they wish to FAX. These files can be bitmapped graphics such as Image, Degas, PCX or FAX files genetrated from an application program with the special FAX printer drivers, object oriented GEM Metafile graphics, ASCII Text files, or Word Processing files such as First Word, First Word Plus or Word Writer ST. In addition, the user can choose to attach a Cover Page to the start of the transfer, the user can enter the necessary Cover Page information and specify a logo graphic to be placed at the top of the Cover Page. The user can then select from up to 100 destination FAX Numbers in the Phone List or enter a single FAX Number to send the FAX to. The FAX transfer can be sent immediately or it can be scheduled to occur at a later date and time of up to a year in advance. After the transfer has taken place, the Send Log will contain information about the transfer, including the status of the transfer. Prior to dialing the destination FAX all files are converted to FAX format as necessary. This requires decompressing bitmapped graphics into a raw bitmapped format and compressing them into FAX format, rendering GEM Metafiles into a FAX resolution bitmap and compressing it into FAX format, and rendering ASCII Text, Word Processing documents and the Cover Page using special internal FAX resolution fonts into a raw bitmap and compressing them into FAX format. In the Receive Mode, things are a bit simpler. The user activates the FAX Auto Receive Mode and waits for a FAX to arrive. The Receive Log will detail information about the received FAX. From the log, the user can choose to View, Print (Via GDOS), Rename, Export or Delete the received FAX. From the hardware point of view, the three different types of FAX Modems (Class 1, Class 2 and SendFAX) present different AT command interfaces to the FAX software. FAX operation is controlled with special commands which are an extension to the basic Hayes compatible AT command set. In addition to the special FAX commands for each type of FAX Modem, standard AT commands such as those that set S Registers (ATSnn=xxx), configure the modem speaker, result code format, dialing, etc. are used. Class 2 and SendFAX are similar in that the microprocessor/firmware in the FAX Modem handles all of the low level Group 3 FAX Protocol. This has the benefit of isolating the FAX software from the low level Group 3 FAX Proctcol, which lightens the processing requirements on the FAX software. The disadvantage, is that if a problem exists during a FAX connection that is not resolved by the firmware in the FAX Modem, there is little that the FAX software can do to recover from the problem. Many early firmware releases of Class 2 FAX Modems had problems connecting with specific models of FAX Machines. These problems were eventually corrected with newer firmware releases by the FAX Modem vendors. For this reason, we strongly encourage users to obtain the latest firmware releases for their FAX Modems. The initial Class 2 specification that the current Class 2 FAX Modems is based on defines 100's of commands, but not all FAX Modem vendors and chipset/firmware manufacturers support every defined command in Class 2. This creates the additional problem of having to send commands to the FAX Modem to ask it if it supports a specific Class 2 capability. If the capability is not implemented, then there is no way to provide it in Class 2. Class 1 defines a very simple set of AT commands, but requires the FAX software to implement the low level Group 3 FAX Protocol. This has the benefit in lowering the cost of the FAX Modem, as it does not require a microprocessor that is as powerful as Class 2 requires. However, most Class 1 FAX Modems are either from companies that do not support Class 2 (since it was not an official standard) and are also high speed data Modems (V.32 or V.32bis) or support both Class 1 and Class 2. Since the FAX Software is required to implement the low level Group 3 FAX Protocol, the Class 1 FAX software is much more complex than Class 2. The processing and timing requirements for Class 1 are also alot higher. For this reason, Class 1 is not recommended in a multitasking operating system unless the CPU is sufficiently fast or the main CPU has an intelligent I/O controller to handle RS-232 communications. However, since the control of the FAX Protocol is in the FAX software, problems can be resolved with updates to the FAX software. In addition, as new Group 3 FAX capabilities are defined by the CCITT, they can be added to the FAX software. AD: Any plans for a C API so one could hook into the Fax Server and send a FAX directly from their own programs? CS: Not at this time. Our FAX Manager CPX and TSR allow a user to specify where generated FAX files should be located. Using one of the special printer drivers that are included for Pagestream (1.8x & 2.x), Calamus (1.09x & S/SL), That's Write 2/3, Original GDOS, FSM/Font GDOS or Speedo GDOS applications, it is possible to FAX directly from an application with MultiTOS or Geneva. One of our goals at this time is to work with developers of other telecommunication software applications (terminal programs and BBSes) to develop ways for both programs to be running at one time on a multi-tasking operating system (such as MultiTOS or Gribnif's Geneva) to allow sharing of the FAX Modem for FAX and Data. AD: Any other enhancements you plan in the future for your product? CS: Full background transfer support is something we are working on. This is not an easy task to accomplish, as an 8MHz 68000 is just not fast enough to do this in real-time and MultiTOS's pre-emptive multitasking is not sufficient for real-time applications (MultiTOS will stop multitasking whenever the CPU is placed into Supervisor mode, this can happen at just about any time and if it does for more than 1 second, the FAX operation will be affected. Operations such as formatting a floppy and printing via GDOS are two that would cause this to occur). There are other difficulties, such as locking a serial port from use by other applications during a FAX transfer. One area we are researching at this time is Voice Mail. Several new and inexpensive Voice/FAX/Data Modems are appearing on the market now and allow such capabilities as Voice and FAX Mailboxes and FAX on Demand. We will also consider adding support to the STraight FAX! for newer FAX Classes as they are defined by the EIA and when FAX Modems are readily available that support these new standards. Class 2 was finally approved in late 1992, but in a much different form than the initial Class 2 specification. To avoid confusion, the official Class 2 is being called "Class 2.0". FAX Modems based on Class 2.0 should be appearing at some point in the near future. If someone is unsure as to exactly which Class(es) a FAX Modem supports, the command AT+FCLASS=? will return a list of the supported Classes, e.g., 0,1 = Class 0 (Data) and Class 1 (FAX) 0,2 = Class 0 (Data) and Class 2 (FAX) 0,1,2 = Class 0 (Data), Class 1 (FAX) and Class 2 (FAX) 0,2.0 = Class 0 (Data) and Class 2.0 (FAX) ERROR = Not a FAX Modem AD: Thank You. For more information: GEnie: C.S.SMETON CompuServe: 73047,2565 Internet: c.s.smeton@genie.geis.com or 73047.2565@compuserve.com [ Editor's Note STraight FAX! is marketed for NewSTar Technology Management by Toad Computers and is distributed in North America by Eastern Front Distributing Company and Pacific Software Supply. For more information contact Toad Computers or your Atari Dealer. Toad Computers 570F Ritchie Highway Severna Park, Maryland 21146 USA 410-544-6943 (Voice) 410-544-1329 (FAX) 410-544-6999 (BBS, 300-14400 baud, allow up to 60 seconds to connect)] /***********************************************************************/ DABBLING IN PASCAL By: Kris Gasteiger /***********************************************************************/ I am currently using OSS/ICD Personal Pascal, Ver 2.02. on a 2.5Mb 520ST with TOS 1.4, one double sided floppy drive, a ToadStor130 hard drive, SC1224 color monitor, 2400 baud modem, 24 pin printer, and a few other peripherals. All code examples I present will run on MY system, other TOS versions, may give problems, so be cautious. I'm going to assume that you, have at least read the manual, and installed Pascal, and that it knows the paths it needs to find its associated files. If you are in a bind about this, I can address this in a future article or privately by E-Mail on Compuserve. Someone once said "Steal from the best.", this I believe to be the secret of programming in Pascal, or any other language. There's no need to "reinvent the wheel" each time you have an idea you want to turn into code. I keep libraries of DOCUMENTED Pascal code so I can cut and paste it into my programs. Key word, DOCUMENTED. If you're a cut and paste programmer like me, you need to know what those snippets of code do MONTHS from the time you hide them away on your disk. I use the { } curly brackets everywhere in my code. Curly brackets denote a comment in Pascal, and comments are just about the only way you'll know what you were trying to do. Aside from my libraries of Procedures, Functions, and assorted Algorithms, I keep three "Program Skeletons" on my hard disk, one each for .TOS (non GEM), .PRG (GEM), and .ACC (Desk accessory) programs. This month, I'll present my TOS program skeleton, and an example. Why use TOS? GEM is so much nicer to work in, it gives you windows, dialogs, alerts, mouse stuff but TOS is just text. I use TOS. when I need a quick and dirty program to solve a simple problem OR, when I want to be able to run my program from the AUTO folder. Quick and Dirty (Q&D) programs are the kind you might dash off to solve simple math problems. Gas mileage calculations, checkbook balancing, printer set up... AUTO folder programs CANNOT use GEM, as GEM has not been initialized when they are run automatically by the operating system at boot up. My TOS program skeleton: ------------------------------------------------------------------------ Program ******* (Input, Output); Const {Declare constants.} Var {Declare Variables.} Function {Declare functions.} Procedure {Declare procedures.} {Main} Begin {Use all of the above to do useful work.} End. ------------------------------------------------------------------------- Notice there is not much there! I use the TOS skeleton mainly to remind me of the basic layout of a TOS program. There are not any $I includes, as there is nothing else needed. An example of a Q&D program: I am a home wine maker, and I sometimes need to calculate the amount of grape brandy to add to a wine in order to fortify it to a certain percentage of alcohol to make Sherry, or other fortified wines. There is a simple way to do this calculation on paper, using a "Pearson square". The method is as follows: 1) Draw a square on a piece of paper. 2) In the upper left corner, enter the alcohol content by volume of the brandy you intend to use (this is usually about 40 percent). Call this number "A". 3) In the lower left corner, enter the alcohol content by volume of the wine to be fortified. Call this number "B". 4) in the center of the square, enter the alcohol content desired in the finished wine. Call this number "C". 5) In the upper right corner, write the difference, C-B. Call this number "D". 6) In the lower right corner, write the difference, A-C. Call this number "E". D represents the number of parts of brandy required. E represents the number of parts of wine to be fortified. Simple right? Well, I tend to forget the formula, and my math skills are non-existent. So, I wrote a Q&D program to take the drudgery out of this simple calculation... Note: The above outlined method is an ALGORITHM. Computer programs are implementations of algorithms. (The text between the dashed lines is a complete Pascal program which I have compiled and run on my system.) ------------------------------------------------------------------------ Program Sherry( Input, Output ); { This program is intended to allow you to figure out the amount of fortifying spirits to be added to a given amount of wine, to achieve a given final proof. Written in OSS/ICD Personal Pascal. 1/14/92 By: Kris J. Gasteiger. Parts Copywrited by OSS/ICD. } { Because this program does not use procedures, all variables are global. } { Global variables are those accessible from anywhere in the program. } Var Pts_Sp_F, Pts_Wn_F, Fortifier_A, Wine_A, F_Wine_A, Parts_spirits, Parts_Wine: Short_Integer; { You should choose your variable names so they contain an explanation about what is going on, it takes more typing, but six months later, you'll still be able to figure out your program!. These variables are pretty well explained by the Writeln statements in the following code... } Begin Writeln; Writeln( ' Enter the % of alcohol by volume in the fortifying spirits:' ); Readln( Fortifier_A ); Writeln( ' Enter the % of alcohol by volume in the wine:' ); Readln( Wine_A ); Writeln( ' Enter the % of alcohol by volume desired in the finished Wine:' ); Readln( F_Wine_A ); { Take the inputs, and act on them. } Parts_Spirits := F_Wine_A - Wine_A; Parts_Wine := Fortifier_A - F_Wine_A; Writeln; Writeln( ' You should use ',Parts_Spirits,' parts spirits to ',Parts_Wine, 'parts wine.' ); Writeln; { Find the actual parts of brandy needed to fortify the amount of wine you have. } Writeln( ' Enter the number of parts of wine to be blended:' ); Readln( Pts_Wn_F ); { Make the answer whole numbers through use of the ROUND function. } Pts_Sp_F := Round((Parts_Spirits * Pts_Wn_F) / Parts_Wine); Writeln; {Display the numbers.} Writeln( ' You will need ',Pts_Sp_F,' parts spirits to make a sherry of ',F_Wine_A, '%.' ); Writeln; Writeln( ' Press to exit...' ); Readln; End. ---------------------------------------------------------------------------- Okay, all that was pretty simplistic (I hope), now, do I go on to show how functions and procedures work, so you can get a handle on Pascal as a second language? Or should I grind on into the intricacies of GEM programming? GEM is a lot of fun, but you do need a handle on Pascal first... so send me FEEDBACK PLEASE! /**********************************************************************/ Practical DSP By: BrainStorm /**********************************************************************/ Falcon030: Programming the 56001 Reprinted from "Passerelle nx2" published by Atari France. Translation and Adaptation: Albert Dayes One of the most outstanding features of the Falcon030 is its DSP 56001 installed as standard. Well used, this processor offers some impressive speed gains in various tasks like compression/ decompression, 3D calculations, video or audio effects. Taking full advantage of the 68030/56001 on the Falcon030 is often faster than a 486DX2/66. However two rules have to be followed: 1) Attempt to use both processors in parallel, dividing parts of the task between the 68030 and the 56001. 2) Write "true" DSP code in the 56001's native tongue. It is stupid to take a 68030 routine and convert it line by line into 56001 assembly because in this case you will not take advantage of the highly parallel architecture of the DSP. We will not explain DSP programming theory. For that just purchase the "DSP 56001 User's Guide" from Motorola. What we want to show with practical examples, are some subtleties of the Motorola DSP 56001. And to illustrate the correct method to utilitize/program the DSP to its greatest potential. Example 1: Copy a memory block ================== The following assembly source copies a block of 32 bytes into memory. ; source pointer move #INBuffer,r0 ; destination pointer move #OUTBuffer,r1 ; loop 32 times do #$20,_EndLoop ; read a word move X:(r0)+,a ; write a word move a,X:(r1)+ _EndLoop This program is fast but does not take advantage of the DSP. Now, we will try to change the destination register R1 to R4, as well as the type of RAM used (remember the DSP uses two RAMs: X and Y). [ Editor's Note: A basic block diagram of the Motorola 56001 DSP ---| | |------------| | | [A][B][C] | <----------------------------------| |------------| ======================================================================== |--------------------------| | program memory | | program controller | <------ contents of [A] | Address Generation Unit | |--------------------------| |--------------------------| | X memory | | Y memory | <------ contents of [B] | MAC (Multiply/Accumulate)| |--------------------------| |--------------------------| | | | input/output | <------ contents of [C] | | |--------------------------| ======================================================================= ] The previous routine can be rewritten like this: ; source move #INBuffer,r0 ; destination move #OUTBuffer,r4 ; read 1 word move X:(r0)+,a ; repeat 31 times rep #$1f ; write a word and read next one move X:(r0)+,a a,Y:(r4)+ ; write last word move a,Y:(r4)+ With this little optimization the speed has been increased by a factor of three! This optimization uses instructions in parallel that allows one to read AND write at the same time! NOTE: To be executed in parallel, two memory moves have to be done in different memories and use registers from two different banks. The DSP56001 uses two banks of registers: Bank number 1 includes: R0, R1, R2, R3 Bank number 2 includes: R4, R5, R6, R7 [ Editor's Note: These registers are located in Address Generation Unit ] For example: In one instruction, it is possible to read from RAM X and write to RAM Y. But you cannot read from RAM Y and write into RAM Y. In the same way, you can associate the same instruction registers R2 and R7, but not R1 and R3. Example 2: Invert a memory bloc ================== In this sample we will try to invert 32 DSP words, using the NEG operation. The easiest way to do that is in the example below: ; ptr source move #INBuffer,r0 ; ptr destination move #OUTBuffer,r1 ; 32 loops do #$20,_EndLoop ; read a word move X:(r0)+,a ; invert it neg a ; write the inverted word move a,Y:(r1)+ _EndLoop Here again, the algorithm choice is not the best one for the DSP. Each loop includes 1 read from memory, 1 arithmetic operation, and 1 write of the data. ON THE DSP, ALL THIS CAN BE DONE IN ONE INSTRUCTION!! Here is how to achieve this goal: ; ptr source move #INBuffer,r0 ; ptr destination move #OUTBuffer,r4 ; read a word move X:(r0)+,a ; invert it, and read the next one. neg a X:(r0)+,b ; repeat 16 times do #$10,_EndLoop ; invert current word(b), read next one(a), write previous one neg b X:(r0)+,a a,Y:(r4)+ ; invert current word (a), read next one (b), write previous one neg a X:(r0)+,b b,Y:(r4)+ _EndLoop This new routine does the job in one instruction instead of three. Because we are dealing with two words at the same time. While one is inverted, the previous one is written down and the next one is read from memory. As you can see, even with simple operations, the DSP can provide an incredible increase in speed. For the next step we will try to avoid the "MOVE" instruction as a memory move can (most of the time) be done in parallel with an arithmetic instruction. Example 3: Memory shift ============= On the DSP, instructions ASL and ASR shift the specified register of only one bit (68030 can shift multiple bits). However one can easily avoid this problem. One has to remember what a shift [left] is... it is just a multiplication by a power of 2. The following routine will shift a register 4 times: ; ptr source move #INBuffer,r0 ; ptr destination move #OUTBuffer,r1 ; loop 32 times do #$20,_EndLoop ; read 1 word move X:(r0)+,a ; shift 4 times to the right rep #4 asr a ; write the shifted word move a,Y:(r1)+ _EndLoop It takes 7 instructions, which is definitely quite a bit for a small DSP job. We can do much better using multiply instructions as detailed below. ; ptr source move #INBuffer,r0 ; ptr destination move #OUTBuffer,r1 ; multiplier move #$80000,y0 ; loop 32 times do #$20,_EndLoop ; read 1 word move X:(r0)+,x0 ; right shift of 4 bits mpy x0,y0,a ; write shifted word move a,Y:(r1)+ _EndLoop This routine only uses 3 instructions. This is much better! But one can do exactly the same job in ONE instruction in the same manner as example 2. ; source move #INBuffer,r0 ; destination move #OUTBuffer,r4 ; multiplier move #$80000,y0 ; read 1 word move X:(r0)+,x0 ; shift it and read the next one mpy x0,y0,b X:(r0)+,x0 ; repeat 31 times the next instruction rep #$1f ; shift the current word, read the next one, write the previous one mpy x0,y0,b X:(r0)+,x0 b,Y:(r4)+ ; write last word move b,Y:(r4)+ Isn't this easy? The art of DSP programming is based on the clever choice of the registers and the combination of memory accesses with arithmetic operations. The DSP can replace the 68030 for many calculations with a speed gain of over 10 times. And do not forget that on the Falcon, the DSP clock is twice the clock of the 68030! That is 32Mhz for the 56001 DSP versus 16mhz for the 68030 cpu. [ Editor's Note: The above article is Copyright 1993 Atari France and BrainStorm. Permission is denied for reproduction in any form other than this issue of AEO-PJ. References: DSP 56000/DSP 56001 Digital Signal Processor User's Manual Author/Publisher: Motorola USA: Motorola Literature Distribution PO Box 20912 Phoenix, Arizona 85036 EUROPE: Motorola Ltd.; European Literature Center; 88 Tanners Drive Blakelands, Milton Keynes MK14 5BP, England Atari Compendium ISBN: 0-9638331-0-3 DSP related sections: XBIOS Overview : 4.7 - 4.10 XBIOS Reference : 4.33 - 4.54 Memory Map : B.24 - B.26 XBIOS Opcodes : A.10 - A.11 ] /***********************************************************************/ THE LIBRARY By: Albert Dayes /***********************************************************************/ X-11R5 & GNU CD-ROM disc. There are many CD-ROM discs that include the X-Windows 11 Release 5 and the complete GNU distribution. There are probably two to five different sources who can provide CD-ROM distributions of the above including Walnut Creek. This overview is just to discuss the contents in general and not any vendor specific version of the X11R5 & GNU CD-ROM. These CD-ROM discs can be found for about 20 to 50 dollars on the current market. The first part is X-Windows 11 Release 5. X-windows is the base windowing environment used on many UNIX workstations. This is produced by the MIT (Massachusetts Institute of Technology) X Consortium. Some brief history follows... X Window System research began in the summer of 1984 at MIT as an informal joint undertaking between the Laboratory for Computer Science and Project Athena. Since that time, researchers and engineers at numerous other universities and companies have been involved in the design and implementation. The MIT X Consortium was formed in January of 1988 to further the development of the X Window System. It is part of the Laboratory for Computer Science at MIT, and has as its major goal the promotion of cooperation within the computer industry in the creation of standard software interfaces at all layers in the X Window System environment. MIT's role is to provide the vendor-neutral architectural and administrative leadership required to make this work. The Consortium is financially self-supporting, with membership open to any organization. Included is the source code, fonts(bitmap and outline), proof of concept code, documents, etc. The GNU distribution contains approximately 120 programs include GNU C/C++, Bash (Bourne shell work-a-like), Sed (stream editor), Grep, Emacs, etc. Many of these have been ported to the Atari platform. Gnu C/C++ is one of the most common and is the compiler currently used in OBJECT::ATARI Column in this very magazine. Most of the source code is set up for UNIX machines (ready to run makefiles, etc) but it can be ported to other platforms including the Atari. As someone once said it's useful to "steal from the best" when it comes to source code. And this is definitely true of this CD-ROM. One does not have to port the programs to the Atari to get the benefits of this CD. Just browsing the source code will reveal wonderful and unique treasures. By looking in the Perl directory one can find routines to handle regular expressions. Even if one is not taking the routine and using it as is; it can give one some good ideas on writing one's own routines. There is even a spell checker called ISPELL which includes a several dictionary files. The indent program allows one make their C/C++ source code to be indented or formatted to his/her specifications. Its default setting is for the standard that GNU uses in most if not all of its source code. This has some interesting code for parsing a text file as well. One can even find some ATARI directories on the CD. Some code written by Dale Schumacher, John Stanley and Eric Smith are some of the names I found in the source code. There is also a file called Jargon... and here are some samples... FEATURE n. 1. A surprising property of a program. Occasionally docu- mented. To call a property a feature sometimes means the author of the program did not consider the particular case, and the program makes an unexpected, although not strictly speaking an incorrect response. See BUG. "That's not a bug, that's a feature!" A bug can be changed to a feature by documenting it. 2. A well-known and beloved property; a facility. Sometimes features are planned, but are called crocks by others. An approximately correct spectrum: (These terms are all used to describe programs or portions thereof, except for the first two, which are included for completeness.) CRASH STOPPAGE BUG SCREW LOSS MISFEATURE CROCK KLUGE HACK WIN FEATURE PERFECTION (The last is never actually attained.) Anyone who written or used software can relate to this very easily. And another one.... HACKER [originally, someone who makes furniture with an axe] n. 1. A person who enjoys learning the details of programming systems and how to stretch their capabilities, as opposed to most users who prefer to learn only the minimum necessary. 2. One who programs enthusiastically, or who enjoys programming rather than just theorizing about programming. 3. A person capable of appreciating hack value (q.v.). 4. A person who is good at programming quickly. Not everything a hacker produces is a hack. 5. An expert at a particular program, or one who frequently does work using it or on it; example: "A SAIL hacker". (Definitions 1 to 5 are correlated, and people who fit them congregate.) 6. A malicious or inquisitive meddler who tries to discover information by poking around. Hence "password hacker", "network hacker". A word to the wise [for programmers and users] DO NOT keep any axes near your computer!!! (smile) In another directory is BSD (University of California, Berkeley developed most of the software) there are some useful UNIX tools. Like tail ( which lists N number of lines from the bottom of the file), head (which lists N number of lines from the top of the file). There some networking code, telnet, FTP protocol and many other tools all in C source code form. BSD has been releasing quite a bit of the source to the general public. The source released does not contain any AT&T copyrighted source code by the way. Most of the GNU software has a readme file so one can learn something about the software before even looking at the source code. For the amount of interesting software/source code one can find on CD-ROMs these days is just incredible. The price that I paid for this CD was only $20 at a CD-ROM tradeshow several months ago. CD-ROM source code is not just limited to C or C++ either. There are many other CDs with pascal, dBASE, Cobol, etc. And the prices are quite low considering the large quantity of source available. Where can one find such CD-ROMs? Computer Shopper Magazine and programming magazines like Dr. Dobbs Journal, Software Development, and C Users Journal generally have a list of a several companies that have such CDs. So look around and one will be surprised at what one can find on CD-ROM. /**********************************************************************/ PERIODICALS By: Damien M. Jones /**********************************************************************/ The Atari Compendium by SDS publishing If you're like most Atari programmers, you probably have half a dozen reference books you use while writing code. You might have a VDI reference, an AES reference, a GEMDOS/BIOS/XBIOS reference, and a few other books you look in for specific pieces of information. The Atari Compendium, from SDS Publishing (Scott Sanders) will effectively replace most of the Atari reference books you own. This gargantuan tome covers almost every aspect of the Atari's operating system - TOS. It totals over 860 pages. While that may not seem like a lot (smile) it is really more like perhaps 2000 pages. Some reference books fill up space with a lot of "fluff"; the Compendium has no such fluff, just pure, distilled information. Let me list the chapters included in this book: Introduction to Atari Programming GEMDOS BIOS XBIOS Hardware AES VDI Line-A The Desktop XCONTROL GEM User Interface Guidelines Several appendices are also included, such as an outstanding memory map, descriptions of native file formats, ASCII tables (and Speedo character code tables as well), and a description of the new Drag & Drop Protocol. What this book DOESN'T do is teach you Atari programming. While each chapter includes an "Overview" to explain some basic concepts, it will not teach you how to write programs. It is a REFERENCE book - a single place that will answer almost any question about the operating system you might have. For the most part, examples are given in C or assembly, whichever is more appropriate, but source code is presented only where it is necessary to understand the topic in discussion. You won't find explanations of how to write DSP code, either, but you WILL find information on how to get that code into the DSP and use it once it's written. That said, now let me dig a little deeper into the structure of the book. As I mentioned, each chapter contains an overview section. This starts out with very simple material, and then proceeds to more advanced topics. Some of the chapters, by their very nature, start out advanced and get even more so. Again, these are not tutorials; they merely explain aspects of TOS that may not be apparent to a non-Atari (or new Atari) programmer. The function references themselves are superb. Each function is listed, along with opcodes (as necessary), parameters, and more. The Compendium even lists how to tell whether the function is available - this may require checking a GEMDOS version, a TOS version, an AES version, checking for SpeedoGDOS, finding a specific cookie, or other things (all of which the overviews will explain how to do). Many functions have a "Caveats" section, which tells of known bugs with the function or possible problems with its use. There are quite a few functions which are documented, but not implemented in TOS (particularly in the VDI); they are included for completeness and are clearly marked as being practically unusable. The Hardware section is very useful. It explains how to work with the hardware in Atari computers, but only when there is no other way to do it. For example, the STe/TT DMA sound does not have any supporting calls in the XBIOS, so the Compendium explains how to work with DMA sound by programming the hardware directly. The memory map (one of the appendices) is more complete than any I have ever seen. It lists addresses for the 680x0 vectors, system variables, and addresses for TT and even Falcon hardware registers. It also tells you which machines those addresses are valid for. Of particular importance to new Atari programmers are the GEM User Interface Guidelines. These are some general principles to follow when designing application interfaces, and are very useful for those who are not too sure of how to make an interface that is friendly, consistent, and intuitive. And of course, no reference book is worth much without a good index... and the Compendium has a fine one. It also has an excellent table of contents, good page headers, and functions are arranged alphabetically by name within their chapters. If you have a function number, but not a name, you can look it up also as one of the appendices is a function listing by opcode, rather than by name. Scott seems to have thought of everything. So there it is. The Atari Compendium could easily have been named the Atari Bible, it is so complete. At the developer's conference held just before the Glendale show, Mike Fulton said he would be able to eliminate a great deal from Atari's developer documentation, now that the Compendium includes so much of what used to be in it. Scott Sanders spent time in Sunnyvale working with Atari staff to make sure the information is accurate and current. It shows. With a suggested list price of just $49.95, this book is an ESSENTIAL buy for Atari programmers of ALL levels. Get it. You won't regret it. SDS Publishing 996 Redondo Ave #404 Long Beach, CA 90804 USA GE: S.SANDERS2 IN: S.SANDERS2@genie.geis.com Atari Compendium ISBN: 0-9638331-0-3 [ Editor's NOTE: By sending in the registration card one will receive: a) Information on how to obtain errata and addendum sheets b) Information on upcoming SDS products c) Sample independent developer's newsletter ] /***********************************************************************/ OBJECT::ATARI By: Warwick Allison /***********************************************************************/ Part 3 : C++ And Your Atari ------------------------------------------------------------------------ ERRATUM: In the last column, I forgot to include one vital environment variable. You need GCCEXEC = /gnu/bin/gcc- (or whatever your path to your gcc-*.ttp files is). Note that the "gcc-" is part of the value. GCC uses this variable and appends each of the subprocess names (like "cpp", "cc1-plus", etc). ------------------------------------------------------------------------ C++ And Your Atari ------------------ 1. Why C++ on Atari? C++ is an excellent language choice for the Atari programmer. Firstly, the Atari computers, like most modern computers, use the C language as the primary systems programming language. This means that all of the operating system functions are designed to be called from C, and while other languages are usually capable of interfacing with the operating system, these other languages will always lag behind. For example, before most people had even SEEN an Atari Falcon030, the interface to its new operating system functions were available (in the "falcon.h" file). For other languages, it is necessary to wait for the next version, or to hand-craft your own assembler language interfaces to the operating system. Since C++ is the successor to C, and can call C in a totally seamless way, C++ is as good as C for interfacing with the operating system. Secondly, the GEM environment on which all Atari GEM applications run is inherently an Object Oriented environment. In fact, one of the basic types in the system is called OBJECT! It was this highly object oriented nature that prompted me to provide the GEM++ library that makes GEM programming in C++ easier than it is plain C. We will be looking at GEM++ in detail in a later column, for now we will look for objects in our Atari.... 2. Objects in the Atari environment The first task when writing a program in an Object Oriented language like C++ is to try to identify the *objects* in your design. For example, if you wanted to write a Space Invaders program in C++, you would quickly think of the following objects: - Player turret - Invaders - Mother ships - Barriers - Attack waves - Score - Lives You would also recognize that there are 6 or 7 different types of invader, and a couple of types of mother ship. Also, you would see that each attack wave contains a number of invaders. Given these observations, you could write a Space Invaders program by writing a PlayerTurret class of object, an Invader class of object (and 6 or 7 "derived classes" for each of the slightly different invaders), a MotherShip class (and 2 derived classes), a Barrier class, etc. Each of the classes of object you identify in your observations has a small number of behaviors. For example, a PlayerTurret can be created at the beginning of a level, can move left, move right, fire a bullet, or, sadly, explode. A Barrier can be created, can take a hit from above at a certain position, be hit from below at a position, or can be gobbled by advancing invaders. A Score can be created at the beginning of a game and can increase by a certain amount. The other object have there own behaviors, which the prospective Space Invaders author would think about. So, objects are easy to identify in games. But so too are they easily seen in GEM applications and any other program you might write. In a GEM application, we would expect to see objects like dialogue boxes, windows, alert boxes, and menu bars. Also, just as there are different types of invader, there are also different types of these GEM objects. Applications would be pretty boring if all of the dialogue boxes did the same thing! So if your application is a drawing program, you might make a special kind of window that you can draw in, and if you are writing a text editor, a kind of window in which you can print text would be useful. 3. A Simple Example The program below is a very simple, but complete example that requires nothing more than your GNU C++ or other C++ setup. The example treats the Atari VDI (Virtual Device Interface) as an object, and allows you to clear the screen and draw lines. // // Simple example program. // // Compile using: // // gcc example1.cc -lg++ -lgem // // When compiling, be sure to put the libraries in the right order. // In general, put any C++ libraries you use, then -lg++ (the // standard GNU C++ library), then any C libraries you use. // // Include the C AES and VDI libraries. // #include #include // We declare a class called "SimpleVDI". This class provides a // small number of drawing functions. // // Usually, a class would be declared like this in a header file, // usually // the file would be called "simplevdi.h". That header // file would then be included into any C++ files (.cc files) that // used SimpleVDI. // // The "VDI" is the Virtual Device Interface of the Atari that // programmers can use to do graphics without directly accessing // the computer's graphics // hardware, thus making their programs portable to graphics // cards, newer hardware, etc. // class SimpleVDI { public: // The "constructor" of the class. This member-function is // automatically called whenever a SimpleVDI is created (such // as a variable declaration). SimpleVDI(); // The "destructor" of the class. This member-function is // automatically called whenever a SimpleVDI is destroyed (such // as at the end of the "scope" of a variable). ~SimpleVDI(); // The member-function "Clear" wipes the SimpleVDI, making the // screen blank. void Clear(); // MaxX returns the maximum X co-ordinate that this SimpleVDI // allows. MaxY returns the maximum Y co-ordinate. // // Here we are using "in-line" member-functions - that is, we // give the code for the member-function right here. The // compiler will often include the code directly into the // program that calls these functions, rather than actually // calling a function, thus making access very fast. // int MaxX() { return work_out[0]; } int MaxY() { return work_out[1]; } // Line draws a line from (x1,y1) to (x2,y2). void Line(int x1, int y1, int x2, int y2); private: // The following members are private data - they are only // "visible" to the member-functions in this class. int handle; // The VDI handle. int work_out[64]; // Attributes found when the VDI is opened. }; // Now we define the member functions. Usually, these would be in // a separate file, usually called "simplevdi.cc". That file would // include the "simplevdi.h" file. // // Notice that member functions deal with a *particular* object. // For this reason, when one of the member functions is called, // it makes sense to refer to the data members of that object. // For example, in the constructor for SimpleVDI, we set "handle" // and "work_out", which are the two data members of every // SimpleVDI object. // The definition of the "constructor" for SimpleVDI. // SimpleVDI::SimpleVDI() { // Find the graphics handle that the aes is using. // int j; handle=graf_handle(&j,&j,&j,&j); // Open a virtual workstation on that handle, giving us a new // handle in "handle" and an array of attributes in "work_out". // int work_in[]={1,1,1,1,1,1,1,1,1,1,2}; v_opnvwk(work_in,&handle,work_out); } // The definition of the "destructor" for SimpleVDI. // SimpleVDI::~SimpleVDI() { // Close the virtual workstation which we opened when this // SimpleVDI was created. // v_clsvwk(handle); } // The definition of other member-functions... void SimpleVDI::Clear() { // Clear the virtual workstation, using the handle we were // given when the workstation was opened in the constructor. // v_clrwk(handle); } void SimpleVDI::Line(int x1, int y1, int x2, int y2) { // Create an array holding the co-ordinates. // int pxy[]={x1,y1,x2,y2}; // Pass the array of 2 points to v_pline. We use the handle // we were given when the workstation was opened in the // constructor above. // v_pline(handle,2,pxy); } // We define some simple functions (non-member functions). // This function finds the minimum of two integers. int minimum(int a, int b) { if (a>b) return b; return a; } // This function, which has the SAME NAME as the function above, // finds the minimum of two integers. As long as the parameters // to the function are different, we are permitted to have // functions with the same name. This is good, because it means // we don't have to invent so many names (eg. min_int, min_dble), // and don't have to use unsafe #define macros. // double minimum(double a, double b) { if (a>b) return b; return a; } // Now the main function. Just as in C, the main() function is // called when the program is run. // main() { // Declare a SimpleVDI variable. This is just like declaring // an integer variable, or any other type of variable. // We are calling our SimpleVDI simply "vdi". We could call // it "fred"! // SimpleVDI vdi; // Clear the SimpleVDI we know as "vdi". // vdi.Clear(); // Find the maximum X or maximum Y co-ordinate, whichever is // smallest. // int size=minimum(vdi.MaxX(),vdi.MaxY()); // Draw a pattern of lines on our SimpleVDI. // for (int i=0; i<=size; i+=3) { vdi.Line(0,i,size-i,0); } // At this point in the program, the variable "vdi" is going // "out of scope", and its destruction, ~SimpleVDI() will be // called automatically. // } -- _-_|\ warwick@cs.uq.oz.au / Times like these: / * <-- Computer Science Department, / Move your mop into the \_.-._/ University of Queensland, / circle and see twice a v Brisbane, Australia. / programming tool. /***********************************************************************/ In the Trenches By: Albert Dayes /***********************************************************************/ "Straight as an Arrow" There are two levels for programming one is the design level and the other is the code level. The design phase is like flying over a large area in a helicopter while mapping it for a new road. The code phase is the physical labor ("In the Trenches") to make the road... digging ditches, moving dirt, etc. Both are equally important but some of us like one phase more than the other. This article deals with some work "in the trenches" I was doing just recently. It involved using a PostScript Library for C. The library gives one full control over fonts including track and pair kerning. There are functions for fully justified text but just in general terms. It does not allow one to use AFM (Adobe Font Metric) information or multiple fonts. After a period of several months I finally created a library that would give me both (justified text and multiple fonts). After making some minor changes to the code I noticed that the justified text was not working quite right. After closer examination it was very noticeable on some columns and not on others. What could be wrong? The next three hours (10pm to 1am) involved stepping through the entire program line by line. And using the Pure C source level debugger to check calculations. It was discovered that the problem was in calculations of the size of the line. So the problem was not in string_wrap() function but in the justify_text() function itself. This was good since the problem was not a logic error which would mean a complete redesign of the string_wrap() function. The justify_text() function works as follows... |<----------- width of the column ---------------->| |<-- size of the string -->||<-- remaining room -->| The string needs to be expanded to make sure it fits exactly within the width of the column. For this to work each space has a small offset added to it. This offset is calculated as follows... space_offset = size_of_a_space + ( remaining_room / number_spaces ); This works perfectly for this calculation. But then came the actual output of the single line of text itself which failed. The output section works as follows... while not end of line { read characters if ( character = a space character ) { output the contents of the word buffer with track and/or pair kerning add the size of the word plus the space offset to the cursor position } else { add characters to the word buffer } } /* while */ output the last word with track and/or pair kerning While stepping through this part of the function with the debugger I noticed that the calculations were different. By the time the output was done it was up to +/- 10 points from where it should be. Then it finally dawned on me that it was a calculation error. So how does one fix this error? After some thought I remembered taking a class on Numerical Analysis. After finding the book I started reading through the section "round-off errors and computer arithmetic." There were several algorithms to fix/control these errors like (Secant, Fixed-Point, Bisection, Newton, etc). But all of the above would take some time to adapt to my particular problem. Then there was something more general about calculating errors. Absolute and relative error looked like something much easier to work with. Here are the simple equations for these errors. Absolute Error = | P - *P | Relative Error = | P - *P | / | P | Where P = correct value and *P = estimated value. The vertical bars indicate absolute value. Absolute value ensures the result is always positive. (i.e., | -7 | = 7 ) So I decided to use a modified version of Absolute Error to fix the error. The absolute value was dropped since the line could bigger or smaller than the column width (after the calculation for output had been completed). Basically the output function was run twice. The first time was just to perform the calculations. The second part involved the error calculations, fixing the error and finally outputting the text. After running through the function the first time with no output the size of the calculated string is known. This is stored in the variable approx_string (declared as a double). Then the approx_string is subtracted from the column_width (declared as double). The difference is the amount of error between the two. This could make the line either longer or shorter than the defined column width. One can see why the absolute value had to be dropped from the equation when it comes to fixing the error. For this to work the error must be subtracted from the calculated value so it will always be perfect. Some examples.... column width ............ = 276 points approximated string width = 282 points ====================================== "absolute" error ........ = -6 points If absolute value was allowed then | -6 | = 6 which would increase the error and not eliminate it. column width ............ = 276 points approximated string width = 253 points ====================================== absolute error .......... = 23 points Then this error is divided by the number of spaces and added to the space offset. So each calculation using the space offset variable will effectively handle the error caused by the calculation itself. A code fragment follows... /* Calculate approximate string error and then fix the calculation error */ error_margin = (column_width - approx_string); /* correct space offset */ if ( number_spaces > 0 ) space_offset += (error_margin/number_spaces); The result makes a perfect straight line down the right side of the column. It does not look half justified and half ragged right but complete... straight as an arrow. The error that is occurring is a linear type error and not an exponential type of error. Basically one can think of linear as a one to one relationship. One can press a single key on the keyboard (L for example) and only 1 character would appear. If it was exponential pressing a single key on the keyboard (E for example) and 1000 characters would appear. Not only would this be frustrating it would not be tolerable. This condition is considered un-stable while the opposite condition is stable. When conditions are stable they are much easier to correct. For example if one had 1000 characters per keypress it would be very hard to correct a 25 page document using a word processor. It would be impossible and could not be tolerated. Since the error rate is linear it can be corrected easily just as easily as one corrects mistakes in a word processor. Using the technique outlined above demonstrates how simple it can be. ========================================================================== GRAPH(s): ERROR GROWTH RATES [ TIME (X-axis) vs ERRORs (Y-axis) ] | E | E | E | E | E | E | E | E |E |E |--------------> X |--------------> X LINEAR EXPONENTIAL ========================================================================== References: Numerical Analysis, 4th Edition Authors: Richard Burden & Douglas Faires Publisher: PWS-KENT Publishing Company ISBN: 0-534-91585-X C_Graph Software Inc PO Box 5641 Austin, TX 78763 USA (512) 444-3336 (voice) c_ps.lib -- Ansi C library for creating PostScript from C applications c_psFontInfo -- Ansi C library for setting PostScript Text from C applications Learning PostScript - A Visual Approach Author: Ross Smith Publisher: PeachPit Press ISBN: 0-938151-12-6 PostScript Language Reference Manual, 2nd Edition Author: Adobe Systems Inc Publisher: Addison-Wesley Publishing Company, Inc ISBN: 0-201-18127-4 (also known as the red book) [ Editor's NOTE: A demo of the PostScript library can be found on Compuserve and GEnie. It includes C source code for the demo and technical specifications for the two libraries. ] /***********************************************************************/ Language Watch -- Current versions of developer tools /***********************************************************************/ DEV| version & date | product ========================================================================== A | 1.1 Jan 1993 | Pure C (with ASM/C source level debugger) (German) A | Sept 4, 1992 | Pure Pascal (German) (Turbo pascal 7.x compatible) A | 2.x | Interface, (resource file editor, with 3D icons) B | 3.00 | Devpac 3 (assembler) B | 5.52 | Lattice C B | 2.10 | HiSoft BASIC 2 (includes compiler) B | 2.03.02 | HiSoft C (C interpreter) B | 1.6 | HiSpeed Pascal (Turbo pascal compatible) B | 1.21 | FTL Modula-2 B | 1.24 | WERCS (resource file editor) C | 2.05 | Personal Pascal D | Aug 3, 1988 | Assempro (assembler) E | 2.1 1989 | Laser C E | 1.1 1989 | Laser DB (assembly & C source level debugger) F | 3.7 1991 | GFA BASIC (includes compiler) G | 1.14, 1989 | Prospero C G | 2.15, 1989 | Prospero Pascal for GEM G | 2.15, 1989 | Prospero Fortran for GEM G | 1.11, 1989 | Prospero Developer's Toolkit H | 3.6d Oct 1, 1988 | Aztec C H | 3.6e Dec 6, 1988 | Aztec SDB (C source level debugger) I | 3.0.9, 1988 | Mark Williams C I | 1.0, 1988 | CSD (C Source level Debugger) J | *** | GNU tools, compilers and assembler A = Gribnif Software/Applications Systems Heidelberg B = Oregon Research Associates and/or HiSoft C = ICD/OSS D = Abacus Software E = Megamax F = GFA G = Prospero H = Manx I = Mark Williams Company J = Free Software Foundation *** see Warwick's OBJECT::ATARI part 2 for specifics [ Editor's NOTE: Producers of development tools are strongly encouraged to send press releases and upgrade announcements to the Editor ] /**********************************************************************/ Bad Example By Albert Dayes /**********************************************************************/ NOTE: Pascal Source code is used this time. ----------------------------------------------------------------------- bad example ----------------------------------------------------------------------- program DRAWDIAGONAL( OUTPUT ); { Draws a diagonal line of integers.} const SIZE = 5; {number of integers printed} var COLUMN : INTEGER; {loop control variable} begin { DRAWDIAGONAL } { Print 5 Integers } For COLUMN := 1 to SIZE do WRITELN ( COLUMN : COLUMN ) end. { DRAWDIAGONAL } ------------------------------------------------------------------------ good example ------------------------------------------------------------------------ program DRAWDIAGONAL( OUTPUT ); { Draws a diagonal line of integers. } const SIZE = 5; { number of integers printed } var COLUMN : INTEGER; { loop control variable } begin { DRAWDIAGONAL } { Print 5 Integers } for COLUMN := 1 to SIZE do WRITELN( COLUMN : COLUMN ) end. { DRAWDIAGONAL } Looking at both programs one can easily see how much easier the good example is to read versus the bad example. Even though both programs do exactly the same thing the first is near impossible to read. Consider if one asked a friend to help write some routines for a program. If the routines were delivered in the form of the bad example I'm sure one would definitely protest. And demmand that the routines be rewritten in a much easier to read style or format. This is not only important for functions/procedures that others write for you but also for you as well. If one writes code to beat a deadline it is very important one go back soon after the deadline is completed to reformat the code. Going back six months later to fix the problem in the code and it looks like the source code in the bad example will not be very appealing. It is best to do it right the first time and then one will not have to go back and "beautify" the code later on. Being able to spot errors is another reason to use a good, readable format for one's source code. One does not have to use the style presented above in the good example but use a style that one finds most comfortable. Also be consistant in your style! If one mixes a "good" style and "bad" style it does not help when looking for problems later on. /************************************************************************/ ON THE NETWORKS /************************************************************************/ Some feedback on our first issue from GEnie and CIS... and other exciting topics. #: 89082 S11/Programming 23-Aug-93 23:34:11 Sb: #AEO Prg. Journal Fm: Shawn Laughlin 76547,1032 To: All I just finished reading Atari Explorer's Programmer's Journal (AEPJ01.ZIP in the news/reviews lib of ATARIARTS) and was very impressed with it. IMHO, it's right on target for the audience its trying to reach. I especially liked the article on interfaces as I am currently trying to design a good one for something I'm working on. I intend to incorporate the idea of the little help window that changes messages as the mouse passes over an icon. Mine is also an icon based interface and I believe this will make it much friendlier. I don't know about "talking dialog boxes " . There was a very helpful tidbit in the developers information section about keeping programs compatable with MultiTOS (i.e., stick to GEM I/O or Bios I/O but don't mix them). I'd like to see more articles on exactly what to watch out for when trying to keep a program portable to the different TOS's . I guess we all know to stay away from the taboo line_a, but I'd like to know more about the different screen resolutions of the Falcon and TT (e.g. do they interleave bit planes like the ST/STE? Are the palettes stored the same ? etc). Think maybe an assembly column could be worked in (for those of us that still like to hack ) ? Maybe Tony @ Moving pixels could do an article or two . All in all it is a well balanced and informative mag. I'll be following the series on lex, and OOP. I do have a question though, why is the mag over in ATARIARTS ? I suspect if it stays around (and it needs to), it will become a reference source for programmers. Perhaps it should be in the programming library? Good job Atari Explorer! Shawn P.S. Dump the ZIP format . Message 104 Sun Aug 29, 1993 MIKE-ALLEN [NM~SysOp] at 16:43 EDT Albert, I really enjoyed the first issue. I would like to see more assembly language stuff in AEO-PJ. I would also like to see information about the OS and the hardware such as that that used to be available from third parties, such as Abacus. I'd like to see some basic stuff (not BASIC, the language) like walking the rectangle list and using event_multi. For instance, I have heard that event_multi really slows down execution time. True? I suspect that many people would get more interested in programming for the ST/STe/TT/F030 if more information were available. I know people will say "buy the developers kit, it's not that expensive," but many folks don't want to invest in the DK until they get their feet wet. I'd sure like to see something on the format and contents of the DESKTOP/NEWDESK.INF files. Hardware address and contents would be nice. Cookie Jar rules and utilization. Using the DMA sound on STes/TTs/F030s. I know you have to respect Atari's NDA, but maybe Atari would allow you to publish some of this info. More assembly and C, less GFA BASIC. (that may just be me. I hate basic in any form ). Maybe comparative routines in all three? I really think that people will be looking to AEO-PJ for the type of info that used to be available from third parties when such parties existed. Now that resources for programmers/users have been reduced to almost exclusively Atari, I feel that Atari needs to be a little more forthcomming with that info. Maybe (I hope) AEO-PJ can fill that void. Mike Allen Message 109 Mon Aug 30, 1993 M.HILL13 [Mike] at 22:55 EDT Albert, I thought the issue was pretty good. I would like to see topics like: "Writing MultiTos/Geneva Compatible Programs" "Fast Sprites routines" "XBRA protocol" "Cookie Jar info" Mike Fulton at Atari had an article on writing Multi-Tos compatible programs in a developers newsletter awhile back. Maybe you guys could talk to Atari about getting reprint rights. I personally would like to see some sprite stuff. I have worked with the other issues and encountered some challenges getting info on those topics until I got the devleopers package. Articles on writing compatible software, XBRA protocol, and the Cookie Jar would be excellent info to get out to programmers just getting started. Mike P.S. Source code for articles with examples is great, but if if gets too lengthy I would recommend keeping it in a separate file. Message 23 Wed Sep 08, 1993 DMJ [dmj] at 22:48 EDT Albert: Personally, I would prefer the User View columns to be written by non- developers. As you stated, developers sometimes get out-of-touch with their userbase. The User View column is the perfect place to remind them who they're dealing with. Have you looked at the typical PC word processor these days? They're chock- full of features that nobody can figure out how to use. You end up with this huge (and I mean MEGAbytes) package sitting on your hard drive, with perhaps 200K of it being actually used. What's the point? It's pathetic, if you ask me... but then, I think that about most of the PC world in general. Anyway, please try to draft some non-technical people to write the User View. -dmj Category 15, Topic 5 Message 27 Thu Sep 09, 1993 TOWNS [John] at 15:09 EDT Albert.. I agree. The author of the Object::Atari column could handle both C++ and OOD type columns. I didn't mean to imply otherwise. As for User Views.. Sounds good to me. I think Developers would enjoy hearing from users about what they are looking for in products. I know that I would certainly listen to what they have to say. I would still suggest that you see if you can reprint those Atari User Interface Guidelines. They could really help steer some developers in the right direction. I look forward to the next issue. it's really great to have a journal for programmers again. The last time I remember having a suitable journal for programmers was the magazine ST Applications (anyone of you remember that magazine?) As for OOP.. I guess I am a fan! I better be.. my job is completely OOP stuff! -- John Category 15, Topic 5 Message 28 Thu Sep 09, 1993 R.WATSON15 [Wayne Watson] at 18:04 EDT I think everyone that writes GEM applications and interfaces should read the Pro GEM series (I believe that was the name of it). It is a very nice series. Maybe you could look into making it a regular series in AEO-PJ. I know it's been out awhile and is available for download and all but, having it in with the PJ would be a nice touch to the Interface section for beginners. Heck, even non-beginners could use it as I have seen some terrible interfaces. Just a thought. ------------ Category 15, Topic 5 Message 24 Thu Sep 09, 1993 R.WHITTAM [Ron - ABUG] at 00:53 EDT Travis, I am very impressed with your initial issue. A lot of good stuff, to say the least. Keep it coming! My most expensive compiler is SOZOBON C. I know it is not ANSI compliant, but I would like to see some tips on this one in the future as well as GNU. I tried GNU (a few years back) but couldn't get it off the ground--took too much space and memory. I don't have a specific question right now, or I would ask it. The general info on basic concepts in this issue is GREAT. However, being new to online, acronyms need to be explained. The letters IMO in the middle of a sentence is unclear. I think a good rule of the thumb (ROTT) would be to give the expanded expression the first time with the acronym in parenthesis, in my humble opinion (IMHO). OTOWA, (or the other way around). I am generally unindated with TLA's (three letter acronyms) at my job as a mainframe tech support using IBM, REI, DEC, and STC hardware. With IBM and Novel's competition in this area, the development of ETLA's (Extended three letter acronyms) have made learning simple acronyms a basic nightmare with ANSI, ASCII, EPCDIC, DFDSS, MVS/OS and a pleathoria (where's that spell checker??) of other similarly understandable letteric, like PCMCIA (which I have heard to really stand for: People Can't Memorize Computer Industry's Acronyms). All in all, (AIA) I think I have made my point. Thanks for listening. Ron Whittam Atari Boise Users Group R.WATSON15 [Wayne Watson] at 23:56 EDT GFA BASIC is used by quite a bit of people so the inclusion of examples for that language would be nice. Just because some people don't like it or use it doesn't mean it shouldn't be included. Also, Pascal is starting to pick up some. I am using HS Pascal. I know a lot of GFA BASIC, intermediate Pascal and some C and a small touch of assembly. Having examples in the different languages would really help out. There was a file placed in the libraries a month or two ago that gave the full hardware layout of the ST/STE/MSTE/TT. I wouldn't waste my money on the Dev. Kit. ------------ Category 15, Topic 20 Message 107 Mon Aug 30, 1993 R.WATSON15 [Wayne Watson] at 05:17 EDT I hope the AEO-PJ continues as it did in the first issue. I liked the the material in it and hope for some more. I have been programming in GFA for a long time. After dealing with problems in GFA in a large application that I have and after finding out that GFA has temporarily dropped support, I decided to expand my horizons a little. I got the Lattice C package and found that C was a hard language to move to from GFA. I learned a lot from people online here who were very helpful showing me how to do things. On a tip from a friend, I tried Pascal and find it a lot easier to move to from GFA. In Pascal, I see some things comman with GFA and some things comman with C. My big problem with C is having to deal with pointers and the like. Anyway, my point is that I hope you continue to provide help with people that are starting to expand their horizons in other languages (beginners). That is why I think that examples in as many languages as possible are important. It helps the beginner in other languages see the differences and can relate things a lot easier. I am not asking that the magazine be a teacher to beginners. I just hope that you do not leave us out. I would like to thank those involved for starting this as I feel it is an important part of the puzzle for people programming on the Atari. Resources like this are common on the other platforms and readily available. It's time we also have those resources. Hopefully Atari can pitch in now and then to help. #: 329775 S5/C Programming 22-Aug-93 06:56:33 Sb: #Substrings from string Fm: renwick preston 73117,3301 To: all If I read in a string composed of the characters shown below, how do I extract the "XX","YY" and "ZZ" into their own strings? . . AAAAA BBBBB CCCCC XXYYZZ . I know how to use strtok if the substrings are separated by spaces but I do not know how to start at a certain character and only copy a certain number of characters. I am trying to port over a program from Turbo Pascal and the only reason I am resorting to C is the limitation in TP of 255 chars in a string. The string I am reading in contains 369 chars. Thanks in advance, #: 329780 S5/C Programming 22-Aug-93 07:49:42 Sb: #329775-#Substrings from string Fm: Gary Blaine (TeamB) 70007,4650 To: renwick preston 73117,3301 (X) Ren, There are lots of ways to do it, depending on just what it is you are wanting to do. Here are some examples: #include #include int main(void) { char* str = "AAAAA BBBBB CCCCC XXYYZZ"; char* ptr_start; char* ptr_end; char x[3]; char y[3]; char z[3]; // use just strncpy() strncpy(x, str+20, 2); x[2] = '\0'; // use strchr(), strrchr() ptr_start = strchr(str, 'Y'); ptr_end = strrchr(ptr_start, 'Y'); strncpy(y, ptr_start, ptr_end-ptr_start+1); y[2] = '\0'; // use strpbrk() ptr_start = strpbrk(str, "Z"); strncpy(z, ptr_start, 2); z[2] = '\0'; printf("%s %s %s\n", x, y, z); return 0; } Category 14, Topic 34 Message 151 Tue Sep 21, 1993 ERIC.SMITH [Eric Smith] at 17:11 EDT Thunderbird: MultiTOS has 2 distinct parts: the MiNT multitasking kernel, and the multitasking AES. If you want to know if MiNT is present, check the cookie jar for the cookie 'MiNT'. If present, its value is the version of MiNT running (e.g. 0x0104 for MiNT 1.04). If you want to know if the AES supports multitasking, check the AES global array. The first word of that array is the AES version number, and the second is either -1 (if the AES supports unlimited multitasking, e.g. MultiTOS) or a positive number (the number of programs that can be loaded at once; 1 under ordinary TOS). Note that you should use the number of applications supported, and not the AES version number, to test for multitasking, since some AESes can run either in single or multi-tasking mode. Which one of the two tests above is appropriate depends upon what you're trying to do. If you want to use a MiNT/GEMDOS feature, test the MiNT cookie; for an AES feature, test the AES global array. Note that it is possible to run MiNT with a single tasking AES (e.g. if you just want the MiNT CD-ROM driver, but don't want the MultiTOS desktop). There are also third party multitasking products (like Mag!X or Geneva) which may not provide MiNT services but do provide AES level multitasking. MiNT does not task switch while the machine is in supervisor mode, so you can protect critical sections of your code that way. Obviously you should do this only when you really, REALLY have to, since users will be very peeved if your application is grabbing all the CPU time and they're trying to do something else! Gordon: The _FLK cookie indicates whether or not file locking is supported; it's always there under MiNT, but may also be there if a MetaDOS network driver is installed on ordinary TOS. M.ABDULKAREE,W.KILWINGER: I think I mentioned this in an earlier post, but just to make sure there's no confusion: (1) Check for the presence of a MiNT cookie if you need MiNT features, including GEMDOS level multitasking. (2) Check the number of AES processes supported (global[1]) if you need AES level multitasking; this will be -1 if the AES is multitasking. (3) The AES version number should *not* be used for either of these purposes, since (as Wilfred correctly pointed out) some AES versions can function in either single or multitasking mode. The AES version may be useful for determining features (like 3D gadgets) present in the system; an even better method of doing the latter, though, is to use the appl_getinfo() system call to determine whether or not various AES features are supported. See the developer's documentation, or the Atari Compendium book from SDS, for details on this call. #: 89354 S11/Programming 30-Aug-93 00:56:57 Sb: #89339-evnt_multi() Fm: Shawn Laughlin 76547,1032 To: Atari Explorer 70007,3615 (X) Albert- The following compilable code demonstrates the problem. The first time you press a key you will go to the function "foobar". While in that function, hit some keys. When the program returns to the evnt_multi loop, these unwanted keypresses will be processed. I don't want the keypresses that happen while the program is in "foobar()". Either mouse button to exit. #include #include /* include your favorite GEM headers */ int main() { int which,dummy[8]; int firstkey = TRUE, done = FALSE; appl_init(); printf("(evnt_multi): Press a key to go to foobar"); do{ which = evnt_multi(MU_KEYBD|MU_BUTTON,0x101,3,0,0,0,0,0,0,0,0,0,0,0, dummy,0,0,dummy,dummy,dummy,dummy,dummy,dummy); if(which & MU_KEYBD){ if(firstkey){ foobar(); firstkey = FALSE; } else printf(" keypress "); } if(which & MU_BUTTON) done = TRUE; /*exit with either mouse button*/ }while(!done); return 0; } foobar() { long i = 1000000; printf( " (foo): Press some keys "); while (i--); } #: 90333 S11/Programming 24-Sep-93 06:50:26 Sb: #89354-evnt_multi() Fm: guus ellenkamp 100111,3146 To: Shawn Laughlin 76547,1032 I had about the same problem and fixed it by calling evnt_multi with the flag of events I don't want + timer event with time value set to zero. Then I just have to wait until the only event that is returned is the timer event. Message 49 Fri Sep 10, 1993 PARADIGM [Mark O'Bryan] at 07:29 EDT Wayne, specifically which 32k limits are you referring to? And what are you trying to accomplish? For the most part, there are no 32k limits in HighSpeed Pascal! This is in spite of the fact that there are numerous references to them in both the manual and the on-line help. I know this can be surprising, as well as confusing. Here are the true limits in HighSpeed Pascal, v1.5 and beyond: - global data = 16 meg (per unit, or program) - stack space = 16 meg - heap space = 16 meg - array size = 16 meg (per global array, 32k for a local array) - program size = 16 meg (code) - unit size = 16 meg (with $F+; 32-50k each without Far on) - record size = 32 kB (each) - procedure size = 32 kB (approx. 60-70 pages of code) - local proc vars = 32 kB (can include pointers to megabytes on the heap) - symbol table = 32 kB (per unit) Obviously, you can't have all of these at once, and of course you're limited to the total RAM in your machine (minus system overhead). I don't consider any of these limits to be significant, although the 32k bound im- posed on local variables in procedures by stack-relative addressing with 16-bit offsets may occasionally require some extra coding. ((O)) /=\ Mark O'Bryan, Paradigm Software Products [Sep09/92 at 9:57p] /===\ (makers of Omni-Banker ST, the universal MIDI librarian) Message 92 Wed Sep 08, 1993 TOWNS [John] at 15:35 EDT Use this trick to make sure that headers don't get included more than once: // top of header file #ifndef __HEADER__ #define __HEADER__ // Body of header goes here #endif Make sure the symbol you define (__HEADER__) is something unique. I usually use the name of the file. Another tip: When including header files, do the following: #ifndef __HEADER__ #include #endif This will cause the C preprocessor to only include the header file if it is included. This should save some time on compiles because this will prevent the C preprocessor from even opening the header file if it is already included. Big time saver on most systems. If you already know about this, feel free to ignore me ;-) -- John Message 44 Thu Oct 07, 1993 C.ROUNTREE2 [RoadKill] at 23:26 EDT DMJ: The fact of the matter is that on the PC I don't have to worry about shifting or masking sprites. Every pixel is a byte and I can write one line of C code to grab a pixel. On the ST it is almost impossible to directly access the graphics from C(the CLUT storage format needs bitwise operations). And the Put_pixel/Get_pixel assem routines that I wrote are nearly 3 (screen) pages long, fully optimised! (err, mostly optimised. I have one multiplication I could get rid of with a screen line address lookup table) Yes, the PC has a miriad of problems, but the graphics format isn't one of them. I would never want to program applications on the PC, nor do I want to do games on the ST. *sigh* Now if the PC was more like the Atari. . . . Dmj, suggesting that he write his own routines for sprites is assuming a lot. It takes a lot of know how to do those routs. Everytime I've sat down to flow chart the code for one, I get the shakes and put the whole idea away. Damien (DMJ) discusses sprites... Yeah, you do have to know a lot to write a sprite routine on the ST. Lessee, were those 16x16 sprites? 16 colors (4 bitplanes) plus one mask plane? Here's a routine to do them, rated at around 420 sprites per second (that's only 7 per VBL, but I didn't spend a lot of time on this routine optimizing it): -- Code begins -- * 16x16 Sprite Blitter Bundle * by dmj, v1.0, October 8, 1993. * This routine trashes d0-d2 and a0-a2; as such, it should be * callable as a C function. Garbage will be returned in d0. * On the stack: * 16(a7).w Y coordinate to put sprite / screen height. * 14(a7).w X coordinate to put sprite. * 10(a7).l Pointer to sprite data (function 0) or screen * address (function 1) * 6(a7).l Pointer to vertical lookup table. * 4(a7).w Function number (0=blit, 1=create vertical * table). * Sprite data is five bitplanes. The last four are sprite image, * the first is the sprite mask. Bits SET in the mask will be * transparent; bits CLEAR will be filled with sprite image. Sprite * data should not occupy transparent areas. * Negative values (up to -15) may be passed for the coordinates. * Sprites will be clipped at the screen's edge. * This routine assumes an ST Low resolution screen. Adapt the * routine as necessary to allow for other screen sizes and depths. * This is NOT the world's fastest code. But it does work, and it * is reasonably fast (250 sprites per second on an 8MHz ST). sprite tst.w 4(a7) ; Function 1? bne make_lookup_table ; It wasn't zero, create table. movem.l 6(a7),a0-a1 ; Get pointers. movem.w 14(a7),d0-d1 ; Get coordinates. movem.l d3-d7,-(a7) ; Save registers. * Account for negative Y coordinates. moveq #15,d2 ; Number of lines to blit. tst.w d1 ; Negative Y coordinate? bge.s .ypositive ; Nope. neg.w d1 ; Make this positive. move.w d1,d2 ; Make a copy. add.w d1,d1 ; Double it. add.w d1,d1 ; Quadruple it. add.w d2,d1 ; Add original to make it * 5. add.w d1,d1 ; Double to get * 10. add.w d1,a1 ; Add offset to sprite address. moveq #0,d1 ; Now treat it as Y-coordinate 0. eor.w #15,d2 ; And this is how many lines are left. * Now calculate the screen address for the sprite. .ypositive add.w d1,d1 ; Double Y-coordinate. add.w d1,d1 ; Quadruple Y-coordinate (offset in * table of longs). move.l 0(a0,d1.w),a0 ; Get address of screen line. lsr.w #2,d1 ; Get Y-coordinate again. add.w d2,d1 ; Add in size of sprite (Y-coordinate of * bottom line). cmp.w #200,d1 ; Off the bottom? blt.s .onscreen ; Nope, just fine. sub.w d2,d1 ; Restore Y coordinate. sub.w #199,d1 ; Figure Y-199. neg.w d1 ; Invert to get 199-Y. move.w d1,d2 ; That's how many lines can be drawn. .onscreen move.w d0,d3 ; Make a copy of the X-coordinate. and.w #$FFF0,d3 ; Clear the low nibble. asr.w #1,d3 ; Get offset in bytes (16 pixels = 8 * bytes). add.w d3,a0 ; Add it to the screen address. and.w #$F,d0 ; Take just the low nibble (right shift * amount). moveq #0,d7 ; Clear right-edge flag. cmp.w #152,d3 ; Past X coordinate of 304? blt.s .loop ; No, not off right edge, blit sprite. moveq #1,d7 ; Set right-edge flag. * Blit the sprite. .loop moveq #-1,d4 ; Start mask out as -1 (all * transparent). move.w (a1)+,d4 ; Read sprite mask. ror.l d0,d4 ; Shift right. * Bitplane 0. moveq #0,d5 ; Clear this. move.w (a1)+,d5 ; Read first bitplane. ror.l d0,d5 ; Shift right. tst.w d3 ; Negative X position? blt.s .skip1 ; Yes, don't draw left edge. move.w (a0),d6 ; Get screen word. and.w d4,d6 ; AND in the mask. or.w d5,d6 ; OR in the image. move.w d6,(a0) ; Put it back on the screen. tst.w d7 ; Off the right edge? bne.s .skip2 ; Yes, don't draw right edge. .skip1 swap d4 ; Swap mask. swap d5 ; Swap data. move.w 8(a0),d6 ; Get screen word. and.w d4,d6 ; AND in the mask. or.w d5,d6 ; OR in the image. move.w d6,8(a0) ; Put it back on the screen. swap d4 ; Swap mask back. * Bitplane 1. .skip2 moveq #0,d5 ; Clear this. move.w (a1)+,d5 ; Read first bitplane. ror.l d0,d5 ; Shift right. tst.w d3 ; Negative X position? blt.s .skip3 ; Yes, don't draw left edge. move.w 2(a0),d6 ; Get screen word. and.w d4,d6 ; AND in the mask. or.w d5,d6 ; OR in the image. move.w d6,2(a0) ; Put it back on the screen. tst.w d7 ; Off the right edge? bne.s .skip4 ; Yes, don't draw right edge. .skip3 swap d4 ; Swap mask. swap d5 ; Swap data. move.w 10(a0),d6 ; Get screen word. and.w d4,d6 ; AND in the mask. or.w d5,d6 ; OR in the image. move.w d6,10(a0) ; Put it back on the screen. swap d4 ; Swap mask back. * Bitplane 2. .skip4 moveq #0,d5 ; Clear this. move.w (a1)+,d5 ; Read first bitplane. ror.l d0,d5 ; Shift right. tst.w d3 ; Negative X position? blt.s .skip5 ; Yes, don't draw left edge. move.w 4(a0),d6 ; Get screen word. and.w d4,d6 ; AND in the mask. or.w d5,d6 ; OR in the image. move.w d6,4(a0) ; Put it back on the screen. tst.w d7 ; Off the right edge? bne.s .skip6 ; Yes, don't draw right edge. .skip5 swap d4 ; Swap mask. swap d5 ; Swap data. move.w 12(a0),d6 ; Get screen word. and.w d4,d6 ; AND in the mask. or.w d5,d6 ; OR in the image. move.w d6,12(a0) ; Put it back on the screen. swap d4 ; Swap mask back. * Bitplane 3. .skip6 moveq #0,d5 ; Clear this. move.w (a1)+,d5 ; Read first bitplane. ror.l d0,d5 ; Shift right. tst.w d3 ; Negative X position? blt.s .skip7 ; Yes, don't draw left edge. move.w 6(a0),d6 ; Get screen word. and.w d4,d6 ; AND in the mask. or.w d5,d6 ; OR in the image. move.w d6,6(a0) ; Put it back on the screen. tst.w d7 ; Off the right edge? bne.s .skip8 ; Yes, don't draw right edge. .skip7 swap d4 ; Swap mask. swap d5 ; Swap data. move.w 14(a0),d6 ; Get screen word. and.w d4,d6 ; AND in the mask. or.w d5,d6 ; OR in the image. move.w d6,14(a0) ; Put it back on the screen. swap d4 ; Swap mask back. * End of loop. .skip8 lea 160(a0),a0 ; Move to next line. dbra d2,.loop ; Next sprite line. movem.l (a7)+,d3-d7 ; Restore registers. rts ; Done. * Function 1: Create lookup table. For this, the sprite address * is interpreted as the screen address, and the Y position as * the screen height (in pixels). The X position is the length * of a screen line in bytes. make_lookup_table movem.l 6(a7),a0-a1 ; Get addresses. movem.w 14(a7),d0-d1 ; Get screen line size & height. subq.w #1,d1 ; One less for looping. .loop move.l a1,(a0)+ ; Store pointer to screen line. adda.w d0,a1 ; Add offset for a single line. dbra d1,.loop ; Fill in the whole table. rts ; All done. -- End of code -- This shows just how much is involved in putting something as simple as a 16x16 sprite on the screen. Agreed, this isn't something to be undertaken lightly; this took me about an hour and a half to put together today. I tested it moderately well (to make sure the border clipping is working), which is how I came up with the 420 sprites per second figure--while I was testing it, I timed it. - DMJ J.STANFORD2 [John] at 20:00 EDT Roadkill: I don't understand why you're saying plane interleaved graphics "is almost impossible... from C" ? The C language has a full complement of bitwise operators (the only one off hand I can think of it lacks is rotate). My set & get pixel routines for an arbitrary number of bit planes are four lines each in C. Though not the speediest, they could easily be optimized significantly with lookup tables for the shifts and/or hard coding the # of planes. here's get_pixel: int pull_pixel(int *image_buffer,int x, int y, int width, int planes) { int pixeloffset, colorindex=0; image_buffer+=(((long)(width+15)/16L)*(long)planes)*(long)y+(long)((x/16)* planes); pixeloffset=15-x%16; while(--planes>=0) colorindex|=((*(ptr+planes)>>pixeloffset)&0x01)<. -- -- -- -- 4. Have a major credit card ready. In the U.S., you may also use -- -- your checking account number. -- -- -- -- For more information in the United States or Canada, call 1-800- -- -- 638-9636 or write: GEnie, c/o GE Information Services, P.O. Box -- -- 6403, Rockville, MD 20850-1785. -- -- -- -- --==--==-- Atari's Official Online Resource! --==--==-- -- --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- --==--==-- CompuServe Sign-Up Information --==--==-- -- -- -- -- -- -- -- -- To sign up for CompuServe service, call (voice call) (800) 848-8199. -- -- Ask for operator #198. You will be sent a $15.00 value CIS membership -- -- kit for free. -- -- -- -- -- -- -- -- --==--==-- CompuServe Sign-Up Information --==--==-- -- --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- --==--==-- Delphi Sign-Up Information --==--==-- -- -- -- -- To enroll as a Delphi subscriber, modem call 1-800-365-4636. Press -- -- [Return] once or twice, and type IP26 [Return] at Password: -- -- -- -- Answer all of the questions, and you'll be cleared for Delphi -- -- access in a few days. If you have questions about Delphi services, -- -- give a voice call to Delphi Member Services at 1-800-544-4005. -- -- -- -- --==--==-- Delphi Sign-Up Information --==--==-- -- --------------------------------------------------------------------------- /***********************************************************************/ USER VIEW By: Ron Whittam /***********************************************************************/ Technical Support In every line of work, help is needed. With a computer it could be a daily necessity. Computers on all platforms are becoming more and more technically advanced. No more "plug and play". Even the Falcon isn't as simple as the old Atari 520 ST. This is due to an ever broadening scope of what people are using computers for. The more diverse the applications get, the more changes the computer must be ready to handle. The basic configuration of the hardware, firmware, and software isn't as cut and dried as it used to be. For a programmer, this could be a nightmare to support. However, the key to a successful application in the last half of the decade will be a good quality product with superior customer support. More recently than in the past has the subject of customer support or technical support come up when people are thinking about software to purchase. No longer is the computer a math or writing tool for the technical elite. The modern computer owner is a person who needs to get a job done. Unlike their earlier counterparts, they don't enjoy tweaking the performance of their computers. They expect them to be operating at optimum performance out of the box. These newer owners want to be able to turn on the computer, do a job, and then leave it; going about their daily routine. They don't want to be encumbered with a computer. I recently set up a computer for a client. While he wanted to do his finances on it, he was more interested in getting his golf program to run without a lot of keystrokes or mouse clicks. Essentially he wanted to just turn on the computer and play golf. He had no real interest as to how it worked as long as it did work. In the recent past programmers have been able to get away with shipping a product that let the user configure it to their own technical whim. While those types still exist, a whole new group of users just want to plug and play. They don't want to know how it works they just want it to work. And when it doesn't they need a quick and simple "how to" to get it running. This is where technical support comes in. With the communication technology of our day, even a one man operation can handle technical support skillfully. The rise of electronic information services, and the media promotion of the internet, allows many developers to use this media to handle technical queries. Many of their customers can easily contact them on-line, (assuming the customer has an electronic service's account). However, in our verbal society, people enjoy and expect person to person technical assistance. The success of WordPerfect Corporation is a tribute to person to person customer support. A quality technical answer desk is not an easy feat when you are a company of one. This is probably why many have resorted to online EMail support, answering machine support, or no support at all except by "snail" mail. I think WordPerfect's 200 plus people in customer support explains why WordPerfect for Windows is the hottest selling Windows' application (second only to the Windows operating system itself). How can a small programmer compete in such a demanding market place? One might argue that a well written manual and start up booklets with step by step illustrated instructions would eliminate the need for technical support. While it might help to alleviate the general and commonly asked questions, it wouldn't eliminate the problem. Face reality: No one reads the manual, (until the technical support person tells them which page the answer is on). At least no one of this new generation of computer users. They want you to do it. As a prime user of technical support phone services, (both hardware and software), it isn't so much that they solve my problem immediately, but that they do something. Granted, I want my problem fixed NOW. However, I understand that fixes sometimes take time... sometimes weeks. What I find really helpful is a quick work-around. But what I also need is communication. This means that I get a status call or can call for a status report. I need to know that they ARE working on my problem. Here are some suggestions to better technical support of your customers: 1. Create a "problem log" form. Have a field for the customer's name, address, and phone number. Have a place for the description of the problem and a place for the resolution. Number these forms. 2. Prioritize problems as they occur. Get colored sticky tabs, (blue, yellow, and red). If a problem is easily fixed but a blue tab on it. If you have provided the customer with a work-a-round use the yellow tab, (you will then work on these yellow problems when your red ones are taken care of). If the problem is critical use the red tab. You might also want to have a bin to use for any problems that you will want to fix in the next release. 3. Keep a "flatfile" of the problems. Here's how. Create a file. Call it PROBLEM.LOG. Then, enter a problem on one line and the solution on the other. Keep it brief but descriptive. In the solution, note the problem log number when applicable. 4. Access the flatfile when needed. Use a program like GREP or EGREP to locate the problem. Or use a search option in your word processor. You will be able to type in key words of the problem. The search will display the problems that match those key words. You can then look at the solution section and find (hopefully) quick answers to past problems. 5. List your technical support phone number. Be careful to have a sufficient number of lines to keep the "busy" signal down to a minimum; but not too many where your customers would be "on hold" for too long. 6. List alternate ways of contacting you. 7. Put an ASCII text problem sheet on your program diskettes for your customers to fill out when mailing a problem. 8. Make a habit of calling your customers back, even if you don't have the problem fixed. People like it when you demonstrate that you care about them. This will cost the programmer more. It will take time away from developing, and fixing those pesky bugs, to answer the phone and listen to problems people are having with their program. However, this may be the key to succeeding or the reason for failure in the last half of this decade. It is something to think about. A good quality product and superior customer support will be the key to a successful software (or hardware) product in this decade. /************************************************************************/ Brain Stem Rotator By: Albert Dayes /************************************************************************/ Use the following program to find the solution to Ackermann( 7, 7 ). Use the source code provided below. Definition of Ackermann's function: A( i, j ) where i and j are integers greather than or equal to Zero if i = 0 then A( 0, j ) = 1 if j = 0 and i = 1 then A( 1, 0 ) = 2 else A( i, 0 ) = i + 2 if i > 0 and j > 0 then A(i,j) = A( A(i -1), j -1 ); < ==== cut here for C source code === > /* Ackermann function in ANSI C */ #include #include /* function prototype */ unsigned int ackermann( unsigned int x, unsigned int y ); /*--------------------------------------------------------------*/ main( int argc, char *argv[] ) { unsigned int x, y; if ( argc != 3 ) { printf("Illegal number of parameters.\n"); printf("Ackerman [x] [y]\n"); return (1); } /* if */ x = atoi( argv[1] ); /* convert strings to integers */ y = atoi( argv[2] ); if ( (x < 0) || (y < 0) ) { printf("X and Y cannot be negative!\n"); return( 2 ); } /* if */ printf( "Working on Ackermann( %u, %u ) ... \n", x, y ); printf ("Ackermann( %u, %u )= %d", x, y, ackermann(x, y) ); return( 0 ); } /* main() */ /*----------------------------------------------------------------*/ unsigned int ackermann( unsigned int x, unsigned int y ) { /* un-comment to view values of x and y within the function itself. printf( "Ackermann(%d,%d)\n", x, y); */ if ( x == 0 ) return (1); if ( y == 0 ) { if ( x == 1 ) return( 2 ); else return( x + 2 ); } /* if */ else return ackermann( ackermann( x -1, y ), y - 1 ); } /* ackermann() */ < ========= end source code ============ > [ Editor's Note: Information below from Joe Celko... One can also find ways to optimize the performance via the algebraic properties of the function in book RECURSIVE FUNCTION THEORY by Ann Yasuhara (Academic Press, ISBN 0-12-768950-8) ] /*************************************************************************/ Glossary of Terms /*************************************************************************/ AES = Application Environment System ALGORITHM = A logical sequence of discrete steps used to solve a problem in a finite amount of time. DSP = Digital Signal Processor EIA = Electronic Industries Association FIRMWARE = System software that is stored in ROM GEM = Graphics Environment Manager LEX = Lexical Analyzer POINT = 1/72 inch, used in PostScript and corresponds to the standard "point" system used in the printing industry. POSTSCRIPT = A page description language created by Adobe Systems Inc. "RAPID" - PROTOTYPE = Proof of concept. In Software - development of a preliminary version of the software system in order to allow certain aspects of that system to be investigated. RECURSION = Principle of expressing an algorithm by using a simpler version of the same algorithm in its explaination. ROM = Read Only Memory VDI = Virtual Device Interface YACC = Yet Another Compiler Compiler /*************************************************************************/ ATARI DEVELOPER INFORMATION /*************************************************************************/ What you can buy from Atari in terms of developer documentation and support. Contact Atari for the specific details. Atari Corp 1196 Borregas Ave Sunnyvale, CA 94089 USA (408)-745-2000 (voice) Some of the benefits: y Several disks and approximately two thousand pages of programming documentation. y Atari Developer Newsletter: ATARI.RSC y Atari Developer RoundTable support on GEnie (private) y Atari Developer CD-ROM (coming soon) y Book: Atari Compendium by SDS Publishing Call or write for details. /************************************************************************/ Sources of Information (References) Books, Magazines and Company Information /************************************************************************/ book: The C Programming Language (2nd edition, ANSI C) by Brian Kernighan and Dennis Ritche ISBN 0-13-110362-8 Prentice Hall Englewood Cliffs, New Jersey 07632 USA ANSI and ISO indexes/documents, EIA, Aerospace, Military, Engineering, and Government documents. Over one million documents available. Some documents are also available on CD-ROM. Global Engineering Documents 15 Inverness Way East Englewood Colorado 80112-5704 Phone 800-624-3974 Fax 303-972-2192 /***********************************************************************/ POST INCREMENT (what is coming up in the next installment) /***********************************************************************/ We are always looking for new articles, tricks, questions, tips and suggestions related to programming on the Atari. Also your favorite brain teasers (Brain Stem Rotator) problems are also needed. * More on Advanced Computing using FLEX * C++/Object Oriented Programming * More on the 56K DSP by BrainStorm The type of articles we are looking for are anything programming related. STOS, dBMAN, C, Assembly, BASIC, Pascal, Lex, YACC, etc, etc. This is of course a very small list. Letters and comments are always welcome! And if you have a better technique for solving a problem we want to hear from you. If one has a suggestion on a particular topic that he/she would like covered please send EMail to the editor. Developers [Worldwide] send press releases about your products as well. We want everyone to know about the newest developer tools available. /************************************************************************/ LEGAL NOTES /************************************************************************/ Articles and letters in Atari Explorer Online Programmers' Journal (AEO-PJ) represent the views of the authors and do not necessarily reflect those of the publisher. Note that all code and listings in Atari Explorer Online Programmers' Journal (AEO-PJ) appear "as is," and AEO-PJ makes no guarantee or warranty of their quality, performance, accuracy, or suitability for any particular purpose. AEO-PJ assumes no responsibility or liability to any person or entity with respect to any damage caused or alleged to be caused by their use. Material published in this issue may be reprinted under the following terms only: articles must remain unedited and include the issue number and author at the top of each article reprinted. Reprint permission is granted, unless otherwise noted at the beginning of the article, to registered Atari user groups and not for profit publications. Atari Explorer Online Programmers' Journal is a service of Atari Explorer Online Magazine. /************************************************************************/