Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

system/options/args is always #[none] #2426

Closed
meshpoint opened this issue Aug 14, 2015 · 42 comments
Closed

system/options/args is always #[none] #2426

meshpoint opened this issue Aug 14, 2015 · 42 comments

Comments

@meshpoint
Copy link

Command line arguments are processed in finish-rl-start:

args [if args [parse args ""]]

This PARSE feature was removed by commit 127e67c0224942c003a1d9f80cb1eb7f9861da80. It seems, the mezzanine SPLIT is not available in finish-rl-start.

By the way, command line arguments are concatenated into a string in host-args.c and then are split back into a block. This is needless work and does not handle properly quoted arguments with spaces. I imagine, this could be intended for use with --args command line option. IMHO, it is better to leave parsing script-specific data to the script. So I propose the following logic for args:

  • no args → none!
  • do/args → whatever the caller provided
  • --args → string!
  • arguments after the script name → block! (even if only 1 arg), parsed by the system
  • both --args and additional arguments → block!
@hostilefork
Copy link
Member

Good find and analysis on that--and welcome--and thanks for the RL_Api PRs!!

What you suggest sounds good to me, especially not putting the arguments into a string and parsing them back out again. If you are on the case and want to do this, that would be fantastic.

The main strong opinions I have are on drawing the line to where the core is less involved. That means continuing the push to where the idea of "args" is not seen as a feature of the language itself...just a particular embedding of it when an idea of "args" makes sense. I guess the main influence that has on anything would be whether the args should live in "system/options/args" or "system/host/options/args", or if there should be an args:// port scheme, or whatever wacky thing brings about a better separation.

(Getting it working again being the most important bit, just bearing that in mind in terms of impact to the surrounding code.)

Hopefully you'll have much more to say... :-) and if you don't have a StackOverflow account please consider joining up. The 20-points-to-chat requirement is trivial, and while irritating it does serve as a decent spam filter...and if you ask a rebol or red tagged question we notice and bump it up quickly. Main rule is to know what to ask and what not to ask: "What topics can I ask about here?"

Thanks again!

@meshpoint
Copy link
Author

Looking at the command line handling code I noticed the following:

  1. currently, system/script/args is a string! and system/options/args is a block!;
  2. command line options are processed even after a script name. So, for example, r3 script.r -v will not execute the script.

So the issue is more complex than I thought. I would change system/script/args to a block!, but it may break some existing scripts. OTOH, it would make args processing cleaner. Consider a multi-argument script callable from both shell and REBOL. Currently you do:

$ r3 print-args.r arg1 arg2
system/script/args = "arg1 arg2"
$ r3 -q
>> do/args %print-args.r reform ["arg1" "arg2"]
system/script/args = "arg1 arg2"

But this would be better:

$ r3 print-args.r arg1 arg2
system/script/args = ["arg1" "arg2"]
$ r3 -q
>> do/args %print-args.r ["arg1" "arg2"]
system/script/args = ["arg1" "arg2"]

For single-argument scripts, however, the string! form is more convenient.

As for the system/options/args, IDK what to do with it. What is it for? Should its format be host-specific or standardized? Why is it preferred in src/tools?

By the way, due to this bug, recent Ren/C builds are not suitable for use in build process as r3-make. One temporary fix would be to remove the offending line from sys-start.r. Another way is to replace system/options/args with system/script/args in make-boot.r.

As for the "--args" switch, it could be changed to function as "all of the following are script arguments". It would make most sense when args is a block! and behaviour (2) is retained, but still makes some sense in other cases. The command line syntax would be:

REBOL [<options>] [<script>] [--args] [<arguments>]

@meshpoint
Copy link
Author

Answering my questions regarding system/options/args. For a multi-file program it provides access to command-line arguments from all scripts, while system/script/args holds DO-arguments.

@earl
Copy link
Contributor

earl commented Aug 14, 2015

Hi @meshpoint, thanks for the bug report and the good thoughts about improving args handling!

