|
Post by Stefan on Jun 18, 2024 4:31:02 GMT -5
Hi George,
I figure you have your hands full with v3, so sorry about suggesting an enhancement!
We already have Environment variable support for commands like SAVEAS/CREATE and REPLACE, e.g. SAVEAS %UserProfile%\Desktop\<filename>
(1) Could that support be extended to FM - FilePath, so users can specify a filepath in the format of %UserProfile%\Desktop\ , etc? It would bring FM - FilePath in line with the command line capability and other users may also find that helpful.
(2) Could the existing implementation be extended to support ANY environment variable? e.g. In the above example, %UserProfile%\Desktop works fine, but not all environment variables are recognsied. I have a variable called DESKTOP which is defined as %UserProfile%\Desktop
Windows' File Explorer expands %Desktop% correctly to C:\Users\Stef\Desktop but SPFLite does not even recognise %Desktop%, let alone perform the implied recursive expansion. If recursive expansion is a step too far, I'd happily settle for single expansion.
By the way, I notice that there is no error message on the FM - FilePath panel if the user specifies a FilePath which SPFLite cannot find. You just get an empty list.
Perhaps there should be a "FilePath not found" or similar message.
|
|
|
Post by George on Jun 18, 2024 10:57:38 GMT -5
Stefan: A single expansion is simple, recursion - not sure.
Yes, a later. right now I'm stumped by a weird V3 bug to do with the CANCEL on missing Profile. Really nasty.
If I seem to have forgotten, please remind me.
George
|
|
|
Post by Robert on Jun 18, 2024 12:30:34 GMT -5
Stefan, George,
Recursive expansion requires recursive code. You don't like writing such code, George - you know it and I know it. Besides, the danger of recursive symbol expansion is looping, like (pseudo code):
%define %ABC = %ABC CHANGE XYZ %ABC
Errors like this CAN be detected at run time, but it requires a "results stack" that must be checked to avoid getting stuck in a loop (and, "loop" means "crash"). That careful code is needed to avoid trickier problems like:
%define %ABC = %DEF %define %DEF = %ABC CHANGE XYZ %ABC
Stefan, my recommendation is to create user environment variables at startup time, with some small utility of your own. That way, at every reboot, the most current variables' values are obtained to create your own 'special' variables. Then, you only need single-level expansion.
R
p.s. IBM compilers and assemblers generally allow nested COPY statements, but they typically limit the nesting to some maximum level. Once they reach the max, the COPY is halted. This is an easy way to prevent recursive copying errors like:
member ABC: COPY ABC
This is one way to prevent recursion errors, by limiting the number of recursion levels to a hard limit, without having to maintain and check a results stack.
|
|
|
Post by George on Jun 18, 2024 14:07:00 GMT -5
Robert: Frankly I can't get too worried about someone who shoots themselves in the foot as in your examples, they deserve whatever happens to them. Recursion is not brain surgery. This is trivial.
And I really wish you'd have a bit more confidence in my abilities. Recursion does not bother me. I've been doing it since the old IBM Assembler days, you do remember the old RENT attribute? RENT routines could call themselves very nicely. And it was a lot harder in Assembler than it is in PB, where you basically have to do nothing.
George
|
|
|
Post by Robert on Jun 18, 2024 14:20:24 GMT -5
Sorry, I meant no offense, I just seem to recall you disliking the idea of recursion.
RENT routines mainly add the RENT attribute to the object file, and for assembler, it does a small amount of checking to try to see if you violated RENT by storing something into the current object file. It also is used as a cross-check for PL/1 programs that have OPTIONS (MAIN, REENTRANT) in their high level procedure.
And yes, a very small example like this is easy to see it's wrong, but the problem comes when you have many definitions that have been edited over and over, and you didn't realize you made a mistake.
I believe the reason to use RENT in assembler was not that the code was going to call itself, but that other programs (maybe other tasks or threads in CICS, possibly) might call the same code, so you had to make sure you didn't modify any memory in the module itself, because it could get restarted in another thread before the first one was finished. Real reentrant code is rarely used.
R
|
|
|
Post by George on Jun 18, 2024 14:37:52 GMT -5
Robert:
Yes, with lots of symbolic equates, it's easier to muck up, best way here is to make it only two levels. As Stefan described his request, that's all that's needed. I can't even picture how additional levels could be logically used. And in IBM-land: These were all effectively Load-module attributes ultimately, as OBJ attributes they were an indication to the LinEdit that they were suitable.
RENT - Usable by any number of callers simultaneously, or recursively. REUS - Usable by only one caller at a time. REFR - Usable by only one caller at a time (I think), and not self modifying. (i.e. the memory image could be refreshed from disk. Nobody ever used this to my knowledge.
George
|
|
|
Post by George on Jun 18, 2024 14:39:40 GMT -5
Stefan: Are symbols to be resolved when 1st entered, or are they to remain in their native form and only resolved when actually put in play?
Big difference.
George
|
|
|
Post by Stefan on Jun 19, 2024 8:44:51 GMT -5
George,
You asked: "Are symbols to be resolved when 1st entered, or are they to remain in their native form and only resolved when actually put in play?"
I assume you mean for the FM Filepath scenario. In short, whatever the user typed should be expanded at the next ATTN event they cause (<ENTER>/navigate away from FM Filepath, etc).
Personally, I enter the name of an %environment-variable% to avoid (mis)typing a longish file path.
And I reckon that when a user manually enters any file path, they tend to press <ENTER> to EITHER...
a) bring up the folder's content, OR... b) expand any %symbolic% names
(Some, me included!, may press <ENTER>, expecting SPFLite to validate the path's existance, but it doesn't do that anyway.)
Robert, You said: "Recursive expansion requires recursive code.
I disagree. I have a routine to do this, albeit in REXX. It's simply a question of nested loops.
EnvDecode: PROCEDURE ------------------------------------------------------------------------------------------ -- Returns value with environment variable(s) (if any) expanded -- Called: path = EnvDecode("%USERPROFILE%\RECENT\") ------------------------------------------------------------------------------------------ PARSE ARG pName DO WHILE pName~POS("%") > 0 /* While %variables% are present */ newName = "" DO WHILE pName~POS("%") > 0 /* Work through the string */ PARSE VAR pName front "%" envVar "%" rear /* Split the string */ envVal = VALUE(envVar,,"ENVIRONMENT") /* Get environment value */ IF envVal = "" THEN envVal = "?"envVar"?" /* If bad, use ?Var_Name? */ newName = newName || front || envVal /* Update new string */ pName = rear /* Search rest of string */ END pName = newName || rear /* Update pName with new value */ END /* Loop for imbedded %vars% */ RETURN pName
If the replacement of % with ? in case of an undefined variable offends, just replace all ? with % before the RETURN
|
|
|
Post by Robert on Jun 19, 2024 12:17:51 GMT -5
Yes, there are several ways to simulate recursion using loops and arrays, this is one of them. Most simulation techniques have much higher overhead than true recursion does, but the strings you are processing are short. I am sure you could convert this logic to PB.
R
|
|
|
Post by George on Jun 19, 2024 12:46:15 GMT -5
Robert: There is already a PB function in SPFLite to do this as we support Env. variables elsewhere. It closely follows Stefan's REXX implementation. i.e. it does a rescan till no %xx% variables are left.
George
|
|