[Info-vax] Local Versus Global Command Options

Mark Berryman mark at theberrymans.com
Sat Feb 15 14:22:59 EST 2025


On 2/14/25 6:02 PM, Arne Vajhøj wrote:
> On 2/14/2025 6:49 PM, Arne Vajhøj wrote:
>> On 2/14/2025 2:02 PM, Simon Clubley wrote:
>>>                                                              It also
>>> doesn't help you with the main problem I mentioned, which is parsing
>>> and validating the filter syntax. 
>>
>>> How would you turn the list of filters, each with their own syntax, into
>>> something that can be validated by DCL ? As a reminder, it is critical
>>> that the filters are available to the program in the order they were
>>> specified on the command line.
>>
>> I think that can be define in CLD.
>>
>> $ type fun4.cld
>> define verb fun4
>>      image "sys$disk:[]fun4"
>>      parameter p1, value(type=$file, list, required)
>> qualifier filter, value(type=filter_type, list, required), 
>> placement=local
>> define type filter_type
>>      keyword filtera, value(type=filtera_type, list, required)
>>      keyword filterb, value(type=filterb_type, list, required)
>> define type filtera_type
>>      keyword a1, value(type=$number, required)
>>      keyword a2, value(type=$number, required)
>>      keyword x, value(type=$number, required)
>> define type filterb_type
>>      keyword b1, value(type=$number, required)
>>      keyword b2, value(type=$number, required)
>>      keyword x, value(type=$number, required)
>> $ type fun4.pas
>> [inherit('sys$library:pascal$cli_routines')]
>> program fun4(input,output);
>>
>> type
>>     pstr = varying [255] of char;
>>     filter_type = (filtera, filterb);
>>
>> var
>>     filter_list : array [1..100] of filter_type;
>>     fnm, filter, a1, a2, b1, b2, x : pstr;
>>     nfilters, i : integer;
>>
>> begin
>>     while odd(cli$get_value('P1', fnm.body, fnm.length)) do begin
>>        write(fnm);
>>        nfilters := 0;
>>        while odd(cli$get_value('FILTER', filter.body, filter.length)) 
>> do begin
>>           nfilters := nfilters + 1;
>>           if index(filter, 'FILTERA') = 1 then
>>              filter_list[nfilters] := filtera
>>           else if index(filter, 'FILTERB') = 1 then
>>              filter_list[nfilters] := filterb
>>           else
>>              halt;
>>        end;
>>        for i := 1 to nfilters do begin
>>           write(' ', filter_list[i]);
>>           case filter_list[i] of
>>              filtera:
>>                 begin
>>                    write(' filtera');
>>                    cli$get_value('FILTERA.A1', a1.body, a1.length);
>>                    write(' a1=', a1);
>>                    cli$get_value('FILTERA.A2', a2.body, a2.length);
>>                    write(' a2=', a2);
>>                    cli$get_value('FILTERA.X', x.body, x.length);
>>                    write(' x=', x);
>>                 end;
>>              filterb:
>>                 begin
>>                    write(' filterb');
>>                    cli$get_value('FILTERB.B1', b1.body, b1.length);
>>                    write(' b1=', b1);
>>                    cli$get_value('FILTERB.B2', b2.body, b2.length);
>>                    write(' b2=', b2);
>>                    cli$get_value('FILTERB.X', x.body, x.length);
>>                    write(' x=', x);
>>                 end;
>>           end;
>>        end;
>>        writeln;
>>     end;
>> end.
>> $ pas fun4
>> $ lin fun4
>> $ set comm fun4
>> $ fun4 f1.dat/ 
>> filter=(filtera=(a1:12,a2:34,x:1234),filterb=(b1:56,b2:78,x:5678)),-
>>
>> f2.dat/filter=(filterb=(b2:87,b1:65,x:8765),filtera=(a2:43,a1:21,x:4321))
>> f1.dat  FILTERA filtera a1=12 a2=34 x=1234  FILTERB filterb b1=56 
>> b2=78 x=5678
>> f2.dat  FILTERB filterb b1=65 b2=87 x=8765  FILTERA filtera a1=21 
>> a2=43 x=4321
> 
> But I like this version better:
> 
> $ type fun5.cld
> define verb fun5
>      image "sys$disk:[]fun5"
>      parameter p1, value(type=$file, list, required)
> qualifier filter, value(type=$quoted_string, list, required), 
> placement=local
> $ type fun5sup.cld
> module fun5sup
> define verb fa
>      qualifier a1, value(type=$number, required)
>      qualifier a2, value(type=$number, required)
>      qualifier x, value(type=$number, required)
> define verb fb
>      qualifier b1, value(type=$number, required)
>      qualifier b2, value(type=$number, required)
>      qualifier x, value(type=$number, required)
> $ type fun5.pas
> [inherit('sys$library:pascal$cli_routines')]
> program fun5(input,output);
> 
> type
>     pstr = varying [255] of char;
>     finfo = record
>                fnm : pstr;
>                nfilter : integer;
>                filter_list : array [1..100] of pstr;
>             end;
> 
> var
>     fun5sup : [external] integer;
> 
> var
>     finfo_list : array [1..100] of finfo;
>     fnm, filter, a1, a2, b1, b2, x : pstr;
>     n, i, j : integer;
> 
> begin
>     n := 0;
>     while odd(cli$get_value('P1', fnm.body, fnm.length)) do begin
>        n := n + 1;
>        finfo_list[n].fnm := fnm;
>        finfo_list[n].nfilter := 0;
>        while odd(cli$get_value('FILTER', filter.body, filter.length)) do 
> begin
>           finfo_list[n].nfilter := finfo_list[n].nfilter + 1;
>           finfo_list[n].filter_list[finfo_list[n].nfilter] := 
> substr(filter, 2, length(filter) - 2);
>        end;
>     end;
>     for i := 1 to n do begin
>        write(finfo_list[i].fnm);
>        for j := 1 to finfo_list[i].nfilter do begin
>           cli$dcl_parse(finfo_list[i].filter_list[j], fun5sup);
>           if index(finfo_list[i].filter_list[j], 'fa') = 1 then begin
>              write(' fa');
>              cli$get_value('A1', a1.body, a1.length);
>              write(' a1=', a1);
>              cli$get_value('A2', a2.body, a2.length);
>              write(' a2=', a2);
>              cli$get_value('X', x.body, x.length);
>              write(' x=', x);
>           end else if index(finfo_list[i].filter_list[j], 'fb') = 1 then 
> begin
>              write(' fb');
>              cli$get_value('B1', b1.body, b1.length);
>              write(' b1=', b1);
>              cli$get_value('B2', b2.body, b2.length);
>              write(' b2=', b2);
>              cli$get_value('X', x.body, x.length);
>              write(' x=', x);
>           end else begin
>              halt;
>           end;
>        end;
>        writeln;
>     end;
> end.
> $ set comm/obj fun5sup
> $ pas fun5
> $ lin fun5 + fun5sup
> $ set comm fun5
> $ fun5 f1.dat/filter=("fa /a1=12 /a2:34 /x=1234","fb /b1=56 /b2=78 / 
> x=5678"),-
>         f2.dat/filter=("fb /b2=87 /b1:65 /x:8765","fa /a2=43 /a1=21 / 
> x=4321")
> f1.dat fa a1=12 a2=34 x=1234 fb b1=56 b2=78 x=5678
> f2.dat fb b1=65 b2=87 x=8765 fa a1=21 a2=43 x=4321

Way back when an Alpha workstation was my desktop, it had a good 
graphics card and a sound card.  During this time I got mplayer running 
on VMS and was even able to use it to play DVDs.  Sadly, subsequent to 
that time, itanium was too noisy for a desktop and VMS on x86 has no 
multimedia support.

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.

So, IMHO, DCL is superior in this regard.  The one thing I wish it had, 
in regards to command-line parsing, was a setting that meant "set the 
PIPE command as default".  I am one of those users who only has ODS-5 
disks, always has parse_style set to extended, and all my utilities 
still using *nix syntax use lib$initialize.

Mark Berryman


More information about the Info-vax mailing list