Be sure to also have a look at related issues in R3's issue tracker (which we are in the process of migrating to Github, but not there yet), in particular CureCode issue #2228 which collects a few long-standing CLI issues. There are links to two bugs pertaining to the issues you encounter here as well: CC#2227 "Interpreter too eagerly consumes command-line arguments" and CC#1890 "Script arguments containing whitespace or double quotes are garbled".

Regarding system/options/args, to just confirm what you found out yourself later: system/options/args is (intended) to be the primary mechanism for passing args from the command-line to the top-level script. Whereas system/script/args is for passing args between Rebol scripts. At the top-level, there is an obvious overlap between the two. Currently, the primary difference at the top-level is that system/options/args is a parsed block!, whereas system/script/args is the "raw" string!.

As you can probably glance from reading through the discussion in CC#1890, I very much agree with not doing the "concat args from an array to a string only to try to later split them up into a block again" dance currently done for system/options/args. As such, I think your logic proposed above for args would be a good fit for how system/options/args should behave (excluding the do/args option, which is not applicable for the top-level script). On top of that, I think system/script/args should be identical to system/options/args for the top-level script and set to whatever the caller provided via do/args for nested script invocation.

Finally, there is one minor additional complication in this matter. There is a non-argv[] world out there as well, notably, Windows: in Win32, arguments are indeed a single string (GetCommandLine) and not an array of strings. However, Win32 also provides a standard argument parsing method (CommandLineToArgv), which (as far as I understand) is also used to pre-split the command line if you use a regular main(int argc, char *argv[]) entry point. I'd suggest we rather ignore this peculiarity of Windows and use their standard argument splitting function and let Rebol live in a platform-abstracted command-line args are a block! world.

@hostilefork
Copy link
Member

I haven't thought about this at all (not a big shell automation person, more interested in language). So I will now try to think about it. Here is my "blank slate" thinking:

