[Info-vax] Local Versus Global Command Options
Arne Vajhøj
arne at vajhoej.dk
Mon Feb 17 21:41:07 EST 2025
On 2/15/2025 3:20 PM, Arne Vajhøj wrote:
> On 2/15/2025 2:22 PM, Mark Berryman wrote:
>> On *nix, one's program can define any command syntax desired since the
>> command-line parsing is done entirely within the program. The shell
>> doesn't really do anything except try to expand unquoted wildcards
>> (which somewhat limits the use of wildcards since the program cannot
>> differentiate between a source wildcard and a destination wildcard).
>> On VMS, DCL can do it either way. One can define a syntax that allows
>> DCL to do the parsing as Arne has shown, or one can tell DCL to simply
>> pass the command line to the program and let the program do all of the
>> parsing. One advantage of the former is that if the command-line
>> fails to parse, the program never even has to be activated.
>
> A VMS program has choices:
> 1A) SET COMM and CLI$
> 1B) SET COMM/OBJ, LIB$GET_FOREIGN and CLI$
> 2) LIB$GET_FOREIGN and custom parsing
> 3) Language specific way to get individual arguments
Pascal demo:
$ type cl1a.cld
define verb cl1a
image "sys$disk:[]cl1a"
qualifier f, value(type=$file, required)
$ set comm cl1a
$ type cl1a.pas
[inherit('pascal$cli_routines')]
program cl1a(input,output);
type
pstr = varying [255] of char;
var
f : pstr;
begin
cli$get_value('F', f.body, f.length);
writeln('Pascal CL1A F=', f);
end.
$ pas cl1a
$ link cl1a
$ cl1a /f=z.z
Pascal CL1A F=z.z
$ type cl1bsup.cld
module cl1bsup
define verb cl1b
qualifier f, value(type=$file, required)
$ type cl1b.pas
[inherit('sys$library:pascal$lib_routines',
'sys$library:pascal$cli_routines')]
program cl1b(input,output);
type
pstr = varying [255] of char;
var
cl1bsup : [external] integer;
cmdlin : pstr;
f : pstr;
i : integer;
begin
lib$get_foreign(cmdlin.body, , cmdlin.length);
for i := 1 to length(cmdlin) do begin
if cmdlin[i] = '-' then begin
cmdlin[i] := '/';
end else if cmdlin[i] = ' ' then begin
cmdlin[i] := '=';
end;
end;
cli$dcl_parse('cl1b ' + cmdlin, cl1bsup);
cli$get_value('F', f.body, f.length);
writeln('Pascal CL1B F=', f);
end.
$ set comm/obj cl1bsup
$ pas cl1b
$ link cl1b + cl1bsup
$ cl1b :== $sys$disk:[]cl1b
$ cl1b /f=z.z
Pascal CL1B F=z.z
$ cl1b -f z.z
Pascal CL1B F=z.z
$ type cl2.pas
[inherit('sys$library:pascal$lib_routines')]
program cl1b(input,output);
type
pstr = varying [255] of char;
var
cmdlin : pstr;
f : pstr;
ix : integer;
begin
lib$get_foreign(cmdlin.body, , cmdlin.length);
ix := index(cmdlin, '-f ');
f := substr(cmdlin, ix + 3, length(cmdlin) - ix - 2);
writeln('Pascal CL2 F=', f);
end.
$ pas cl2
$ link cl2
$ cl2 :== $sys$disk:[]cl2
$ cl2 -f z.z
Pascal CL2 F=z.z
C demo:
$ type cl1a.cld
define verb cl1a
image "sys$disk:[]cl1a"
qualifier f, value(type=$file, required)
$ set comm cl1a
$ type cl1a.c
#include <stdio.h>
#include <stdint.h>
#include <descrip.h>
#include <cli$routines.h>
int main()
{
char f[255];
int16_t flen;
$DESCRIPTOR(fnamedesc, "F");
$DESCRIPTOR(fdesc, f);
cli$get_value(&fnamedesc, &fdesc, &flen);
f[flen] = 0;
printf("C CL1A F=%s\n", f);
return 0;
}
$ cc cl1a
$ link cl1a
$ cl1a /f=z.z
C CL1A F=z.z
$ type cl1bsup.cld
module cl1bsup
define verb cl1b
qualifier f, value(type=$file, required)
$ type cl1b.c
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <descrip.h>
#include <lib$routines.h>
#include <cli$routines.h>
globalvalue int32_t cl1bsup;
int main()
{
char cmdlin[256];
int16_t cmdlinlen;
$DESCRIPTOR(cmdlindesc, cmdlin);
lib$get_foreign(&cmdlindesc, 0, &cmdlinlen);
cmdlin[cmdlinlen] = 0;
for(int i = 0; i < cmdlinlen; i++)
{
if(cmdlin[i] == '-') cmdlin[i] = '/';
if(cmdlin[i] == ' ') cmdlin[i] = '=';
}
char cmdlin2[256];
$DESCRIPTOR(cmdlin2desc, cmdlin2);
strcpy(cmdlin2, "CL1B ");
strcat(cmdlin2, cmdlin);
cmdlin2desc.dsc$w_length = strlen(cmdlin2);
cli$dcl_parse(&cmdlin2desc, cl1bsup);
char f[256];
int16_t flen;
$DESCRIPTOR(fnamedesc, "F");
$DESCRIPTOR(fdesc, f);
cli$get_value(&fnamedesc, &fdesc, &flen);
f[flen] = 0;
printf("C CL1B F=%s\n", f);
return 0;
}
$ set comm/obj cl1bsup
$ cc cl1b
$ link cl1b + cl1bsup
$ cl1b :== $sys$disk:[]cl1b
$ cl1b /f=z.z
C CL1B F=z.z
$ cl1b -f z.z
C CL1B F=z.z
$ type cl2.c
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <descrip.h>
#include <lib$routines.h>
int main()
{
char cmdlin[256];
int16_t cmdlinlen;
$DESCRIPTOR(cmdlindesc, cmdlin);
lib$get_foreign(&cmdlindesc, 0, &cmdlinlen);
cmdlin[cmdlinlen] = 0;
char *p = strstr(cmdlin, "-f");
char f[256];
strcpy(f, p + 3);
printf("C CL2 F=%s\n", f);
return 0;
}
$ cc cl2
$ link cl2
$ cl2 :== $sys$disk:[]cl2
$ cl2 -f z.z
C CL2 F=z.z
$ type cl3.c
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main(int argc, char *argv[])
{
char *f = "";
bool fnext = false;
for(int i = 0; i < argc; i++)
{
if(fnext) f = argv[i];
fnext = strcmp(argv[i], "-f") == 0;
}
printf("C CL3 F=%s\n", f);
return 0;
}
$ cc cl3
$ link cl3
$ cl3 :== $sys$disk:[]cl3
$ cl3 -f z.z
C CL3 F=z.z
Python demo:
$ type cl3.py
import sys
f = ''
fnext = False
for arg in sys.argv:
if fnext:
f = arg
fnext = arg == '-f'
print(f"Python C3 F={f}")
$ python cl3.py -f z.z
Python C3 F=z.z
(the CL2 parsing examples are not robust, but that is another
topic)
Arne
More information about the Info-vax
mailing list