Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 10:30 01 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : PicoMite: an implementation of MM.CMDLINE$ for your consideration

Author Message
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 4311
Posted: 11:16pm 11 Feb 2023
Copy link to clipboard 
Print this post

Peter,

Would you mind considering the code below or something similar for addition to the PicoMite(+VGA) firmware ?

I have taken a different approach to the CMM2/MMB4W by using an MMBasic global constant instead of storing the command line as a C global and thus also saved using a function slot for it.

Yes, it uses up a variable slot + 256 bytes of the MMBasic heap, but programs that are resource scarce can just ERASE MM.CMDLINE$.

An alternative would be to not allocate the variable if there are no command line arguments and expect the called program to handle the ERROR if none have been provided. HOWEVER I'd rather not do that because assuming your acceptance of the concept I'd like to use the same mechanism to store MM.CURRENT$, the full pathname of the current program (with various *magic* values for the flash slots) and that would always be set.

Note I haven't yet fixed up the * command, I thought I'd wait until I receive your blessing (or not).

void cmd_run(void) {
   // RUN [ filename$ ] [, cmd_args$ ]
   getargs(&cmdline, 3, ",");
   unsigned char *filename = "", *cmd_args = "";
   switch (argc) {
       case 0:
           break;
       case 1:
           filename = getCstring(argv[0]);
           break;
       case 2:
           cmd_args = getCstring(argv[1]);
           break;
       default:
           filename = getCstring(argv[0]);
           cmd_args = getCstring(argv[2]);
           break;
   }

   // The memory allocated by getCstring() is not preserved across
   // a call to FileLoadProgram() so we need to cache 'filename' and
   // 'cmd_args' on the stack.
   unsigned char buf[MAXSTRLEN + 1];
   if (snprintf(buf, MAXSTRLEN + 1, "\"%s\",\"%s\"", filename, cmd_args) > MAXSTRLEN) {
       error("RUN command line too long");
   }
   unsigned char *pcmd_args = buf + strlen(filename) + 3;

   if (*filename && !FileLoadProgram(buf)) return;

   ClearRuntime();
   WatchdogSet = false;
   PrepareProgram(true);

   // Create a global constant MM.CMDLINE$ containing 'cmd_args'.
   void *ptr = findvar("MM.CMDLINE$", V_FIND | V_DIM_VAR | T_CONST);
   CtoM(pcmd_args);
   memcpy(ptr, pcmd_args + 1, *pcmd_args - 1);

   IgnorePIN = false;
   if(*ProgMemory != T_NEWLINE) return;                            // no program to run
   nextstmt = ProgMemory;
}


An example run:

> list "cmdline.bas"
Option Explicit On
Print "MM.CMDLINE$='" + Mm.CmdLine$ + "'"
End
> run "cmdline.bas"
MM.CMDLINE$=''
> run "cmdline.bas", "--foo --bar"
MM.CMDLINE$='--foo --bar'
> run , "--wom --bat"
MM.CMDLINE$='--wom --bat'
>


Best wishes,

Tom
Edited 2023-02-12 09:18 by thwill
MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 08:40am 12 Feb 2023
Copy link to clipboard 
Print this post

Looks neat. Let me have the update for the * command as well and I'll include them.
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 4311
Posted: 04:47pm 12 Feb 2023
Copy link to clipboard 
Print this post

  matherp said  Looks neat. Let me have the update for the * command as well and I'll include them.


How memory tight do I need to keep the implementation Peter ? MMB4L has a very(?) robust implementation of * (below) so it can handle both the name of the program being quoted (because on Linux it may contain spaces) and also some of the program arguments being quoted. Are you happy if I just lift this (it will need some minor adjusting because it depends on MMResult and cstring_cpy() that are specific to MMB4L).

/**
* @brief Transforms input beginning with * into a corresponding RUN command.
*
* e.g.
*   *foo              =>  RUN "foo"
*   *"foo bar"        =>  RUN "foo bar"
*   *foo --wombat     =>  RUN "foo", "--wombat"
*   *foo "wom"        =>  RUN "foo", Chr$(34) + "wom" + Chr$(34)
*   *foo "wom" "bat"  =>  RUN "foo", Chr$(34) + "wom" + Chr$(34) + " " + Chr$(34) + "bat" + Chr$(34)
*   *foo --wom="bat"  =>  RUN "foo", "--wom=" + Chr$(34) + "bat" + Chr$(34)
*/
static MmResult parse_transform_star_command(char *input) {
   char *src = input;
   while (isspace(*src)) src++; // Skip leading whitespace.
   if (*src != '*') return kInternalFault;
   src++;

   // Trim any trailing whitespace from the input.
   char *end = input + strlen(input) - 1;
   while (isspace(*end)) *end-- = '\0';

   // Allocate extra space to avoid string overrun.
   // We rely on the caller to clean this up.
   char *tmp = (char *) GetTempMemory(STRINGSIZE + 32);
   strcpy(tmp, "RUN");
   char *dst = tmp + 3;

   if (*src == '"') {
       // Everything before the second quote is the name of the file to RUN.
       *dst++ = ' ';
       *dst++ = *src++; // Leading quote.
       while (*src && *src != '"') *dst++ = *src++;
       if (*src == '"') *dst++ = *src++; // Trailing quote.
   } else {
       // Everything before the first space is the name of the file to RUN.
       int count = 0;
       while (*src && !isspace(*src)) {
           if (++count == 1) {
               *dst++ = ' ';
               *dst++ = '\"';
           }
           *dst++ = *src++;
       }
       if (count) *dst++ = '\"';
   }

   while (isspace(*src)) src++; // Skip whitespace.

   // Anything else is arguments.
   if (*src) {
       *dst++ = ',';
       *dst++ = ' ';

       // If 'src' starts with double-quote then replace with: Chr$(34) +
       if (*src == '"') {
           memcpy(dst, "Chr$(34) + ", 11);
           dst += 11;
           src++;
       }

       *dst++ = '\"';

       // Copy from 'src' to 'dst'.
       while (*src) {
           if (*src == '"') {
               // Close current set of quotes to insert a Chr$(34)
               memcpy(dst, "\" + Chr$(34)", 12);
               dst += 12;

               // Open another set of quotes unless this was the last character.
               if (*(src + 1)) {
                   memcpy(dst, " + \"", 4);
                   dst += 4;
               }
               src++;
           } else {
               *dst++ = *src++;
           }
           if (dst - tmp >= STRINGSIZE) return kStringTooLong;
       }

       // End with a double quote unless 'src' ended with one.
       if (*(src - 1) != '"') *dst++ = '\"';

       *dst = '\0';
   }

   if (dst - tmp >= STRINGSIZE) return kStringTooLong;

   // Copy transformed string back into the input buffer.
   cstring_cpy(input, tmp, STRINGSIZE);

   return kOk;
}


Best wishes,

Tom
MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 06:47pm 12 Feb 2023
Copy link to clipboard 
Print this post

Size no issue. I'll integrate when you post the completed code
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 4311
Posted: 10:17pm 13 Feb 2023
Copy link to clipboard 
Print this post

Hi Peter,

You will find the changes required (ontop of the current GitHub version) here:

https://github.com/thwill1000/picomite-firmware/commit/a2f28ff9ad023700db59eda74c1c968ea0e63591

If you want me to provide them by some other means then please let me know.

Best wishes,

Tom
MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 07:35pm 21 Feb 2023
Copy link to clipboard 
Print this post

This is why I absolutely despise this approach and there is no way I would ever do an automatic update




Attached VGA version with the changes


PicoMiteVGA (4).zip
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 4311
Posted: 08:00pm 21 Feb 2023
Copy link to clipboard 
Print this post

  matherp said  This is why I absolutely despise this approach and there is no way I would ever do an automatic update.


Thanks Peter I'll check it out later ... though I'm not sure what your comment is regarding, as far as I'm concerned the screen-shot clearly shows that in that small section of code I updated the whitespace for consistency (there was a mix of spaces and tabs which I converted to spaces) and one of the comments had strayed a space from alignment with the others in the file so I fixed it.

I doubt you can be converted but these tools really are worth investing time in.

Best wishes,

Tom
Edited 2023-02-22 06:15 by thwill
MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 10:52pm 21 Feb 2023
Copy link to clipboard 
Print this post

If you had posted the complete files I could have done the change in 50% of the time and with less chance of error using winmerge - and I would have done it days ago rather than putting it off
Edited 2023-02-22 08:53 by matherp
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 4311
Posted: 11:32pm 21 Feb 2023
Copy link to clipboard 
Print this post

  matherp said  If you had posted the complete files I could have done the change in 50% of the time and with less chance of error using winmerge - and I would have done it days ago rather than putting it off


  thwill said  If you want me to provide them by some other means then please let me know.




Plus if you follow the link supplied, at the top of each file/section on the RHS there is a [...] button, click that and select "View file".

Anyway we got there in the end, thank you, I'll drop you an email with some further comments.

Best wishes,

Tom
Edited 2023-02-22 09:33 by thwill
MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025