(Note: @earl's post arrived in the middle, I may repeat or contradict him)


There's a difference from what a calling script would like to provide (a value or block of values) and what the OS interface provides (a string with some amount of filtering or pre-processing). ANSI C cuts that string into items, and you don't know how many spaces were between those items. Windows appears to be able give back a whole string, maybe that has spaces preserved...it strips the executable name from that string.

Perhaps obviously, a command line script cannot be constrained to LOADed values if Rebol is to be used for general purposes (not all strings are loadable). That means there needs to be at least a mode by which arguments can be passed in a string form. When that is desired, I think it could be reasonably argued that a block of strings is the reasonable and established choice.

Hence: even though the Windows implementation must go through the API call for the string and break it up to get unicode arguments, I see no reason to make the un-broken string available. The ability to represent a difference does not exist on all platforms (ANSI C strips spaces). If someone is on Windows and needs to tell if it was my-program foo(1 space)bar or my-program foo(3 spaces)bar they can use the FFI and call GetCommandLineW() directly.

(Note: @earl agrees here.)

Moving on... a name like "args" certainly suggests plurality. I would suggest DO/ARGS be constrained to BLOCK! args. Combined with the rule above, this would constrain also system/script/args to a block. Disruptive perhaps, but we are doing disruptive things here if they represent improvements. args: 1 is not literate, and args: "foo" isn't any more so (unless each arg is a character?). Anyway, it can be worked around in a way where the fix still works in old code...and it will read more correctly by doing so. ("Just pass a block, even if it's a block of one.")

Next we have the balance between the Rebol ergonomic of wanting values and not strings (unless you put them in delimiters), and the idea of having an executable marked script whose arguments you do not control. You don't always have a place to turn off the value interpretation (e.g. if it's an executable script with a #! shebang line). So the default should be to pass as strings so you can work in arbitrarily constrained environments. Hence:

rebol %script.reb %arg-not-another-script.reb {AE} 1unparseable$thing

...should probably give the block of strings ["%arg-not-another-script.reb" "{AE}" "1unparseable$thing"]. Then perhaps --load-args (or something?) would switch on value interpretation so:

rebol --load-args %script.reb %arg-not-another-script.reb {AE} 1unparseable$thing

...would give you an error about not being able to parse the third bit. But if it hadn't, it would have given you a block with a FILE!, STRING!, and whatever the third thing was if it were good.


I should point out that while we're very interested in getting feedback and keeping the train going, we're not critically concerned at the moment about if Ren/C builds break r3-make, or has any other unsuitability of purpose at this time. It is specifically not beholden to the "don't change anything" rules of Rebol3 master or rebolsource, in order to be pushing things forward, even if things get messy. We'll try and be dutiful about cleaning the mess before moving much forward.

(Believe it or not that is what I'm doing, I'm doing small things in a "wait cycle" while StableStack is absorbed. Though sometimes the smaller things may seem more disruptive. Who knows.)

So definitely using Ren/C is now is for those ready to work within a process that is going toward stability, but has a lot going on in the meantime. There aren't tagged releases to which changes are hotfixed, or anything of that sort. When that moment comes, it will be announced and git-flow will be used and procedures relating to that followed.

Though regarding r3-make, we actually are already using in the Travis build the download of Rebol3 alpha from prior to open sourcing. So that helps keep from introducing bootstrapping dependencies from prior to that, which is important. The next step--making sure that Ren/C can build and then build again--will have a more interesting twist soon. If you've follow some of the recent work, it has been built with the TCC compiler; and we are looking into the creation of a Red-like self-contained Rebol which can be used as the sole tool in building itself (no make dependency and no C compiler installation).

@meshpoint
Copy link
Author

I would prefer -- after the script name to be passed to the script.

rebol -- script.r arg
["arg"]
rebol script.r -- arg
["--" "arg"]

@earl
Copy link
Contributor

earl commented Aug 14, 2015

Right, so do I. Thanks for pointing this out, I tried to improve the phrasing in CC#2227 and added the following three examples to clarify:

;; Example 6: suggested behaviour with improvement (1) "stop options parsing for the interpreter on --"
$ rebol3 -- probe-args.r -v -x
["-v" "-x"]
$

;; Example 7: suggested behaviour with improvement (2) "stop options parsing after having found a scriptname"
$ rebol3 probe-args.r -v -x
["-v" "-x"]
$

;; Example 8: suggested behaviour with (2) and (1), when a scriptname is found, all further args are passed to the script, even a --
$ rebol3 probe-args.r -- -v -x
["--" "-v" "-x"]
$ rebol3 probe-args.r -v -- -x
["-v" "--" "-x"]
$

@meshpoint
Copy link
Author

Currently, a command line option is silently ignored if it asks for an argument and the argument is missing, i.e. at the end of args or if the next arg starts with "--". I make it display USAGE instead.

Edit: The option argument will be treated as such, even if it starts with "--". It allows specifying "weird" option values.

@meshpoint
Copy link
Author

Funny bug: it only looks at the second character of the potential option value.

r3 --do a-b
** access error: script not found: %a-b

@meshpoint
Copy link
Author

Ugh, another oddity.

 r3 --script script.r --args arg

sets system/options/flags: 'script and 'args.

r3 script.r arg

does not set the flags.

What is the desired behaviour?

P.S. I feel like I stepped in a swamp.

@hostilefork
Copy link
Member

Funny bug: ...

Will be good to keep a sense of humor as you look, we have some good jokes about alligators and swamp gas. :-) We are all in the same boat in that respect, though I'll tell you it is cleaner somewhat and more structured elsewhere. The closer you get to interfacing the outside world instead of the internal C universe the worse it seemed to become.

It would seem that the flags there--if they are serving any purpose at all--are giving the running program knowledge of whether the --script or --args switches were provided. The usual question of need-to-know comes up to ask "should a script be able to detect that, and have conditional behavior based on it?"

