I'd like to have a Gambit repl on an embedded system (Nintendo DS). I'm tired of not having a real language to program the thing. :)
The primary constraint is 4MB of working RAM. A second constraint would be to have the repl over a socket (I looked at web-repl, so that doesn't look to be much of a problem). I can access files from external compact flash storage, but I would prefer to limit that as much as possible.
I took a quick trip over to gmane to search the archives to see if someone else has tried this, but nothing obvious came up.
I figured I'd ask for some pointers before running blindly down the wrong path.
I'd also like to be running termite on this, eventually. However, I figure that I'm going to have enough issues without complicating my life like that at the start.
Any pointers/advice would be deeply appreciated.
Thanks, -a
Afficher les réponses par date
On 10/5/06, Andrew Lentvorski bsder@allcaps.org wrote:
I took a quick trip over to gmane to search the archives to see if someone else has tried this, but nothing obvious came up.
I had a brief look at doing this about a year ago but never started it - at the time the homebrew tools weren't quite up to the task I thought. Given the number of tools out now allowing file systems on CF and SD it would be a bit easier.
I believe some of the 3rd party storage options have external RAM too. I seem to recall DSLinux being modified to use an extra 32MB of ram. Here's a blog post about it:
http://www.dslinux.org/blogs/pepsiman/?p=70
If you could utilize that extra memory in some way it would make it easier too.
I'd also like to be running termite on this, eventually.
It would be pretty neat if you could run two instances of termite, one on the ARM7 and one on the ARM9 and have them communicate to each other via the DS FIFO - but wrapped nicely in a termite process.
I'm interested in any progress you make.
Chris.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Andrew, that's a neat project! For a long time I have been thinking of running Gambit "on the bare metal" and, although I have never tried to do it, the runtime system has been designed so that there are few dependencies on a specific OS. The C code generated by the compiler is very plain (it only uses the header files limits.h, wchar.h, float.h, setjmp.h, and math.h). The OS dependent stuff is mostly contained in the lib/os*.c files. One important file is lib/ os.h. It is there that the OS calls are selected based on the OS, for example in os.h you will find this ifdef cascade to select the OS function to get the most precise real time, based on the availability of certain functions (determined by the configure script):
/* Determine which function for getting real time is most precise. */
#ifdef HAVE_CLOCK_GETTIME #define USE_clock_gettime #else #ifdef HAVE_GETCLOCK #define USE_getclock #else #ifdef HAVE_GETSYSTEMTIME #define USE_GetSystemTime #else #ifdef HAVE_GETTIMEOFDAY #define USE_gettimeofday #else #ifdef HAVE_FTIME #define USE_ftime #else #ifdef HAVE_TIME #define USE_time #endif #endif #endif #endif #endif #endif
and in lib/os_time.c the function to get the real time implements that functionality based on the USE_xxx symbols defined in os.h:
void ___time_get_current_time ___P((___time *tim), (tim) ___time *tim;) { #ifndef USE_clock_gettime #ifndef USE_getclock #ifndef USE_GetSystemTime #ifndef USE_gettimeofday #ifndef USE_ftime #ifndef USE_time #ifndef USE_CLASSIC_MACOS
*tim = ___time_mod.time_neg_infinity;
#endif #endif #endif #endif #endif #endif #endif
#ifdef USE_clock_gettime
/* The clock_gettime function is in POSIX.1b (realtime programming). */
struct timespec ts; if (clock_gettime (CLOCK_REALTIME, &ts) == 0) ___time_from_nsecs (tim, ts.tv_sec-JAN_1(1970), ts.tv_nsec); else *tim = ___time_mod.time_neg_infinity;
#endif
#ifdef USE_getclock ... #endif
#ifdef USE_GetSystemTime ... #endif
#ifdef USE_gettimeofday ... #endif
#ifdef USE_ftime ... #endif
#ifdef USE_time ... #endif
#ifdef USE_CLASSIC_MACOS ... #endif }
Some OS functionality is not strictly required by Gambit, for example the Gambit Scheme "rename-file" procedure is only defined for user programs, it is not used by the runtime system. The C functions which implement such functionality return an error code of ___UNIMPL_ERR (unimplemented function error) when the function is called. For example, here is how ___os_rename_file is implemented in lib/os_files.c:
___SCMOBJ ___os_rename_file ___P((___SCMOBJ path1, ___SCMOBJ path2), (path1, path2) ___SCMOBJ path1; ___SCMOBJ path2;) { ___SCMOBJ e; void *cpath1; void *cpath2;
#ifndef USE_rename #ifndef USE_MoveFile
e = ___FIX(___UNIMPL_ERR);
#endif #endif
#ifdef USE_rename ... #endif
#ifdef USE_MoveFile ... #endif
return e; }
So for your project I think you should start with modifying lib/os.h to select a minimal set of OS functions that are provided by the Nintendo DS operating system. Once you have something minimal working, you can tie in to more and more OS functionality as your needs grow.
Please keep me informed. In beta 20, I have reorganize the lib/os* files so that porting Gambit to an embedded system is easier. If you find other things that would help I would like to add them to the runtime system.
Marc
On 5-Oct-06, at 5:46 AM, Andrew Lentvorski wrote:
I'd like to have a Gambit repl on an embedded system (Nintendo DS). I'm tired of not having a real language to program the thing. :)
The primary constraint is 4MB of working RAM. A second constraint would be to have the repl over a socket (I looked at web-repl, so that doesn't look to be much of a problem). I can access files from external compact flash storage, but I would prefer to limit that as much as possible.
I took a quick trip over to gmane to search the archives to see if someone else has tried this, but nothing obvious came up.
I figured I'd ask for some pointers before running blindly down the wrong path.
I'd also like to be running termite on this, eventually. However, I figure that I'm going to have enough issues without complicating my life like that at the start.
Any pointers/advice would be deeply appreciated.
Thanks, -a _______________________________________________ Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Marc Feeley wrote:
So for your project I think you should start with modifying lib/os.h to select a minimal set of OS functions that are provided by the Nintendo DS operating system. Once you have something minimal working, you can tie in to more and more OS functionality as your needs grow.
Please keep me informed. In beta 20, I have reorganize the lib/os* files so that porting Gambit to an embedded system is easier. If you find other things that would help I would like to add them to the runtime system.
Well, the size of my gsi is too large for the DS. Upon looking at the symbol table with nm, the most obvious candidate for removal is anything having to do with "six".
Is there a particular file I should look at to remove this?
Thanks, -a
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 18-Oct-06, at 6:51 AM, Andrew Lentvorski wrote:
Marc Feeley wrote:
So for your project I think you should start with modifying lib/ os.h to select a minimal set of OS functions that are provided by the Nintendo DS operating system. Once you have something minimal working, you can tie in to more and more OS functionality as your needs grow. Please keep me informed. In beta 20, I have reorganize the lib/ os* files so that porting Gambit to an embedded system is easier. If you find other things that would help I would like to add them to the runtime system.
Well, the size of my gsi is too large for the DS. Upon looking at the symbol table with nm, the most obvious candidate for removal is anything having to do with "six".
Is there a particular file I should look at to remove this?
Thanks, -a
How large is your gsi and how much memory do you have on the DS? In principle you can remove all of the Gambit runtime except for _kernel.scm and you can still compile programs (as long as they don't use the stuff you removed of course). You can also create your own specialized runtime library with whatever you need. If you want to keep the Gambit runtime more or less like it is, here are some simple things you can do:
- - strip the executable, this saves about 15% - - define ___OPTIMIZE_SPACE at the top of gambit.h, this saves about 3% - - use the configure option --enable-char-size=1, this saves about 10% - - remove the code for SIX (in _io.scm remove all the section with the title "Scheme infix extension (SIX) parser", and in _nonstd.scm remove all the section starting with (define-runtime-macro (six.!x x) ...)); this saves about 10% - - change _num.scm so that it does not use the fast bignum algorithms, i.e. (##define-macro (use-fast-bignum-algorithms) #f), this saves about 4% - - remove the procedures for homogeneous numeric vectors (in _std.scm remove the calls to the macro define-prim-vector-procedures for all the vector types you do not need) - - in _io.scm get rid of the code for all the port types you do not need, for example, to get rid of process ports remove the section with the title "Implementation of process device ports." - - experiment with different C compiler options to see what reduces the code size
The executatble for the unmodified Gambit on my MacBook Pro is 3.1 megabytes. After applying the first five suggestions the executable is 31% smaller. I'm sure you can get it to half the original size with only a little bit more work.
I wish there was a more programmatic way to disable all these subsystems, but that's the best that can be done now.
Marc
On 10/19/06, Marc Feeley feeley@iro.umontreal.ca wrote:
How large is your gsi and how much memory do you have on the DS?
The DS has 4MB of RAM. Some optional add-ons can provide up to an additional 32MB but they require bank switching and other techniques to enable.
Chris.
Marc Feeley wrote:
Andrew, that's a neat project! For a long time I have been thinking of running Gambit "on the bare metal" and, although I have never tried to do it, the runtime system has been designed so that there are few dependencies on a specific OS. The C code generated by the compiler is very plain (it only uses the header files limits.h, wchar.h, float.h, setjmp.h, and math.h). The OS dependent stuff is mostly contained in the lib/os*.c files.
I located main() inside gambit.h after peeling apart the preprocessor stuff with -E. This then calls ___main_char or ___main_UCS_2 inside os_base.c.
I need to initialize some things (interrupts, keyboard, display, timers, wifi, etc.) before letting Gambit take over. Where should I hook in? Should I hook in before letting the call float through to ___main_char or ___main_UCS_2, or is there somewhere else that I should break out and start initializing?
Thanks, -a
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 19-Oct-06, at 7:19 AM, Andrew Lentvorski wrote:
Marc Feeley wrote:
Andrew, that's a neat project! For a long time I have been thinking of running Gambit "on the bare metal" and, although I have never tried to do it, the runtime system has been designed so that there are few dependencies on a specific OS. The C code generated by the compiler is very plain (it only uses the header files limits.h, wchar.h, float.h, setjmp.h, and math.h). The OS dependent stuff is mostly contained in the lib/os*.c files.
I located main() inside gambit.h after peeling apart the preprocessor stuff with -E. This then calls ___main_char or ___main_UCS_2 inside os_base.c.
I need to initialize some things (interrupts, keyboard, display, timers, wifi, etc.) before letting Gambit take over. Where should I hook in? Should I hook in before letting the call float through to ___main_char or ___main_UCS_2, or is there somewhere else that I should break out and start initializing?
Thanks, -a
You can either add your initialization code to ___main_* in lib/ os_base.c , or start Gambit from your own main (see the examples in tests/client.c and examples/pthread to see how to do this).
Marc
Marc Feeley wrote:
You can either add your initialization code to ___main_* in lib/os_base.c , or start Gambit from your own main (see the examples in tests/client.c and examples/pthread to see how to do this).
I managed to get the system started, and I get a: "*** START OF DEBUGGING TRACES" line, but then, nothing.
Running it under the no$gba emulator indicates a crash.
Is there a flag or a define I can set to get Gambit to spew a lot of debugging and tracing info? It needs to be in one of the compiled files as I don't have command line arguments.
Thanks, -a
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 21-Oct-06, at 4:02 AM, Andrew Lentvorski wrote:
Marc Feeley wrote:
You can either add your initialization code to ___main_* in lib/ os_base.c , or start Gambit from your own main (see the examples in tests/client.c and examples/pthread to see how to do this).
I managed to get the system started, and I get a: "*** START OF DEBUGGING TRACES" line, but then, nothing.
Running it under the no$gba emulator indicates a crash.
Is there a flag or a define I can set to get Gambit to spew a lot of debugging and tracing info? It needs to be in one of the compiled files as I don't have command line arguments.
Thanks, -a
It sounds like the development environment is rather minimal on the Nintendo DS. Is there no C debugger you can use to know in which C function the system crashed?
Also, add a printf in ___call in lib/setup.c to see if it is called and how many times. The function ___call is used when Scheme code is being executed. It is doesn't make it that far then you'll have to use printfs to narrow down the crash location. Start at ___setup in lib/setup.c (for example before calls to ___setup_os, ___setup_mem, etc).
If the crash is in the Scheme code part of the runtime, something else you can do is add
#define ___DEBUG_HOST_CHANGES
at the top of include/gambit.h and recompile the whole system from scratch ("make mostlyclean; make"). This will add to the trace all control transfers between Scheme functions, which can tell you roughly in which Scheme procedure the program crashed.
Marc
Marc Feeley wrote:
It sounds like the development environment is rather minimal on the Nintendo DS. Is there no C debugger you can use to know in which C function the system crashed?
No. This *is* an embedded system, after all. Why do you think I want Gambit running over a socket? That gives me a *much* better environment in which to do development.
In addition, the system has no MMU. Consequently, a "crash" may or may not have any relation to the problem which actually caused the crash.
Also, add a printf in ___call in lib/setup.c to see if it is called and how many times. The function ___call is used when Scheme code is being executed. It is doesn't make it that far then you'll have to use printfs to narrow down the crash location. Start at ___setup in lib/setup.c (for example before calls to ___setup_os, ___setup_mem, etc).
Thanks for this advice. Is there a "preferred form" for a debugging printf in the library? I would be helpful for other people doing ports to have those in the code but disabled by the C macro system.
-a
Marc Feeley wrote:
It sounds like the development environment is rather minimal on the Nintendo DS. Is there no C debugger you can use to know in which C function the system crashed?
The system crashes here: if (___NONNULLCHARSTRINGLIST_to_NONNULLUCS_2STRINGLIST (argv, &___program_startup_info.argv) != ___FIX(___NO_ERR))
You make an assumption that argv is a valid pointer even when argc comes back with a 0. It is certainly possible that having a NULL argv violates the standard; I don't know the standard well enough.
How do I have to get around this? I am concerned that just removing this call will leave ___program_startup_info.argv in a state that will just push the crash further along. I'd prefer to stop the problem here so that the system can just proceed.
Thanks, -a
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 21-Oct-06, at 8:58 PM, Andrew Lentvorski wrote:
Marc Feeley wrote:
It sounds like the development environment is rather minimal on the Nintendo DS. Is there no C debugger you can use to know in which C function the system crashed?
The system crashes here: if (___NONNULLCHARSTRINGLIST_to_NONNULLUCS_2STRINGLIST (argv, &___program_startup_info.argv) != ___FIX(___NO_ERR))
You make an assumption that argv is a valid pointer even when argc comes back with a 0. It is certainly possible that having a NULL argv violates the standard; I don't know the standard well enough.
How do I have to get around this? I am concerned that just removing this call will leave ___program_startup_info.argv in a state that will just push the crash further along. I'd prefer to stop the problem here so that the system can just proceed.
For now, just replace that with "___program_startup_info.argv = NULL;". I'll try to come up with a better alternative.
Marc Feeley wrote:
If the crash is in the Scheme code part of the runtime, something else you can do is add #define ___DEBUG_HOST_CHANGES
That was way useful.
I'm having some problems though.
The system seems to be very tied to having a file system; fopen error codes of 88 are giving it fits. In trying to dig through things, I'm finding that I get a crash somewhere after it tosses an error from (I hope I type this in right as I can't cut and paste):
*** ERROR IN ##main -- (path-expand "~") *** Entering _io (subprocedure 445) *** Entering ##os-device-force-output (subprocedure 705) *** Entering _io (subprocedure 329) *** Entering
And then it crashes.
-a
It is expanding "~" (to get the user's home directory) to generate the path to the user's initialization file. You probably don't have that on the Nintendo DS... Normally this step is avoided when gsi by doing:
gsi -f
You could modify gsi/_gsi.scm so that it does not search for the initialization file, for example you could remove:
(if (##not skip-initialization-file?) (process-initialization-file))
That should get you to the next problem, but I think you are getting close to a working Gambit.
By the way, make sure you are using beta 20 because there were some problems in previous versions with program termination (when closing the predefined ports just before the final "exit").
Marc
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 22-Oct-06, at 9:11 AM, Marc Feeley wrote:
You could modify gsi/_gsi.scm so that it does not search for the initialization file, for example you could remove:
(if (##not skip-initialization-file?) (process-initialization-file))
That should get you to the next problem, but I think you are getting close to a working Gambit.
Actually, for the moment, you can replace all of gsi/_gsi.scm with the call
(##repl-debug-main)
Now since you will not have a console on the Nintendo, you have to start thinking about how the interaction will work. Using the web- repl example is a good idea, but before you can use that you have to debug the networking layer. So you should use gsi/_gsi.scm as your testing module, starting with things like:
(define p (open-tcp-client (list server-address: "www.iro.umontreal.ca" ; or #u8(192 168 0 1) port-number: 80 eol-encoding: 'cr-lf))) (pretty-print p)
(display "GET /index.html\n\n" p) (force-output p) (pretty-print (read-line p))
Marc
Marc Feeley wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 22-Oct-06, at 9:11 AM, Marc Feeley wrote:
You could modify gsi/_gsi.scm so that it does not search for the initialization file, for example you could remove:
(if (##not skip-initialization-file?) (process-initialization-file))
That should get you to the next problem, but I think you are getting close to a working Gambit.
Actually, for the moment, you can replace all of gsi/_gsi.scm with the call
(##repl-debug-main)
This is the first change which is requiring me to actually rerun gsc.
So, the question:
How do I build gsc to work in a cross compiling environment?
Presumably, I need to specify an option which will use an installation of gambit *external* to the currently compiling gambit (which will not work on the host OS).
Where would I do so? The makefiles seem to want to pull in the gambit from the current directories.
Thanks, -a
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 22-Oct-06, at 6:28 PM, Andrew Lentvorski wrote:
This is the first change which is requiring me to actually rerun gsc.
So, the question:
How do I build gsc to work in a cross compiling environment?
Presumably, I need to specify an option which will use an installation of gambit *external* to the currently compiling gambit (which will not work on the host OS).
Where would I do so? The makefiles seem to want to pull in the gambit from the current directories.
Go to a workstation which supports Gambit (Unix, Mac OS X, or Windows with MinGW) and build Gambit 4.0 beta 20 from the standard distribution. This will give you the Gambit compiler in gsc/gsc .
Now modify whatever Scheme sources you want in the lib and gsi subdirectories. If you modify something in the lib directory then do a make **in that directory**. If you modify something in the gsi directory then do a make **in that directory**. This will create new .c files from the .scm files you have changed **and** new link files (either lib/_gambc.c or gsi/_gsi_.c). Make sure you copy all the .c files that have changed to the directory where you keep the Nintendo sources.
Be careful, if you do a make in the gsc subdirectory or in Gambit's root directory then you will create a new gsc/gsc that includes your Nintendo specific modifications, which may break the compiler sufficiently to make it unusable for future compilations. It is a good idea to make a backup of gsc/gsc (i.e. "cp gsc/gsc gsc/gsc- good") so that you can revert to it. It might also be simpler to have two copies of the whole Gambit source tree. One is used to build gsc/gsc, and the other to build the runtime system (just do "cd gambit-copy1 ; make ; cp gsc/gsc ../gambit-copy2/gsc/gsc ; cd ../ gambit-copy2 ; make clean ; cd lib ; make ; cd ../gsi ; make").
I'll see if I can change the makefiles to make it easier to use Gambit as a cross-compiler (my idea is to use "gsc/gsc-comp" as the Gambit compiler to compile the .scm files in the source tree, and "gsc/gsc" is the target of the make; there will be an extra step needed to copy "gsc/gsc" to "gsc/gsc-comp" to bootstrap the system, obtained with a "make bootstrap").
Marc
Marc Feeley wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 22-Oct-06, at 6:28 PM, Andrew Lentvorski wrote:
This is the first change which is requiring me to actually rerun gsc.
So, the question:
How do I build gsc to work in a cross compiling environment?
Presumably, I need to specify an option which will use an installation of gambit *external* to the currently compiling gambit (which will not work on the host OS).
Where would I do so? The makefiles seem to want to pull in the gambit from the current directories.
Go to a workstation which supports Gambit (Unix, Mac OS X, or Windows with MinGW) and build Gambit 4.0 beta 20 from the standard distribution. This will give you the Gambit compiler in gsc/gsc .
Okay, so it's not a simple flag.
In that case, I got lucky. I am using scons to build the DS version of gambit. What this means is that I can use the make system to build it natively and recompile the .scm files and use the scons system to build the cross compiled version.
Okay, that will work until you shuffle some things around for cross compile bootstrapping.
Thanks, -a
Marc Feeley wrote:
I'll see if I can change the makefiles to make it easier to use Gambit as a cross-compiler (my idea is to use "gsc/gsc-comp" as the Gambit compiler to compile the .scm files in the source tree, and "gsc/gsc" is the target of the make; there will be an extra step needed to copy "gsc/gsc" to "gsc/gsc-comp" to bootstrap the system, obtained with a "make bootstrap").
If you wind up doing any refactoring of code, may I suggest an adjustment to the debugging output statements?
It would make things nicer if the debugging fprintf calls were made to your own function dbfprintf declared as follows in a separate file:
#include <stdio.h> #include <stdarg.h>
int dbfprintf(FILE * fp, const char *fmt,...) { int ret; va_list ap, ap2;
va_start (ap, fmt);
#if 0 /* Useful to create a copy of the output to somewhere else, too */ va_copy (ap2, ap); vprintf(fmt, ap2); va_end (ap2); #endif
ret = vfprintf (fp, fmt, ap); va_end (ap);
return ret; }
I used this to be able to split output to both a logfile as well as stdout. At various points, I used it to send the debug output to a normal stream but which also wrote to a flash cartridge in a non-cached fashion so that I could see when things crashed. It was *very* useful.
Thanks, -a
Andrew, what development system are you using? Are you using devkitpro, or the official Nintendo SDK?
Chris.
Marc Feeley wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 22-Oct-06, at 9:11 AM, Marc Feeley wrote:
You could modify gsi/_gsi.scm so that it does not search for the initialization file, for example you could remove:
(if (##not skip-initialization-file?) (process-initialization-file))
That should get you to the next problem, but I think you are getting close to a working Gambit.
Actually, for the moment, you can replace all of gsi/_gsi.scm with the call
(##repl-debug-main)
I think I have a repl loop firing. I appear to be in an infinite loop and am calling various subprocedures of _repl. ##dynamic-env-bind, ##continuation-ret, ##subprocedure-parent, (and a lot of others).
This even appears to be working under the no$gba emulator.
Where does it try to grab input? If I can find where it does that, I can substitute on of the DS touchscreen keyboard emulators for stdin and put together a functional console.
Now since you will not have a console on the Nintendo, you have to start thinking about how the interaction will work. Using the web-repl example is a good idea, but before you can use that you have to debug the networking layer.
That's not going to be easy. 802.11 on the DS is annoying.
-a
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 22-Oct-06, at 11:11 PM, Andrew Lentvorski wrote:
Marc Feeley wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 22-Oct-06, at 9:11 AM, Marc Feeley wrote:
You could modify gsi/_gsi.scm so that it does not search for the initialization file, for example you could remove:
(if (##not skip-initialization-file?) (process-initialization-file))
That should get you to the next problem, but I think you are getting close to a working Gambit.
Actually, for the moment, you can replace all of gsi/_gsi.scm with the call (##repl-debug-main)
I think I have a repl loop firing. I appear to be in an infinite loop and am calling various subprocedures of _repl. ##dynamic-env- bind, ##continuation-ret, ##subprocedure-parent, (and a lot of others).
This sounds like you are in the dreaded "debugging the I/O" infinite loop... there's an initial error that raises an exception, so the REPL tries to report it but fails because of some I/O error, so the REPL tries to report that error, and so on.
So your next step should be to make sure you can write on stdout and read on stdin.
This even appears to be working under the no$gba emulator.
Where does it try to grab input? If I can find where it does that, I can substitute on of the DS touchscreen keyboard emulators for stdin and put together a functional console.
In lib/os_io.c you will find this call to fread:
#ifndef USE_POSIX #ifndef USE_WIN32
{ int n; FILE *stream = d->stream;
if (stream == 0) stream = stdin;
if (stream == stdin) len = 1; /* only read 1 byte at a time to prevent blocking on tty */
if ((n = fread (buf, 1, len, stream)) == 0) { if (ferror (stream)) { clearerr (stream); return ___FIX(___UNKNOWN_ERR); } clearerr (stream); }
*len_done = n; }
#endif #endif
Note that when reading from the console d->stream is NULL, so you can use this condition to bypass the call to fread and do your own thing. You can also force len to 1 (to read 1 character at a time).
There is similar code which uses fwrite to do output (there is a single call in all of lib/os_io.c).
Marc
Marc Feeley wrote:
This sounds like you are in the dreaded "debugging the I/O" infinite loop... there's an initial error that raises an exception, so the REPL tries to report it but fails because of some I/O error, so the REPL tries to report that error, and so on.
Yeah, it looks like that. I get:
Gambit Version 4.0 beta 20
*** ERROR -- Unknown error
(peek-char '#<input-output-port #2 (console)>)
<Repeat ad infinitum>
So your next step should be to make sure you can write on stdout and read on stdin.
Got it.
-a
Marc Feeley wrote:
This sounds like you are in the dreaded "debugging the I/O" infinite loop... there's an initial error that raises an exception, so the REPL tries to report it but fails because of some I/O error, so the REPL tries to report that error, and so on.
So your next step should be to make sure you can write on stdout and read on stdin.
Well, I've got a repl, but it's broken.
First, it doesn't echo input characters to stdout.
Second, it executes immediately upon closing the final paren rather than waiting for a return.
Third, it's broken: (+ 1 1) results in 4 (cons 'a '(1 2)) results in (a 2 1)
Probably, I need to start backing out debugging changes I made to bring it back into line with the original source rather than trying to debug these on the fly.
-a
Marc Feeley wrote:
If the crash is in the Scheme code part of the runtime, something else you can do is add
#define ___DEBUG_HOST_CHANGES
That was way useful.
I'm having some problems though.
The system seems to be very tied to having a file system; fopen error codes of 88 are giving it fits. In trying to dig through things, I'm finding that I get a crash somewhere after it tosses an error from (I hope I type this in right as I can't cut and paste):
*** ERROR IN ##main -- (path-expand "~") *** Entering _io (subprocedure 445) *** Entering ##os-device-force-output (subprocedure 705) *** Entering _io (subprocedure 329) *** Entering
And then it crashes.
-a