@L}5 _$% l0$)$$Hȱ$ UhL" `e$$%`$%`  R@P!( L(1   Y I`  d  Ld M * @  $ % CC$$)%1 Udߥ$9%: !0 S$% DD˙`  }J)Lr d M * @  $ % CC$$)%1 Udߥ$9%: !0 S$%} DD˙`  }J)Lr J  ((  p L ()   J}L= ( L 0q A    IB JC;? D W } LL  ` W )LA!  ߰")-݆ p" } $G@LL 08`Q")<2Q0 -G$Ș݆ UL# ; p8(()(0ʥ)NQ` }$GȘ݆LU )L ݆ L GȘ ݆LL )W>Z   HH)H }p h  hyhy D L> L JJ    ! LA*` BF }7'8  M HN H` 8 Z  \LdJJ!"! GFE@F (!L }EE !E^ ^ E E7EȩEdE/EȩE  D } .L }  ;F d  ;?F7F? ( .   Z D LL d } . D  L    p  E` , d)  D L) 0BM݊L݉} ML  N݆ L NLML [ TEqEHȱEqEh 0Gȹ G} HLL GɛL  LFREE SECTORS G) *Gȩ GȽG GȌ*jj >G} C8jJ3j2CD( C202C ԠBX` N 1? l LlD:RAMDISK}.COMLu L1 L ;LHL  T`  `8  ɐ     `TU  } L ? .  t`GBJ ~DEHI B V0dV!}QDEHI VF9 ,0 ,0 s0hhL  L` H hDHEh"}DEL8HI4 0 HI,0 0  9 .G VLO#},0 L4*IJ`llD1:AUTORUN.SYSNEED MEM.SAV TO LOAD THIS FILE.D8:MEM.SAV J y08 B|DEHI$} V0 0`B;DEL`?<0LV`@ʆ v s? F0Ξ05: [ BDEHI%} VY8 B V  @  /DE `E:D8:DUP.SYSERROR-SAVING USER MEMORY ON DISKTYPE Y TO &}STILL RUN DOS B;DE J  (` 9 V⪍ ઍ  -'}LLu ÝDEHILV 9 .l 9 .l  `` s$B BH(}I|DE V BLV nB,DE JLV B V BLVDEIʩ BꭝLu } 3E:}DISK OPERATING SYSTEM II VERSION COPYRIGHT 1984 ATARI CORP.A. DISK DIRECTORY I. FORMAT DISKB. RUN CARTRIDG*}E J. DUPLICATE DISKC. COPY FILE K. BINARY SAVED. DELETE FILE(S) L. BINARY LOADE. RENAME FILE M. RUN AT ADDRES+}SF. LOCK FILE N. CREATE MEM.SAVG. UNLOCK FILE O. DUPLICATE FILEH. WRITE DOS FILES P. FORMAT SINGLEL !N',}#"&))9(&*)/h)''-&؆莟R'S  vL/ˢ L }Insert DOS 2.0s, type Y Λx -}DEfHI 1莏#q! @ y0ɛ8A0,' ȅ 1 1ild! 1L!NO SUCH ITEMSELECT.} ITEM OR FOR MENU! 0 .z:*{}.|{ 1 0 0JB 18L%|DL/}%DIRECTORY--SEARCH SPEC,LIST FILE?[# 0 0 &|D3" 1L!NOT A DISK FILEN !B 1L!E# 1 !BD0}ED:}:1BJ|DE 1DEBHI 1 h0ߢ 0.1}  0?詛 1 y0YЛ 1 ;#L" ;#L! BL1TYPE "Y" TO DELETE...DELETE FILE SPEC2}COPY--FROM, TO?OPTION NOT ALLOWED697 FREE SECTORS COPYING---D8:COPY32.COMl# 0|D .L/%#3}##JB|DE 1BHID#E 1#0: B 1L!#͑### B 1#c$0SY4}S1}:## # # .#Ƚ# # 𩛙## 1,#PD#ELJ- <.BJD#E 5}1 1HH 0hh|DL%1}:̳# L% #D#EL% 1 0 . .0O% 1L!WILD CARDS NOT A6}LLOWED IN DESTINATION 0 <.|K}N 2 FORMAT. t* 5) 1L!`) 0NΞ 0 L1) 1 L!BAD LOAD FILELOAD FROM WHAT FILE?) 0 ?}0#B 1L!WHAT FILE TO LOCK?) 0 0$B 1L!WHAT FILE TO UNLOCK?DUP DISK-SOURCE,DEST DRIVES?TYPE "Y" IF OK TO US@}E PROGRAM AREACAUTION: A "Y" INVALIDATES MEM.SAV.FE! +L1   `*  70 2 2A} 0.* 1 y0 0)INSERT BOTH DISKS, TYPE RETURN^, 1 y038逍 N, 1L! ,B}C, t*  Lx+, 0 ^, 1 y0 , ,0,0 ,L+ ,I0 ,Vǭ0C}Ξ, 0 }, 1 y0C,ШC, 0K'!" H H 'h h Lx+!EF 5L1L!D,I,HhD}` NOT ENOUGH ROOMINSERT SOURCE DISK,TYPE RETURNINSERT DESTINATION DISK,TYPE RETURNE}`  `8 rL1`-* 1P* 1 y0Y`hhL!NAME OF FILE TO MOVE?- 0 0|DL% <.F},^ 1 70 0 .@L# .BJ 1  DEHIB V L1 ,} 1 70,L.  G}JB|,#P#DE 1 HI BDEHHII 1 B 1 ,^ 1 70,0La- B V,#PH},^ 1 70 0L#L!-* 1P* 1 y0Yj383}mm ݭI}}`8}``|* ? ɛ,`|:-)| / 1L!`DESTINATION CANT BE DOJ}S.SYS0 0H{ 24Δ 28/L!/) 2 Π 2 0 ξK}hAΞB,0 J 1 BDEHI,HÝDE 1HIHIDELSAVE-GIVE L}FILE,START,END(,INIT,RUN)O S0 1`BDEPHI V` S0H 1 L!M}0 0 1L~0`PLEASE TYPE 1 LETTER,0`hhL! 70 1L0L<1 ,;ɛ7,"ɛ:ݦ1ݥN}A"D|ݤD|ȩ:|ȩ|ɛ,,(/+.ީ1 1,ɛ`轤{NAMEO} TOO LONG B VL!` L1I H1EΝDL1|mDiE` V0`8d/8 i:222 1 LP}!ERROR- 165ɛ+,' 20*.. өr2 1``2TOO MANY DIGITSINVALID HEXAQ}DECIMAL PARAMETER800 0 8 00`,0'D800 H,ɛh`2L1NEED D1 THRU D8uR} ECIMAL PARAMETER800 0 8 00`,0'D800 H,ɛh`2L1NEED D1 THRU D8u05  15 2 2151^116115ύ011$r2ԭ5 3)5)5ԭx GT}@@L00)+& 2 L0=ɛ -L!1LV1L1 /3 3ȹ441L-4 v3 25 2H 2h͔5U}L3L3 2 k3U hh`DOC`QL3P1Lk0S1H /3h0B k3@ VL0LU!#$53 1181118V}1111Ε5 1Lk0552 1Ȍ1i111i11115Lk0pppB4f5&&&&&&&&^6f^6&&&&&W}&&A1@BJ D2ELVK@BHILV^Щ6 2BD2EJ VBD5EHI0 V0%5X}5 2iХiL[2 25 25`D:*.*` i@`8 ``@i `8@`0 BLV525<4Y}5`HH i ԍΗ552 ԍhh@ Lح1Э1Ѣ 24.4 24Z}4`D4E` 2BJ k3LVRH` 2BD4EhK)I JLV333. Type the line -V HELLO.C at the promp o}t and hit return. CC65 will compile hello.c, producing hello.m65. Run RA65.COM. When it starts, it will prompt with RA p}65>. Type the line HELLO.M65 at the prompt and hit return. RA65 will assemble hello.m65, producing hello.obj. At th q}is point you can delete hello.m65 if you want. Run LINK65.COM. When it starts, it will prompt with LINK65>. Type the r}line -O HELLO.COM RUNTIME.OBJ HELLO.OBJ C.OLB at the prompt and hit return. Link65 will link hello.obj with the C run s}time stuff, and produce an executable program called hello.com. You're done! You can now run hello.com, to see the cano t}nical message. The procedures for building bigger programs are much the same. If you've got multiple source files, you u}'ll compile and assemble each of them separately, then feed all of them to LINK65, where you typed HELLO.OBJ in the exampl v}e above. See the link65.doc for more details. then feed all of them to LINK65, where you typed HELLO.OBJ in the exampl 2 CC65 Library Documentation by Mark Miller 9/21/91 x} ---------------------------- John Dunning, the author of CC65, said in the documentation y} that he hadn't made any detailed doc's for the libraries, and if anyone else wanted to do so, to go ahead z}and make them. I didn't see any doc's on the libraries at atari.archive, in the 8bit directory. I decid{}ed to take it upon myself to do this documentation, to help myself use the CC65 library functions, and to|} help others. I have derived this documentation from the source code of the library functions John Dunning provide}}d. I have been rather discriminating in choosing which functions to document, and which others are ~}not worth worrying about. I knew there were some things in the library sources that were primarily just }for use by other library functions. Some of the lower-level functions are actually accessible by calling } certain functions which I document here, without much loss of programmer control. These types of functions act as} interfaces to the lower-level ones. They may manipulate the data you input to them a little bit, but ot}herwise the result you get is the same, or almost the same, as if you called the equivalent lower-level f}unction. This is because all these types of functions do is call a lower-level function with certain par}ameters. Where such functions are documented here, I have included which lower-level functions they call. } If you are the type who likes to program "down to the bare metal" I really recommend you get the sources to} the library functions yourself. There is a lot to see in the sources, some of which I don't understand.} I don't claim to be an expert on CC65, but I am experienced in the C language. Since many of the }library functions have a standard C equivalent, I will indicate when a function is non-standard. I }would like to thank Gary Duzan for helping me understand many things in the library sources, and John Dunning himse}lf, who has helped me in editing this documentation. If anyone has suggestions or corrections, send them} to me at millerm@mozart.cs.colostate.edu. It took a lot of effort to create this documentation, mainly }because I had to derive it from the source code, both C and assembly, which was scantily documented in mo}st cases (I don't mean this to be a major flame), and it needed to be interpreted correctly. I also did lots of } correspondence with Gary Duzan and John Dunning, making sure I interpreted everything alright (at least as }far as they can remember...). So this is a start, and I'm not going to come right out and say it's perfe}ct. I submit this in the same spirit that CC65 was released: In hopes that it will be helpful, but ther}e are no guarantees that it has no errors. Just something to note, ERR is a global value in stdio.h.} Character Processing ---------------------- int isalnum(c) int c; } Returns a nonzero value if c is alphanumeric. int isalpha(c) char c; Returns a} nonzero value if c is an alphabetic character. int isascii(c) char *c; Returns a non}zero value if c is an ASCII character (values in the range of 0-127). int isatty(fd) int fd}; Returns a nonzero value if fd (an IOCB channel number) is a device. This is not a standard C fun}ction. int iscntrl(c) char *c; Returns a nonzero value if c is a control character (v}alues in the range of 0-31, 127). int iscons(fd) int fd; Returns a nonzero }value if fd (an IOCB channel number) is the console (stdout?). This is not a standard C function. int i}sdigit(c) char c; Returns a nonzero value if c is a decimal digit. int isgraph(c) } int c; Returns a nonzero value if c is a graphics character (values in the range of 33-12}6). int islower(c) int c; Returns a nonzero value if c is a lower-case character.} int isprint(c) int c; Returns a nonzero value if c is a printable character} (values in the range of 32-126). int isodigit(c) char c; Returns a nonzero }value if c is an octal digit. int ispunct(c) int c; Returns a nonzero value if c is a} punctuation character. int isspace(c) int c; Returns a nonzero value if c is a white}-space character (a space, tab, or carriage-return). int isupper(c) int c; }Returns a nonzero value if c is an upper-case character. int iswhite(c) char c; See i}sspace(). int isxdigit(c) int c; Returns a nonzero value if c is a hexadecimal digit} (characters '0'-'9', 'A'-'F', or 'a'-'f'). char toascii(c) int c; Returns t}he ASCII equivalent of c. int tolower(c) int c; Returns the upper-case character c as} the equivalent lower-case character. int toupper(c) int c; Converts the lo}wer-case character c as the equivalent upper-case character. String Processing --}----------------- int atoi(s) char *s; Returns the numeric integer version the intege}r string s. int atoib(s, b) char *s; int b; Converts the number string s}, in base b, to an unsigned integer. Returns the converted value. This function is like strtoul() in st}andard C. int dtoi(decstr, nbr) char *decstr; int *nbr; Converts the sig}ned decimal in the string decstr to a numeric signed integer. It puts the result in nbr. Returns the fi}eld length of the integer, otherwise ERR if an error occurs. This is not a standard C function. int find}(str, len, c) char *str; int len; char c; Searches for the character c} in string str of length len. Returns the index where c is found in str. This function is similar to str}pos() in standard C. The exception is that this function expects a length for the string. itoa(i, s) } int i; char *s; Converts the signed integer i to a signed integer string. T}he string s becomes the converted string. This is not a standard C function. itoab(n, s, b) } int n; char *s; int b; Converts the unsigned integer n to a string in base b. Th}e string s becomes this string. This is not a standard C function. char *itod(}nbr, str, sz) int nbr; char *str; int sz; Converts the signed integer }nbr to a signed decimal string of length sz. The string str becomes this string. This string will be ri}ght-justified. If sz > 0, str will be null-terminated, with the '\0' character at sz index location. } If sz = 0, itod finds the end of the string. The string is expected to be null-terminated. If sz <} 0, itod puts the converted number in str at location (-sz)-1. Returns str (string ptr). This is not a s}tandard C function. char *itoo(nbr, str, sz) int nbr; char *str; int sz; } Converts the integer nbr to an octal string of length sz. The rest is the same as itod(). This is no}t a standard C function. char *itou(nbr, str, sz) int nbr; char *str; } int sz; Converts integer nbr to an unsigned decimal string of size sz. The rest is the same a}s itod(). This is not a standard C function. char *itox(nbr, str, sz) int nbr; } char *str; int sz; Converts integer nbr to a hexadecimal string of length sz. The re}st is the same as itod(). This is not a standard C function. int otoi(octstr, nbr) char *o}ctstr; int *nbr; Converts the unsigned octal number in the string octstr to an integer}. The integer nbr becomes the converted number. Returns the field size of the number, else ERR if an error } occurs. This is not a standard C function. reverse(s) char *s; } Reverses the characters in string s. This is not a standard C function. char *strcat(str1, str2)} char *str1, *str2; Puts str2 on the end of str1. The null character '\0' of str2 beco}mes the null character of the combined string, str1. Returns str1 (string ptr). char *strchr(str, chr) } char *str, chr; Searches for the character chr in the string str. Returns a pointer to} the location of the character in this string. Note what is returned is _not_ an index in str. It is a pointer to} a location in memory. int strcmp(s, t) char *s, *t; Returns a value less t}han 0, if s "is less than" t, equal to 0, if s is equal to t, more than 0 if s "is more than" t. char *s}trcpy(s1, s2) char *s1, *s2; Copies the string s2 to s1, overwriting the contents of s1. } This includes the null-character of s2. It copies all of s2 even if s2 is longer than s1. Returns s1 (string p}tr). int strlen(str) char *str; Returns the length of the string str, excluding the '}\0' character. int utoi(decstr, nbr) char *decstr; int *nbr; C}onverts the unsigned decimal string decstr to an unsigned numeric integer. The integer nbr becomes this value. Re}turns the field size of the converted number, else ERR if an error occurs. This is not a standard C func}tion. int xtoi(hexstr, nbr) char *hexstr; int *nbr; } Converts the hexadecimal string hexstr to a numeric integer. The integer nbr becomes this value. Returns th}e field size of the converted number, else ERR if an error occurs. This is not a standard C function. } Memory Functions ------------------ char *bcopy(p1, p2, nbytes) char *p1, *p2; } int nbytes; Copies nbytes bytes from address p1 to p2. Returns p1 (pointer). } bzero(ptr, nbytes) char *ptr; int nbytes; Zeroes out nbytes bytes starting at loca}tion ptr. Input/Output -------------- [Note: The global variables stdin, stdout, and stderr} in stdio.h are of type FILE *, so they can be used with any of the following functions that have paramet}ers of type FILE *. These are standard C functions. A file pointer is typically called a stream. fd st}ands for "file descriptor."] cclose (iocb) int iocb; Closes the IOCB channel "iocb". } This function is like fclose() in standard C. char cgetc(iocb) int iocb; R}eturns a character from IOCB channel "iocb", else negative of error code if an error occurs. errno is set to the n}egative of the error code. This function is like fgetc() in standard C. ch}ar *cgets(str, size, iocb) char *str; int size, iocb; Gets a string from the IOCB c}hannel "iocb", "size" bytes long. Returns str (string ptr), or NULL if an error occurs. This function is} like fgets() in standard C. close(fnum) int fnum; Closes the file associated with fn}um. fnum is the value returned from open(). This function is like fclose() in standard C. cl}oseall() Closes all IOCB channels, not including the screen, and/or files. This is not a standard }C function. int copen(name, mode) char *name, mode; Opens a free IOCB channel in mode} "mode". The possible modes are: 'r' - read, 'w' - write, 'a' - append, and 'd' - directory. Returns t}he opened IOCB channel number, or negative of error code if an error occurs. errno is set to the negative } of the error code. This function is similar to fopen() in standard C. int cputc(ch, iocb) } char ch; int iocb; Puts the character ch into IOCB channel "iocb". Returns negative} of error code if an error occurs. errno is set to the negative of the error code. This function is like fputc() }in standard C. int delete(name) char *name; Deletes file specified by the s}tring "name". It calls fdelete(). Returns negative of error code, if an error occurs. errno is set to t}he negative of the error code. This is not a standard K & R C function, but there is an equivalent function in } ANSI C called remove(). int fclose(fd) FILE *fd; Closes the stream fd. It cal}ls close(). Returns NULL if the file is closed successfully, else ERR if an error occurs. } char fgetc(fd) FILE *fd; Returns a character from stream fd, else negative of error } code if an error occurs. errno is set to the negative of the error code. char *fgets(str, size, }fd) char *str; int size FILE *fd; Gets an entire string from the strea}m fd, including the carriage-return, or size-1 characters, whichever comes first. The string str gets the} input. fn_default(name, ext, target) char *name, *ext, *target; Fixes up the filenam}e "name". It adds a drive number and the extender "ext". The string "target" is the modified string. "n}ame" is not altered. This is not a standard C function. FILE *fopen(fn, mode) char *fn, *mode; } Opens the file fn in the mode specified by the string "mode". It calls copen(). Returns the FILE point}er (the stream) to the file, otherwise NULL if an error occurs. errno is set to the negative of the erro}r code. The possible modes are: "a" - append, "r" - read, "w" - write, "u" - update (the equivalent mode} in the standard fopen() function for "u" is "r+"). int fprint}f(argc) int argc; Prints in a format to a stream. The parameters are: fprintf(fd, ctr}lstr, args...). FILE *fd; char *ctrlstr; The string ctrlstr is the control string, where} the output format is specified. The possible options in the control string are: %b - print binary numbe}r %c - print character %d - print signed decimal number %o - print unsigned octal number } %s - print string %u - print unsigned decimal %x - print unsigned hexadecimal number The %}b - binary option is non-standard. The %f - float option is not supported, because currently there is no type floa}t in CC65. Returns the number of items output, or a negative number if an error occurs. errno is set to }the negative of the error code. int fputc(ch, fd) char ch; FILE *fd; Out}puts the character ch to stream fd. Returns the negative of the error code if an error occurs. errno is set to th}e negative of the error code. int fputs(string, fd) char *string; FILE *fd; } Writes "string" to stream fd. It calls write(). Returns NULL always. int fread(buf, sz, }n, fd) char *buf; int sz, n FILE *fd; Reads n items of size sz (in byt}es) from stream fd into string buf. It calls read(). Returns the number of items of size sz read.} int fwrite(buf, sz, n, fd) char *buf; int sz, n FIL}E *fd; Writes n items of size sz (in bytes) from string buf to stream fd. It calls write(). Retur}ns the number of items written, or NULL if an error occurs. char kbdchar() Returns a cha }racter from keyboard input (stdin). The equivalent function in standard C is getchar(). char *gets(str) } char *str; Gets a line from standard input (stdin), excluding the carriage-return. T }he limit of characters that can be input is 32767. The array str must be large enough to hold the user's  } input. It calls fgets(). Returns str (string ptr) if input is successful, otherwise NULL if an error occurs.  } int open(name, mode) char *name; int mode; Opens the file with filename "na}me" in mode "mode". The two possible modes are: 4 = read, 8 = write. It calls copen(). Returns a non-n}egative value if successful, otherwise ERR if an error occurs. The returned value should be kept, if the open } operation is successful. You will need it for other functions in this "family" of functions. This is not a }standard C function. int printf(args) int args; Prints in a format to the screen. Th}ere is no stream parameter. The parameters are: printf(ctrlstr, args...) char *ctrlstr; } The rest works the same as fprintf(). Returns the number of items output, or a negative number if an error} occurs. int read(fnum, buf, size) int fnum; char *buf; } int size; Gets "size" number of characters from the file associated with fnum and puts }them into the string buf. fnum is the value returned from open(). Returns the number of characters read, or } negative of error code if an error occurs. errno is set to the negative of the error code. This is not a sta}ndard C function. int rename(old, new) char *old, *new; Renames file "old" with new f}ilename "new". It calls frename(). Returns 0 on success, else ERR if an error occurs. This is not a sta}ndard K & R C function, but there is an equivalent function in ANSI C by the same name. int write(fnum, }buf, nbytes) int fnum; char *buf; int nbytes; Writes nbytes number of }characters to the file associated with fnum. fnum is the value returned from open(). Returns the number} of bytes written. This is not a standard C function. Storage Al}location -------------------- char *pmalloc(nbytes) int nbytes; Permanently} allocates memory of size nbytes in free RAM starting at __himem. Note that this is _not_ the same pointer as  } the Atari DOS HIMEM pointer. It is a global variable whose value is set after the program is loaded into mem!}ory. pmalloc() moves the __himem pointer forward nbytes bytes. Returns a pointer to the space allocated"}. Note there is no corresponding free() function in this library. The memory sections look like this:#} DOS LOMEM>| ||< heap >| ...stack>|< HIMEM >|}macros using something like MAC/65.feeding to RA65, although you could probably get it to work by defining a couple of & INTERNALS DOC FOR CC65 ---------------------- The runtime model: Stacks: The program stack used by programs compile@}d with CC65 is located in high memory, typically #xBC00 or so. The stack starts there and grows down. Arguments to funcA}tions, local data etc are allocated on this stack, and deallocated when functions exit. The stack pointer is kept in pageB} 0 location #x80. All pushing and popping of things on/off the stack is done with subroutine calls to library routines (C}PUSHAX and POPAX), which adjust the stack pointer as appropriate. [There are a bunch of other things defined in page 0 tD}hat are used by the runtime library; see global.m65] Registers: Since CC65 is a member of the Small-C family of compilE}ers, it uses the notion of a 'primary register'. In the Atari implementation, I used the AX register pair as the primaryF} register. Just about everything interesting that the library code does is done by somehow getting a value into AX, and G}then calling some routine or other. In places where Small-C would use a secondary register, top-of-stack is used, so forH} instance two argument function like integer-multiply work by loading AX, pushing it on the stack, loading the second valI}ue, and calling the internal function. The stack is popped, and the result comes back in AX. Calling sequences: C funJ}ctions are called by pushing their args on the stack, and JSR'ing to the entry point. (See ex 1, below) If the function K}returns a value, it comes back in AX. NOTE!!! A potentially significant difference between the CC65 environment and otheL}r C environments is that the CALLEE pops arguments, not the CALLER. (This is done so as to generate more compact code) M}In normal use, this doesn't cause any problems, as the normal function entry/exit conventions take care of popping the riN}ght number of things off the stack, but you may have to worry about it when doing things like writing hand-coded assemblyO} language routines that take variable numbers of arguments. More about that later. Ex 1: Function call: Assuming 'i'P} declared int and 'c' declared char, the following C code i = baz(i, c); generates this assembler code. I've added thQ}e comments. lda _i; get 'i', low byte ldx _i+1; get 'i', hi byte jsr pushax; push it lda _c; get 'c' ldx #0; fill hi byR}te with 0 jsr pushax; push it ldy #2; arg count jsr _baz; call the function sta _i; store the result stx _i+1 Note thaS}t the two words of arguments to baz were popped before it exitted. The way baz could tell how much to pop was by the argT}ument count in Y at call time. Thus, even if baz had been called with 3 args instead of the 2 it was expecting, that woulU}d not cause stack corruption. There's another tricky part about all this, though. Note that the args to baz are pushed V}in FORWARD order, ie the order they appear in the C statement. That means that if you call a function with a different nW}umber of args than it was expecting, they wont end up in the right places, ie if you call baz, as above, with 3 args, it'lX}l operate on the LAST two, not the first two. Symbols: CC65 does the usual trick of prepending an underbar ('_') to sY}ymbol names when compiling them into assembler. Therefore if you have a C function named 'bar', CC65 will define and refeZ}r to it as '_bar'. Note! One way in which the CC65 environment deviates from normal C environments is that all symbol na[}mes are upper-cased by the assembler. This behaviour is often the right thing for assembly-language programming, but not \}at all the right thing for C programs. It was originally intended that this behaviour be switchable, but I never got arou]}nd to implementing it.r C programs. It was originally intended that this behaviour be switchable, but I never got arou CC65 ---- Link-65 preliminary doc. Link-65 is a linker for relocatable object modules. It inputs object files and o_}utputs an executable image. Link-65 accepts as input a series of names and switches. Valid switches: -O Specify outpu`}t file, as "-O FOO.COM". -B Specify exec base address, as -B2800. Number is a hex constant. Default value is #x2000. a}-M Write a map file. A bunch of information gets dumped to the map, like how big each oject module ended up in the executb}able, and what addresses of global symbols etc. The name of the map file is the name of the output file, with the extensc}ion .MAP, ie "-M -O FOO.COM" will output the executable in FOO.COM, and the map in FOO.MAP. -V Verbose. Turns on printid}ng of various debug info while the link proceeds. Anything that's not a switch is expected to be a file name. All files e}are linked together to produce the executable. Ex: You could say something like: LINK65 -m -o foo.com start.obj foo.of}bj to link START.OBJ and FOO.OBJ together to form FOO.COM, and write the linker map to FOO.MAP. Link-65 knows how to seg}arch object libraries (.OLB files) to resolve references to undefined symbols. This is especially useful when linking C q}&?B%DOS SYSB*)DUP SYSB SAUTORUN SYSB_INTRO DOCBwCC65LIB DOCB 6CC65 DOCB?INTERNALDOCB^LINK65 DOCB%yRA65 DOCB OBJ DOCBLIBR65 DOCBATOI C BATOIB C BDELETE C BDTOI C BFCLOSE C BFGETS C BFNAME C BFOPEN C BFPRINTF C BFPUTS C BFREAD C BFWRITE C BGETS C BISALNUM C BISASCII C BISATTY C BISCNTRL C BISCONS C BISGRAPH C BISLOWER C B ISPRINT C B ISPUNCT C BISSPACE C BISUPPER C BISXDIGITC BITOAB C BITOD C B"ITOO C B(ITOU C B.ITOX C B4OPEN C B7OTOI C B;PMALLOC C B?READARGSC BCRENAME C BGREVERSE C BJSTARTUP C BRSTRCAT C BTSTRCMP C B WTIME C BdTOASCII C BfUTOI C BjXTOI C BrCTYPE H BsFILE H BuSTDIO H BxASCII BATBATASCII BATBREADME DOCB COPYLEFTDOCprograms, as they'll typically reference all kinds of canned library routines. Libraries are specified as files like anyr}thing else. Ex: LINK65 -o hello.com runtime.obj hello.obj c.olb Runtime.obj is the C startup/runtime module, hello.objs} is the main program, and c.olb is the C library. If a filespec contains a leading at-sign ('@') it is interpreted as at}n indirect command file. That means it's expected to contain a list of names of the files that are really supposed to be u}linked. Using this scheme, the above example would look like this: LINK65 -o hello.com @hello.lnk where hello.lnk contv}ains the following 3 lines: runtime.obj hello.obj c.olb Case does not matter in command line args; ie -v is equivalenw}t to -V. As usual, Link-65 will prompt for a command line if there isn't one, either because you didn't type it, or 'causx}e you're running on some system that doesn't do command lines, like DOS 2.5. either because you didn't type it, or 'causP CC65 ---- A65 preliminary doc [If anyone can come up with a better name than RA65, please let me know...] RA65 is !z}the assembler that goes with CC65, although it can just as well be used by itself. RA65 eats 6502 assembly-language sourc!{}e files, and produces relocatable object files, suitable for linking into executables with LINK65. When you start up RA6!|}5, it wants an optional name for the output file, optional debugging switches, and any number of input file names. The i!}}nput files are read in order, and an output file is written. If no output file is specified, the output file name will b!~}e the first input file name, with .OBJ substituted for whatever extension was there. Ex: RA65 foo.m65 assembles foo.m!}65, producing foo.obj. RA65 -o foo.obj foo.m65 does the same thing. RA65 -o foo.obj defs.m65 moredefs.m65 foo.m65 !}This form is useful when you've got some files of equates or something that you want to assemble your code with. Switche!}s: -O output file name, as described above. -V verbose. If verbose is turned on, the assembler will print lines to th!}e screen as it assembles them. Differences between RA65 and other assemblers for the Atari: RA65 is NOT the same sort o!}f beast as most other assemblers for Atari 8-bitters, at least all the ones I've ever seen. The output of this assembler!} is not an executable image, but a relocatable object module. [The format of .OBJ files is described in more detail els!}ewhere] These files are essentially instructions to the linker about how to construct the real executable. A .OBJ file !}contains instructions, raw data, specialized reference codes (things like "generate a byte that's the hi byte of the addr!}ess of symbol foo") and symbol tables. The symbol table contains both definitions of symbols that are defined in this mo!}dule, as "symbol _BAZ is defined as 27 bytes in from the beginning of this module" and references to symbols not defined !}in this module, as "value of symbol _QUUX + 20". There are some differences in how you use this assembler, compared to t!}raditional ones. o No ORG or *= directive. It's meaningless in this kind of assembler; as the starting address, like a!}ll other addresses, is determined at link time, not assemble time. o Undefined symbols. These are errors in an ordinar!}y assembler, but are not necessarily errors here. Undefined symbols are assumed to be references to something to be defi!}ned elsewhere. Note! Since the default way to reference a symbol as a 16-bit quantity, addresses on page 0 must be defin!}ed properly before you reference them, otherwise they'll error, or at least generate incorrect code. o No symbol for th!}e current PC. This is really a bug, as it's possible to make it work, I've just never gotten around to it. This means yo!}u can't say things like sym = * when defining symbols; you should use the sym: form instead. Special ops: RA65 unde!}rstands a couple of other things that aren't usually done in traditional assemblers. The following pseudo-ops are used by!} CC65, in particular: ldax #foo This loads the AX pair with the constant value foo, by generating an lda and an ldx. !}It will not work with non-constants. lbne labl This is a long-branch pseudo-op. It generates a bne if the label can be!} reached that way, otherwise it generates a beq *+5 followed by a jmp to the label. There are similar ones for lbeq, lbcc!} etc. Other stuff: RA65 understands the following pseudo-ops: .globl Define or reference a global symbol.used!} as: .globl foo .word Generate one or more 16-bit values.Values can be constants, expressions, symbol refere!}nces etc. Values are separated by commas. .byte Generate one or more 8-bit values. Similar to above. .blkb !}n Generate n bytes of empty space. = Set the value of a symbol. Used as: foo = 3 [There's more; finish later] Comm!}and lines: Like all the members of the CC65 family, RA65 can either grok command lines as used by Spartados and DOS XL, !}or prompt for its command line. If no command line is given, or you're running something that doesn't do command lines, R!}A65 will prompt, as RA65> You're then expected to type in the rest of the command line. Ex: under Spartados, if you ty!}ped RA65 -v foo.m65 you get the same effect under DOS 2.5 by starting up RA65, then at the RA65> prompt, typing -v fo!}o.m65A65 -v foo.m65 you get the same effect under DOS 2.5 by starting up RA65, then at the RA65> prompt, typing -v fo  CC65 ---- Relocatable object file format: Header: #xFDFD identifies this as a relocatable obj file. Nbytes symb%}ol: word. Nbytes of symbol table. Includes 'nsymbols'. Nbytes segment: word. N bytes this segment uses. Nbytes da%}ta: word. N bytes in segment data this object file. Nsymbols: word. N symbol structs following. Symtab: some nu%}mber of symbol structs. Each one looks like: namelen: byte length of namestring value: word symbol value flags: word fl%}ag bits this sym, one of: abs: value absolute rel: value relative to start of module Data: a bunch of op bytes, follow%}ed by data per op. ops: lit |0.0.0.n.n.n.n.n| n literal bytes follow. rel |0.0.1.0.0.0.0.0| generate the following wo%}rd offset by the start address of this segment rel-hi |0.0.1.0.0.0.0.1| generate a byte, the high half of the following %}word, offset by segment base rel-lo |0.0.1.0.0.0.1.0| generate a byte, the low half of the following word, offset by seg%}ment base sym |0.1.s.n.n.n.n.n| if s is clear, sym number is nnnnn, if set, nnnnn is top 5 bits, next byte is bottom 8%}. followed by a word. Generate the following word offset by the value of symbol n. sym-hi |1.0.s.n.n.n.n.n| Same as abo%}ve, but generate hi byte of resultant value sym-lo|1.1.s.n.n.n.n.n| Same, but generate lo bytes.n.n.n.n.n| Same as abo$d CC65 ---- Libr-65 preliminary DOC Libr65 is the object library maintenance utility part of the CC65 package. Its mi)}ssion in life is to build, maintain, list etc libraries of object modules. Object libraries are useful when building t)}hings like C programs, as there are all kinds of functions that want to be optionally linked in, and keeping track of the)}m all by hand is too big a pain to be worthwhile. See the LINK65 doc for a [brief] explanation.nd keeping track of the(e#define NOARGC /* no argument count passing */#define FIXARGC /* don't expect arg counts passed in *//*** atoi(s) - conve-}rt s to integer.*/atoi(s) char *s; $( int sign, n; while(isspace(*s)) ++s; sign = 1; switch(*s) $( case -}'-': sign = -1; case '+': ++s; $) n = 0; while(isdigit(*s)) n = 10 * n + *s++ - '0'; return (sign * n);$) ,|#define NOARGC /* no argument count passing */#define FIXARGC /* don't expect arg counts passed in *//*** atoib(s,b) - Co1}nvert s to "unsigned" integer in base b.** NOTE: This is a non-standard function.*/atoib(s, b) char *s; int1} b; $( int n, digit; n = 0; while(isspace(*s)) ++s; while((digit = (127 & *s++)) >= '0') $( if(digit >= 'a'1}) digit -= 87; else if(digit >= 'A') digit -= 55; else digit -= '0'; if(digit >= b1}) break; n = b * n + digit; $) return (n);$)t -= 55; else digit -= '0'; if(digit >= b09/* delete a file */int delete(name)char * name;$( char buf[80]; fn_default(name, 0, buf); strcat(buf, "\n"); ret5}urn(fdelete(buf));$)t delete(name)char * name;$( char buf[80]; fn_default(name, 0, buf); strcat(buf, "\n"); ret4#define NOARGC /* no argument count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*9}** dtoi -- convert signed decimal string to integer nbr** returns field length, else ERR on error*/dtoi(decstr, n9}br)char *decstr;int *nbr;$( int len, s; if((*decstr)=='-') $(s=1; ++decstr;$) else s=0; if((len=utoi(decstr, nbr))<09}) return ERR; if(*nbr<0) return ERR; if(s) $(*nbr = -*nbr; return ++len;$) else return len;$)((len=utoi(decstr, nbr))<08c#define NOARGC /* no argument count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*=}** Close fd ** Entry: fd = File descriptor for file to be closed.** Returns NULL for success, otherwise ERR*/fclose(fd)=}int fd; $(/* if (close(fd) >= 0) return(NULL); else return(ERR); ... we can do better than that... */ retu=}rn(close(fd) >= 0 ? NULL : ERR);$) return(NULL); else return(ERR); ... we can do better than that... */ retu<%#define NOARGC /* no argument count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*A}** Gets an entire string (including its newline** terminator) or size-1 characters, whichever comes** first. The input is A}terminated by a null character.** Entry: str = Pointer to destination buffer.** size = Size of the destination buffA}er.** fd = File descriptor of pertinent file.** Returns str on success, else NULL.*/fgets(str, size, fd)char * A} str;int size, fd;$( int ch; char * retval; retval = NULL; /* default */ for ( ; --size > 0 ; ) $( ch = fgeA}tc(fd); /* get one */ if (ch == EOF) break; if (!retval) retval = str; *str++ = ch; /* store it */ if (A}ch == '\n') break; /* stop at EOL */ $) *str = '\0'; return(retval);$) *str++ = ch; /* store it */ if (@V/* handy util for fixing up file names*/fn_default(name, ext, target)char * name;char * ext;char * target;$( chaE}r buf[80]; /* temp storage *//* this is bummed for space, not speed; it'll copy the data around even when it doesn't E}have to... */ if (!strchr(name, ':')) $( strcpy(buf, "D:"); strcat(buf, name); strcpy(target, buf);E} $) else strcpy(target, name); if (ext) if (!strchr(target, '.')) $( strcat(target, ext); $)$)D}#define NOARGC /* no argument count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*I}** Open file indicated by fn.** Entry: fn = ASCIIZ file name.** May be prefixed by letter of drive.** I} mode = "a" - append** "r" - read** "w" - write** "u" - update** (some oI}f those might not work on atari -- jrd)** Returns a file descriptor on success, else NULL.*/FILE * fopen(fn, mode)char * I}fn, * mode;$( int iocb; iocb = copen(fn, *mode); if (iocb < 0) $( errno = iocb; return(0); $) return(iocbI}); /* just return it as a (FILE * ) */$)n, *mode); if (iocb < 0) $( errno = iocb; return(0); $) return(iocbH./* #define NOARGC /* no argument count passing *//*** Yes, that is correct. Although these functions use an** argument cM}ount, they do not call functions which need one.*/#include /*** fprintf(fd, ctlstring, arg, arg, ...) - FormatteM}d print.** Operates as described by Kernighan & Ritchie.** b, c, d, o, s, u, and x specifications are supported.** Note: bM} (binary) is a non-standard extension.*/fprintf(argc)int argc; $( int dummy[1]; int * nxtarg;/* nxtarg = CCARGC() +M} &argc; */ nxtarg = &argc + dummy[1] - 1; return(_pfguts(*nxtarg, --nxtarg));$)/*** printf(ctlstring, arg, arg, ...) M}- Formatted print.** Operates as described by Kernighan & Ritchie.** b, c, d, o, s, u, and x specifications are supported.M}** Note: b (binary) is a non-standard extension.*/printf(args) int args; $( int dummy[1]; /* tprintf("printf: &argsM}=%x &argc=%x argc=%d\n", &args, &dummy[1], dummy[1]); */ return(_pfguts(stdout, &args + dummy[1] - 1));$)/*** _pfguts(fM}d, ctlstring, arg, arg, ...)** Called by fprintf() and printf().*/_pfguts(fd, nxtarg)int fd;int *nxtarg; $( int arg,M} left, pad, cc, len, maxchr, width; char *ctl, *sptr, str[17]; cc = 0; ctl = *M}nxtarg--; while(*ctl) $( if(*ctl!='%') $( fputc(*ctl++, fd); ++cc; continue; $) elseM} ++ctl; if(*ctl=='%') $( fputc(*ctl++, fd); ++cc; continue; $) if(*ctl=='-') $( left = 1; ++ctl; $) else M} left = 0; if(*ctl=='0') pad = '0'; else pad = ' '; if(isdigit(*ctl)) $( width = atoi(M}ctl++); while(isdigit(*ctl)) ++ctl; $) else width = 0; if(*ctl=='.') $( maxchr M}= atoi(++ctl); while(isdigit(*ctl)) ++ctl; $) else maxchr = 0; arg = *nxtarg--; sptr = str; switM}ch(tolower(*ctl++)) $( case 'c': str[0] = arg; str[1] = NULL; break; case 's': sptr = arg; break; M} case 'd': itoa(arg,str); break; case 'b': itoab(arg,str,2); break; case 'o': itoab(arg,str,8); break; M} case 'u': itoab(arg,str,10); break; case 'x': itoab(arg,str,16); break; default: return (cc); $) M}len = strlen(sptr);/* tprintf(" pf: str '%s' len %d wid %d\n", sptr, len, width); */ if(maxchr && maxchrlen) width = width - len; else width = 0; /* tprintf(" pf: str '%s' len %d wid %d iocb %x\n", sptr, len, M}width, fd); */ if(!left) while(width--) $(/* tprintf(" pf: pad, iocb %x, %d remaining\n", fd, width); */ fputcM}(pad,fd); ++cc;$) while(len--) $(fputc(*sptr++,fd); ++cc; $) if(left) while(width--) $(/* tprintf(" pf: fin, %d remaM}ining\n", width); */ fputc(pad,fd); ++cc;$) $) return(cc); $)idth--) $(/* tprintf(" pf: fin, %d remaLU#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** WQ}rite a string to fd. ** Entry: string = Pointer to null-terminated string.** fd = File descriptor of pertinent fQ}ile.*/fputs(string,fd) char *string; int fd; $(/* we can do better than this ... while(*string) if(fputc(*string++,fdQ})==EOF) return(EOF);*/ write(fd, string, strlen(string)); return(0);$)is ... while(*string) if(fputc(*string++,fdPN#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** Item-stream read froU}m fd.** Entry: buf = address of target buffer** sz = size of items in bytes** n = number of items to readU}** fd = file descriptor** Returns a count of the items actually read.** Use feof() and ferror() to determine file U}status.*/fread(buf, sz, n, fd) char * buf; int sz, n, fd; $( return (read(fd, buf, n * sz) / sz);$)o determine file Tl#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** Item-stream write toY} fd.** Entry: buf = address of source buffer** sz = size of items in bytes** n = number of items to writeY}** fd = file descriptor** Returns a count of the items actually written or** zero if an error occurred.** May useY} ferror(), as always, to detect errors.*/fwrite(buf, sz, n, fd) char * buf; int sz, n, fd; $( if (write(fd, buf, n*sz)Y} <= 0) return (0); return (n);$).*/fwrite(buf, sz, n, fd) char * buf; int sz, n, fd; $( if (write(fd, buf, n*sz)X&#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** Gets an entire strin]}g from stdin (excluding its newline** terminator) or size-1 characters, whichever comes** first. The input is terminated by]} a null character.** The user buffer must be large enough to hold the data.** Entry: str = Pointer to destination buffer.]}** Returns str on success, else NULL.*/#include gets(str)char *str; $( return (fgets(str, 32767, stdin));$)]}* Returns str on success, else NULL.*/#include gets(str)char *str; $( return (fgets(str, 32767, stdin));$)\#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return 'true' if c ia}s alphanumeric*/isalnum(c) int c; $( return ((c<='z' && c>='a') || (c<='Z' && c>='A') || (c<='9' && a}c>='0'));$)c*/isalnum(c) int c; $( return ((c<='z' && c>='a') || (c<='Z' && c>='A') || (c<='9' && ` #define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return 'true' if c ie}s an ASCII character (0-127)*/isascii(c) char * c; $( /* c is a simulated unsigned integer */ return (c <= 127);$)id|#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */extern int Udevice[];/**i}* Return "true" if fd is a device, else "false"*/isatty(fd) int fd; $( return (Udevice[fd]);$)ern int Udevice[];/**hf#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return 'true' if c in}s a control character** (0-31 or 127)*/iscntrl(c) char * c; $( /* c is a simulated unsigned integer */ return ((c <=n} 31) || (c == 127));$) (0-31 or 127)*/iscntrl(c) char * c; $( /* c is a simulated unsigned integer */ return ((c <=l#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** Dr}etermine if fd is the console.*/iscons(fd) int fd; $( return(fd == 0); /* kludge. need a way to tell what iocb is or}pen on */$)d is the console.*/iscons(fd) int fd; $( return(fd == 0); /* kludge. need a way to tell what iocb is op #define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return 'true' if c iv}s a graphic character** (33-126)*/isgraph(c) int c; $( return (c>=33 && c<=126);$)d in *//*** return 'true' if c it[#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return 'true' if c iz }s lower-case alphabetic*/islower(c) int c; $( return (c<='z' && c>='a');ounts passed in *//*** return 'true' if c ixP#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return 'true' if c i~ }s a printable character** (32-126)*/isprint(c) int c; $( return (c>=32 && c<=126);$)in *//*** return 'true' if c i|]#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return 'true' if c i }s a punctuation character** (all but control and alphanumeric)*/ispunct(c) int c; $( return (!isalnum(c) && !iscntrl(c}));$)ctuation character** (all but control and alphanumeric)*/ispunct(c) int c; $( return (!isalnum(c) && !iscntrl(c#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return 'true' if c i}s a white-space character*/isspace(c) int c; $( /* first check gives quick exit in most cases */ return(c<=' ' && (c=}=' ' || (c<=13 && c>=9)));$)space(c) int c; $( /* first check gives quick exit in most cases */ return(c<=' ' && (c=#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return 'true' if c i}s upper-case alphabetic*/isupper(c) int c; $( return (c<='Z' && c>='A');$)nts passed in *//*** return 'true' if c iR#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return 'true' if c i}s a hexadecimal digit** (0-9, A-F, or a-f)*/isxdigit(c) int c; $( return ((c<='f' && c>='a') || (c<='F' && c}>='A') || (c<='9' && c>='0'));$)*/isxdigit(c) int c; $( return ((c<='f' && c>='a') || (c<='F' && c,#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** itoab(n,s,b) - Conve}rt "unsigned" n to characters in s using base b.** NOTE: This is a non-standard function.*/itoab(n, s, b) }int n; char *s; int b; $( char *ptr; int lowbit; ptr = s; b >>= 1; do $( lowbit = n & 1; n = (n >> 1) & }32767; *ptr = ((n % b) << 1) + lowbit; if(*ptr < 10) *ptr += '0'; else *ptr += 55; ++ptr; $) while(n /= b); } *ptr = 0; reverse (s);$)1) + lowbit; if(*ptr < 10) *ptr += '0'; else *ptr += 55; ++ptr; $) while(n /= b); #define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** i}tod -- convert nbr to signed decimal string of width sz** right adjusted, blank filled; returns str**** if }sz > 0 terminate with null byte** if sz = 0 find end of string** if sz < 0 use last byte for data*/itod(nbr}, str, sz) int nbr; char str[]; int sz; $( char sgn; if(nbr<0) $(nbr = -nbr; sgn='-';$) else sgn=' '; if(sz>0 }) str[--sz]=NULL; else if(sz<0) sz = -sz; else while(str[sz]!=NULL) ++sz; while(sz) $( str[--sz]=(nbr%10+'0');!} if((nbr=nbr/10)==0) break; $) if(sz) str[--sz]=sgn; while(sz>0) str[--sz]=' '; return str;$)z]=(nbr%10+'0');m#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** itoo -- converts nbr#} to octal string of length sz** right adjusted and blank filled, returns str**** if sz > 0 terminate with n$}ull byte** if sz = 0 find end of string** if sz < 0 use last byte for data*/itoo(nbr, str, sz) int nbr; %}char str[]; int sz; $( int digit; if(sz>0) str[--sz]=0; else if(sz<0) sz = -sz; else while(str[sz]!=0) ++sz; w&}hile(sz) $( digit=nbr&7; nbr=(nbr>>3)&8191; str[--sz]=digit+48; if(nbr==0) break; $) while(sz) str[--s'}z]=' '; return str;$)t=nbr&7; nbr=(nbr>>3)&8191; str[--sz]=digit+48; if(nbr==0) break; $) while(sz) str[--s#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** i)}tou -- convert nbr to unsigned decimal string of width sz** right adjusted, blank filled; returns str**** i*}f sz > 0 terminate with null byte** if sz = 0 find end of string** if sz < 0 use last byte for data*/itou(n+}br, str, sz) int nbr; char str[]; int sz; $( int lowbit; if(sz>0) str[--sz]=NULL; else if(sz<0) sz = -sz; els,}e while(str[sz]!=NULL) ++sz; while(sz) $( lowbit=nbr&1; nbr=(nbr>>1)&32767; /* divide by 2 */ str[--sz]=(-}(nbr%5)<<1)+lowbit+'0'; if((nbr=nbr/5)==0) break; $) while(sz) str[--sz]=' '; return str;$)2 */ str[--sz]=(i#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** itox -- converts nbr/} to hex string of length sz** right adjusted and blank filled, returns str**** if sz > 0 terminate with nul0}l byte** if sz = 0 find end of string** if sz < 0 use last byte for data*/itox(nbr, str, sz) int nbr; c1}har str[]; int sz; $( int digit, offset; if(sz>0) str[--sz]=0; else if(sz<0) sz = -sz; else while(str[sz]!=0) ++s2}z; while(sz) $( digit=nbr&15; nbr=(nbr>>4)&4095; if(digit<10) offset=48; else offset=55; str[--sz]=digit+o3}ffset; if(nbr==0) break; $) while(sz) str[--sz]=' '; return str;$)set=48; else offset=55; str[--sz]=digit+oP/* open kludge */#include int open(name, mode)char * name;int mode;$( char copen_mode; if (mode & O_RDON5}LY) copen_mode = 'r'; else if (mode & O_WRONLY) copen_mode = 'w'; else /* error */ return(-1); return(cop6}en(name, copen_mode));$) lse if (mode & O_WRONLY) copen_mode = 'w'; else /* error */ return(-1); return(cop#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** o8}toi -- convert unsigned octal string to integer nbr** returns field size, else ERR on error*/otoi(octstr, nbr) 9}char *octstr; int *nbr; $( int d,t; d=0; *nbr=0; while((*octstr>='0')&(*octstr<='7')) $( t=*nbr; t=(t<:}<3) + (*octstr++ - '0'); if ((t>=0)&(*nbr<0)) return ERR; d++; *nbr=t; $) return d;$)$( t=*nbr; t=(t<e#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//* * homebrew memory man<}agement routines, by jrd *//* these vars defined in heap.m65 */extern int _himem; /* pointer to next unused mem */=}/* permanent alloc */pmalloc(nbytes)int nbytes;$( int ptr; ptr = _himem; /* get current ptr */ _himem += nbytes;>} /* move up by nbytes */ return(ptr);$)tes;$( int ptr; ptr = _himem; /* get current ptr */ _himem += nbytes;-#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//* handy util for 8-bitte@}rs. handed a prompt string, prompt with it, and read an arg string. parse it into the passed argv */#include A}int readargs(prompt, buf, argv)char * prompt;char * buf;char ** argv;$( fputs(prompt, stderr); /* prompt */ fgets(B}buf, 80, stderr); /* get a buf */ return(_parseline(buf, argv));$)gv;$( fputs(prompt, stderr); /* prompt */ fgets(G/* rename a file */int rename(old,new)char * old;char * new;$( char str[80]; /* buffer for rename string */ chD}ar * ptr; fn_default(old, 0, str); /* copy/default first name */ strcat(str, ","); /* put in the comma for ataridos E}*/ if (ptr = strchr(new, ':')) ++ptr; /* skip the colon */ else ptr = new; strcat(str, ptr); strcat(str,F} "\n"); return(frename(str)); /* do the rename */$) the colon */ else ptr = new; strcat(str, ptr); strcat(str,8#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** reverse string in plH}ace */reverse(s) char *s; $( char *j; int c; j = s + strlen(s) - 1; while(s < j) $( c = *s; *s++ = *I}j; *j-- = c; $)$) $( char *j; int c; j = s + strlen(s) - 1; while(s < j) $( c = *s; *s++ = */* standard startup piece for c programs. replace this by by supplying your own _main if you want... *//* int _argv[16K}]; .. use PRNBUF instead */int _argv = 0x3C0; /* Atari Rom OS's Printer buf, 32 bytes */#ifdef parser/* the C parser.L} The .m65 one is in parselin.m65 */static char ___ch;/* arg line parser. it's separate so it can be called independentlM}y */_parseline(line, argv)char * line;int * argv;$( int nargs; char * p; nargs = 0; if ((p = line) == 0) returN}n(0); while (*p) /* while not at eos, scan */ $( while (iswhite(___ch = *p)) *p++ = 0; /* zap and skip whitespaO}ce */ if ((___ch == 0) || (___ch == '\n')) break; /* end of str, stop */ *argv++ = p; /* remember the pointer *P}/ ++nargs; while (!iswhite(*p)) ++p; /* find end of string */ $) return(nargs);$)#endif_main(cmdline)char * cmQ}dline;$( main(_parseline(cmdline, _argv), _argv);$) string */ $) return(nargs);$)#endif_main(cmdline)char * cm8#define FIXARGC#define NOARGC/* somebody ought to rewrite this in m65 code */strcat(str1, str2)char * str1;char * str2;S}$( strcpy(str1 + strlen(str1), str2);$)ought to rewrite this in m65 code */strcat(str1, str2)char * str1;char * str2;,#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return <0, 0, >0 U}aUording to** st*/strcmp(s, t) char *s, *t; $( while(*s == *t) $( if(*s == 0) return (0); V} ++s; ++t; $) return (*s - *t);$)p(s, t) char *s, *t; $( while(*s == *t) $( if(*s == 0) return (0); +#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//* * time-hacking stuffX} */#define RTCLOK ((char *)0x12)gtime(time)char * time; /* snapshot RTCLOK */$( time[0] = *(RTCLOK); time[1] = *Y}(RTCLOK+1); time[2] = *(RTCLOK+2);$)calctim(t0, xtime)char * t0; /* initial time */char * xtime; /* 4 bytes,Z} hr, min, sec, 60th */$( char t1[3]; int temp[4]; gtime(t1); /* get current time *//* subtrace t0 from t1 */[}#asm ldy #8 ; index of t1 jsr locysp ; point at it sta $E0 ; tmp ptr stx $E1 ldy #15 ; index of t0 js\}r ldaxysp ; get pointer sta $D4 stx $D5 ldy #2 sec lda ($E0),y ; get t1 byte sbc ($D4),y ; sub t0 byte ]} sta ($E0),y ; back in t1 dey lda ($E0),y ; get t1 byte sbc ($D4),y ; sub t0 byte sta ($E0),y ; back in t^}1 dey lda ($E0),y ; get t1 byte sbc ($D4),y ; sub t0 byte sta ($E0),y ; back in t1#endasm/* tprintf(" t1 _}%x %x %x\n", t1[0], t1[1], t1[2]); */ temp[3] = (t1[2] & 0x3F) * 100 / 64; /* compute hundreths */ temp[2] = ((t1[2] `}& 0xC0) / 64) | /* compute seconds */ ((t1[1] & 0xFF) * 4) | ((t1[0] & 0x1F) * 1024); temp[1] = tempa}[2] / 60; /* ... minutes */ temp[2] = temp[2] % 60; temp[0] = temp[1] / 60; /* ... hours */ temp[1] = temp[1]b} % 60;/* tprintf(" temp %d %d %d %d\n", temp[0], temp[1], temp[2], temp[3]); */ xtime[0] = temp[0]; xtime[1] = temp[1]c}; xtime[2] = temp[2]; xtime[3] = temp[3];$), temp[1], temp[2], temp[3]); */ xtime[0] = temp[0]; xtime[1] = temp[1]1#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return ASCII equivale}ent of c*/toascii(c) int c; $( return (c);$)IXARGC /* don't expect arg counts passed in *//*** return ASCII equival4#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** ug}toi -- convert unsigned decimal string to integer nbr** returns field size, else ERR on error*/#define ERR -1utoh}i(decstr, nbr) char *decstr; int *nbr; $( int d,t; d=0; *nbr=0; while((*decstr>='0')&(*decstr<='9')) $( i}t=*nbr;t=(10*t) + (*decstr++ - '0'); if ((t>=0)&(*nbr<0)) return ERR; d++; *nbr=t; $) return d;$) $( q#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** xk}toi -- convert hex string to integer nbr** returns field size, else ERR on error*//* what should this be?? -- jrdl} */#define ERR -1xtoi(hexstr, nbr) char *hexstr; int *nbr; $( int d, b; char *cp; d = *nbr = 0; cp = hexstr; whim}le(*cp == '0') ++cp; while(1) $( switch(*cp) $( case '0': case '1': case '2': case '3': case '4n}': case '5': case '6': case '7': case '8': case '9': b=48; break; case 'A': case 'B': co}ase 'C': case 'D': case 'E': case 'F': b=55; break; case 'a': case 'b': case 'c': case 'd': case 'e': case p}'f': b=87; break; default: return (cp - hexstr); $) if(d < 4) ++d; else return (ERR); *nbr = (*nbr << 4)q} + (*cp++ - b); $)$)efault: return (cp - hexstr); $) if(d < 4) ++d; else return (ERR); *nbr = (*nbr << 4)/* nothing here? */extern int iswhite(); - hexstr); $) if(d < 4) ++d; else return (ERR); *nbr = (*nbr << 4),/* defs for file opening. these are the values passed to CIO in AUX1, when opening */#define O_RDONLY 0x04#define O_t}WRONLY 0x08#define O_CREAT 0x08#define O_TRUNC 0x08to CIO in AUX1, when opening */#define O_RDONLY 0x04#define O_8/* cc65 stdio.h *//* say we're running cc65 */#define M6502#define __CC65__#define FILE charextern FILE * stdin;extv}ern FILE * stdout;extern FILE * stderr;extern int errno; /* error number from open, etc */#define EOF -1#define NULL w}0#define NEWLINE 0x9B#define YES 1#define NO 0t errno; /* error number from open, etc */#define EOF -1#define NULL 2at2a atoi.cunsan atoi.cat2a fopen.cunsan fopen.cat2a isascii.cunsan isascii.cat2a ispunct.cunsan ispunct.cat2a itou.cy}unsan itou.cat2a reverse.cunsan reverse.cat2a xtoi.cunsan xtoi.cat2a atoib.cunsan atoib.cat2a fprintf.cunsan fprintfz}.cat2a isatty.cunsan isatty.cat2a isspace.cunsan isspace.cat2a itox.cunsan itox.cat2a startup.cunsan startup.cat2a d{}elete.cunsan delete.cat2a fputs.cunsan fputs.cat2a iscntrl.cunsan iscntrl.cat2a isupper.cunsan isupper.cat2a open.cu|}nsan open.cat2a strcat.cunsan strcat.cat2a dtoi.cunsan dtoi.cat2a fread.cunsan fread.cat2a iscons.cunsan iscons.cat2}}a isxdigit.cunsan isxdigit.cat2a otoi.cunsan otoi.cat2a strcmp.cunsan strcmp.cat2a fclose.cunsan fclose.cat2a fwrite.~}cunsan fwrite.cat2a isgraph.cunsan isgraph.cat2a itoab.cunsan itoab.cat2a pmalloc.cunsan pmalloc.cat2a time.cunsan t}ime.cat2a fgets.cunsan fgets.cat2a gets.cunsan gets.cat2a islower.cunsan islower.cat2a itod.cunsan itod.cat2a readar}gs.cunsan readargs.cat2a toascii.cunsan toascii.cat2a fname.cunsan fname.cat2a isalnum.cunsan isalnum.cat2a isprint.c}unsan isprint.cat2a itoo.cunsan itoo.cat2a rename.cunsan rename.cat2a utoi.cunsan utoi.cat2a atari.m65unsan atari.m6}5at2a close.m65unsan close.m65at2a getch.m65unsan getch.m65at2a isodigit.m65unsan isodigit.m65at2a runtime.m65unsan r}untime.m65at2a toupper.m65unsan toupper.m65at2a bcopy.m65unsan bcopy.m65at2a closeall.m65unsan closeall.m65at2a global}.m65unsan global.m65at2a iswhite.m65unsan iswhite.m65at2a rwcommon.m65unsan rwcommon.m65at2a tprintf.m65unsan tprintf.}m65at2a bzero.m65unsan bzero.m65at2a cputc.m65unsan cputc.m65at2a heap.m65unsan heap.m65at2a itoa.m65unsan itoa.m65a}t2a stdio.m65unsan stdio.m65at2a write.m65unsan write.m65at2a cgetc.m65unsan cgetc.m65at2a fdelete.m65unsan fdelete.m6}5at2a isalpha.m65unsan isalpha.m65at2a parselin.m65unsan parselin.m65at2a strchr.m65unsan strchr.m65at2a cgets.m65uns}an cgets.m65at2a frename.m65unsan frename.m65at2a isdigit.m65unsan isdigit.m65at2a read.m65unsan read.m65at2a tolower.}m65unsan tolower.m65at2a ctype.hunsan ctype.hat2a file.hunsan file.hat2a stdio.hunsan stdio.hn read.m65at2a tolower.ea2at atoi.csanitize atoi.ca2at fopen.csanitize fopen.ca2at isascii.csanitize isascii.ca2at ispunct.csanitize ispunct.c}a2at itou.csanitize itou.ca2at reverse.csanitize reverse.ca2at xtoi.csanitize xtoi.ca2at atoib.csanitize atoib.ca2at} fprintf.csanitize fprintf.ca2at isatty.csanitize isatty.ca2at isspace.csanitize isspace.ca2at itox.csanitize itox.ca}2at startup.csanitize startup.ca2at delete.csanitize delete.ca2at fputs.csanitize fputs.ca2at iscntrl.csanitize iscntr}l.ca2at isupper.csanitize isupper.ca2at open.csanitize open.ca2at strcat.csanitize strcat.ca2at dtoi.csanitize dtoi.c}a2at fread.csanitize fread.ca2at iscons.csanitize iscons.ca2at isxdigit.csanitize isxdigit.ca2at otoi.csanitize otoi.}ca2at strcmp.csanitize strcmp.ca2at fclose.csanitize fclose.ca2at fwrite.csanitize fwrite.ca2at isgraph.csanitize isg}raph.ca2at itoab.csanitize itoab.ca2at pmalloc.csanitize pmalloc.ca2at time.csanitize time.ca2at fgets.csanitize fget}s.ca2at gets.csanitize gets.ca2at islower.csanitize islower.ca2at itod.csanitize itod.ca2at readargs.csanitize readar}gs.ca2at toascii.csanitize toascii.ca2at fname.csanitize fname.ca2at isalnum.csanitize isalnum.ca2at isprint.csanitiz}e isprint.ca2at itoo.csanitize itoo.ca2at rename.csanitize rename.ca2at utoi.csanitize utoi.ca2at atari.m65sanitize a}tari.m65a2at close.m65sanitize close.m65a2at getch.m65sanitize getch.m65a2at isodigit.m65sanitize isodigit.m65a2at run}time.m65sanitize runtime.m65a2at toupper.m65sanitize toupper.m65a2at bcopy.m65sanitize bcopy.m65a2at closeall.m65sanit}ize closeall.m65a2at global.m65sanitize global.m65a2at iswhite.m65sanitize iswhite.m65a2at rwcommon.m65sanitize rwcommo}n.m65a2at tprintf.m65sanitize tprintf.m65a2at bzero.m65sanitize bzero.m65a2at cputc.m65sanitize cputc.m65a2at heap.m65}sanitize heap.m65a2at itoa.m65sanitize itoa.m65a2at stdio.m65sanitize stdio.m65a2at write.m65sanitize write.m65a2at c}getc.m65sanitize cgetc.m65a2at fdelete.m65sanitize fdelete.m65a2at isalpha.m65sanitize isalpha.m65a2at parselin.m65san}itize parselin.m65a2at strchr.m65sanitize strchr.m65a2at cgets.m65sanitize cgets.m65a2at frename.m65sanitize frename.m6}5a2at isdigit.m65sanitize isdigit.m65a2at read.m65sanitize read.m65a2at tolower.m65sanitize tolower.m65a2at ctype.hsa}nitize ctype.ha2at file.hsanitize file.ha2at stdio.hsanitize stdio.h2at tolower.m65sanitize tolower.m65a2at ctype.hsaICC65---- This is the latest library source code for CC65, as of 10/12/89. All known bugs have been fixed. ctype.hsar CC65 ---- This is the (c) copyright notice for RA65, LINK65, LIBR65, and other Atari 8-bit programs. Said programs a}re Copyright 1989, by John R. Dunning. All rights reserved, with the following exceptions: Anyone may copy or redistrib}ute these programs, provided that: 1: You don't charge anything for the copy. It is permissable to charge a no}minal fee for media, etc. 2: All source code and documentation for the programs is made available as part o}f the distribution. 3: This copyright notice is preserved verbatim, and included in the distribution. You} are allowed to modify these programs, and redistribute the modified versions, provided that the modifications are clearly} noted. There is NO WARRANTY with this software, it comes as is, and is distributed in the hope that it may be useful.} This copyright notice is based on the one published by the Free Software Foundation, sometimes known as the GNU project.} The idea is the same as theirs, ie the software is free, and is intended to stay that way. Everybody has the right to c}opy, modify, and redistribute this software. Nobody has the right to prevent anyone else from copying, modifying or redis}tributing it.d redistribute this software. Nobody has the right to prevent anyone else from copying, modifying or redis