From bb05ae48bad14b20be00ceb54a9b2a2e9050b9e4 Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Sun, 28 Jun 2015 22:24:58 +0100 Subject: [PATCH] Initial import of files from a2tools-v003.zip (on ftp.asimov.net). --- LICENSE | 339 +++++++++++++++++++++ README | 57 ++++ a2tools.6 | 170 +++++++++++ a2tools.c | 834 ++++++++++++++++++++++++++++++++++++++++++++++++++++ a2tools.exe | Bin 0 -> 20942 bytes install.csh | 28 ++ manual.dos | 146 +++++++++ 7 files changed, 1574 insertions(+) create mode 100644 LICENSE create mode 100644 README create mode 100644 a2tools.6 create mode 100644 a2tools.c create mode 100755 a2tools.exe create mode 100755 install.csh create mode 100644 manual.dos diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9285110 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/README b/README new file mode 100644 index 0000000..bbfe0b6 --- /dev/null +++ b/README @@ -0,0 +1,57 @@ + + a2tools - utilities for transferring data between Unix and Apple II + DOS 3.3 disk images. + + Copyright (C) 1998, 2001 Terry Kyriacopoulos + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Author's e-mail address: terryk@echo-on.net + +------------------------------------------------------------------------- + +PACKAGE CONTENTS: + README This file. + LICENSE Details of the license that applies to this package. + A2TOOLS.EXE MS-DOS executable program. + manual.dos User's manual for the DOS version. + a2tools.6 User's manual for the UNIX version, in manpage format. + a2tools.c Source program that should compile automatically on any + MS-DOS or UNIX ANSI C compiler. + install.csh C-shell script for easy UNIX installation. + (Inspect before running it.) + +SUPPORTED PLATFORMS: + MS-DOS and UNIX. The source is in ANSI C, and should compile properly + on both platforms. + +UNIX/Linux INSTALLATION: + Review the shell script "install.csh" and make any changes appropriate + for your system. $BINDIR is the directory where the executable program + will end up; $MANDIR/man6 is the directory where the manual page will + end up. The symbolic links are necessary - the program behaves + differently depending on what name it is called as, and thus is + equivalent to having several different programs. See the manual page + for details. + + Running "install.csh" will compile the program and install it on your + system, ready for use. + +DOS INSTALLATION: + A prebuilt executable is furnished in this package. Renaming it to an + acceptable short name is recommended. + + Optionally, the source program may be compiled with any ANSI C + compiler. diff --git a/a2tools.6 b/a2tools.6 new file mode 100644 index 0000000..5299566 --- /dev/null +++ b/a2tools.6 @@ -0,0 +1,170 @@ +.TH A2TOOLS 6 " 6 April 2001" +.SH NAME +.B a2tools +\- tools to move data to and from Apple DOS 3.3 disk images + +.br +.B a2ls +\- show directory of disk image +.br +.B a2out +\- read a file from disk image +.br +.B a2in +\- write a file into disk image +.br +.B a2rm +\- remove a file from disk image +.SH SYNOPSIS +.B a2ls +disk_image +.br +.B a2out +[\fB\-r\fR] disk_image a2_file [target_file] +.br +.B a2in +[\fB\-r\fR] filetype disk_image a2_file [source_file] +.br +.B a2rm +filename +.SH DESCRIPTION +.B a2tools +is a set of commands that +facilitates the transfer of data between Unix and the Apple II environment +via disk images (\fB.dsk\fR files). It is intended for use mainly with +Apple II emulators such as \fBapple2\fR(6). +.SS Features +.TP +.B - +Works with DOS 3.3-order \fB.dsk\fR disk images. +.TP +.B - +Expands tokenized Integer and Applesoft BASIC programs. +.TP +.B - +Knows about sparse files. +.PP +.B a2ls +shows the directory contents of the specified image, +including the disk volume and number of free sectors. +.PP +.B a2out +writes the file contained in the image to the target file if specified, +or to the standard output otherwise. +If the target file exists, it is overwritten. Unless the +\fB-r\fR option is given, the data will be processed according to the file +type as follows: +.TP +.B Text: +Output all data from the beginning of the file up to the first zero byte. +The high bit is cleared and linefeeds are substituted for carriage +returns. +.TP +.B BASIC (Integer and Applesoft): +Expand (detokenize) the program and output it as readable ASCII. +.TP +.B Binary: +Ignore the first two file bytes (base address), and use the next +two bytes (length) to produce a binary file of the exact original size in +bytes. +.TP +.B Other types: +Not accepted unless in raw mode (see below). +.PP +If the \fB-r\fR (raw mode) option is given, no postprocessing of file data +is done. For files of type other than T (text), the first +0/0 pair in the track/ sector list is assumed to mark the end of file. +However, type T files may be sparse, with 0/0 pairs marking unwritten +segments. Hence, this mode will always output type T files in multiples +of 31232 bytes, and others in multiples of 256 bytes. + +.br +.B a2in +writes to a new file in the image the source file if specified, +or the standard input otherwise. +The file must not already exist. The \fIfiletype\fP argument must +consist of a single letter denoting the type of the new file. Valid +values are: + +.br +\fBT\fR,\fBt\fR - text +.br +\fBI\fR,\fBi\fR - Integer BASIC +.br +\fBA\fR,\fBa\fR - Applesoft BASIC +.br +\fBB\fR,\fBb\fR[.addr] - binary (optional base address in hex) +.br +\fBR\fR,\fBr\fR - relocatable binary +.br +\fBS\fR,\fBs\fR - type S (obscure) +.br +\fBX\fR,\fBx\fR - "new A" (obscure) +.br +\fBY\fR,\fBy\fR - "new B" (obscure) + +.br +Unless the \fB\-r\fR (raw mode) option is given, only types T and B +are acceptable to \fBa2in\fR. Input processing is as follows: +.TP +.B Text: +Set the high bit and substitute carriage returns for linefeeds. +.TP +.B Binary: +Set the base address to that given in the \fIfiletype\fP argument, or to +the default of 0x2000. Set the file length to the exact length of the +standard input stream. Since the length field is only two bytes wide, +file lengths of 64K or more are illegal. +.PP +In raw mode, the standard input is written directly to the file. Zeroes +are used to pad any partial last sectors. If the new file is type T, +blocks containing all zeroes are denoted by a 0/0 entry in the track/sector +list instead of being allocated a sector. That is, sparse files will be +created. +.SH EXAMPLES +Send a readable copy of the BASIC program "PLOT FUNCTION" on the disk +image "basic.dsk" to the printer: + +.br +% +.B a2out basic.dsk 'PLOT FUNCTION' | lpr + +.br +Import the binary file "pics/airplane" into the disk image "pics.dsk". +Assign it a name of "AIRPLANE" and a base address of 0x4000 (second hi- +res graphics page): + +.br +% +.B a2in b.4000 pics.dsk 'AIRPLANE' pics/airplane + +.br +Copy the Applesoft program "ROOT FINDER" from disk image "math.dsk" to +"demo.dsk": + +.br +% +.B a2out -r math.dsk 'ROOT FINDER'|a2in -r a demo.dsk 'ROOT FINDER' + +.br +Import the sparse database "ACCOUNTS" from a gzip-compressed file: + +.br +% +.B zcat accounts.gz | a2in -r t shop.dsk ACCOUNTS +.SH BUGS +.TP +.B - +Works with 143360-byte DOS 3.3-order images only. +.TP +.B - +Does not tokenize plain-text BASIC source files, although this +is easily accomplished using the DOS 3.3 EXEC command on such a file. +.TP +.B - +Doesn't handle multiple files, although it can easily be wrapped +in shell scripts to enhance convenience. +.SH AUTHOR +Terry Kyriacopoulos +.SH SEE ALSO +\fBapple2\fR(6) diff --git a/a2tools.c b/a2tools.c new file mode 100644 index 0000000..958ab15 --- /dev/null +++ b/a2tools.c @@ -0,0 +1,834 @@ +/* + + a2tools - utilities for transferring data between Unix and Apple II + DOS 3.3 disk images. + + Copyright (C) 1998, 2001 Terry Kyriacopoulos + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Author's e-mail address: terryk@echo-on.net + + ------------------------------------------------------------------- + + Modified to be more portable: Unix specifics are marked as such. + ANSI-C is assumed, code is now acceptable to C++ as well, + type definitions are straighetend up, unused variables are removed, + casts are added when required by C++. + + Paul Schlyter, 2001-03-20, pausch@saaf.se + + ------------------------------------------------------------------- + + Improvements to accomodate MS-DOS have been made: + + - code fixed to work properly on a 16-bit platform + - conditional compilation used to select OS-specific code + automatically + - user interface is now more OS-specific: + - argv[0] command selection for UNIX, argv[1] for DOS + - stdin/stdout forbidden on binary data in DOS + - optional source/destination pathnames for in/out commands + - improved documentation + + Terry Kyriacopoulos, April 8, 2001 terryk@echo-on.net + + +*/ + +#ifndef UNIX + #ifdef __unix__ + #define UNIX + #endif +#endif +#ifndef DOS + #ifdef __MSDOS__ + #define DOS + #endif +#endif + +#ifndef UNIX + #ifndef DOS + #error Please define macro UNIX or DOS. + #endif +#else + #ifdef DOS + #error Both macros UNIX and DOS are defined! + #endif +#endif + +#ifdef DOS +const char *const DOS_HelpText = + +"\n" +"a2tools - utility for transferring files from/to Apple II .dsk images\n" +" Copyright (C) 1998, 2001 Terry Kyriacopoulos\n" +"\n" +" Usage:\n" +"\n" +" a2 dir \n" +" a2 out [-r] []\n" +" a2 in [-r] [.] []\n" +" a2 del \n" +"\n" +" -r (raw mode): Suppress all filetype-dependent processing\n" +" and copy everything as-is.\n" +"\n" +" : one of t,i,a,b,s,r,x,y (do not use -)\n" +" : base address in hex, for type B (binary)\n" +"\n" +" Quotes may be used around names with spaces, use \\\"\n" +" to include a quote in the name.\n" +; +#endif + +/* Apple Integer and AppleSoft BASIC tokens. */ + +const char *const Integer_tokens[] = { + +" HIMEM:", "", " _ ", ":", +" LOAD ", " SAVE ", " CON ", " RUN ", +" RUN ", " DEL ", ",", " NEW ", +" CLR ", " AUTO ", ",", " MAN ", +" HIMEM:", " LOMEM:", "+", "-", +"*", "/", "=", "#", +">=", ">", "<=", "<>", +"<", " AND ", " OR ", " MOD ", +" ^ ", "+", "(", ",", +" THEN ", " THEN ", ",", ",", +"\"", "\"", "(", "!", +"!", "(", " PEEK ", " RND ", +" SGN ", " ABS ", " PDL ", " RNDX ", +"(", "+", "-", " NOT ", +"(", "=", "#", " LEN(", +" ASC(", " SCRN(", ",", "(", + +"$", "$", "(", ",", +",", ";", ";", ";", +",", ",", ",", " TEXT ", +" GR ", " CALL ", " DIM ", " DIM ", +" TAB ", " END ", " INPUT ", " INPUT ", +" INPUT ", " FOR ", "=", " TO ", +" STEP ", " NEXT ", ",", " RETURN ", +" GOSUB ", " REM ", " LET ", " GOTO ", +" IF ", " PRINT ", " PRINT ", " PRINT ", +" POKE ", ",", " COLOR=", " PLOT ", +",", " HLIN ", ",", " AT ", +" VLIN ", ",", " AT ", " VTAB ", +"=", "=", ")", ")", +" LIST ", ",", " LIST ", " POP ", +" NODSP ", " NODSP ", " NOTRACE ", " DSP ", +" DSP ", " TRACE ", " PR#", " IN#" + +}; + + +const char *const Applesoft_tokens[] = { + +" END ", " FOR ", " NEXT ", " DATA ", +" INPUT ", " DEL ", " DIM ", " READ ", +" GR ", " TEXT ", " PR#", " IN#", +" CALL ", " PLOT ", " HLIN ", " VLIN ", +" HGR2 ", " HGR ", " HCOLOR=", " HPLOT ", +" DRAW ", " XDRAW ", " HTAB ", " HOME ", +" ROT=", " SCALE=", " SHLOAD ", " TRACE ", +" NOTRACE ", " NORMAL ", " INVERSE ", " FLASH ", +" COLOR=", " POP ", " VTAB ", " HIMEM:", +" LOMEM:", " ONERR ", " RESUME ", " RECALL ", +" STORE ", " SPEED=", " LET ", " GOTO ", +" RUN ", " IF ", " RESTORE ", " & ", +" GOSUB ", " RETURN ", " REM ", " STOP ", +" ON ", " WAIT ", " LOAD ", " SAVE ", +" DEF ", " POKE ", " PRINT ", " CONT ", +" LIST ", " CLEAR ", " GET ", " NEW ", + +" TAB(", " TO ", " FN ", " SPC(", +" THEN ", " AT ", " NOT ", " STEP ", +" + ", " - ", " * ", " / ", +" ^ ", " AND ", " OR ", " > ", +" = ", " < ", " SGN ", " INT ", +" ABS ", " USR ", " FRE ", " SCRN(", +" PDL ", " POS ", " SQR ", " RND ", +" LOG ", " EXP ", " COS ", " SIN ", +" TAN ", " ATN ", " PEEK ", " LEN ", +" STR$ ", " VAL ", " ASC ", " CHR$ ", +" LEFT$ ", " RIGHT$ ", " MID$ ", " ", + +" SYNTAX ", " RETURN WITHOUT GOSUB ", +" OUT OF DATA ", " ILLEGAL QUANTITY ", +" OVERFLOW ", " OUT OF MEMORY ", +" UNDEF'D STATEMENT ", " BAD SUBSCRIPT ", +" REDIM'D ARRAY ", " DIVISION BY ZERO ", +" ILLEGAL DIRECT ", " TYPE MISMATCH ", +" STRING TOO LONG ", " FORMULA TOO COMPLEX ", +" CAN'T CONTINUE ", " UNDEF'D FUNCTION ", + +" ERROR \a", "", "", "" + +}; + +#include +#include +#include +#include + +#define FILETYPE_T 0x00 +#define FILETYPE_I 0x01 +#define FILETYPE_A 0x02 +#define FILETYPE_B 0x04 +#define FILETYPE_S 0x08 +#define FILETYPE_R 0x10 +#define FILETYPE_X 0x20 +#define FILETYPE_Y 0x40 +/* X - "new A", Y - "new B" */ + +#define MAX_HOPS 560 + +#define VTOC_CHK_NO 6 +const unsigned char vtoc_chk_offset[VTOC_CHK_NO] = + { 0x03, 0x27, 0x34, 0x35, 0x36, 0x37}; +const unsigned char vtoc_chk_value[VTOC_CHK_NO] = + { 0x03, 0x7a, 0x23, 0x10, 0x00, 0x01}; + +FILE *from_file=NULL, *to_file=NULL, *image_fp=NULL; +char *extfilename, *extfilemode; + +unsigned char padded_name[30], dir_entry_data[35]; +unsigned char vtocbuffer[256]; +unsigned int begun, baseaddress, rawmode, filetype, new_sectors; +unsigned long dir_entry_pos; + +void quit(int exitcode, char *exitmsg) { + fprintf(stderr,"%s",exitmsg); + if (image_fp) fclose(image_fp); + if (from_file) fclose(from_file); + if (to_file) fclose(to_file); + exit(exitcode); + } + +int seek_sect (unsigned int track, unsigned int sector) { + if (track >= 35 || sector >= 16) + quit(1,"seek on .dsk out of range.\n"); + return fseek(image_fp, (track*16uL+sector)*256, SEEK_SET); + } + +void read_sect (int track, int sector, unsigned char buffer[256]) { + int i; + seek_sect(track, sector); + for (i=0; i<256; i++) buffer[i]=fgetc(image_fp); + } + +void write_sect (int track, int sector, unsigned char buffer[256]) { + int i; + seek_sect(track, sector); + for (i=0; i<256; i++) fputc(buffer[i],image_fp); + } + +int dir_do (int (*what_to_do)(unsigned char *) ) { + unsigned char buffer[256]; + unsigned int cur_trk, cur_sec, i, found, hop; + hop=found=0; + buffer[1]=vtocbuffer[1]; + buffer[2]=vtocbuffer[2]; + while(++hop < MAX_HOPS && !found && (buffer[1] || buffer[2])) { + cur_trk=buffer[1]; + cur_sec=buffer[2]; + read_sect (buffer[1],buffer[2],buffer); + i=0x0b; + while(i<=0xdd && !(found=(*what_to_do)(&buffer[i]))) i+=35; + if (found) dir_entry_pos=(cur_trk*16uL+cur_sec)*256+i; + } + if (hop >= MAX_HOPS) quit(2,"\n***Corrupted directory\n\n"); + return found; + } + +int dir_find_name(unsigned char *buffer) { + int j; + j=0; + if (buffer[0] == 0xff || buffer[3] == 0) return 0; + while(j<30 && padded_name[j]==(buffer[j+3] & 0x7f)) j++; + if (j != 30) return 0; + for (j=0; j<35; j++) dir_entry_data[j]=buffer[j]; + return 1; + } + +int dir_find_space(unsigned char *buffer) { + return (buffer[0] == 0xff || buffer[3] ==0); + } + +int dir_print_entry(unsigned char *buffer) { + int j; + if (buffer[0]!=0xff && buffer[3]!=0) { + /* entry is present */ + printf(" "); + if (buffer[2] & 0x80) printf("*"); else printf(" "); + switch(buffer[2] & 0x7f) { + case FILETYPE_T : printf("T"); break; + case FILETYPE_I : printf("I"); break; + case FILETYPE_A : printf("A"); break; + case FILETYPE_B : printf("B"); break; + case FILETYPE_S : printf("S"); break; + case FILETYPE_R : printf("R"); break; + case FILETYPE_X : printf("X"); break; + case FILETYPE_Y : printf("Y"); break; + default : printf("?"); + } + printf(" %03u ",buffer[33]+buffer[34]*256u); + for (j=3; j<33; j++) + printf("%c",(buffer[j] & 0x7f)); + printf("\n"); + } + return 0; + } + +int preproc (int procmode) { + /* procmode: 0 - raw, 1 - text, 2 -binary */ + static unsigned long bytepos, lengthspec_pos; + static int c; + unsigned int sect_pos; + sect_pos=0; + if (!begun) { + begun = 1; + bytepos = 0; + c=fgetc(from_file); + if (procmode == 2) { + fputc((baseaddress & 0xff),image_fp); + fputc((baseaddress >> 8),image_fp); + /* we don't know the length now, so save the spot in the image */ + lengthspec_pos=ftell(image_fp); + fputc(0xff,image_fp); + fputc(0xff,image_fp); + sect_pos = 4; + } + } + while (c != EOF && sect_pos < 256) { + if (procmode == 1) { + if ((c & 0x7f) == '\n') c = '\r'; + c |= 0x80; + } + fputc(c,image_fp); + c=fgetc(from_file); + sect_pos++; + bytepos++; + } + while (sect_pos++ < 256) fputc(0,image_fp); + if (c == EOF && procmode == 2) { + /* now we know the length */ + fseek(image_fp, lengthspec_pos, SEEK_SET); + fputc((bytepos & 0xff),image_fp); + fputc((bytepos >> 8),image_fp); + } + return (c == EOF); + } + +void new_sector(unsigned int *track, unsigned int *sector) { + /* find a free sector, quit if no more */ + unsigned int byteoffset, bitmask; + int lasttrack, cur_track, cur_sector, direction; + /* force sane values, in case vtoc contains garbage */ + if (vtocbuffer[0x31]==1) direction=1; else direction=-1; + cur_track=lasttrack=vtocbuffer[0x30] % 35u; + cur_sector=15; + for (;;) { + byteoffset=0x39+(cur_track<<2)-(cur_sector>>3&1); + bitmask=(1 <<(cur_sector & 0x07)); + if (vtocbuffer[byteoffset] & bitmask) { + vtocbuffer[byteoffset]&=0xff^bitmask; + break; + } + else if (!cur_sector--) { + cur_sector=15; + cur_track+=direction; + if (cur_track >= 35) { + cur_track=17; + direction=-1; + } + else if (cur_track < 0) { + cur_track=18; + direction=1; + } + if (cur_track==lasttrack) quit(3,"Disk Full.\n"); + } + } + *track=vtocbuffer[0x30]=cur_track; + *sector=cur_sector; + vtocbuffer[0x31]=direction % 256u; + new_sectors++; + } + +void free_sector(int track, int sector) { + vtocbuffer[0x39+(track<<2)-(sector>>3&1)]|=1<<(sector&0x07); + } + +void postproc_B (void) { + static unsigned int filelength, bytepos; + unsigned int sect_pos; + sect_pos=0; + if (!begun) { + begun = 1; + bytepos = 0; + fgetc(image_fp); /* Ignore 2 byte base address */ + fgetc(image_fp); + filelength= fgetc(image_fp) + (fgetc(image_fp) * 256u); + sect_pos = 4; + } + while (bytepos < filelength && sect_pos < 256) { + fputc(fgetc(image_fp),to_file); + sect_pos++; + bytepos++; + } + } + +void postproc_A (void) { + static unsigned int bufstat, tokens_left, lastspot; + static unsigned char lineheader[4]; + unsigned int sect_pos, c; + sect_pos=0; + if (!begun) { /* first sector, initialize */ + begun = 1; + fgetc(image_fp); /* ignore the length data, we use */ + fgetc(image_fp); /* null line pointer as EOF */ + sect_pos = 2; + lastspot = 0x0801; /* normal absolute beginning address */ + tokens_left = bufstat = 0; + } + while(lastspot && sect_pos < 256) { + if (!tokens_left && !bufstat) bufstat = 4; + while (bufstat > 0 && sect_pos < 256) { + lineheader[4-bufstat]=fgetc(image_fp); + sect_pos++; + bufstat--; + } + if (!tokens_left && !bufstat && + (lastspot=lineheader[0]+lineheader[1]*256u)) { + tokens_left = 1; + fprintf(to_file,"\n"); + fprintf(to_file," %u ",lineheader[2]+lineheader[3]*256u); + } + while (tokens_left && lastspot && sect_pos < 256) { + if ((tokens_left=c=fgetc(image_fp)) & 0x80) + fprintf(to_file,"%s",Applesoft_tokens[(c & 0x7f)]); + else if (c) fprintf(to_file,"%c",c); + sect_pos++; + } + } + if (!lastspot) fprintf(to_file,"\n\n"); + } + +void postproc_I (void) { + static unsigned int filelength, bytepos; + static unsigned int bufstat, inputmode, quotemode, varmode; + static unsigned char numbuf[3]; + unsigned int sect_pos, c; + sect_pos=0; + if (!begun) { /* first sector, initialize */ + begun = 1; + filelength = fgetc(image_fp) + (fgetc(image_fp) * 256u); + sect_pos = 2; + bytepos = inputmode = bufstat = quotemode = varmode = 0; + } + /* inputmode: 0 - header, 1 - integer, 2 - tokens */ + /* varmode: 1 means we are in the middle of an identifier */ + while(bytepos < filelength && sect_pos < 256) { + if (inputmode < 2 && !bufstat) bufstat = 3 - inputmode; + while (bufstat > 0 && bytepos < filelength && sect_pos < 256) { + numbuf[3-bufstat]=fgetc(image_fp); + sect_pos++; + bytepos++; + bufstat--; + } + if (!bufstat && inputmode == 0) { + fprintf(to_file,"\n"); + fprintf(to_file,"%5u ",numbuf[1]+(numbuf[2]*256u)); + inputmode = 2; + } + if (!bufstat && inputmode == 1) { + fprintf(to_file,"%u",numbuf[1]+(numbuf[2]*256u)); + inputmode = 2; + } + while (inputmode == 2 && bytepos < filelength && sect_pos < 256) { + c=fgetc(image_fp); + sect_pos++; + bytepos++; + /* 0x28: open quote, 0x29: close quote, 0x5d: REM token */ + if (c == 0x28 || c == 0x5d) quotemode = 1; + if (c == 0x29) quotemode = 0; + /* Look for integer, unless in comment, string, or identifier */ + if (!quotemode && !varmode && c >= 0xb0 && c <= 0xb9) + inputmode = 1; + else { + /* Identifiers begin with letter, may contain digit */ + varmode = (c >= 0xc1 && c <= 0xda) || + ((c >= 0xb0 && c <= 0xb9) && varmode); + if (c == 0x01) inputmode = quotemode = 0; + else if (c & 0x80) fprintf(to_file,"%c",(c & 0x7f)); + else fprintf(to_file,"%s",Integer_tokens[c]); + } + } + } + if (bytepos >= filelength) fprintf(to_file,"\n\n"); + } + +void postproc_T (void) { + static unsigned int not_eof; + unsigned int sect_pos, c; + sect_pos=0; + if (!begun) begun = not_eof = 1; + while (not_eof && sect_pos < 256 && + (not_eof=c=fgetc(image_fp))) { + c &= 0x7f; + if (c == '\r') c='\n'; + fputc(c,to_file); + sect_pos++; + } + } + +void postproc_raw (void) { + unsigned int sect_pos; + for (sect_pos=0; sect_pos < 256; sect_pos++) + fputc(fgetc(image_fp),to_file); + } + +void a2ls (void) { + unsigned int trkmap, free_sect, i, j; + free_sect = 0; + + /* count the free sectors */ + for (i=0x38; i<=0xc0; i+=4) { + trkmap=vtocbuffer[i]*256u + vtocbuffer[i+1]; + for (j=0; j<16; j++) free_sect += ((trkmap & (1<= MAX_HOPS) quit(5,"Corrupted sector list\n\n"); + write_sect(0x11, 0, vtocbuffer); + } + +void a2out (void) { + unsigned char listbuffer[256]; + unsigned int hop, next_trk, next_sec, i, j; + void (*postproc_function)(void); + if (!dir_do(dir_find_name)) quit(6,"File not found.\n"); + hop = begun = 0; + next_trk=dir_entry_data[0]; + next_sec=dir_entry_data[1]; + filetype=(dir_entry_data[2] & 0x7f); + + if (filetype == FILETYPE_T) postproc_function= postproc_T; + else if (filetype == FILETYPE_B) postproc_function= postproc_B; + else if (filetype == FILETYPE_A) postproc_function= postproc_A; + else if (filetype == FILETYPE_I) postproc_function= postproc_I; + else if (!rawmode) + quit(7,"File type supported in raw mode only.\n"); + if (rawmode) postproc_function= postproc_raw; + +#ifdef DOS + extfilemode="w"; + if (rawmode || filetype == FILETYPE_B) { + extfilemode="wb"; + if (to_file) + quit(8,"stdout not allowed for binary output.\n"); + } +#else + extfilemode="w"; +#endif + + if (!to_file && !(to_file=fopen(extfilename,extfilemode))) { + perror(extfilename); + quit(9,""); + } + + while(++hop < MAX_HOPS && (next_trk || next_sec)) { + read_sect(next_trk, next_sec, listbuffer); + next_trk=listbuffer[1]; + next_sec=listbuffer[2]; + for (i=0x0c; i <= 0xfe; i+=2) + if (!listbuffer[i] && !listbuffer[i+1]) { + if (filetype != FILETYPE_T || !rawmode) { + next_trk=next_sec=0; + break; + } + else for (j=0; j<256; j++) fputc(0,to_file); + } + else { + ++hop; + seek_sect(listbuffer[i],listbuffer[i+1]); + (*postproc_function) (); + } + } + if (hop >= MAX_HOPS) quit(10,"Corrupted sector list\n\n"); + + fclose(to_file); + } + +void a2in (void) { + unsigned char listbuffer[256], databuffer[256]; + unsigned int i, curlist_trk, curlist_sec, listentry_pos, list_no; + unsigned int curdata_trk, curdata_sec, procmode; + unsigned int newlist_trk, newlist_sec; + int c; + new_sectors=list_no=procmode=0; + if (!rawmode) { + if (filetype==FILETYPE_T) procmode=1; + else if (filetype==FILETYPE_B) procmode=2; + else quit(11,"This type is supported only in raw mode.\n"); + } + +#ifdef DOS + extfilemode="r"; + if (procmode !=1) { + extfilemode="rb"; + if (from_file) + quit(12,"stdin not allowed for binary input.\n"); + } +#else + extfilemode="r"; +#endif + + if (!from_file && !(from_file=fopen(extfilename,extfilemode))) { + perror(extfilename); + quit(13,""); + } + + if (dir_do(dir_find_name)) quit(14,"File exists.\n"); + if (!dir_do(dir_find_space)) quit(15,"No space in directory.\n"); + if (padded_name[0] < 'A') + quit(16,"Bad first filename character, must be >= 'A'.\n"); + for (i=0;i<30;i++) + if (padded_name[i]==',') + quit(17,"Filename must not contain a comma.\n"); + for (i=0;i<30;i++) dir_entry_data[i+3]=padded_name[i]|0x80; + dir_entry_data[2]=filetype; + + new_sector(&curlist_trk,&curlist_sec); + dir_entry_data[0]=curlist_trk; + dir_entry_data[1]=curlist_sec; + for (i=0;i<256;i++) listbuffer[i]=0; + listentry_pos=0; + + for (;;) { + if (!rawmode || filetype!=FILETYPE_T) { + new_sector(&curdata_trk,&curdata_sec); + listbuffer[0x0c+(listentry_pos<<1)]=curdata_trk; + listbuffer[0x0d+(listentry_pos<<1)]=curdata_sec; + seek_sect(curdata_trk,curdata_sec); + if (preproc(procmode)) break; + } + else { + /* Check for all-zero sectors for sparse T file */ + for (i=0;i<256;i++) databuffer[i]=0; + i=0; + while((c=fgetc(from_file))!=EOF && i<256) databuffer[i++]=c; + while(i && !databuffer[i-1]) i--; + if (!i) { + listbuffer[0x0c+(listentry_pos<<1)]=0; + listbuffer[0x0d+(listentry_pos<<1)]=0; + } + else { + new_sector(&curdata_trk,&curdata_sec); + listbuffer[0x0c+(listentry_pos<<1)]=curdata_trk; + listbuffer[0x0d+(listentry_pos<<1)]=curdata_sec; + write_sect(curdata_trk,curdata_sec,databuffer); + } + if (c == EOF) break; + ungetc(c,from_file); + } + if (++listentry_pos >= 0x7a) { + new_sector(&newlist_trk,&newlist_sec); + listbuffer[1]=newlist_trk; + listbuffer[2]=newlist_sec; + write_sect(curlist_trk,curlist_sec,listbuffer); + curlist_trk=newlist_trk; + curlist_sec=newlist_sec; + for (i=0;i<256;i++) listbuffer[i]=0; + listentry_pos=0; + listbuffer[5]=(++list_no*0x7a) & 0xff; + listbuffer[6]=(list_no*0x7a) >> 8; + } + } + + listbuffer[1]=listbuffer[2]=0; + write_sect(curlist_trk,curlist_sec,listbuffer); + write_sect(0x11, 0, vtocbuffer); + dir_entry_data[33]=new_sectors & 0xff; + dir_entry_data[34]=new_sectors >> 8; + fseek(image_fp,dir_entry_pos,SEEK_SET); + /* writing ff first ensures directory is always in a safe state */ + fputc(0xff,image_fp); + for (i=1;i<35;i++) fputc(dir_entry_data[i],image_fp); + fseek(image_fp,dir_entry_pos,SEEK_SET); + fputc(dir_entry_data[0],image_fp); + + fclose(from_file); + } + +int main (int argc, char *argv[]) { + char *image_name, *image_mode, *a2_name, *basename, *typestr; + unsigned int i, bad_vtoc; + char *ls_cmd, *in_cmd, *out_cmd, *rm_cmd; + char *ls_hlp, *in_hlp, *out_hlp, *rm_hlp, *general_hlp; + int dos, x, image_rw=0; + void (*command)(void) = NULL; + +#ifdef DOS + dos=1; + ls_cmd="dir"; + in_cmd="in"; + out_cmd="out"; + rm_cmd="del"; + ls_hlp=in_hlp=out_hlp=rm_hlp=general_hlp=(char *) DOS_HelpText; +#else + dos=0; + general_hlp="Invoke as a2ls, a2in, a2out, or a2rm.\n"; + ls_cmd="a2ls"; + ls_hlp="Usage: a2ls \n"; + in_cmd="a2in"; + in_hlp= + "Usage: a2in [-r] [.] []\n"; + out_cmd="a2out"; + out_hlp="Usage: a2out [-r] []\n"; + rm_cmd="a2rm"; + rm_hlp="Usage: a2rm \n"; +#endif + + baseaddress=0x2000; /* default, hi-res page 1 */ + rawmode = begun = 0; + extfilename = a2_name = image_name = ""; + +#ifdef DOS + basename=""; + if (argc >=2) basename=argv[1]; +#else + basename=argv[0]; + /* strip off any leading directories */ + basename+=(i=strlen(basename)); + while(i-->0 && *--basename!='/'); + if (*basename=='/') basename++; +#endif + + if (!strcmp(basename,ls_cmd)) { + if (argc !=2+dos) quit(18,ls_hlp); + else { + image_name=argv[1+dos]; + image_rw=0; + command= a2ls; + } + } + else if (!strcmp(basename,out_cmd)) { + if (argc > 1+dos && !strcmp(argv[1+dos],"-r")) rawmode=1; + x=3+dos+rawmode; + if (argc != x && argc != x+1) quit(19,out_hlp); + else { + image_name=argv[x-2]; + image_rw=0; + a2_name=argv[x-1]; + if (argc-x) + extfilename=argv[x]; + else + to_file=stdout; + command= a2out; + } + } + else if (!strcmp(basename,in_cmd)) { + if (argc > 1+dos && !strcmp(argv[1+dos],"-r")) rawmode=1; + x=4+dos+rawmode; + if (argc != x && argc != x+1) quit(20,in_hlp); + else { + typestr=argv[x-3]; + image_name=argv[x-2]; + image_rw=1; + a2_name=argv[x-1]; + if (argc-x) + extfilename=argv[x]; + else + from_file=stdin; + switch(typestr[0]|0x20) { + case 't': filetype=FILETYPE_T; break; + case 'i': filetype=FILETYPE_I; break; + case 'a': filetype=FILETYPE_A; break; + case 'b': filetype=FILETYPE_B; break; + case 's': filetype=FILETYPE_S; break; + case 'r': filetype=FILETYPE_R; break; + case 'x': filetype=FILETYPE_X; break; + case 'y': filetype=FILETYPE_Y; break; + default: quit(21,": one of t,i,a,b,s,r,x,y without -\n"); + } + if (typestr[1]=='.') { + if (filetype==FILETYPE_B) + sscanf(&typestr[2],"%x",&baseaddress); + else quit(22,"Base address applicable to type B only.\n"); + } + else if (typestr[1]!=0) + quit(23,"The only modifier for is .\n"); + command= a2in; + } + } + else if (!strcmp(basename,rm_cmd)) { + if (argc != 3+dos) quit(24,rm_hlp); + else { + image_name=argv[1+dos]; + image_rw=1; + a2_name=argv[2+dos]; + command= a2rm; + } + } + else + quit(25,general_hlp); + + if (image_rw==1) image_mode="rb+"; else image_mode="rb"; + if (!(image_fp=fopen(image_name, image_mode)) || seek_sect(0, 0)) { + perror(image_name); + quit(26,""); + } + + /* prepare source filename by padding blanks */ + i=0; + while(i<30 && a2_name[i]) padded_name[i]=a2_name[i++] & 0x7f; + while(i<30) padded_name[i++]=' '; + + /* get VTOC and check validity */ + read_sect(0x11, 0, vtocbuffer); + bad_vtoc=0; + for (i=0; iZ*R_L0-Hx6oCXV1d)tENQeZIhK!K3Nl0iBm;eDYLc(-c2b>#1 z$5u#piQ}k8amJZJ@i@wG=ja^N2E7;)O-3D+$BY6hBKWAL5F=m`Lg>1`UDX}H2l( zm;fzwyVKkgjfE*m?u-}N!{5%!|JFUyj|w94en5#g{&kX=|Lq1|x~v$(pBSXijK>1$ zJHW;>!0{!^G&Gy@B@?K0?yn(?f>EuQKGlvF;o8tdY{c8iqGv&-_;n6f}JH&gaN{kS;~R zN-+t*9%FckVGnt4R3Pm!5{TbUtnH#bG@Crw{_1*?)x{ffztQ^MpOS{|CB!5K?n2R*uC*&-+U7O2T2c+o8KE7NEe}*CK6(`!bTK+NkS&A(2PP032|D% zhr+!iL^2Dw6jv>GxJr(BgvUCtuujM~J7{@v~j zbtO9G(ro{moWJljhKOc0?=?nlp6K!yhV){Hk=N1UKE1e)k(W($sZFdrkm6d}2};#9 zQWGn+aQ?_RkIAnly5mAGgRlX;J*K)`x$RD=EBDZgtjwkwyZwjAi)J*faB3aRLCmBg!v=DC{8tM5CI975*w9%%e7#)N9aBV5ZF1!WO64;$_ ztm+t$90RkaGM*7O)tlnme#RxuzQHvO*W^%Ggk^UAZpQZ&!wg2JA{wXwa_2g(7yv93pX`$;3J3(Uj)cJtSC_@iI*5 z@JVBbGsL2T$#J<}HxeZUv}ekAKd*RL^Z-bhxyS!)VDZqoR0_`#XMp9UuVg(F$0 zlTID?9>q>uU_Qz$8c1D^S%99=P`tA#^ZBS#^M->boiBOk1WZqD1jFC%NCNSv zhOwB+PI%#$0M*G{F`1}E`OjEkGcByI@Fzxtm+yA;!lq1ksOpYf;~w(rIFfs)?|h(o zQ0l~{1g5X_E)Ck~!4%^*^B|G@$J^`A6kcSt?KvVPy^Jk0X&2|8i#GlIhXu%@^d z)M<{0fUH5&El8#Aco26Jxv&N1xHv20j@`HY3t$N3A#-~rnk!=l>}TFb61*Q+eaP9MXz zZOvpIYWx^hLu=A|{a9~Wp*Ov4M<$CYo0i4K=IqXKEF5NTH#ZjZDRf;N#)!z$KHlZp zF+oF}IE3m9rAMou8V@I|6lwiCvfy*Uo?rwMcV zRl=MSt*#meQFNnM25P2UuQ*$)rZGHR%is*^tYHTAs{CY&EsE;!#rMt#tzM6e;tdvEV37M|1Cr*)O{Xx z1i?pHM0X>+W~AFONQg2L90kh;51*hOF(xr%zltoRWiZkGxxb5TjkJ@d*J^fH;Le<( zTM-WbmI>*E-ejHfhrO=Q3PAQ{!p@^T&|GO=mguLVJQFMdoXmB2+T1N z?D<|7!8SDHfEYqUO#~P^l>n7QR0KOt>S@nT3+Ai^MvutX-)&P0X^GWJ@n&TzEiqcD z)vRRDk`^QT|7KBA{DnN)#f5&4-gxx(Q}m|6M1;@&5%zAbop}pBjACJFN6C(&ux`L; zt{xY92QAHLnW(h{%sWZVYe&S`&&boqxLiB;F;Ho$R(^1tEA$=kExB^??kJP?+;$iTgrv+@ zu1DB~$tFwvFKxB2H`YtZ3xRK%lV0j+oz^YBJm0kc?#iUd^TqQY0$!4!GoLiYof z2-q0F;8#+8uXQk!fx8EAYS}#CbcNvl3bi)6O0fId?mI;n0_pCa9TxWKlgu{9pmUoe z;*^VeF&iC`r%y0J$KcbSGibtf-Fr5oFT~szXbgn7=(YlsEH2#U=taYRr))+;=`)%J z*|%*uORd4t-^S~ZxEQ3jjaQp`)uw*=weO&srVH}J7wCwM;n{|8H;Hz3d8o5q#T;~; zZM*mEWrvn=&r5d&9A{^#vE=roVkooqio>Mix1o#6F%uL|+j_kj*KpItV`W6Si}Hf9 zGG~bS+u+u&LH{Sr(@x;Ov=KCXhsoh@IZIbX_i76Qwdt(8&tDSv-P;^Jkj*)# zd_+Ef*r;yAWL|VcN&l#Q)j@;#d2*S14eIjYTSJFg|5NGJjZpnlb*+d;ekd z)!zFZ_>KLT7Fs|HVi8HF2K7CEA!BQCX22SxNgTM zSXDWW(Vr7oWjW3riSKswe1e~|pW)}ssraXM!ONZuIKButz6v~EgXM-R44%1)!OKW!Ac3nGWPiZmh!}$jYLgsF z0fX;;gP<@-G!8H89QFQ?T@3cWVmHJ*no4f5OL1d>xrq$B=IBR0%CcxsCJ$KJGV z4z7eKCG-g+n?;}Sx;N7&RvtO@X(mc0eI^n_5j+K=q|)bX>YcxZr%MI5*MnPhK=yMT2J z1j+c#ZE)_?t$WM>_--NIui?D`6Et7{{ndWp{xgsRf*qk=_xj*{yD_JwBSEZHXWsW0 zW+;=iI4+|>+suCOH(IB zp{~^0RBX5S3!h97^qr?ilK@_m9|qUHJK3)(y_A`|73zrUVU6hqn#43BL5|`rb%9tk@2}>kB77oZEi*poQ)is>dVom37xD&g1J*vR>H-}$x_$0>{Q9WCJ%e&+ja zWykxD8s8r*3$l}~9+sV{7#Rn<>*TjDkX^jwuxiP6hdnA)eG{0bZ7<+otyBKFy0n9( zmD>JF>mTJ|>g7Fif(|RnQkfYWFHkk3n4Iz#ktehvV3ZUL?HTv~EDbub9fD1{lN3hk za8}Eeb{E!J52>N1B$Qr8KBkF7Q)_gS6XR#Ap+x^I6)oX|jL@OMB%zbvt5Ofmkg8?( zWo<5gBz5T{xWZ)LR(Tk5aE>l8l%zekUdt&=a%Lnd>l>lSO|7lJ#c(Wg| ze!Ovn?{)e<>}ssdUxmwzXj7?HbC|Ma1Ii2e-QsRQoH0na$QUj(YWrhd4wdZQ9%!;Y zZd02_27lL_G)?tiN^LTREk?~-`_dl|Z&1StMqim~Q2y@!cIwuaUf{k1&Gmh4aP%te zs4*-1@XIQD@XIKF_N`VwQ=Y@SpgfJtCHoKtYY?5vzwC!ww`2XR@cZG|k!<#L3&d;j ztBXaJ5}=voHpc*U-kIuVXEhzWeps;4=zkMozMr&=pv1fhSn$fPME-;VD>4uNDclul zHiqwF!nZRrA>q{s<5vdUy1G~0Ou=5JqF|<&YHM$SW4=;<#{(ZLqiOvjW(n#ND=M$9 zU2=!kW1>7if=(Z%T?!)e$e+TMk?<))jOCEJc^q=%D;!UX^S^1=IKCz5P`5vCz?wrg zQ4$)@CakZOIJ}zSdm$FOK&p}Z?fy5}@W5sHyghv3viyy``N{Aj2Flu_28|0&?zjvR z+K9wS8pyB<`p4Q@GZP;CCt2G!S{~7Cd)z<-@&+OQobOHYG;*&u;K z8w}%!@~ZjSl6;li#V=j{H;n4%V!umyJ^RpJmOu~9B^9?{Y2ms9y1F^?cJoa^+4s#< z_YJONarDH|(?<7>?jOaDj*J>N`i|=^T$eUFXLQ?W>*&PMl|E&vJHvO$ z(v;-8bi)RdPvI4#Pnkd=wwXsgd~tFAD=^9>7imQGpW&)&sH=$iFario#S(Q)cWr;9 zx6|h}zy61WUW37V>Jhcf-h4+vw#Y-zX%UA?%RjxQ$<5ilQba1Vo?7U?IDW$v-$lkf zsbH%2ZUjy5DvCbs3VOjt@%Dnn;zGp(_o=Ehcfz*9kVUIygW2s*g#U;+LJFpKJFGZC z8AnNcdxZp`W&%2F!D4R?3h+L|(fcFv_mM~3FFdALAM0CfHTEPAcqh}A3$C=(us(=9 z;`vm$;jzBYAK&^;-$`R%@*9sQedwJ>afKh??gZ|KS2HJl^q8+j#S*&j7{cf=BDKUz z%LWbCOD)Ke2LjhCX|S$+>So5F`u3?h1bBXHZ5Mi8s+;fTK zN~))Ag*}Ud;k#3@_S>EMw{uh4YiGE{-dQtMg0J3 z5pPeCp1MU-vuS-xJA+*^LxLTDPuy|>FI!Hq4^2p!Jz*E6(R$`FLIdPkx+Xm1#LsE0 z4;(dnRdrhXxj*+EEM4B2*Jhd*DLdo6vGVo`ZrhfhtJ(eZ*IA>Pp%n=T%;Gd%PlAA< z1&{6P{O|^jt18x1lM6vf}79EyHzC|{)aKp)Uz8EUjsGw?LgVN zKv|@%?0c*)RaHMrGVGrAg>*nV;!_0QrJs3{gMTn3`!5Ygux!(VVbuN(KMFW{BX5OQ(1PckmvHdh8(yS7 zJbCJNG}? z!#N2!{Wk1UUok7zSFHF;{P!?(tjqB|X{)}Jd#J5?K<83Pe8t-37%%{;1D=>SFVMtc zP>Dn|b1wy@h;UWKOOkf>SwExp(@#6|`>V=J6B!S3x&9Kty(<)3|@#!J<`wnLkY z;d3N>nf3%y+gkP^!OByo&z&1s#)7aw#Kb&lxK>Q#<=yadR(dGQI-X^0|)*HV6N@Em}MjQ8Xq~`W*%U-Rlz*HHB zj1qg*&l7`aLDUB!tAfmrHEUbV=U9ys^lB#J2po&r4z&!E`v$XovvRzK((HpR#z6Hs zS`uwR$M>-0l=7@LlfUI0X|YDTQ_IfDZw*R))Y_NzBQr&pvrJgz1Xo}34L0JK57?VA zSI*IGPv781(c~Lk>>UOz%)ae5f5SOu6Rjk~SauGKz#{Dm_ktj|4BnQ1baO92v#~08 zVXC}tFzC1>uNjo8&w#p(`GcjmZGGny5Byn!CokeP zDf?*F?%3Qj%2NkV_Simdu}JTtk5NDg-!TaFz=U+!+lFMX@KMQ!oa6?_8KdKDR=@-# zm=`~9URJjWNz!P{@E(l(g-rSVOPJ~2eqYNO=O&~4_9fomavFvRSF0E$$5}m78-qzqriwv2Z(4rP3lk)J`v9nUzK@m0nh+lV!S<^ZvtmHys(nlSkt9)9POI2}|h-Q1(Ng8&YOFseBt z_at@s(qAzp5?kLOjN6+3HxIWJ;2$=ii_T|M{WcEBKT(0>8r6mJzSYT!ao^p^drc&I zCur{kvTuFzp4sn>4WIZJEKAkqJ;gx>J-S9b!#WCyDHgu0)S+;6>HP3_OL3n{x**-j z`4!e3pP&AlWYHwg!GcIO(o0k`(zhpz5ojy1&mnO)@&Q)5)p#l3Wu)VvKaJ3mWO~jZ8afTU z)MxAo+{s9vNt-!bl!^}&KA9|SU;|z@(9Csqb5AA{(kbOViAB4ZC^d6|JGsD8Hn5os zY+ySB=}#sHma~E7oIadl4&JT8WFqdo%!oS6Ogu(9>k79g6LAc729j+bV+4n1@Sai9 zaxVXv_j`FYQO3$aqFg6mha3TFOO|^4UFI3nJz@E7Rpq5l>_kE$G!i=HyvULzIQttq_Hed`qINC4vxK%k3f2XG&Tl{!0@tFns=BvAZdck1UavMPQ$uQis38oPTh`&C)@tVsAo#S9xP67`Y9MDCyEAV}D>N zlYL;)aOmM&pqZHyNR{4|K9i?Mq@!RSVx{J^%#8Is`kW5=<-lU3gi`5%zr*A|8SxL8 zJ;r@zlK+m|zQKehido)@IVYE^Qm2BG$GV8ZRmu-t&TU_^6mnFv>}hINJpK~#my|}x zuehg^f5kn6zh{%DJdo~~6v%rnIZ(JOdGJA8q}=Z#)4s^sJ^O*Twto1Clouop2b{Kk zOL5qP+yg|4yttWW4W}A>-)(kEZx}mgL-*2PcE9^h>1%FG8h?A~`DdoJ?|Sglt>?BL zl{%#ZbLEj_1Mi+KCy@;o;l0cSaqwUkuRN_?`2xe_=j?(nG0fd^Vp{vfQ>nX4CufKW zY(~MIUfx%b;bnH0+Il;~O-EeDcW@0445$A-d9Lwe%%?Niiu)_+%fOT!$*1B2O~n5e zlLxgCtB%~^a*qs= zIjBp@ua3Aa8%(%zgT0$q^iIcrbM^hU{i-@+Q@nS%e-pNwuJg|#n=CbQHKBRvZG9yS zJ$q8UW_kG~mv0kGnr*=n7Ky4!h41YyVURJFaQK1u?|K7H%|E% z-@Cd?>`0npo>_C>I43sA4MbUuuJxd>3_UkbLWgGD)R4O2GiH=ny$(uvsC0`|Vh)s8 zm8r@Usf06{W=lPjZg%QGr_R?%Ea18PE-?<22;=4a3z76#m{L$#M{eTU3euBS-!)u$vpm6()C+HD7P!WyN5ZkS*FdO9W4pTg6U!S#54z#Vn6>K=oP?ps?); zB3RiC87Ng6t7GDX8M7I4nqr%1IJ=(m9ak+Ut4|mlgTtyL3VP*euY)72BNF~O2DNJ? z)itlD5NhAaQZbWBjI)T*YpO;TiEA5C1OE!%A9AMMK`zjxQT{7E>D5_w>MZaaj3R)$ zG%aTTD&{ljA{{K?k_f17j^K0&2BnzkNc{_#M2uxfSRkun6PzX3%a8Sgtzr&1;l~LT zSe$B??zF1K)*v7DQ%G|a7)dmE7vh1S?trcNh`$+r$&T%06^8Ym(yqK6<93uv7r&u~ zv?#AjOyCt-9H+DX?0{<)sBn}qC2%#v;a{r0!iKasFAq{kr~gccwxc0!550mLqD%5J z)ur)VgWdTS7Ry!yfP>+|^Z)8GJOfW1RhCr7?kR|Ej3Xkv`}LJA^z65@577iLYCG`o z)Hab=oBO&*yVo3@&j>@>()~9VT{vowpw1v}99Ni>By~UU!)X;Aq3rn@S1(lWIDcVU z5+hnw97D*G8Khy7kw{vE+aJzcThfo3)GY#i0Y0_g?7^w#%@fDU|OIxgNq z_uAo0jeI@5%A;6O!-#B+9Eo66KzA{z6)k zJ*oEF4pit(^&t_%9q@O!MG$yg9u{?NR4Z`CIDIPP`rg3m$oc})_Xh5hFfZU9EBj(k zMj2;)W6vzazEKc}tyai+hnpr;eD9Pt~lQ$*%3m+w<*)F9& zN^l(Z_->lh_oPzC6N;qjH~6<+itVq2;C<*m3~IMIIH$b#Y|O?v)m|NRXdx1UjG8_@ zcL(t4^=UZi*fdi$NlUG2iM5T_HU}k$p#SpH}N@$NID@-EE0>hyPT9 z?z|goa1mq>AobzB#$tFN<2Hs*5M^ulVw}-=*cfo=fu}aitID04=4UB4s-{gTx~g$3 zM+L;T;eMEsFeERhd?!xQsJM*b_vy^gh1IRVMO+!*5k?;$?rlB~Bs~Sv&ti2S7R^(w zTDp7mB=&tJhk5oahPdOdNm`+j2k0iTMx2#@ieXSa{t$Dv7lMc=E2Odr+#}p=L^?jW zyI_= zrUM0M^2niEe?@cXCE1rAA4=x5BmpO{GsJi=7UE`RGp_imoAFHp0PU@jXA|j-4l{rVSYiU@i%yPe`O`jhiFl$V%%WMI(&Iu{Ip1B3 z^jPXbJ{!c4%=-5AASA`t;i7zyTCZ1#vwiVY)Na zljoFAo%FwH)#jS6r)w&^hAOLTuy@NsH6KlD$CmK9KX3D@aA?|V-$88d_4ReZ-!spY z(iJZveW_L!>HEi^h+din#{&nAh z`OBkz6?YAqIHW=1PayV9+CV4MsI9UR3ulA##06F)6Tyx)9@`+gxM``_ggJooXk7@c zXWFpQtw;2HECBGI(K=0@7d`ItSk=>j5l#-D&YR-a5gWZOye7Sm#(vt!36l);p~$t@YOR z){WN9)-Bctt&duNW8Go>SL-h83pfLL&Dvpo+xnjMp!FZtqt;KYr>wH|jJ3yl!8%|i zHqK_ZCD}&W#@I4#*|wW((`~bCb8V%za@!)?owgOWdRwE-YiqXMXWM3b)b_Y-hwT;H zTec&%Q?~Oq-agzu!9LS|n|+CWo!xJL)c!~N3-%Z7f3X`U{N(1m>Be7*@-HB?YVM zJmPZ7W#Lk-L489MU%Y31UEz``1$WhLTwc3smAmkt)9^HU-78}RR@JTj@y@_xj$4@M zuH7K4Yg|<~X{I1lde^Ua*LgfbEu1Q4f_9p-s&0KO5DX8iKT1EEejaG5ULi zx~4k!J>p$dzO|m5de0P)F3|X$DKs|J35}}-adQ3S+Q};>dnUUlZ=8IOFmY9*(9kFf zUQeBnGYRNJ!q%_LeB!}EUZX~nFI8r!^6q15jqyWEYS4O)krz94Z)7NDJ$tDvi`KtLP zl$8FM3`hpP6UkV7ClbL~QgRz=E422N^C)J~oJ#yUi@_a*FBX7Ddlt&dtLQuJU06_3 zhSo)ubMad_w*rO9s2YzieVa`3wJ&|6ER-xpOJN>mZ*I{7O1QXm;m~hY(Hy*&Xe^YL zITumfA3hy)Y_mWL;t?vVN}PC%TFWvjVa$EyIs44sF=cfeOV%RYhnQ6OCp+Q9)LeXtt(F zI4bQcq@p6%#}pk=bST37c@@(@6A$_u8~*$#ZgE8swavxR=X_mL^I?sER+LvkQk9@y zLZ9=a_8uDwtR*_ovhs?BMO5jfWz{7Wm9(v6K~d#=JYyZ|vZ{{K*XL2p>V@*Mk_yUR zMM>o%z2}nXkSeRnD=4{2m~kTfn(65?8-v0m(TvbRjkMB9Crxx(YG$QPte912 z10@H4H{kC^{9z_vJ-rK2oQ1yv{OR*mH)(y=E~=!xJ9MFF(=s}do#k{=-CQ7Sl1$)oZD#3ssuuDXOCHQSX4sjzVQs#dtibHC1Bf<9+UY4YZ)dQAMjNO6Sej zUKW-X(=z^5y2`4G;6h?^w5GIbemQ1%Ob7J6+%aU@3l@~j1O3|<6_r($R=Low946yf zP)^M-iVIg*UO}rCl|dsDiosY>Rms8uFy1NnU z^hAONdBi;A9c$_kPOLZFaKqe2x7)j3M0`S4P`6TSbl-yuaRP#XK&nV7DI#-7C8;2b ziHqDygv_bAUV&t;Bvw*fkJQA0RSuVQ01 zaJcIbG}kt+yxTJq0E$8!2<=+_ z8A~D{g0=U6-UhN^1@VZhs3d5ZM?TTG0jM+|)1$Y5s`XwGxc{{Cs=Mkvg4P$FSGuEJ zT-_%~xQScq4xIdx-s&5oooNH8+lb*IO(A8CdUinR4JiijIkn)m-t7^!EQsb3!pgg9 z-L)&RY@95t^P&RzM&T@BLeT`EQ=%G@Rzq1>+1Mb~f@m$?)~%}r4#<=G27+M|q-3y~ z95?;J?pTp@p*$CRBeBni zD9^!`VC?f1%Kv|TQi$Pa48H6RX2*Xq^4Y4YVI(sQYvN!RDXFGpHO(}PQLp}(Ojnoa zdxAQS!4E#ks>(2?1ljcB z!jKdrn_?O2NS{91Z^G~dGhX{;J&|6BPH6bCvY)whwQj%=(DJjEJ>?tX+da@p? zVNvj`tZi5=%oJ9yZNyF(mT%fd8ubdI6xbxZ1x>3MtVv#GD79#73AC3K@s zm`X|;nrhe9!~J?2R?^)$p~1UuMV(u7)!vnNX%1Nc=8(H4&RQ(;sMFP=8L4V)#DcKl z9-$G-Rt?=loOHJj3s;cCLbkqcRn)`NFsPGXSho%_8LLM)a=K;UxeG|tBi1!Ede__~ ztkdd;xYLWm3K~~qYt^C3x`w8DccZosIRw*XI#jG(Nf*)x4y)>hV5@4y+M!{ts%xrW zSx1UQv2LA~H^9fc!9x=wk=G3_#j7Mh`Sj2r6>WvEhSAhT2OpDYt$PiUf(DTkxz}g` z9&w`);dl)x*;uzSs&#$Cl+1NEdOTS9Qzn4ha5q^ a2 out basic.dsk "PLOT FUNCTION" prn + + Import the binary file "pics\airplane" into the disk image + "pics.dsk". Assign it a name of "AIRPLANE" and a base + address of 0x4000 (second hi- res graphics page): + + C> a2 in b.4000 pics.dsk AIRPLANE pics\airplane + +BUGS + - Works with 143360-byte DOS 3.3-order images only. + + - Does not tokenize plain-text BASIC source files, + although this is easily accomplished using the DOS + 3.3 EXEC command on such a file. + + - Doesn't handle multiple files, although it can eas- + ily be wrapped in shell scripts to enhance conve- + nience. + +AUTHOR + Terry Kyriacopoulos + + + + + 7 April 2001 + +