Command line parameters for C program (@ZX81) ?

Requests for features
Post Reply
siggi
Well known member
Posts: 344
Joined: Thu Jul 26, 2007 9:06 am

Command line parameters for C program (@ZX81) ?

Post by siggi »

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:

Code: Select all

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:

Code: Select all

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:

Code: Select all

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
stefano
Well known member
Posts: 2137
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

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).
SirMorris
Member
Posts: 21
Joined: Wed Mar 23, 2011 2:02 pm

Post by SirMorris »

This feature gets a big thumbs-up from me.

Charlie
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

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.
stefano
Well known member
Posts: 2137
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

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 ?
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

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.
Post Reply