DEEP BLUE C by John Howard Palevich INTRODUCTION OVERVIEW The DEEP BLUE C COMPILER helps you create large programs -- ones that take more than a day to write and can contain more than a hundred lines of code -- for your ATARI home computer. It lets you write your programs in a subset of the popular programming language "C". C is a general purpose programming language designed to fill the gap between BASIC and assembly language. Created by systems programmers as a high level alternative to assembly language, C is more powerful and faster than BASIC, yet clearer and less error-prone than assembly language. While slower running than assembly language, C code is much easier to write and understand. Pointers, recursive functions, and high level control structures make complex software systems easy to design, implement and maintain. Furthermore, C is the de facto systems programming language of the new generation of "workstation computers". Unlike programs written in assembly language, you'll be able to transport your valuable C programs to other (especially non-6502-based) computers, with only minor modifications. DEEP BLUE C is a proper subset of version 7 C, which mean that programs written for it will run almost without change on computers supporting the full language. The DEEP BLUE C COMPILER is an extensively modified version of Ron Cain's public domain Small-C Compiler. While the original Small-C Compiler was in the public domain this version is protected by copyright. REQUIRED ACCESSORIES 48K RAM ATARI Disk Drive ATARI Program Text Editor (or other non-line-oriented text editor) OPTIONAL ACCESSORIES ATARI Macro Assembler SUPPORTED FEATURES DEEP BLUE C supports the following features: 1) char,int and pointer data types 2) single dimension arrays 3) Unary operators: +,-,*,&,++,--,!,$- (tilde) 4) Binary operators: +,-,*,/,%,|,^,&,==,!=,<,<=,>=,<<,>>,<op>=,&&,||,?:,comma 5) Statments: if,else,while,break,continue,return,for,do,switch,case,default 6) #define and #include compiler directives 7) Relocating linker 8) Constants: hexadecimal, octal and backslash UNSUPPORTED FEATURES Features in C not supported in DEEP BLUE C are: 1) structures, unions 2) multidimension arrays 3) Floating point numbers 4) Functions returning anything but int 5) Unary operators: sizeof 6) Binary operators: typecasting DIFFERENCES FROM STANDARD C THE DEEP BLUE C language has the following nonstandard features: 1. The last clause of a "switch" statement, either "case" or "default", must be terminated with a "break", a "continue" or a "return" statement. 2. The ancient =<op> construct has been removed. Use <op>= instead. 3. Characters are unsigned. Chars range in value from 0 to 255. 4. Strings can not be continued on the next logical line. 5. C source code lines can be a maximum of 79 characters long. 6. Functions can have a maximum of 126 arguments. SPECIAL SYNTAX C uses several ASCII characters not available on the ATARI computer's keyboard. In particular the braces have been replaced by to two-letter combinations $( and $), and the tilde has been replaced by $-. The $ character is not used in C, so your editor's find and replace command can be used to convert standard c programs into a format acceptable to DEEP BLUE C. CONSTANTS DEEP BLUE C supports the following types of constants: 1. decimal numbers like -12, 134, 4500 2. octal numbers like 017, 045, 017777 3. hexadecimal numbers like 0xd400, 0xff, 0x2fc 4. character constants like 'a', 'ee', '0' 5. string constants like "foo", "bar blatz", "spam" You can embed in a DEEP BLUE C string any control or inverse video character that can be embedded in a BASIC character string (like control-A thru control-Z or the directional arrow keys), with one exception. The control-comma (the heart) is used to signal the end of the string and thus shouldn't be used in a string constant. In addition, the backslash character (\) is used to generate certain useful characters: \f -- clear screen \g -- ring bell \h -- backspace \n -- EOL (new line) \r -- delete line \\ -- backslash \' -- apostrophe \" -- quote \t -- tab \###, where ### is a one-to-three digit octal constant which produces the ATASCII character with that ATASCII code. RELATED PUBLICATIONS This manual won't teach you C. If you don't know C, you should obtain a copy of THE C PROGRAMMING LANGUAGE, by Brian W. Kernighan and Dennis M. Richie, 1978, Bell Telephone Laboratories, Inc., which is published by Prentice-Hall, Inc., Englewood Cliffs, NJ 07632. Many of the examples in the book use the UNIX I/O functions, which are slightly different from the ones supplied with DEEP BLUE C. GETTING STARTED DUPLICATE THE DISKETTE You should first make working copies of your DEEP BLUE C diskette, and store the original. Files on your diskette are as follows: 1. DOS.SYS -- standard DOS-II FMS file 2. DUP.SYS -- standard DOS-II DUP file 3. CC.COM -- Deep Blue C Compiler 4. CLINK.COM -- Deep Blue C Linker 5. DBC.OBJ -- C Run-time Module 6. AIO.C -- source for I/O functions 7. AIO.CCC -- object for AIO.C 8. GRAPHICS.C -- source for graphic and game I/O 9. GRAPHICS.CCC -- object for GRAPHICS.C 10. PMG.C -- source for player/missile and character set graphics 11. PMG.CCC -- object for PMG.C 12. PRINTF.C -- source for formatted output 13. PRINTF.CCC -- object for PRINTF.C 14. X.C -- source for demo program 15. X.CCC -- object for X.C 16. X.LNK -- link file for X.C 17. X.COM -- executable version of X.C 18. BOUNCE.* -- source, etc., for graphics demo 19. MEDITC.ECF -- PROGRAM/TEXT EDITOR ".C" customization file USING DEEP BLUE C INTRODUCTION Four steps are necessary to turn a C program on paper into an executable machine language file on the ATARI computer: 1. You enter the program as one or more source files, using a text editor. 2. You compile the source files into object files by the Deep Blue C Compiler. 3. You create a link file. The link file contains the names of all the object files that are part of the program, and is used by the linker (in step 4) to gather together all the parts of the program. 4. Using the Deep Blue C Linker, you link together into an executable file the individual object files that make up the whole program. FILE EXTENSIONS Each kind of file has its own extension. The extensions used by DEEP BLUE C are as follows: Source file -- .C Object file -- .CCC Link file -- .LNK Executable file -- .COM EDITING A C SOURCE FILE DEEP BLUE C source files contains the text representation of a C program, the comments associated with that program, and the compiler directives needed to compile the program. C is a modern high-level language best edited with a screen-oriented text editor. The ATARI Program Text Editor, available through the ATARI Program Exchange (also included in the ATARI Macro Assembler), is excellent for editing C programs. The editor's file MEDIT.ECF contains the appropriate tab settings for editing C text. If you have another text editor, you can also use it to edit your C programs. The only requirement is that your editor must not insert line numbers at the beginning of each line. Thus you can't use the ATARI BASIC or Assembler Editor editors to edit your C text, unless you write a utility program to remove the line numbers before compilation. All C files should have the extension ".C", as in AIO.C, PRINTF.C and X.C . The ".C" extension is traditional, and is also is the default extension assumed by the compiler. C source may contain all ATASCII characters. The two formattings characters TAB (decimal 127) and EOL (decimal 155) are treated as if they were spaces, which means you can use them to indent the C text to make it more readable. COMPILING, LINKING AND EXECUTING A C PROGRAM THE COMPILER Once entered, the C program must be translated into a special code (called object code) before it can be executed. The program that does this translation is called the Deep Blue C Compiler. The compiler reads a program from a C file, translates it into object code, and then writes the object code into a file with the extension .CCC . For example, to compile the program X.C you would do the following: 1. Remove all cartridges from your ATARI computer. 2. Turn on the disk drive and insert the Deep Blue C diskette. 3. Turn on your computer and TV set. 4. When the DOS-II menu displays, type L (for Load File), press the RETURN key, type CC.COM and press RETURN again. 5. Once the Deep Blue C Compiler loads into computer memory, it clears the screen and prints its header message: Deep Blue C Compiler version 1.1 (C)1982 John Howard Palevich File to compile (or RETURN to exit) Figure 1. Deep Blue C Compiler Display 6. insert the diskette containing the source text file and type in the name of the C text file you want to compile. Where the full name is in the form D:X.C, you need type only the main part of the file name -- X in this case -- and the rest of the name will default to the D: disk drive and the .C file. Thus, you would type X and press the RETURN key. 7. The compiler prints D:X.C->D:X.CCC which mean that the input file D:X.C is being read in, translated to object code, and written out to a file called D:X.CCC . In general, the name Dn:<name>.C will be translated into the file Dn:<name>.CCC . 8. The compilation may take several minutes, depending on the length and complexity of the source program. To give you an idea of what it is doing, the compiler prints the name of the current function it's parsing. 9. If you have any syntax errors, the compiler prints the line where it detected the error, an arrow pointing to the point in the line where it detected the error, and the line of text discribing the error An example is: main()$(printf("Hello, World/n"); Missing final end Figure 2. Compiler error message. 10. If you have no syntax errors, the compiler prints the reassuring message "No errors.". In either case, you are again prompted File to Compile (or RETURN to exit) If you have more than one file to compile at a time, you can type the next file name now, followed by RETURN. 11. When the compiler has finished compiling your files, press RETURN to go back to the DOS-II menu. LINKING A C PROGRAM Once you have compiled without error, the individual files making up the c program, you must link the whole program into an executable file. To link together a C program, you construct the text file, called a "link" file, that contains the names of all the files to be linked to produce the complete program. A typical small program, such as X.C, needs two files in addition to itself: AIO.CCC (the compiled C code of the I/O functions) and the DBC.OBJ (the run-time package). If you were to print out the file X.LNK, you would see that it contains the following text: X AIO DBC.OBJ Figure 3. Contents of X.LNK file The files must have the Dn: prefix if they are other than drive 1. If no extension is given, a "CCC" extension is assumed. The LNK file can't contain any blank lines, not even at the end of the file. Two types of files make up an executable C program: .CCC files, produced by the compiler, and .OBJ files, produced by the ATARI Macro Assembler (or other assembler), which cotain machine language. ".CCC" files are linked together in a C program, while .OBJ files are copied verbatim into the output file. All C programs must include the file name DBC.OBJ in their link file. DBC.OBJ contains the run-time routines and the C-code interpreter needed to execute properly. If you see the "asm" keyword (discribed later) then you want to have your own machine language file loaded automatically, then you would list it to the link file, too. Once you've written the link file for your program, you can link it by running the DEEP BLUE C Linker. Put the DEEP BLUE C diskette into the disk drive, close the door, boot DOS-II, and type L [RETURN], and then CLINK.COM [RETURN]. The DEEP BLUE C Linker will load into memory and display its message: Deep Blue C Linker version 1.1 (C)1982 John Howard Palevich Link program, Duplicate file or Quit Figure 4. Deep Blue C Linker display Type the first letter (L,D, or Q) of a command, followed by pressing the RETURN key. Link constructs a working C program out of its parts. Duplicate lets you move small files from one diskette to another without having to use DOS-II's O command. Quit returns you to DOS-II. Duplicating a file You can now use this command to copy .CCC files from the diskette where the were compiled onto the diskettes on which they are to be linked. Except for the limited file size (about five thousand characters), this command acts like the O command in DOS-II. To duplicate a file, type the letter D, then a space, and then the name of the file you want to duplicate. The linker prompts you to insert the source diskette, after which you should press RETURN. The linker reads in the file, and then prompts you to insert the destination diskette, after which you should press RETURN. The linker then writes a duplicate copy of the file onto the destination diskette. Linking a file Once you've compiled all the files making up your C program, you must link them together using the L command of the linker. To link the separate parts of your program together, type L, space, link file name, and then press RETURN. For example, L X [RETURN] instructs the linker to link together the program X.COM according to the directions in x.LNK. The linker will fail to link if the files you specify don't exist. In addition, if it can't find a function or external variable declaration, it will complain "undefined label: ", and list the missing variable's name. If you mistyped a variable name (such as "alhpa" instead of "alpha" ), the misspelling will show up here. If there are no errors, the linker prints "No errors" before redisplaying the "Link,Duplicate, or Quit" prompt. Exiting the linker When you've finished duplicating files and linking programs, you can exit the linker by typing Q [RETURN]. RUNNING A C PROGRAM A compiled and linked C program can be treated like any other executable file. You can even rename it AUTORUN.SYS to have it load into memory automatically when you turn on the disk drive and the computer. Like other object code files, it should be loaded with the L command on the DOS II menu. Run-time errors Only 4 errors can occur at run time (that is, while the C program is executing). Of these, only the first is common. Should any of them occur, your program stops and the following message displays on the screen: dbc 1 run-time-error <letter> type a key to return to DOS. Figure 5. Run-time Error message The <letter>will be one of the following: A - stack overflowed RAMTOP -- either you are recursing endlessly, or you have defined too many variables. B - Illegal op-code -- your program has messed up its code area, and tried to execute garbage. C - version error -- you have versions of CC.COM, CLINK.COM, and DBC.OBJ that don't have the same version number. D - divide by zero -- you've tried to divide a number (or take its remainder) by zero. EXECUTING THE DEMONSTRATION PROGRAMS Included on your Deep Blue C diskette are two useful demonstration programs to help you get aquainted with DEEP BLUE C. The source, compiled object, link, and executable object files are included for each program. The first program, X, demonstrates some of the I/O capabilities of DEEP BLUE C. It includes options for reading and writing files. To execute X, first load in DOS, and then type L (for Load File), press the RETURN key, type X.COM, and press RETURN again. Once X loads into memory, it prints the following message: File reader/writer Command: r,w,q -> Figure 6. X Display Screen You may read a file by typing "r", write one by typing "w", or exit the program by typing "q". A useful exercise might be to read the file X.C, which illustrates the use of open, cclose, gets, getchar, and printf functions. The second demonstration, illustrates the use of player/missle graphics. It includes examples of the functions color, plot, drawto, sound, pmcinit, plmove, and pmcolor among others. It can be executed like X by selecting the file BOUNCE.COM instead of X.COM. Once again, the useful exercise might be to examine the source contained in the file BOUNCE.C. THE DEEP BLUE C LIBRARY INTRODUCTION Unlike most other languages, C has no built-in I/O statements. Instead of BASIC's PRINT or Pascal's WRITE statements, C uses functions for its I/O. While extremely useful, this aspect of C means that each C has its own version of the basic input/output functions. Deep Blue C is, alas, no exception, but if you find its mix of predefined functions lacking in one way or another, you are welcome to define new I/O functions to fit your needs! The functions defined in the files AIO.C, GRAPHICS.C, PMG.C, and PRINTF.C, give you access to the ATARI Computer's hardware at about the same level as BASIC does. C library functions with familiar names (like plot(), drawto(), and poke() act, on the whole, like their BASIC counterparts. While the most accurate definition of each function is its C code, her is a description of each function. FUNCTIONS DEFINED IN AIO.C clear(s,len) char *s; int len; clear90 puts zero bytes in s[0..len-1], which makes it useful for initializing large arrays. For initializing integer arrays, the length argument should be multiplied by two, so that the length is in bytes rather than in words. copen(fn,mode) char *fn,mode) The copen function opens the file named in the string 'fn' for reading, writing, or appending, depending upon the value of the character 'mode': 'r' -- read file (like OPEN #n,4,fn$) 'w' -- write file (like OPEN #n,8,0,fn$) 'a' -- append file (like #n,12,0,fn$) If the file is opened successfully, the IOCB number used by that file (0 to 7) is returned as the value of the function. You must save this value in a variable to be able to use the file. If the file doesn't open successfully, the function will return a negative @WN å@WN å@WN å@WN å@WN å@WN å@WN å@WN ånumber, where the number is the negative of the CIO error code. For example, if you pressed the BREAK key while copen was trying to open a file, then copen would return a -128. open(iocb,ax1,ax2,fname) char iocb,ax1,ax2,*fname This is the familiar OPEN statement from BASIC, open() returns 1 if there was no problem; otherwise, it returns the negative of the CIO error code. close(i) char i; This is the familiar CLOSE from the BASIC. It closes the IOCB and returns 1 or the negative of the CIO error code. cclose(i) int i; When you want to close a particular file, you should call cclose() with the number returned by copen(). cclose() will return either a 1 (if everything turned out OK), or a negative number (the negative of the CIO error code) if the file failed to close. cgetc(iocb) int iocb; cgetc() is very much like the BASIC GET statment. You pass the iocb number and it returns either the next character in the file (which will be between 0 and 255) or a negative number that's the CIO error code. cputc(c,iocb) char c; int iocb; cputc() is very much like the BASIC PUT statement. You give it the character you wish to print and the iocb number, and it prints that character into that file. If there is no error, cputc() returns 1; otherwise, it returns the negative of the CIO error code. getchar() getchar() gets one character from the screen (iocb 0) and returns it to you (or the negative of the CIO error code). putchar(c) char c; putchar() prints the character you give it onto the screen (iocb 0), and returns 1 or the negative of the CIO error code. gets(string) char *string; gets() is like the BASIC INPUT statement. It gets an entire logical line of text from the user and places that line in the character array you give as an argument. Make sure your character array is at least 120 characters long; otherwise the user could overflow your array by typing in a very long line. If ther are no errors, gets() returns the number of characters in the line of input (0 to 120). If there is an error, gets() returns the negative of the CIO error code. cprint(string) char *string; cprint() is like the BASIC Print statement. It prints the string you give it out onto the screen. It will not print a RETURN, but you can use the statement "putchar(155);" to cause a carriage return. cputs(string,iocb) char *string; int iocb; cputs() is like the BASIC PRINT# statement. It prints the string you give it out to the file you specify. You should use the iocb number that copen() returned. If there are no errors, cputs() returns a 1; otherwise, it returns the negative of the CIO error code. ciov(iocb,com,bad,blen,ax1,ax2) int iocb,com,blen,ax1,ax2; char *bad; ciov() is like the BASIC XIO call. You can set up the iocb of your choice, and then call the CIO via this function. The argument iocb should be between 0 and 7, and it should specify which I/O control block you're using. Com is the ICCOM command code, bad is the ICBAD buffer address, blen is the ICBLEN buffer length, ax1 is the ICAX1 auxiliary byte, and ax2 is the ICAX2 auxiliary byte. If you don't want to change the current value of any of the last four arguments (buf,blen,ax1, or ax2), use the value -1. Thus, to read another line into the current buffer, you would use: ciov(1,5,-1,-1,-1,-1); Most of the I/O functions are implemented using calls to ciov(). The two exeptions, cgetc() and cputc(), are coded in assembly language to speed them up slightly. If the CIO returns a result less than 128, ciov() returns it as it is, but if the CIO result code is greater than or equal to 128 (which means that an error has occurred),ciov() returns the negative of that code. This approach is in keeping with "standard usage" in C, which has error codes less than zero. normalize(fname,fext) char *fname,*fext; normalize() is a handy utility function used to convert free-form file names into CIO and FMS standard file names. First the file name is converted into upper case, and then, if there is no device prefix, D: is added to the front of the name. If there is no extension, a period and the extension in the string text is appened on to the file name. A typical use, "char fname; gets (fname); normalize(fname,"BAS"), would ensure that the file name in fname is acceptable to the CIO system. For example, if the user had input "prog", after normalize(fname,"BAS), the string would contain "D:PROG.BAS". toupper(c) char c; If c is lower case, toupper() returns the uppercase equivalent, or else toupper() returns c. tolower(c) char c; If c is upper case, tolower() returns the lowercase equivalent, or else returns c. strcpy(a,b) char *a,*b; strcpy() copies a string from character array b to character arry a. strcpy returns the length of the string it copied, not counting the trailing zero byte. move(a,b,len) char *a,*b; int len; move() moves len bytes from a to b, starting with the byte at a and finishing with the byte at a[len-1]. Funny things will happen if a<=b<=a+len. usr(addr,. . . .) int addr; usr() is like the BASIC USR(x) function. The first argument is the address of the machine language subroutine, and the rest of the arguments are passed on to that subroutine. The result is passed in the A(low) and X(high) registers. When the user's routine is called, the stack looks (in the order items would be PLA'd off the stack) like this: <number of arguments (zero to 120) besides the address> <high byte first argument> <low byte first argument> <high byte second argument> <low byte second argument,etc.> <return address (two bytes)> zero page variables $F6 to $FF are free for use with usr() subroutines find(addr,len,ch) char *addr,ch; int len; find() searches menory from addr to addr+len-1 for the first occurrence of ch. IF it doesn't find ch, it returns -1; otherwise, it returns the number of characters past addr that it found ch (range of 0 to len-1). peek(i) char *i,d; peek() returns the byte at memory address i. poke(i,d) char *1,d; poke() pokes byte d into address i, and then returns the OLD byte at i. dpeek(i) char *i; dpeek() returns the word at i (least signifigant byte) to i+1 (most signifigant byte). dpoke(i,w) char *i; int w; dpoke() pokes the word w into address i 10 i+1, and then returns the old word at that address. val(s) char *s; val(), like BASIC's VAL function, takes a string as input and returns its numeric value. hval(s) char *s; hval() takes a string as input and returns its hexadecimal value. FUNCTIONS DEFINED IN GRAPHICS.C graphics(n) char n; graphics() changes the screen's graphics mode, just like the BASIC GRAPHICS statement. It returns the same status as open(). color(c) char c; color() sets the color to plot() or drawto(), just like the BASIC COLOR statement. It returns garbage. srawto(x,y) int x,y; drawto() draws a line from the last plotted point to (x,y), just like BASIC's DRAWTO. It returns 1 if there are no errors; otherwise, it returns the CIO error code. locate(x,y) int x,y; locate() locates the graphics cursor at the position (x,y) and returns the value of that pixel, or the CIO error code. It's exactly like BASIC's LOCATE statement. plot(x,y) int x,y; plot() plots a point at (x,y) just like BASIC's PLOT statement. It returns 1 if there are no errors; otherwise it returns the CIO error code. position(x,y) int x,y; position() positions the graphics cursor at new (x,y). The cursor isn't actually moved until the next output. setcolor(reg,hue,lum) char reg,hue,lum; setcolor() sets the color # reg to the color combination hue,lum. It's just like the BASIC SETCOLOR statement. fill(x,y,c) int x,y; char c; Fill implements the FILL command of the S: device. It draws a line from the last point plotted to (x,y), filling the background to the right of the line with the color provided. This is somewhat useful for filling in large trapezoidal regions of the screen with color. See page 54 of the ATARI BASIC Reference Manual for more details. paddle(n) char n; paddle() returns the value of the numbered paddle, just like BASIC's PADDLE function. ptrig(n) char n; ptrig() returns the value of the numbered paddle trigger, just like BASIC's PTRIG function. stick(n) char n; stick() returns the value of the numbered joystick, just like BASIC'S STICK function. strig(n) char n; strig() returns the value of the numbered joystick's trigger button, just like BASIC's STRIG function. vstick(n) char n; vstick() returns the vertical component of the joystick n. If the joystick is pointed forward (up), vstick() returns 1. If it's pointed back (down), vstick() returns -1. If it's centered (vertically), vstick() returnd 0. hstick(n) char n; hstick() returns the horizontal component of the joystick n. If the joystick is pointed left, hstick() returns -1. If it's pointed right, hstick() returns 1. If it's centered (horizontally), hstick() returns 0. sound(voice,pitch,dist,volume) char voice,pitch,dist,volume; sound() makes sound effects just like BASIC's SOUND statement. rnd(n) int n; rnd() returns a random number between 0 and n-1 (inclusive). Therefore, to generate a random number between 1 and 10, you would use the expression: 1+rnd(10). If n is less than 2, then rnd() will return 0. FUNCTIONS DEFINED IN PMG.C pmcinit() pmcinit() initializes player/missile and character set graphics. pmcinit may be called only once, and should be used BEFORE any calls to graphics(). pmcflush() pmcflush flushes player/missile and character set graphics buffers out of ram, returning the 4k of RAM that they use. pmcflush() should be called only once, just before returning to DOS. pmgraphics(i) int i; pmgraphics() should be called AFTER each call to graphics() to set up the resolution of the player/missile graphics. pmgraphics(1) produces single-line resolution, pmgraphics(2) produces double-line resolution and pmgraphics(0) inhibits player/missile graphics altogether. hitclear() hitclear() clears the collision registers. hitp2pf(from,to) char from,to; hitp2pf() returns 1 if player # "from" hit playfield # "to"; otherwise, it returns 0. hitp2p1(from,to) char from,to; hitp2p1() returns 1 if player "from" hits player "to". Returns 0 if player "from" did not hit player "to". If "from" is equal to "to" then 1 is returned. pmclear(n) char n; pmclear() clears player number "n". pmcolor(n,c,i) char n,c,i; pmcolor() sets the color of player/missile "n" to hue "c" and intensity "i". pmwidth(n,w) char n,w; pmwidth sets the width of player "n" to "w": w == 0 means normal size w == 1 means twice normal w == 3 means four times normal pladdr(n) char n; pladdr() returns the address of the buffer containing player "n". plmove() moves player "n" to position "x","y" (in the current pmgraphics() mode's coordinates) and draws its shape from the character array "shape". shape is the size of the player's shape, and shape[1..size] is the byte pattern for the player itself. Be sure to put several zero bytes before and after the actual graphic so that previous images will be erased properly. chget(c,s) char c,*s; chget() fills the s[0..7] with the character font for the ATARI internal character whose code is c. ATASCII blank-space's internal representation is 0, so its current font could b3 obtained by chget(0,s). choget(c,s) char c,*s; choget() fills s[0..7] with the ORIGINAL (ROM) character font for internal character code c. chput(c,s) char c,*s; chput() makes the contents of s[0..7] the font for internal character code c. To put a dot in tie middle of the space, one would say chput(0,"\0\0\0\60\60\0\0\0"); REMEMBER, you must use pmcinit() before any other function in PMG.C will work. FUNCTIONS IN PRINTF In addition to the functions in AIO, there are two MOre library functions in PRINTF. printf(s, ... ) char *s; printf() is the standard C formatted output function. It takes a variable number of arguments. The first one is a formatting string containing the message to be printed, along with characters specifying where to insert the rest of the arguments. The % character is special when it appears in the format string. The characters following the % tell how to print one of the arguments. The first % matches the first argument after the format string, the second % matches the second argument and so on. If you specify too few arguments (or too many %'s), your output string will be garbled. After a % you may type one of the following letters: d -- to print a decimal number. x -- to print a hexadecimal number. c -- to print a character. s -- to print a string. % -- to print a %. If you want the argument to take at least a certain number of characters, type a number between the % and the format character. The velue will be right-justified. If you want it left-justified, then insert a minus sign before the number. Here are some examples: printf("abcd"); produces abcd printf("=%s=","abcd"); produces =abcd= printf("=5d=",99); produces = 99= printf("=-5d=",99);produces =99 = printf("%c %d %x",65,65,65); produces A 65 41 fprintf(iocb,s, ... ) int iocb; char *s; fprintf() is just like printf() except that it takes an additional argument, iocb, and outputs to that iocb. printf( ... ) is essentially fprintf(0, ... ). TECHNICAL NOTES ADDING MACHINE-LANGUAGE FUNCTIONS TO DEEP BLUE C If you look at the AIO.C file, you'll note that the "primative" functions, like ciov(), are defined in a pecular way, using the asm statement: ciov(iocb,com,bad,blen,ax1,ax2) int iocb,com,blen,ax1,ax2; char *bad; asm 12291; This kind of function definition, using asm rather than $(<statements>$), creates a "hook" into machine language. When an "asm" function is called, the arguments are pushed onto the machine stack just like the BASIC USR() function, and then a jump is made to the address that follows the "asm" keyword. If you want to add a hook into your machine language program starting at memory location $600, you would simply write: foo() asm 0x600; In addition, you've got to put your machine language into a binary file (which must have the extension .OBJ) and include the file name in your link file. Note that you can use any assembler that can produce object files. Don't forget that the number of arguments you actually get may vary, depending upon how many the user supplies. You should use the byte on the top of the stack to tell you how many arguments to pop off the stack before returning. RAM USAGE The DEEP BLUE C run-time package uses ram from $3000 to $3FFF, and the user's program starts at $4000 and continues towards the top of memory. You can use page six and any ram free between the top of the OS and $3000 for your own purposes. Although the compiler needs 48k of RAM, most DEEP BLUE C programs will run in much less space. It's certainly possible to create useful programs that run in as little as 24k of RAM.