To my own tastes I'd rather not have such flags, because it seems like any conditional behavior based on them would only be bad. Most likely people wouldn't know what they did, actually, and would mistakenly test for "args" to see if they had any args given...merrily going along until someone tried to call the script without --args. It would have worked if only they'd not put in that test. Etc. etc.

So from this side of the bayou, I'd say kill the flags if technically possible. Even if they're needed to get to some part of the boot process, wipe them out by the time the user code is running. I'd apply the same premise to any other "why-do-you-need-to-know" flags, for instance "--halt". It's not really the running script's business what the caller wants done when their work is through, and if they need to know someone should give them an argument explicitly.

Also: don't feel like you have to be a hero and work out all the quirks. Though that is absolutely more than welcome, and a thorough examination of these issues is fantastic. But even small improvements help, and add up over time.

@meshpoint
Copy link
Author

Current Progress

For this test I renamed the compiled r3 to rebol3. These are files with test scripts:

script.r
probe-args.r
--quiet
--
-weird

The Tests

$ rebol3 script.r -v
This is the script %script.r
Arguments are: ["-v"]

$ rebol3 script.r -x
This is the script %script.r
Arguments are: ["-x"]

$ rebol3 script.r -- -v
This is the script %script.r
Arguments are: ["--" "-v"]

$ rebol3 probe-args.r 10 foo
["10" "foo"]

I killed --args option in favour of --. --script is now mostly unnecessary too, but it's alive so far.

$ rebol3 probe-args.r --args "-v -x"
["--args" "-v -x"]

$ rebol3 -- probe-args.r -v -x
["-v" "-x"]

$ rebol3 probe-args.r -v -x
["-v" "-x"]

$ rebol3 probe-args.r -- -v -x
["--" "-v" "-x"]

$ rebol3 probe-args.r -v -- -x
["-v" "--" "-x"]

Weirdness tests:

$ rebol3 --script --quiet
This is the script %--quiet
Arguments are: #[none]

$ rebol3 --script -- arg
This is the script %--
Arguments are: ["arg"]

$ rebol3 -- -weird
This is the script %-weird
Arguments are: #[none]

$ rebol3 --do "-1 print 'ok"
ok

Discuss the new behaviour.

@meshpoint
Copy link
Author

Missing option value triggers 'help. Also check out the description of --.

$ rebol3 --do
REBOL 3.0 A0 14-Aug-2015/20:36:10

Command line usage:

        REBOL |options| |script| |arguments|

Standard options:

        --do expr        Evaluate expression (quoted)
        --help (-?)      Display this usage information
        --script file    Explicit script filename
        --version tuple  Script must be this version or greater
        --               End of options; a script filename may
                          follow if it was not specified before,
                          then script arguments may follow

Special options:

        --boot level     Valid levels: base sys mods

Another new (questionable) feature: empty script name is equivalent to not specifying it. This way you can supply arguments without executing a script. Previously it was achievable by using --args.

$ rebol3 --do "probe system/options/script probe system/options/args" "" arg
none
["arg"]

@hostilefork
Copy link
Member

Looks like improvement, and I'm sure it is! Good thinking on the pathological filename cases.

Having the arguments always a block (and changing the spec of do/args such that it only takes blocks) would likely provide the most consistency. If someone wants to call it with a split string they can do so explicitly with do/args %filename.reb split my-string. So in the "Arguments are #none" cases I'd think that should be "Arguments are []"

Your empty script idea is an interesting one. But what an argument "is" varies by platform (or has in my limited experience with cross-platform argument weirdness). It is definitely not part of the ANSI C standard. So relying on the ability to pass an empty string may not work some places, but I'd argue the bigger issue is probably that it's not very clear. It would leave me scratching my head.

I understand the desire to kill --args due to not wanting it to wander into positionings after the script. But perhaps the thing would be to say that invocation either is exclusively a --do or a script, and if it is a --do then the do string becomes the element after which everything is an argument.

