![]() |
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 KingdomPosts: 4311 |
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 KingdomPosts: 10310 |
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 KingdomPosts: 4311 |
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 KingdomPosts: 10310 |
Size no issue. I'll integrate when you post the completed code |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
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 KingdomPosts: 10310 |
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 KingdomPosts: 4311 |
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 KingdomPosts: 10310 |
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 KingdomPosts: 4311 |
![]() 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 |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |