z80 Development Kit
You are not logged in.
To be able to use the network functions (LOAD/SAVE file via Ethernet) implemented in my Network Filemanager NFM (written in C) by a BASIC program, I wrote a small function to fetch parameters at the "command line" in BASIC into the C-program to process them.
Now I can call NFM like usual by
RAND USR 32768
But I can call it also with
PRINT USR 32768
or
PRINT USR 32768,"do something for me"+A$+N$(1)
The C program reads the string (or string expression) behind the "," (if given) and uses them as startup parameters.
That is the function that I use:
void __FASTCALL__ zx_getCommand(char * buffer)
{
#asm
push HL
call restore81
rst $18 ; get next char
cp 26 ; ',' in zx char set?
jr nz, no_param ; no, no parameter given
rst $20
CALL $F55 ; routine SCANNING
CALL $13F8 ; routine STK-FETCH
LD H,D ; put ZX81 string pointer into HL
LD L,E ;
pop de ; get pointer to ASCII buffer
getstr:
push bc
push de
push hl
XREF zx81toasc
call zx81toasc ; convert (HL) into ASCII
pop hl
pop de
pop bc
ld (de),a ; store ASCII char in buffer
inc de
inc hl
dec bc ; count down string length counter
ld a,b
or c
jr nz, getstr
xor a ; terminate string with \0
ld (de), a
RET
no_param:
pop hl ; cleanup stack
ld (hl), 0 ; return empty string
ret
#endasm
}And the C program starts with:
void main(void)
{
char loop_exit;
zx_getCommand(buffer);
if (*buffer)
{
/* a command line was given: PRINT USR ...,"command" or PRINT USR ...,C$ */
/* delete trailing " (which is necessary for the USB driver) */
...and reads the given string into its own buffer.
The C program then must use a special exit function when having done its job:
void C_exit() /* abort C program, cleanup stack, goto BASIC */
{
ZX81Slow();
#asm
rst 8 ; call error restart
defb $FF ; $FF: no error
#endasm
}That function cleans up the stack and abort the initial PRINT USR ... statement. It returns to BASIC via the ROM error entry, but uses error number NO ERROR. So the BASIC program contiues execution at the next BASIC line.
Of course the exit function is not complete, because it does not cleanup other ressources used by the C program (but works good in my program).
This exit routine is also useful, if the calling BASIC environment does no more exist (e. g. has been deleted or overwritten by another BASIC program).
Maybe you could add these or similar functions to z88dk to make that a standard feature for ZX81?
Siggi
Offline
very nice,
I like the idea very much, I thoght many times to provide a 'standard' parameter passing mechanism, but it should be extended with a standard argv/argc parser.
Since the Zeddies had no OS by default I'd keep this optional (i.e. activated by a #pragma directive, an env variable or a zcc compiler parameter).
Offline
This feature gets a big thumbs-up from me.
Charlie
Offline
I am looking at commmand line parameters and environment variables now, done via the normal C interface. In your case, the command line would be generated at startup into a buffer and then split into words (by eg bufsplit()) which would then be presented as argv[] array entries. ie -- passed the usual way in main(int argc, char **argv)
The environment is a single block of memory containing NUL terminated strings of 'name=value' pairings. The size of the environment (or its presence) has to be determined at compile time and its initial state would have to be set by an external shell.
Offline
Why should in this case be at compile time ?
If the string comes from the BASIC and is put in the FP STACK's buffer, then the startup code could determine its size and split it into chunks.
I was wondering if there is a way to pass multiple arguments and split them directly in the BASIC command line,
perhaps:
PRINT USR MAIN,"do something for me",A$,N$(1)
..would put three different strings on the FP calculator's stack ?
Offline
stefano wrote:
If the string comes from the BASIC and is put in the FP STACK's buffer, then the startup code could determine its size and split it into chunks.
I was wondering if there is a way to pass multiple arguments and split them directly in the BASIC command line,
perhaps:
PRINT USR MAIN,"do something for me",A$,N$(1)
..would put three different strings on the FP calculator's stack ?
Yes the crt0 entrypoint should have a pointer to the complete command line string (and environment block mentioned below) communicated via registers. Each target could have optional preamble code inserted in front to collect these things and the crt0 will do its thing splitting the command line into argv pointers. The argv array itself has to be statically allocated at compile time though, which places a limit on how many words would be parsed.
stefano wrote:
Why should in this case be at compile time ?
This I was talking about environment variables. But I changed my mind last night and decided the shell should provide the space for an executing program's environment variables. So the shell should communicate the size and location of the environment block via registers on startup.
Offline