So instead of:

 $ rebol3 --do "stuff before script" script-name.r arg1 arg2 arg3

You would write:

 $ rebol3 --do "stuff before script do %script-name.r" arg1 arg2 arg3

What I like about not mixing is it prevents having to get into documenting "the DO runs before the script" or "the DO runs after the script", but further "does the script run if the DO has an error" or "are the args for the DO or just for the script". It cleans up that ambiguity.

I'm not sure exactly what kinds of scenarios that are important are enabled by being able to have the DO string separate and a script file as well. Until I know, I believe I'd prefer this.

From a usage perspective, I find myself interested in that --load-args functionality, so I'm trying to think of a better name or if there's a more clever way to ask for it.

@hostilefork
Copy link
Member

I guess the issue is if you want to pass the args to the script you would have to do so manually, e.g.

$ rebol3 --do "stuff before do %script-name.r [arg1 arg2 arg3]"

So the question is "what if you want args to be visible to both do and the script without repeating them" which seems pretty obviously to be:

$ rebol3 --do "stuff before do/args %script-name.r system/options/args" arg1 arg2 arg3

However often that comes up.

Anyway, like I may have already said, my opinion on this isn't informed by practice of trying to automate the scripting and launching of Rebol. (Mostly I just running one script at a time that doesn't call any others with parameters.)

@meshpoint
Copy link
Author

@hostilefork Regarding your exclusive --do proposal, should we kill --script so they don't get into conflict?

@hostilefork
Copy link
Member

Under that proposal, it would seem so, but I'd definitely run the idea by @earl. I would imagine in the field there are examples of things that run a little bit of --do code before running the script (perhaps to prepare the environment in some way that the script isn't ready to control by argument). And I don't know if there's some benefit to not being inside do quotations... some kind of environment variable string expansion perhaps you get outside a quote that you wouldn't get in it?

Regarding arguments getting LOADed, interesting idea came up:

Rebol [
    Parameters: [
        foo [string!] {The foo parameter...}
        baz [integer! float!] {The baz parameter...}
        bar {bar...}
    ]
]
print [foo baz bar]

Random idea was that if no type were provided it might give you just the string, but if you provided a type (including string) it would load and check it for you. Anyway, might be better than my idea of putting the LOAD burden on the command line. Also suggests that if you did --help and then had a script name, it would give you a constructed help like it does for the function, except for that script invocation.

@meshpoint
Copy link
Author

One advantage of script + do: the script may be outside the current directory, and you can use shell completion features to construct the correct path.

Also, sometimes it makes sense to execute --do after the script. The script may be a library, and you use the defined functions in --do.

@hostilefork
Copy link
Member

I guess I'm willing to say that if you're using the --do "..." then you have the freedom you need to load N libraries instead of 1, and order them how you want. It gets rid of the whole semantics of what to do if there's a failure along the way. If command line completion is lost for those cases that want to do some code injection before or after a script, I'd call that an acceptable loss... if that's all that's lost.

It's nice to be doing something cool, and especially nice when your language lets you --do "things {like embed strings without escaping}". Features above and beyond that confuse matters and have a complexity and maintenance cost. So maybe we should omit the --script plus do until someone demands it back, and let the shape of that demand (should it arise) help guide the re-inclusion. And in that go ahead and omit --script.

Odds are people will come with demands, but they'll just be demanding something else... :-/

@meshpoint
Copy link
Author

Here is what I have so far: 90d5d89aa841b1585c1388c020325b19e2dd012b. Please review the changes in src/core/b-init.c; I'm not familiar with these internals.

@hostilefork
Copy link
Member

It looks very good overall. And I don't know how much prior time you've spent looking at this code, but that's on target!

I tried your examples with the weird files under address sanitizer on Debian Linux 64 and OS/X 64 without incident. (I mentioned how it seems one could fix the NONEs, and I guess we just need a word from @earl on if the --do and script mutual exclusion seems okay.)

But then on Win32 it crashed on the first test of r3 script.r -v. The crash is in OS_STRLEN_ on the Set_String() in Init_Main_Args, where n=1. (Windows is not my environment of choice but I have an old WinXP VM I run for just such occasions.)

I can look further into it if you don't have such an environment to test with.

@meshpoint
Copy link
Author

@hostilefork Yep, I was thinking about testing with -DOS_WIDE_CHAR after we decide on which way to go.

Meanwhile I added the parentheses: c3dcef1b2795115959d677d8d4575454537324e3, 35072841533bbc9a83a367897397c7630e1f824b.

@hostilefork
Copy link
Member

Cool. I'll mention the maybe-obvious that you can't test non-Windows builds with -DOS_WIDE_CHAR. I added some notes on REBCHR generally and what it all is doing to the file that generates reb-host.h:

https://github.com/metaeducation/ren-c/blob/0d855a419c238f95557b02e90ef16106ec527bfd/src/tools/make-os-ext.r#L321

On my 64-bit Debian wchar_t is 4 bytes, for instance, and a lot of things would break (including that the bytes incoming doesn't change by passing -DOS_WIDE_CHAR to the C program.)

@meshpoint
Copy link
Author

I have a feeling that now unneeded --script mostly adds confusion. Let's kill it while we are at it? 054d622af5581fb5822ff407977d455df38d7d66

I noticed a bad feature: if there is an error in command line, other options are still honoured.

Intended:

$ r3 --debug test-mode script.r
This is the script %script.r
Host arguments: #[none]
Script arguments: #[none]
Debug options: [test-mode]

Typo:

$ r3 --dbug test-mode script.r
REBOL 3.0 A0 15-Aug-2015/9:18:58

Command line usage:

...

This is the script %test-mode
Host arguments: ["script.r"]
Script arguments: ["script.r"]
Debug options: #[none]

Also, if an option is specified several times, only the last value is effective.

$ r3 --debug test-mode --debug dump script.r
This is the script %script.r
Host arguments: #[none]
Script arguments: #[none]
Debug options: [dump]

Other programs do it too, so it should not be surprising for users.

@hostilefork
Copy link
Member

if an option is specified several times, only the last value is effective.

Lots of compiler switches work that way, for instance. It can be useful when you are including a set of switches via variable expansion that you mostly want but then want to override after it. So that's fine.

I noticed a bad feature: if there is an error in command line, other options are still honoured.

It definitely shouldn't continue running with bad options.

On the #[none] again: I definitely think that "no args" should canonize as an empty block. Because otherwise you have two ways of saying "no args". What if a caller is generating an argument block via COMPOSE and it happens to wind up empty. The callee has decided they will check for none and handle that gracefully, but if not none assume they can get the first arg...and it raises an error. Hence the initializations I mentioned in sys-obj should be to [], I'm pretty sure:

https://github.com/metaeducation/ren-c/blob/0d855a419c238f95557b02e90ef16106ec527bfd/src/boot/sysobj.r#L122

https://github.com/metaeducation/ren-c/blob/0d855a419c238f95557b02e90ef16106ec527bfd/src/boot/sysobj.r#L174

@earl has expressed a wish I interpret as "system/script/args shouldn't exist, and system/options/args be what the currently executed script always sees...with no access to the "top level args that started it all" except if it were passed through". If that's correct, it sounds reasonable to me.

@meshpoint
Copy link
Author

I filed a new report metaeducation/ren-c#48 for tracking the bad options issue.

@hostilefork When the script is executed with DO/ARGS, raising an error may be the desired behaviour. Consider a combined library/doer script that expects exactly 2 arguments in doer mode. If the caller created a block of args but failed to fill it properly, it's an error and not just loading the library.

If you want an empty block from command line, it's better done in C, I think.

@hostilefork
Copy link
Member

I'm not sure I understand your point. Additionally, I am currently working through a concept in which NONE! arguments when passed to a refinement will "nevermind" the refinement. So:

do/args %some-script.reb if false [append [a] 'b]

That would wind up in the evaluation telling DO that it does not have an /args refinement. (Explicit override of this would be via adding NONE! to the refinement arg's accepted types, in a parallel to how ordinary arguments must be explicitly told to accept UNSET!, but if NONE! were omitted the only way you would get it would be the usual if the refinement were not present. I would suggest not having NONE! on the argument for DO's /ARGS)

(This also pertains to the concerns addressed in CC#2235 about the use of refinement arguments as a potential test of whether the refinement itself is present, which is a practice people want to employ, and the reasoning why refinement arguments do not default to UNSET!...)

All a long winded way of saying "I need to understand more concretely (with code) a scenario in which having the NONE vs empty block alternative has value, as there are many reasons I see to avoid the distinction"

@meshpoint
Copy link
Author

@hostilefork Without examples, but in simpler words. Passing none is a way of saying "don't do stuff, just load". Passing a block means "do your thing with this data". When a caller wants to load a library, it will not pass any args. And when the caller wants stuff to be done, it's an error to pass incorrect args, e.g. an empty block, while the doer script expects some mandatory args. So if system/script/args [do stuff] construction is currently a good practice.

I'm not entirely against the "empty block equals to no args" idea, but the current logic is useful in its own way.

@hostilefork
Copy link
Member

Passing none is a way of saying "don't do stuff, just load"

DO/ARGS purpose is to bridge the gap to the command-line for invoking a script as a file. In that role, I don't think fattening the interface to a form which proxies the /ARGS-was-provided-or-not bit is a good idea. It encourages scripts to have conditional behavior which only triggers when called by Rebol. Or it means you'd have to have a --noargs or --emptyblock switch to get full coverage (and ensuing concerns about what happens if they provide arguments anyway...)

@meshpoint
Copy link
Author

I tried to run this 242c1e28cb38818f2f4d4bc3dbc06ac89c7c2b02 pre-regression version under wine and it behaves strangely. r3.exe script.r does not work, while r3.exe --do "do %script.r" does work. Please check if it works for you.

@hostilefork
Copy link
Member

Same issue. As I say, it's up to you if you want to worry about the Windows version or not (I'm not a Windows person, but I can certainly look into it when I finish what I'm doing right now).

@meshpoint
Copy link
Author

This bug is like a snowball that rolls over issues and gets bigger and bigger, lol.

@hostilefork
Copy link
Member

Yup. People will be very grateful to see this particular set of things get hammered into shape, because it's the sort of everyday-issue every time you run. Even so, only do it if it's fun!

I try not to look outside the core too much. It starts to sprawl into a sort of ad-hoc IOCTL thing with no type safety or clear separation of concerns that I am not interested in. So if you've seen any of my plans, there's a C++ interface...and if that gets sharpened up I'd be saying goodbye to basically all of the "host code" and wire it up with other things. Already have: Ren Garden. Value Explorer...

Again, feel free to join chat and discuss your motivations...and if there's something we can support in helping you work on. Will be a snowball either way, just maybe a more exciting one.

@meshpoint
Copy link
Author

In r3.exe script.r case PRINT does not work, but WRITE works.

@hostilefork
Copy link
Member

In r3.exe script.r case PRINT does not work, but WRITE works.

If your tests have hit a wall with the Windows build--regardless of whether that wall is in code you're messing with or is a pre-existing condition--I'll again say you can feel free to not worry about it. The main thing I'd need to know is when you're in a state ready to call the OS/X and Linux versions ready via PR "with caveats". I can put on the investigator hat, shift priorities, and figure out what to do about whatever is going on with Windows at that time...command line or otherwise.

The main thing being not really wanting to have two people working on the same bug at the same time (especially if Windows work no one wanted to do in the first place), so clarity about that is important.

@meshpoint
Copy link
Author

My code depends on a standard C feature: argv[argc]==0. On Windows, R3 host uses CommandLineToArgvW(), which is not required to append null to the array.

BTW, CommandLineToArgvW() on wine does append null. Also, wmain is required to provide null-terminated argv, just as standard main.

@meshpoint
Copy link
Author

So I fixed Windows: 005b87ed49fb8b8849da82faea0f242bff9834ee.

It's desirable to also fix metaeducation/ren-c#48 in this batch because it involves the same code that I changed.

@earl
Copy link
Contributor

earl commented Aug 16, 2015

In the case at hand, combining the fix to metaeducation/ren-c#48 with the fix to this issue is perfectly fine.

(I'm currently looking into fixing metaeducation/ren-c#49, will get back with more detail on the other open points in this thread after that.)

@hostilefork
Copy link
Member

I had a thought about being able to take a URL instead of a script filename on the command line, which led me to another thought I thought I'd mention. Couldn't the "--do" switch be dropped in favor of the first argument starting with an open square bracket or paren? So instead of:

rebol --do "foo baz bar"

You would write:

rebol "[foo baz bar]"

--do is 4 characters, and the block is only two characters. It looks cleaner to me. If you're on a filesystem where square brackets and spaces constitute legal filenames, you could say:

rebol "%{[foo baz bar]}"

...I guess. Anyway, my point being that the square brackets seem a pretty safe cue that what's inside of them is desired to be run with DO. Gets rid of a switch and looks more elegant to me.

@meshpoint
Copy link
Author

@hostilefork

rebol "[foo]"
rebol -- "[bar].r"

@hostilefork
Copy link
Member

@meshpoint I realize there's some ambiguity but there's something about it that is interesting, and it could be as narrow as "begins with [ and ends with ]". Though my point here is about the idea of stretching into more kinds of values that DO can process. Besides the URL! I mention, we've discussed special meanings for TAG! also (to use a level of indirection to look up the script by name, a kind of standard library). So do <matrix> and even maybe do '<matrix>/0.3.04 to pass a "NewPath" PATH!

Perhaps three modes, with the idea that starting Rebol is implicitly a "DO":

  • --string - would DO the input interpreting it as a STRING! --string "foo.r" would say Script Error: foo.r has no value. As it is today. In essence this says that the content being passed is interpreted as a string.
  • --file - A sort of rebirth of --script but with a more accurate name, meaning "interpret the first value as a FILE!" for DO. Even though you say "[foo]" it knows you mean what Rebol would call %"[foo]" and operates accordingly. If you say rebol --file "%foo" it looks for the file %%foo. As the version without --do acts today.
  • the default - Use a heuristic biased heavily toward the --file/--script interpretation. But make an exception for some inputs, such as those beginning with "[" and ending with "]"... or if asked to invoke on %foo.reb to assume you didn't mean a file with two leading %s.

(It could of course go back and be called --script and --do and be more backwards compatible, and probably be a better choice in that sense, but calling it --file and --string with the "do" implicit in the Rebol invocation is kind of interesting if designing from scratch.)

Heuristics can be messy, but there's a time and a place to invoke them. And the command line is one of those places where heuristics couldn't hurt too much, because some large number of these command lines will be typed in directly. So IF just using --file or --do can take care of the requirements of rigorous clients, having more options for the average interaction to be streamlined and smart could be worth it.

 rebol "[print {Hello}]"
 rebol "<demo>"

vs.

rebol --do "print {Hello}"
rebol --do "do <demo>"

So what this does is it turns the command line invocation into a sort of "implicit do", and lets you read it that way.

@earl
Copy link
Contributor

earl commented Aug 24, 2015

Fixed in d08fdc78fcc0bf483bd37a4cb1349d93253768dc.

@earl earl closed this as completed Aug 24, 2015
@hostilefork hostilefork transferred this issue from metaeducation/ren-c Aug 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants