summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--INSTALL34
-rw-r--r--LICENSE341
-rw-r--r--src/Makefile113
-rw-r--r--src/config.c222
-rw-r--r--src/config.h68
-rw-r--r--src/disk.c610
-rw-r--r--src/disk.h39
-rw-r--r--src/diskimg.c263
-rw-r--r--src/diskimg.h99
-rw-r--r--src/main.c140
-rw-r--r--src/serial.c472
-rw-r--r--src/serial.h134
-rw-r--r--src/siorc.example17
-rw-r--r--src/tmpbin0 -> 92176 bytes
-rw-r--r--src/token.c257
-rw-r--r--src/token.h71
-rw-r--r--src/util.c165
-rw-r--r--src/util.h82
18 files changed, 3127 insertions, 0 deletions
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..e5f0064
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,34 @@
+
+Requirements
+============
+
+- an ANSI C compiler
+- a BSD, UNIX, GNU/Linux, or POSIX like operating system/environment for the
+ Makefile (though it may work elsewhere OK too). The features used are:
+
+ * POSIX terminal interface
+ * POSIX threads
+ * UNIX serial IO ioctls
+
+
+Building
+========
+
+This program does not unfortunately use the configure script, but I have been
+careful to write is as portably as possible.
+
+To build the software, type the following:
+
+ cd src
+ make depend
+ make
+
+This will output the executable atarisio. Copy this to whereever you like to
+keep your binaries.
+
+There is an example config file in the src directory called siorc.example.
+Copy this to ~/.siorc and edit as required.
+
+
+-------------------------------------------------------------------------------
+$Id: INSTALL,v 1.1.1.1 2007-05-07 02:05:54 ianc Exp $
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..abd3cf7
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,341 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
+
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+
+ <signature of Ty Coon>, 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/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..639860c
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,113 @@
+# atarisio - A UNIX back end for an Atari SIO2PC lead.
+#
+# Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# -------------------------------------------------------------------------
+#
+# $Id: Makefile,v 1.1.1.1 2007-05-07 02:05:54 ianc Exp $
+#
+
+
+# This CFLAGS assumes that gcc is being used.
+# Simply comment out if not, and replace as needed.
+#
+# Note that the -pthread is *IMPORTANT* - this is a FreeBSD extension
+# that links with the appropriate libc for pthreads. Consult your OS
+# documentation on what to do on other systems.
+#
+#
+CFLAGS = -g -Wall -Werror -pthread
+
+TARGET = atarisio
+
+SOURCE = main.c \
+ token.c \
+ config.c \
+ serial.c \
+ disk.c \
+ diskimg.c \
+ util.c
+
+OBJECTS = main.o \
+ token.o \
+ serial.o \
+ config.o \
+ disk.o \
+ diskimg.o \
+ util.o
+
+all: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+ $(CC) $(CFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)
+
+clean:
+ rm -f $(TARGET) $(OBJECTS) core
+
+depend:
+ makedepend -- $(CFLAGS) -- $(SOURCE)
+ if test -e Makefile ; then rm -f Makefile.bak ; fi
+
+# DO NOT DELETE THIS LINE -- make depend depends on it
+
+main.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+main.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+main.o: /usr/include/limits.h /usr/include/sys/limits.h
+main.o: /usr/include/machine/_limits.h /usr/include/sys/syslimits.h
+main.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+main.o: /usr/include/errno.h /usr/include/unistd.h /usr/include/sys/types.h
+main.o: /usr/include/machine/endian.h /usr/include/sys/select.h
+main.o: /usr/include/sys/_sigset.h /usr/include/sys/_timeval.h
+main.o: /usr/include/sys/timespec.h /usr/include/sys/unistd.h
+main.o: /usr/include/fcntl.h serial.h util.h disk.h config.h token.h
+token.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+token.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+token.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+token.o: /usr/include/ctype.h /usr/include/runetype.h token.h util.h
+config.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+config.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+config.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+config.o: config.h util.h token.h
+serial.o: /usr/include/pthread.h /usr/include/sys/cdefs.h
+serial.o: /usr/include/sys/types.h /usr/include/machine/endian.h
+serial.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+serial.o: /usr/include/sys/select.h /usr/include/sys/_sigset.h
+serial.o: /usr/include/sys/_timeval.h /usr/include/sys/timespec.h
+serial.o: /usr/include/sys/time.h /usr/include/time.h
+serial.o: /usr/include/sys/signal.h /usr/include/machine/signal.h
+serial.o: /usr/include/machine/trap.h /usr/include/limits.h
+serial.o: /usr/include/sys/limits.h /usr/include/machine/_limits.h
+serial.o: /usr/include/sys/syslimits.h /usr/include/sched.h
+serial.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+serial.o: /usr/include/ctype.h /usr/include/runetype.h /usr/include/unistd.h
+serial.o: /usr/include/sys/unistd.h /usr/include/termios.h
+serial.o: /usr/include/sys/ttycom.h /usr/include/sys/ioccom.h
+serial.o: /usr/include/sys/ttydefaults.h /usr/include/fcntl.h
+serial.o: /usr/include/errno.h serial.h /usr/include/stdlib.h util.h
+disk.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+disk.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+disk.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+disk.o: /usr/include/ctype.h /usr/include/runetype.h disk.h util.h diskimg.h
+disk.o: config.h token.h serial.h
+diskimg.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+diskimg.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+diskimg.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+diskimg.o: diskimg.h util.h
+util.o: /usr/include/stdio.h /usr/include/sys/cdefs.h
+util.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+util.o: /usr/include/string.h /usr/include/strings.h /usr/include/ctype.h
+util.o: /usr/include/runetype.h util.h /usr/include/stdlib.h
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..6d05005
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,222 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Config file
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+#include "token.h"
+
+static const char ident_h[]=ATARIOSIO_CONFIG_H;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+
+/* ---------------------------------------- CONFIG
+*/
+static char *serial_path=NULL;
+static char *prompt=NULL;
+
+static const struct
+{
+ const char *name;
+ void *var;
+ int is_int;
+} config[]= {
+ {"device", &serial_path, FALSE},
+ {"prompt", &prompt, FALSE},
+ {NULL, NULL, FALSE}
+ };
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void Parse(FILE *fp)
+{
+ char buff[1024];
+
+ while(fgets(buff,sizeof buff,fp))
+ {
+ size_t l;
+
+ l=strlen(buff);
+
+ if (buff[l-1]=='\n')
+ buff[--l]=0;
+
+ if (l>0 && buff[0]!='#')
+ TokenRun(buff);
+ }
+}
+
+
+static void Set(int argc, char *argv[])
+{
+ int f;
+
+ for(f=0;config[f].name;f++)
+ {
+ if (strcmp(config[f].name,argv[1])==0)
+ {
+ if (config[f].is_int)
+ {
+ int *i;
+
+ i=config[f].var;
+ *i=atoi(argv[2]);
+ }
+ else
+ {
+ char **p;
+
+ p=config[f].var;
+
+ if (*p)
+ free(*p);
+
+ *p=StrCopy(argv[2]);
+ }
+ }
+ }
+}
+
+
+static void Show(int argc, char *argv[])
+{
+ int f;
+
+ if (argc==2)
+ {
+ for(f=0;config[f].name;f++)
+ {
+ if (strcmp(config[f].name,argv[1])==0)
+ {
+ if (config[f].is_int)
+ {
+ int *i;
+
+ i=config[f].var;
+ printf("%s = %d\n",argv[1],*i);
+ }
+ else
+ {
+ char **p;
+
+ p=config[f].var;
+ printf("%s = %s\n",argv[1],*p ? *p:"undefined");
+ }
+ }
+ }
+ }
+ else
+ {
+ for(f=0;config[f].name;f++)
+ {
+ printf("%s = ",config[f].name);
+
+ if (config[f].is_int)
+ {
+ int *i;
+
+ i=config[f].var;
+ printf("%d\n",*i);
+ }
+ else
+ {
+ char **p;
+
+ p=config[f].var;
+ printf("%s\n",*p ? *p:"undefined");
+ }
+ }
+ }
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+int ConfigRead(void)
+{
+ static Command cmd[2]=
+ {
+ {"set",3,3,"set variable value","Set a variable",Set},
+ {"show",1,2,"show [variable]","Show variables",Show}
+ };
+
+ FILE *fp;
+ char path[FILENAME_MAX]={0};
+
+ serial_path=StrCopy("/dev/cuaa0");
+ prompt=StrCopy("SIO% ");
+
+ if (getenv("HOME"))
+ strcpy(path,getenv("HOME"));
+
+ strcat(path,"/.siorc");
+
+ if (!(fp=fopen(path,"r")))
+ return FALSE;
+
+ TokenRegister(2,cmd);
+
+ Parse(fp);
+ fclose(fp);
+
+ return TRUE;
+}
+
+
+int IConfig(IConfigVar v)
+{
+ static const int *vars[]=
+ {
+ NULL
+ };
+
+ return *vars[v];
+}
+
+
+const char *SConfig(SConfigVar v)
+{
+ static char **vars[]=
+ {
+ &serial_path,
+ &prompt
+ };
+
+ return (const char *)*vars[v];
+}
+
+
+/* END OF FILE */
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..8e58514
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,68 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Config file
+
+*/
+
+#ifndef ATARIOSIO_CONFIG_H
+#define ATARIOSIO_CONFIG_H "$Id$"
+
+#include "util.h"
+
+
+/* Integer settings
+*/
+typedef enum
+{
+ CONF_NONE
+} IConfigVar;
+
+
+/* String settings
+*/
+typedef enum
+{
+ CONF_DEVICE,
+ CONF_PROMPT
+} SConfigVar;
+
+
+/* Read config file
+*/
+int ConfigRead(void);
+
+
+/* Get integer setting
+*/
+int IConfig(IConfigVar v);
+
+
+/* Get string setting
+*/
+const char *SConfig(SConfigVar v);
+
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/disk.c b/src/disk.c
new file mode 100644
index 0000000..d058154
--- /dev/null
+++ b/src/disk.c
@@ -0,0 +1,610 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Disk handling
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "disk.h"
+#include "diskimg.h"
+#include "config.h"
+#include "token.h"
+#include "serial.h"
+
+static const char ident_h[]=ATARIOSIO_DISK_H;
+
+
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define HEX_DUMP_LINE 16
+
+#define MAX_DRIVE 8
+
+
+/* ---------------------------------------- STATICS
+*/
+static DiskImg drive[MAX_DRIVE]={0};
+static DiskInfo info[MAX_DRIVE];
+static uchar *buff[MAX_DRIVE]={0};
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static int Word(uchar lo, uchar hi)
+{
+ return ((int)hi<<8)|(int)lo;
+}
+
+
+static int ParseDrive(const char *p)
+{
+ int d;
+
+ if (*p++!='d')
+ return -1;
+
+ d=(*p-'0')-1;
+
+ if (d<0 || d>=MAX_DRIVE)
+ return -1;
+
+ return d;
+}
+
+
+
+static void DoMount(int d, const char *p)
+{
+ drive[d]=DiskImgLoad(p);
+
+ if (!drive[d])
+ printf("Disk image error: %s\n",DiskImgError());
+ else
+ {
+ DiskImgInfo(drive[d],info+d);
+ buff[d]=Malloc(info[d].bytes_per_sector);
+ }
+}
+
+
+static void DoUnmount(int d)
+{
+ if (drive[d])
+ DiskImgFree(drive[d]);
+
+ drive[d]=NULL;
+ free(buff[d]);
+}
+
+
+static void ShowDir(const uchar *p, unsigned len)
+{
+ unsigned f;
+
+ if (!p)
+ return;
+
+ f=0;
+
+ while(f<len)
+ {
+ uchar flag;
+
+ flag=p[f];
+
+ if (flag&0x40)
+ {
+ int secs;
+ int i;
+
+ secs=Word(p[f+1],p[f+2]);
+
+ for(i=5;i<16;i++)
+ {
+ putchar(p[f+i]);
+ }
+
+ printf(" %4d sectors\n",secs);
+ }
+
+ f+=16;
+ }
+}
+
+
+/* ---------------------------------------- COMMAND HANDLERS
+*/
+static void Mount(int argc, char *argv[])
+{
+ int d;
+
+ if (argc==1)
+ {
+ for(d=0;d<MAX_DRIVE;d++)
+ if (drive[d])
+ printf("d%d %s\n",d+1,DiskImgPath(drive[d]));
+ }
+ else if (argc==3)
+ {
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (drive[d])
+ {
+ printf("Disk already mounted\n");
+ return;
+ }
+
+ DoMount(d,argv[2]);
+ }
+ else
+ {
+ printf("Invalid arguments\n");
+ }
+}
+
+
+static void Unmount(int argc, char *argv[])
+{
+ int d;
+
+ if (argc==1)
+ {
+ for(d=0;d<MAX_DRIVE;d++)
+ {
+ if (drive[d])
+ {
+ printf("Unmounting %s from d%d\n",DiskImgPath(drive[d]),d+1);
+ DoUnmount(d);
+ }
+ }
+ }
+ else
+ {
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+
+ DoUnmount(d);
+ }
+}
+
+
+static void ReadOnly(int argc, char *argv[])
+{
+ int d;
+ int flag;
+
+ if (!YesNo(argv[2],&flag))
+ {
+ printf("Invalid parameter\n");
+ return;
+ }
+
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+}
+
+
+static void Info(int argc, char *argv[])
+{
+ int d;
+
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+
+ printf("Sectors : %d\n",info[d].sectors);
+ printf("Bytes per sector: %d\n",info[d].bytes_per_sector);
+ printf("Write protect : %s\n",info[d].write_protect ? "ON":"OFF");
+}
+
+
+static void Sector(int argc, char *argv[])
+{
+ const uchar *p;
+ int d;
+
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+
+ if (!(p=DiskImgGetSector(drive[d],GetInt(argv[2]))))
+ {
+ printf("Invalid sector\n");
+ return;
+ }
+
+ HexDump(p,info[d].bytes_per_sector);
+}
+
+
+static void New(int argc, char *argv[])
+{
+ DiskImg img;
+ DiskInfo inf;
+
+ img=DiskImgNew(GetInt(argv[2]),GetInt(argv[3]));
+
+ if (!img)
+ {
+ printf("Failed to create image\n");
+ return;
+ }
+
+ DiskImgInfo(img,&inf);
+
+ if (argc==5)
+ {
+ uchar *buff;
+ FILE *fp;
+ int rd;
+ unsigned sec;
+
+ buff=Malloc(inf.bytes_per_sector);
+
+ if (!(fp=fopen(argv[4],"rb")))
+ {
+ printf("Failed to open %s\n",argv[4]);
+ DiskImgFree(img);
+ free(buff);
+ return;
+ }
+
+ sec=0;
+
+ do
+ {
+ rd=fread(buff,1,inf.bytes_per_sector,fp);
+
+ if (rd>0)
+ {
+ DiskImgPutSector(img,sec++,buff);
+ }
+ } while(rd==inf.bytes_per_sector);
+
+ fclose(fp);
+
+ free(buff);
+ }
+
+ if (!DiskImgSave(img,argv[1]))
+ {
+ printf("Failed to save image\n");
+ }
+
+ DiskImgFree(img);
+}
+
+
+static void Ls(int argc, char *argv[])
+{
+ int d;
+ unsigned f;
+
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+
+ for(f=360;f<368;f++)
+ ShowDir(DiskImgGetSector(drive[d],f),info[d].bytes_per_sector);
+}
+
+
+static void Save(int argc, char *argv[])
+{
+ int d;
+
+ if ((d=ParseDrive(argv[1]))==-1)
+ {
+ printf("Invalid drive specifier\n");
+ return;
+ }
+
+ if (!drive[d])
+ {
+ printf("Disk not mounted\n");
+ return;
+ }
+
+ if (argc==2)
+ DiskImgSave(drive[d],NULL);
+ else
+ DiskImgSave(drive[d],argv[2]);
+}
+
+
+/* ---------------------------------------- COMMAND TABLE
+*/
+static Command cmd[]=
+{
+ {
+ "mount",
+ 1,3,
+ "mount [dN file]",
+ "Mount a disk image",
+ Mount
+ },
+ {
+ "umount",
+ 1,2,
+ "unmount [dN]",
+ "Unmount a disk image",
+ Unmount
+ },
+ {
+ "readonly",
+ 3,3,
+ "readonly dN on|off",
+ "Set a disk read only/writeable",
+ ReadOnly
+ },
+ {
+ "info",
+ 2,2,
+ "info dN",
+ "Returns info on a mounted disk",
+ Info
+ },
+ {
+ "sector",
+ 3,3,
+ "sector dN sector",
+ "Hex dumps supplied sector",
+ Sector
+ },
+ {
+ "new",
+ 4,5,
+ "new path sectors secsize [file]",
+ "Creates a new disk file, with optional data",
+ New
+ },
+ {
+ "ls",
+ 2,2,
+ "ls dN",
+ "Lists directory on disk",
+ Ls
+ },
+ {
+ "save",
+ 2,3,
+ "save dN [file]",
+ "Saves a disk back to, er, disk",
+ Save
+ }
+};
+
+
+/* ---------------------------------------- SIO HANDLER
+*/
+static void StatusHandler(int d, const SIOCommand *cmd)
+{
+ static uchar status[4]={0x00, 0x00, 0x01, 0x00};
+
+ usleep(TIME_ACK);
+
+ if (!drive[d])
+ {
+ cmd->putchar(SIO_NACK);
+ return;
+ }
+
+ cmd->putchar(SIO_ACK);
+
+ if (info[d].bytes_per_sector==128)
+ {
+ if (info[d].sectors>720)
+ status[0]=0x80;
+ else
+ status[0]=0x10;
+ }
+ else
+ status[0]=0x60;
+
+ if (info[d].write_protect)
+ status[0]|=8;
+ else
+ status[0]&=~8;
+
+ usleep(TIME_ACK_TO_COMPLETE);
+ cmd->putchar(SIO_COMPLETE);
+ usleep(TIME_COMPLETE_TO_DATA);
+ cmd->write(status,4);
+}
+
+
+static void PutHandler(int d, const SIOCommand *cmd)
+{
+ int sec;
+ size_t len;
+
+ sec=Word(cmd->aux1,cmd->aux2);
+
+ usleep(TIME_ACK);
+
+ if (!drive[d] || info[d].write_protect || sec>info[d].sectors)
+ {
+ cmd->putchar(SIO_NACK);
+ return;
+ }
+
+ if (sec<3)
+ len=128;
+ else
+ len=info[d].bytes_per_sector;
+
+ sec--;
+
+ cmd->putchar(SIO_ACK);
+ if (cmd->read(buff[d],len))
+ {
+ cmd->putchar(SIO_ACK);
+ cmd->putchar(SIO_COMPLETE);
+ }
+ else
+ {
+ cmd->putchar(SIO_NACK);
+ }
+}
+
+
+static void GetHandler(int d, const SIOCommand *cmd)
+{
+ int sec;
+ size_t len;
+
+ sec=Word(cmd->aux1,cmd->aux2);
+
+ usleep(TIME_ACK);
+
+ if (!drive[d] || info[d].write_protect || sec>info[d].sectors)
+ {
+ cmd->putchar(SIO_NACK);
+ return;
+ }
+
+ if (sec<3)
+ len=128;
+ else
+ len=info[d].bytes_per_sector;
+
+ sec--;
+
+ cmd->putchar(SIO_ACK);
+ usleep(TIME_ACK_TO_COMPLETE);
+ cmd->putchar(SIO_COMPLETE);
+ usleep(TIME_COMPLETE_TO_DATA);
+
+ cmd->write(DiskImgGetSector(drive[d],sec),len);
+}
+
+
+static void SIOHandler(const SIOCommand *cmd)
+{
+ switch(cmd->cmd)
+ {
+ case eRead:
+ GetHandler(cmd->device-0x31,cmd);
+ break;
+
+ case eWrite:
+ PutHandler(cmd->device-0x31,cmd);
+ break;
+
+ case eStatus:
+ StatusHandler(cmd->device-0x31,cmd);
+ break;
+
+ case ePut:
+ PutHandler(cmd->device-0x31,cmd);
+ break;
+
+ case eFormat:
+ break;
+
+ case eVerifySec:
+ break;
+
+ case eDownload:
+ case eReadAddr:
+ case eReadSpin:
+ case eMotorOn:
+ break;
+ }
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+void DiskInit(void)
+{
+ int f;
+
+ TokenRegister(sizeof cmd/sizeof cmd[0],cmd);
+
+ for(f=0x31;f<0x31+MAX_DRIVE;f++)
+ SerialRegister(f,SIOHandler);
+}
+
+
+/* END OF FILE */
diff --git a/src/disk.h b/src/disk.h
new file mode 100644
index 0000000..952f6ba
--- /dev/null
+++ b/src/disk.h
@@ -0,0 +1,39 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Disk handling
+
+*/
+
+#ifndef ATARIOSIO_DISK_H
+#define ATARIOSIO_DISK_H "$Id$"
+
+#include "util.h"
+
+/* Initialise disk routines
+*/
+void DiskInit(void);
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/diskimg.c b/src/diskimg.c
new file mode 100644
index 0000000..74e0243
--- /dev/null
+++ b/src/diskimg.c
@@ -0,0 +1,263 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Disk handling
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "diskimg.h"
+
+static const char ident_h[]=ATARIOSIO_DISKIMG_H;
+
+
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MAGIC ('N'+'I'+'C'+'K'+'A'+'T'+'A'+'R'+'I')
+
+#define WRITE_PROTECT 0x01
+
+
+/* ---------------------------------------- TYPES
+*/
+struct sDiskImg
+{
+ char *path;
+ unsigned sectors;
+ unsigned bps;
+ int flags;
+ uchar *data;
+};
+
+
+/* ---------------------------------------- STATICS
+*/
+static char error[256];
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static unsigned GetWord(FILE *fp)
+{
+ unsigned w;
+ int i;
+
+ if ((i=getc(fp))==EOF)
+ return 0;
+
+ w=i;
+
+ if ((i=getc(fp))==EOF)
+ return 0;
+
+ w|=i<<8;
+
+ return w;
+}
+
+
+static void PutWord(FILE *fp,int w)
+{
+ uchar c;
+
+ c=(w&0xff);
+
+ putc(c,fp);
+
+ c=(w>>8);
+
+ putc(c,fp);
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+DiskImg DiskImgLoad(const char *path)
+{
+ FILE *fp;
+ DiskImg img;
+ unsigned long hi,lo;
+ int f;
+
+ if (!(fp=fopen(path,"rb")))
+ {
+ strcpy(error,"Disk file does not exist");
+ return NULL;
+ }
+
+ if (GetWord(fp)!=MAGIC)
+ {
+ strcpy(error,"Not an ATR disk file");
+ return NULL;
+ }
+
+ img=Malloc(sizeof *img);
+
+ img->path=StrCopy(path);
+
+ lo=GetWord(fp);
+
+ img->bps=GetWord(fp);
+
+ img->flags=getc(fp);
+
+ hi=GetWord(fp);
+
+ hi=(hi<<16)|lo;
+
+ img->sectors=(hi*16)/img->bps;
+
+ img->data=Malloc(img->sectors*img->bps);
+
+ for(f=0;f<7;f++)
+ getc(fp);
+
+ for(f=0;f<img->sectors*img->bps;f++)
+ {
+ int i;
+
+ if ((i=getc(fp))==EOF)
+ {
+ free(img->path);
+ free(img->data);
+ free(img);
+ strcpy(error,"Corrupt disk file - too short");
+ return NULL;
+ }
+
+ img->data[f]=i;
+ }
+
+ return img;
+}
+
+
+const char *DiskImgError(void)
+{
+ return error;
+}
+
+
+const uchar *DiskImgGetSector(DiskImg img, unsigned sector)
+{
+ if (sector>=img->sectors)
+ return NULL;
+
+ return img->data+sector*img->bps;
+}
+
+
+int DiskImgPutSector(DiskImg img, unsigned sector, const uchar *data)
+{
+ if (sector>=img->sectors)
+ return FALSE;
+
+ memcpy(img->data+sector*img->bps,data,img->bps);
+
+ return TRUE;
+}
+
+DiskImg DiskImgNew(unsigned sectors, unsigned bytes_per_sector)
+{
+ DiskImg img;
+
+ img=Malloc(sizeof *img);
+
+ img->path=StrCopy("blank.atr");
+ img->sectors=sectors;
+ img->bps=bytes_per_sector;
+ img->flags=0;
+ img->data=Malloc(sectors*bytes_per_sector);
+
+ return img;
+}
+
+
+int DiskImgSave(DiskImg img, const char *path)
+{
+ unsigned long l;
+ FILE *fp;
+ int f;
+
+ if (path)
+ fp=fopen(path,"wb");
+ else
+ fp=fopen(img->path,"wb");
+
+ if (!fp)
+ return FALSE;
+
+ l=(img->sectors/img->bps)/16;
+
+ PutWord(fp,MAGIC);
+ PutWord(fp,l&0xffff);
+ PutWord(fp,img->bps);
+ putc(0,fp);
+ PutWord(fp,l>>16);
+
+ for(f=0;f<7;f++)
+ putc(0,fp);
+
+ for(f=0;f<img->sectors*img->bps;f++)
+ {
+ putc(img->data[f],fp);
+ }
+
+ return TRUE;
+}
+
+
+void DiskImgFree(DiskImg img)
+{
+ free(img->path);
+ free(img->data);
+ free(img);
+}
+
+
+void DiskImgInfo(DiskImg img, DiskInfo *info)
+{
+ info->sectors=img->sectors;
+ info->bytes_per_sector=img->bps;
+ info->write_protect=img->flags&WRITE_PROTECT;
+}
+
+
+const char *DiskImgPath(DiskImg img)
+{
+ return img->path;
+}
+
+
+/* END OF FILE */
diff --git a/src/diskimg.h b/src/diskimg.h
new file mode 100644
index 0000000..f355c50
--- /dev/null
+++ b/src/diskimg.h
@@ -0,0 +1,99 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Disk handling
+
+*/
+
+#ifndef ATARIOSIO_DISKIMG_H
+#define ATARIOSIO_DISKIMG_H "$Id$"
+
+#include "util.h"
+
+
+/* Type representing a disk
+*/
+struct sDiskImg;
+typedef struct sDiskImg *DiskImg;
+
+
+/* Type representing disk config
+*/
+typedef struct
+{
+ unsigned sectors;
+ unsigned bytes_per_sector;
+ int write_protect;
+} DiskInfo;
+
+
+/* Load a disk - returns NULL for error.
+*/
+DiskImg DiskImgLoad(const char *path);
+
+
+/* Why the last operation failed
+*/
+const char *DiskImgError(void);
+
+
+/* Read a sector (NULL if invalid sector)
+*/
+const uchar *DiskImgGetSector(DiskImg img, unsigned sector);
+
+
+/* Write a sector (returns FALSE for invalid sector)
+*/
+int DiskImgPutSector(DiskImg img, unsigned sector,
+ const uchar *data);
+
+
+/* Create a blank disk
+*/
+DiskImg DiskImgNew(unsigned sectors, unsigned bytes_per_sector);
+
+
+/* Write a disk image - silently ignored for read only disks. Returns TRUE
+ for success. If path is NULL then the path the file was loaded from is used.
+*/
+int DiskImgSave(DiskImg img, const char *path);
+
+
+/* Free up a disk image
+*/
+void DiskImgFree(DiskImg img);
+
+
+/* Returns info on a disk
+*/
+void DiskImgInfo(DiskImg img, DiskInfo *info);
+
+
+/* Returns path to a disk
+*/
+const char *DiskImgPath(DiskImg img);
+
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..3c9ef78
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,140 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "serial.h"
+#include "disk.h"
+#include "config.h"
+#include "token.h"
+#include "util.h"
+
+
+/* ---------------------------------------- MACROS
+*/
+#define TRUE 1
+#define FALSE 0
+
+
+/* ---------------------------------------- STATIC
+*/
+static int quit=FALSE;
+
+
+/* ---------------------------------------- COMMAND HANDLERS
+*/
+
+static void Quit(int argc, char *argv[])
+{
+ quit=TRUE;
+}
+
+
+static void Start(int argc, char *argv[])
+{
+ SerialOpen(SConfig(CONF_DEVICE));
+}
+
+
+static void Stop(int argc, char *argv[])
+{
+ SerialClose();
+}
+
+
+static void Debug(int argc, char *argv[])
+{
+ int flag;
+
+ if (YesNo(argv[1],&flag))
+ {
+ SerialDebug(flag);
+ }
+ else
+ {
+ printf("Invalid argument\n");
+ }
+}
+
+
+/* ---------------------------------------- COMMAND TABLE
+*/
+
+static Command cmd[]=
+{
+ {"quit", 1,1, "quit", "Exit atarisio", Quit},
+ {"start", 1,1, "start", "Start emulation", Start},
+ {"stop", 1,1, "stop", "Stop emulation", Stop},
+ {"debug", 2,2, "debug on|off", "Switch debug on/off", Debug}
+};
+
+
+/* ---------------------------------------- MAIN
+*/
+int main(int argc, char *argv[])
+{
+ char buff[1024];
+
+ TokenRegister(sizeof cmd/sizeof cmd[0],cmd);
+ SerialInit();
+ DiskInit();
+
+ printf("atarsio, Copyright (C) 2004 Ian Cowburn\n");
+ printf("atarsio comes with with ABSOLUTELY NO WARRANTY.\n");
+
+ if (!ConfigRead())
+ {
+ fprintf(stderr,"Failed to read ~/.siorc\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!quit)
+ {
+ printf("%s",SConfig(CONF_PROMPT));
+ fflush(stdout);
+
+ while(fgets(buff,sizeof buff,stdin))
+ {
+ TokenRun(buff);
+
+ if (quit)
+ break;
+
+ printf("%s",SConfig(CONF_PROMPT));
+ fflush(stdout);
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+/* END OF FILE */
diff --git a/src/serial.c b/src/serial.c
new file mode 100644
index 0000000..6f25892
--- /dev/null
+++ b/src/serial.c
@@ -0,0 +1,472 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Serial wrappers.
+
+*/
+static const char ident[]="$Id$";
+
+#include <pthread.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+
+#include "serial.h"
+#include "token.h"
+
+static const char ident_h[]=ATARISIO_SERIAL_H;
+
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define WHICH (pthread_equal(pthread_self(),thread) ? "READ":"MAIN")
+
+/* Just as I'm always forgetting how many...
+*/
+#define MILLI2MICRO(x) ((x)*1000)
+
+
+/* ---------------------------------------- EXTERN
+*/
+const uchar SIO_ACK=0x41;
+const uchar SIO_NACK=0x4e;
+const uchar SIO_COMPLETE=0x43;
+const uchar SIO_ERROR=0x45;
+
+
+/* ---------------------------------------- STATICS
+*/
+static int fd=-1;
+static SIOCallback devtable[256]={0};
+static int debug=FALSE;
+static int thread_created=FALSE;
+
+static int do_debug;
+
+static pthread_mutex_t mutex;
+static pthread_t thread;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void Error(const char *p)
+{
+ perror(p);
+
+ if (fd!=-1)
+ {
+ if (pthread_equal(pthread_self(),thread))
+ {
+ printf("WARNING: Reader thread exiting - "
+ "serial port is still open\n");
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ else
+ {
+ printf("Trying to closing serial device\n");
+ SerialClose();
+ }
+ }
+}
+
+
+static void Fatal(const char *p)
+{
+ fprintf(stderr,"FATAL: ");
+ perror(p);
+ exit(EXIT_FAILURE);
+}
+
+
+static void Lock(void)
+{
+ /* printf("[LOCK %s]\n",WHICH); */
+ pthread_mutex_lock(&mutex);
+}
+
+
+static void Unlock(void)
+{
+ /* printf("[UNLOCK %s]\n",WHICH); */
+ pthread_mutex_unlock(&mutex);
+}
+
+
+void SerialPutchar(uchar c)
+{
+ if (do_debug)
+ printf("PUTCHAR: %2.2x (%c)\n",c,isprint(c) ? c:'?');
+
+ if (write(fd,&c,1)==-1)
+ {
+ Error("write:");
+ return;
+ }
+}
+
+
+void SerialWrite(const uchar *p, size_t len)
+{
+ uchar csum;
+
+ if (do_debug)
+ {
+ printf("SENDING:\n");
+ HexDump(p,len);
+ }
+
+ csum=Checksum(p,len);
+
+ while(len>0)
+ {
+ ssize_t w;
+
+ w=write(fd,p,len);
+
+ if (w==-1)
+ {
+ Error("write:");
+ return;
+ }
+
+ p+=w;
+ len-=w;
+ }
+
+ write(fd,&csum,1);
+
+ if (do_debug)
+ printf("CHECKSUM: %2.2x\n",csum);
+}
+
+
+int SerialRead(uchar *p, size_t len)
+{
+ uchar *orig;
+ uchar csum;
+
+ orig=p;
+
+ while(len>0)
+ {
+ ssize_t r;
+
+ r=read(fd,p,len);
+
+ if (r==-1)
+ {
+ Error("read:");
+ return FALSE;
+ }
+
+ p+=r;
+ len-=r;
+ }
+
+ if (read(fd,&csum,1)!=1)
+ {
+ Error("read:");
+ return FALSE;
+ }
+
+ return Checksum(orig,len)==csum;
+}
+
+
+/* ---------------------------------------- READER
+*/
+static void *ReaderThread(void *p)
+{
+ SIOCommand cmd;
+ time_t start;
+ int st;
+ int no;
+ uchar frame[5];
+ uchar c;
+ uchar csum;
+
+ cmd.putchar=SerialPutchar;
+ cmd.write=SerialWrite;
+ cmd.read=SerialRead;
+
+ while(TRUE)
+ {
+ Lock();
+ do_debug=debug;
+ Unlock();
+
+ no=0;
+
+ while(no<5)
+ {
+ if (read(fd,&c,1)==-1)
+ Error("read");
+
+ if (ioctl(fd,TIOCMGET,&st)==-1)
+ Error("ioctl(TIOCMGET)");
+
+ if (st&TIOCM_RNG)
+ {
+ if (do_debug)
+ printf("Got byte %d (%c) and RNG set\n",
+ c,isprint(c) ? c:'?');
+
+ if (no==0)
+ start=time(NULL);
+
+ frame[no++]=c;
+ }
+ else if (do_debug)
+ {
+ printf("Got byte %d (%c) and RNG *NOT* set\n",
+ c,isprint(c) ? c:'?');
+ }
+ }
+
+ if ((time(NULL)-start)>1)
+ {
+ printf("Reader: Got 5 bytes, but too slowly - ignored\n");
+ }
+ else
+ {
+ Lock();
+
+ csum=Checksum(frame,4);
+
+ if (csum==frame[4])
+ {
+ if (do_debug)
+ {
+ printf("Frame:\n");
+ HexDump(frame,5);
+ }
+
+ if (devtable[frame[0]])
+ {
+ /* Fill up the command structure
+ */
+ cmd.device=frame[0];
+ cmd.cmd=frame[1];
+ cmd.aux1=frame[2];
+ cmd.aux2=frame[3];
+
+ /* Let the device do its work
+ */
+ if (do_debug)
+ printf("Calling handler for device %2.2x\n",cmd.device);
+
+ devtable[cmd.device](&cmd);
+ }
+ }
+ else
+ {
+ printf("Reader: Bad checksum, expected %2.2x. Frame:\n",csum);
+ HexDump(frame,5);
+ }
+
+ Unlock();
+ }
+ }
+}
+
+
+/* ---------------------------------------- COMMAND HANDLERS
+*/
+static void Register(int argc, char *argv[])
+{
+ int f;
+
+ for(f=0;f<256;f++)
+ if (devtable[f])
+ printf("Device %2.2x regsitered\n",f);
+}
+
+
+/* ---------------------------------------- COMMAND TABLE
+*/
+static Command cmd[]=
+{
+ {
+ "register",
+ 1,1,
+ "register",
+ "Show registered devices",
+ Register
+ }
+};
+
+
+/* ---------------------------------------- INTERFACES
+*/
+void SerialInit(void)
+{
+ if (pthread_mutex_init(&mutex,NULL)==-1)
+ Fatal("pthread_mutex_init");
+
+ TokenRegister(sizeof cmd/sizeof cmd[0],cmd);
+}
+
+
+void SerialOpen(const char *path)
+{
+ struct termios ios;
+
+ if (fd!=-1)
+ {
+ printf("Serial device already open\n");
+ return;
+ }
+
+ fd=open(path,O_RDWR|O_NOCTTY|O_NDELAY);
+
+ if (fd==-1)
+ {
+ Error(path);
+ return;
+ }
+
+ if (fcntl(fd,F_SETFL,0)==-1)
+ {
+ Error("fcntl(F_SETFL,0)");
+ return;
+ }
+
+ if (tcgetattr(fd,&ios)==-1)
+ {
+ Error("tcgetattr");
+ return;
+ }
+
+ cfsetispeed(&ios,B19200);
+ cfsetospeed(&ios,B19200);
+
+ ios.c_cflag|=(CLOCAL|CREAD);
+
+ ios.c_cflag&=~PARENB;
+ ios.c_cflag&=~CSTOPB;
+ ios.c_cflag&=~CSIZE;
+ ios.c_cflag|=CS8;
+
+ /* Not that it'll work if we can't disable it...
+ */
+#ifdef CRTSCTS
+ ios.c_cflag&=~CRTSCTS;
+#endif
+
+ ios.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
+
+ ios.c_iflag&=~(IXON|IXOFF|IXANY);
+
+ ios.c_oflag&=~OPOST;
+
+ if (tcsetattr(fd,TCSANOW,&ios))
+ {
+ Error("tcsetattr");
+ return;
+ }
+
+ if (pthread_create(&thread,NULL,ReaderThread,NULL)==-1)
+ Fatal("pthread_create");
+
+ thread_created=TRUE;
+}
+
+
+void SerialRegister(int device, SIOCallback func)
+{
+ if (device<0 || device>255)
+ {
+ printf("Illegal device number %d registered\n",device);
+ return;
+ }
+
+ Lock();
+ devtable[device]=func;
+ Unlock();
+}
+
+
+void SerialDeregister(int device)
+{
+ if (device<0 || device>255)
+ {
+ printf("Illegal device number %d deregistered\n",device);
+ return;
+ }
+
+ Lock();
+ devtable[device]=NULL;
+ Unlock();
+}
+
+
+void SerialDebug(int mode)
+{
+ Lock();
+ debug=mode;
+ Unlock();
+}
+
+
+void SerialClose(void)
+{
+ if (fd==-1)
+ {
+ printf("Serial not open\n");
+ }
+
+ Lock();
+
+ if (thread_created)
+ {
+ printf("Cancelling reader thread...");
+ fflush(stdout);
+ pthread_cancel(thread);
+ pthread_join(thread,NULL);
+ printf("Done\n");
+ }
+
+ Unlock();
+
+ close(fd);
+
+ fd=-1;
+ thread_created=FALSE;
+}
+
+
+/* END OF FILE */
diff --git a/src/serial.h b/src/serial.h
new file mode 100644
index 0000000..740bed7
--- /dev/null
+++ b/src/serial.h
@@ -0,0 +1,134 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Serial wrappers.
+
+*/
+
+#ifndef ATARISIO_SERIAL_H
+#define ATARISIO_SERIAL_H "$Id$"
+
+#include <stdlib.h>
+#include "util.h"
+
+
+/* ---------------------------------------- TYPES
+*/
+
+/* Private callbacks furnished to registered devices to read/write serial
+ data. On errors these will not return. Note that SWrite appends the sent
+ data with its checksum. SRead reads len+1, the last byte being the checksum.
+ It returns TRUE if the checksum matches.
+*/
+typedef void (*SPutchar)(uchar c);
+typedef void (*SWrite)(const uchar *p, size_t len);
+typedef int (*SRead)(uchar *p, size_t len);
+
+
+/* Constants (usable with SWrite) for Atari ACK, COMPLETE and ERROR repsonses
+*/
+extern const uchar SIO_ACK;
+extern const uchar SIO_NACK;
+extern const uchar SIO_COMPLETE;
+extern const uchar SIO_ERROR;
+
+
+/* Microsecond timings
+*/
+#define TIME_ACK 85
+#define TIME_ACK_TO_COMPLETE 255
+#define TIME_COMPLETE_TO_DATA 425
+
+
+/* A command from the Atari
+*/
+typedef enum
+{
+ eRead = 0x52,
+ eWrite = 0x57,
+ eStatus = 0x53,
+ ePut = 0x50,
+ eFormat = 0x21,
+ eDownload = 0x20,
+ eReadAddr = 0x54,
+ eReadSpin = 0x51,
+ eMotorOn = 0x55,
+ eVerifySec = 0x56
+} ESIOCmdType;
+
+
+typedef struct
+{
+ uchar device; /* The device ID */
+ ESIOCmdType cmd; /* The command frame type */
+ uchar aux1; /* Data */
+ uchar aux2; /* Data */
+ SPutchar putchar; /* To write a char to the serial port */
+ SWrite write; /* To write to the serial port */
+ SRead read; /* To read from the serial port */
+} SIOCommand;
+
+
+/* Interface for recieving SIO commands. Note that this interface is expected
+ to all serial IO responses, including the initial ACK (in case the device
+ wants to NACK instead).
+*/
+typedef void (*SIOCallback)(const SIOCommand* cmd);
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Initialise the serial routines. Must be called first.
+*/
+void SerialInit(void);
+
+
+/* Opens the passed serial device and configures it for SIO2PC usage.
+*/
+void SerialOpen(const char *path);
+
+
+/* Registers a command handler
+*/
+void SerialRegister(int device, SIOCallback func);
+
+
+/* Deregisters a command handler
+*/
+void SerialDeregister(int device);
+
+
+/* Switch debug mode on/off
+*/
+void SerialDebug(int mode);
+
+
+/* Close the serial device
+*/
+void SerialClose(void);
+
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/siorc.example b/src/siorc.example
new file mode 100644
index 0000000..e1d4217
--- /dev/null
+++ b/src/siorc.example
@@ -0,0 +1,17 @@
+# Example rc file
+#
+# $Id: siorc.example,v 1.1.1.1 2007-05-07 02:05:54 ianc Exp $
+#
+
+# Path to the serial device
+#
+set device /dev/cuaa0
+
+# Load up initial disks
+#
+mount d1 /files/atari/dosdisk
+
+
+# Open up the device
+#
+start
diff --git a/src/tmp b/src/tmp
new file mode 100644
index 0000000..05bd099
--- /dev/null
+++ b/src/tmp
Binary files differ
diff --git a/src/token.c b/src/token.c
new file mode 100644
index 0000000..b71a6cb
--- /dev/null
+++ b/src/token.c
@@ -0,0 +1,257 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Command parsing and execution
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "token.h"
+
+static const char ident_h[]=ATARIOSIO_TOKEN_H;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MAX_ARGS 128
+
+
+/* ---------------------------------------- STATICS
+*/
+
+static int no_cmds=0;
+static Command *cmd_table=NULL;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static int QCompare(const void *a, const void *b)
+{
+ const Command *ca;
+ const Command *cb;
+
+ ca=a;
+ cb=b;
+
+ return strcmp(ca->cmd,cb->cmd);
+}
+
+
+static int BCompare(const void *a, const void *b)
+{
+ const Command *cb;
+
+ cb=b;
+
+ return strcmp(a,cb->cmd);
+}
+
+
+static char *GetToken(char **ptr)
+{
+ char qu=0;
+ char *tok;
+ char *p;
+
+ p=*ptr;
+
+ while(*p && isspace(*p))
+ p++;
+
+ if (!*p)
+ return NULL;
+
+ if (*p=='\'' || *p=='"')
+ qu=*p++;
+
+ tok=p;
+
+ if (qu)
+ {
+ while(*p && *p!=qu)
+ p++;
+
+ if (*p)
+ *p++=0;
+ else
+ printf("Warning: unterminated quotes\n");
+ }
+ else
+ {
+ while(*p && !isspace(*p))
+ p++;
+
+ if (*p)
+ *p++=0;
+ }
+
+ *ptr=p;
+
+ return tok;
+}
+
+static int Split(char *p, char **argv)
+{
+ int argc=0;
+
+ while((argv[argc]=GetToken(&p)))
+ {
+ if (argc==MAX_ARGS)
+ {
+ argv[argc]=0;
+ return argc;
+ }
+
+ argc++;
+ }
+
+ return argc;
+}
+
+
+static void ShowHelp(const char *usage, const char *help)
+{
+ int l;
+
+ printf("%s ",usage);
+
+ for(l=strlen(usage);l<35;l++)
+ putchar('.');
+
+ printf(" %s\n",help);
+}
+
+
+static void HelpCommand(int argc, char *argv[])
+{
+ if (argc==1)
+ {
+ int f;
+
+ for(f=0;f<no_cmds;f++)
+ ShowHelp(cmd_table[f].usage,cmd_table[f].help);
+ }
+ else
+ {
+ Command *cmd;
+
+ cmd=bsearch(argv[1],cmd_table,no_cmds,sizeof *cmd_table,BCompare);
+
+ if (!cmd)
+ printf("Unknown command: %s\n",argv[1]);
+ else
+ ShowHelp(cmd->usage,cmd->help);
+ }
+}
+
+
+static void Init(void)
+{
+ static Command cmd[]=
+ {
+ {"help",1,2,"help [command]","Get help on commands",HelpCommand}
+ };
+
+ static int init=FALSE;
+
+ if (!init)
+ {
+ init=TRUE;
+ TokenRegister(sizeof cmd/sizeof cmd[0],cmd);
+ }
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+void TokenRegister(int no, const Command *cmds)
+{
+ Init();
+
+ cmd_table=Realloc(cmd_table,sizeof(*cmds)*(no+no_cmds));
+ memcpy(cmd_table+no_cmds,cmds,sizeof(*cmds)*no);
+ no_cmds+=no;
+ qsort(cmd_table,no_cmds,sizeof *cmd_table,QCompare);
+}
+
+
+int TokenRun(const char *line)
+{
+ char *p;
+ char *argv[MAX_ARGS];
+ int argc;
+ int res;
+ int l;
+
+ if (!(l=strlen(line)))
+ return FALSE;
+
+ res=FALSE;
+
+ p=StrCopy(line);
+
+ if (p[l-1]=='\n')
+ p[--l]=0;
+
+ argc=Split(p,argv);
+
+ if (argc)
+ {
+ Command *cmd;
+
+ cmd=bsearch(argv[0],cmd_table,no_cmds,sizeof *cmd_table,BCompare);
+
+ if (cmd)
+ {
+ if (argc>=cmd->min_args && argc<=cmd->max_args)
+ {
+ res=TRUE;
+ cmd->func(argc,argv);
+ }
+ else
+ {
+ printf("usage: %s\n",cmd->usage);
+ }
+ }
+ else
+ {
+ printf("Unrecognised command %s\n",argv[0]);
+ }
+ }
+
+ free(p);
+
+ return res;
+}
+
+
+/* END OF FILE */
diff --git a/src/token.h b/src/token.h
new file mode 100644
index 0000000..b143aa5
--- /dev/null
+++ b/src/token.h
@@ -0,0 +1,71 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Command parsing and execution
+
+*/
+
+#ifndef ATARIOSIO_TOKEN_H
+#define ATARIOSIO_TOKEN_H "$Id$"
+
+#include "util.h"
+
+
+/* ---------------------------------------- TYPES
+*/
+
+/* A command callback (note argv[0] is the command itself)
+*/
+typedef void (*TokenHandler)(int argc, char *argv[]);
+
+
+/* A command. min and max args have to include the command itself.
+*/
+typedef struct
+{
+ const char *cmd;
+ int min_args;
+ int max_args;
+ const char *usage;
+ const char *help;
+ TokenHandler func;
+} Command;
+
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Register commands
+*/
+void TokenRegister(int no, const Command *cmds);
+
+
+/* Parse a command line. Returns TRUE if command parsed and run.
+*/
+int TokenRun(const char *line);
+
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..9ea5749
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,165 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Global utilities and types
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include "util.h"
+
+static const char ident_h[]=ATARISIO_UTIL_H;
+
+#define HEX_DUMP_LINE 16
+
+
+/* ---------------------------------------- INTERFACES
+*/
+void *Malloc(size_t size)
+{
+ void *new=malloc(size);
+
+ if (!new)
+ {
+ fprintf(stderr,"malloc failed for %lu bytes\n",(unsigned long)size);
+ exit(EXIT_FAILURE);
+ }
+
+ return new;
+}
+
+
+void *Realloc(void *p, size_t size)
+{
+ void *new=realloc(p,size);
+
+ if (!new)
+ {
+ fprintf(stderr,"realloc failed for %lu bytes\n",(unsigned long)size);
+ exit(EXIT_FAILURE);
+ }
+
+ return new;
+}
+
+
+char *StrCopy(const char *source)
+{
+ return strcpy(Malloc(strlen(source)+1),source);
+}
+
+
+int YesNo(const char *str, int *flag)
+{
+ if (strcasecmp(str,"on")==0 ||
+ strcasecmp(str,"yes")==0 ||
+ strcasecmp(str,"1")==0)
+ {
+ *flag=1;
+ return 1;
+ }
+
+ if (strcasecmp(str,"off")==0 ||
+ strcasecmp(str,"no")==0 ||
+ strcasecmp(str,"0")==0)
+ {
+ *flag=0;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void HexDump(const uchar *p, size_t len)
+{
+ char asc[HEX_DUMP_LINE+1];
+ size_t f;
+
+ f=0;
+
+ while(f<len)
+ {
+ if ((f%HEX_DUMP_LINE)==0)
+ printf("%4.4x: ",f);
+
+ printf(" %2.2x",p[f]);
+
+ if (isprint(p[f]))
+ asc[f%HEX_DUMP_LINE]=p[f];
+ else
+ asc[f%HEX_DUMP_LINE]='.';
+
+ asc[(f%HEX_DUMP_LINE)+1]=0;
+
+ f++;
+
+ if ((f%HEX_DUMP_LINE)==0)
+ printf(" %s\n",asc);
+ }
+
+ if (f%HEX_DUMP_LINE)
+ {
+ while(f%HEX_DUMP_LINE)
+ {
+ printf(" ");
+ f++;
+ }
+
+ printf(" %s\n",asc);
+ }
+}
+
+
+int GetInt(const char *p)
+{
+ long l;
+
+ l=strtol(p,NULL,0);
+
+ return l;
+}
+
+
+uchar Checksum(const uchar *p, size_t len)
+{
+ int sum;
+ size_t f;
+
+ sum=0;
+
+ for(f=0;f<len;f++)
+ {
+ sum+=p[f];
+ sum=(sum&0xff)+(sum>>8);
+ }
+
+ return (uchar)(sum&0xff);
+}
+
+
+
+/* END OF FILE */
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..304e02f
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,82 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Global utilities and types
+
+*/
+
+#ifndef ATARISIO_UTIL_H
+#define ATARISIO_UTIL_H "$Id$"
+
+#include <stdlib.h>
+
+/* ---------------------------------------- TYPES
+*/
+
+typedef unsigned char uchar;
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Returns result from malloc(size), calling exit() if it fails.
+*/
+void *Malloc(size_t size);
+
+
+/* Returns result from realloc(p,size), calling exit() if it fails.
+*/
+void *Realloc(void *p, size_t size);
+
+
+/* Copies a string. The result must be freed.
+*/
+char *StrCopy(const char *source);
+
+
+/* Set flag TRUE/FALSE depending on the contents of str.
+ 'on', 'yes' and '1' are TRUE, 'off', 'no' and '0' false.
+
+ Returns FALSE is str is invalid.
+*/
+int YesNo(const char *str, int *flag);
+
+
+/* Hex dump to stdout
+*/
+void HexDump(const uchar *p, size_t len);
+
+
+/* Get an integer from a string
+*/
+int GetInt(const char *p);
+
+
+/* Returns an Atari serial style checksum.
+*/
+uchar Checksum(const uchar *p, size_t len);
+
+
+#endif
+
+
+/* END OF FILE */