The C/C++ Language Reference on p. 207 says "Under z/OS batch . argv[0]
Returns the program name in uppercase argv[1 to n] Returns the arguments as
you enter them." Not the most useful documentation - I don't think "as you
enter them" is terribly clear as it pertains to z/OS batch.
The C/C++ User's Guide on p. 70 says "When NOARGPARSE is in effect,
arguments on the invocation line are not parsed, argc has a value of 2, and
argv contains a pointer to the string."
Question: Does anyone know if a NOARGPARSE C++ program called via LINK or
ATTACH would receive parm 2 - the second word pointed to by R1 - anywhere?
Is there a recommended way to do this?
What I'd like to end up with is a C program that "did me no favors" - if
invoked from JCL EXEC, then argv[1] would point to the PARM= string if any
("as is") and if called via LINK or ATTACH would get the vector pointed to
by the caller's R1 as argv[1, 2, 3 .].
Anyone know the answer to this?
Thanks,
Charles Mills
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to list...@bama.ua.edu with the message: GET IBM-MAIN INFO
Search the archives at http://bama.ua.edu/archives/ibm-main.html
I'm assuming that if you are going to call via link or attach that you will
have an assembler main program that does not have a valid
LE environment established. That is to say a traditional assembler program.
If this is the case, you should refer to the CEEPIPI documentation (located
in Language Environment Programming Guide) on how to establish a valid
LE environment and call a C program from assembler. It will tell you how to
pass parms to your C program.
The comment "argv[1 to n]" is trying to say that the characters in parms 1
... N are not modified by converter/interpreter processing when JCL is
submitted. If you turn CAPS OFF, you can pass mixed case characters as parm
and they will be received by the C program as mixed case. Naturally, you
will need to enclose them in quotes. See the JCL reference manual for
details.
I would not recommend linking or attaching to a C program from an assembler
program without going through CEEPIPI. CEEPIPI does a lot of setup related
to LE and has provisions for keeping the C runtime separate by "enclave".
Let me know if you have questions about CEEPIPI. I have some programs that
use it, but they would need to be cut done as they are to intertwined with
other logic to post.
Regards,
Sam
The other option you have is to look at METAL C or system C. Or a third
party compiler.
Regards,
Sam
On Sat, Dec 26, 2009 at 9:14 PM, Charles Mills <char...@mcn.org> wrote:
Well, you normally get an integer which contains the number of
subsequent arguments:
void main(int argc, char *argv[]);
'argc' is the traditional name used for a variable to hold
the first value, and argv the traditional name for the
second value; the second value is an array of words, each
word presented as a separate element in the array, in the
case you entered it on the PARM= parameter on the EXEC
statement. Actually, each argument is a pointer to the
corresponding word. As you noted, argv[0] contains the
program name.
A 'word' is delimited by blanks; leading and trailing spaces
are stripped off. In this list of words, each is terminated
by a null (x'00).
>
>
>
> The C/C++ User's Guide on p. 70 says "When NOARGPARSE is in effect,
> arguments on the invocation line are not parsed, argc has a value of 2, and
> argv contains a pointer to the string."
Right. argv[0] is still the program name; argv[1] is the unparsed
parm string as entered on the EXEC statement.
>
>
>
> Question: Does anyone know if a NOARGPARSE C++ program called via LINK or
> ATTACH would receive parm 2 - the second word pointed to by R1 - anywhere?
> Is there a recommended way to do this?
Well, I don't do C++, but some notes for C below:
>
>
>
> What I'd like to end up with is a C program that "did me no favors" - if
> invoked from JCL EXEC, then argv[1] would point to the PARM= string if any
> ("as is") and if called via LINK or ATTACH would get the vector pointed to
> by the caller's R1 as argv[1, 2, 3 .].
Since C programs are LE-based, why not use the LE callable service CEE3PRM?
_VSTRING p_mess;
char char_work [88];
char * p_ptr;
...
CEE3PRM(char_work, &fc);
strcpy(p_mess.string, "Parm = ");
p_ptr = strcat(p_mess.string,char_work);
p_mess.length = 87;
CEEMOUT(&p_mess, &dest, &fc);
(well, one reason is that CEE3PRM is restricted to 80 characters;
but if that's not a problem, this is a good way to go)
>
>
>
> Anyone know the answer to this?
Not sure if this will get you going or not. Good luck.
--
Kind regards,
-Steve Comstock
The Trainer's Friend, Inc.
303-393-8716
http://www.trainersfriend.com
z/OS Application development made easier
* Our classes include
+ How things work
+ Programming examples with realistic applications
+ Starter / skeleton code
+ Complete working programs
+ Useful utilities and subroutines
+ Tips and techniques
==> Ask about being added to our opt-in list: <==
==> * Early announcement of new courses <==
==> * Early announcement of new techincal papers <==
==> * Early announcement of new promotions <==
Thanks and thanks.
I'm trying to write a C++ program that will allow "standard" z/OS utility
linkage. It wants to look as much as possible like other programs that
expect a parm 1 and a parm 2 passed via R1 -> words 0 and 1.
I can do whatever I want on the C++ side but I would like the caller to be
able to use "standard" linkage.
The C++ program is big and involved and I really can't afford to give up the
C/C++ library.
I just ran an experiment and determined two things:
1. The C++ program can be loaded via "standard" assembler macros absent any
CEE routines with no problems. I used LINKMVS from Rexx because it was easy
to do.
2. However ... argv[0] = the C program's name; argv[1] = the first parameter
passed on LINKMVS; the second parameter was nowhere to be found. This is a
problem.
I see writing an assembler stub to get control first, establish the LE
environment, and then call the C++ main (or a "pseudo-" main), passing the
two arguments somehow, probably as a list passed as argv[1].
Does anyone know an easier way? Seems like a pretty obvious need: write a
C++ program that starts up with standard z/OS
multiple-parameter-pointers-pointed-to-by-R1 linkage.
Charles
Charles,
Regards,
Sam
----------------------------------------------------------------------
Actually, the linkage you describe is only 'standard' for a
subroutine. Standard linkage for a main program is to be
passed a single parm, the address of a half-word prefixed string,
pointed at by R1. A main program cannot accept multiple parms,
in the sense of a list of addresses longer than one entry.
--
Kind regards,
-Steve Comstock
The Trainer's Friend, Inc.
303-393-8716
http://www.trainersfriend.com
z/OS Application development made easier
* Our classes include
+ How things work
+ Programming examples with realistic applications
+ Starter / skeleton code
+ Complete working programs
+ Useful utilities and subroutines
+ Tips and techniques
==> Ask about being added to our opt-in list: <==
==> * Early announcement of new courses <==
==> * Early announcement of new techincal papers <==
==> * Early announcement of new promotions <==
----------------------------------------------------------------------
Look at the PLIST(OS) option in the C/C++ users guide for a way to pass
parms in the traditional MVS way of a pointer to an array of pointers to
parameters.
Then look at the Language Environment Programming Guide chapter "using
language environment parameter list formats" and also Appendix D "Operating
System and Subsystem Parameter List Formats".
Between these two you may get what you want.
I've never used LINKMVS or its relations as I'm not a REXX guy. However,
based on experience using C/C++ in a multi-TCB application, the use of
CEEPIPI is required if the C/C++ program is called as a sub-routine from an
assembler main. I suspect that LINKMVS (or the C/C++ program) is establish
the C/C++ enclave in each call and it is destroyed on each return. The
performance hit on this is huge. If the assembler main is only making one
call the C/C++ program then it does not matter. If repeated calls are
involved, the look into CEEPIPI.
Regards,
Sam
o The parameter string
o a list of alternate DD names
o An initial page number for SYSPRINT.
Are utilities subroutines or main programs if they can accept
multiple parms?
I believe this is a restriction of the caller, not the called
"program" or "subroutine". JCL (and perhaps some other languages)
can pass only one parm. Assembler, Rexx, and many other languages
can pass multiple parms. The OP is seeking a way that a C program
can access those parms. He'd be home free if he could get the
content of GR1 as passed to CALL/LINK/ATTACH.
-- gil
> A main program cannot accept multiple parms
Really? Tell that to all of the compilers and the DFSMS utilities <g>.
Charles
-----Original Message-----
From: IBM Mainframe Discussion List [mailto:IBM-...@bama.ua.edu] On Behalf
Of Steve Comstock
Sent: Saturday, December 26, 2009 5:28 PM
To: IBM-...@bama.ua.edu
Subject: Re: argv for z/OS C++ batch
Well, OK, a program invoked by JCL can only be passed a single
parm string; as Paul pointed out, this is a limitation of JCL,
not the invoked program.
>For caps on/caps off, I was referring to ISPF edit.
>
That has very little to do with how JCL passes parms, nor
how C/C++ receives them, nor with any other editor the user
chooses because it has less restrictive conventions.
More relevant, and truly dismaying, I stumbled onto:
Title: z/OS V1R10.0 XL C/C++ User's Guide
Document Number: SC09-4767-07
http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/cbcug170/11.3.2
11.3.2 Passing arguments to the z/OS XL C/C++ application
How the z/OS XL C/C++
program is invoked Example Case of argument
By CALL command (with CALL program Args ASIS Mixed case (However,
control arguments if you pass the
ASIS arguments entirely in
upper case, the
argument will be
changed to lower
case.)
WTF!?
Sheesh. "ASIS" should mean ASIS. Lower case is left lower _and_
upper case is left upper.
This is an egregious example of not fixing breakage where it
occurred, but introducing additional breakage elsewhere with
the misguided and futile hope that it will offset the original.
A C/C++ program will recieve parms as passed (subject to the PLIST(OS|HOST)
setting) and will not change the case of the passed parameters. In fact you
can send hex values (except x'00') in a parm from JCL by turing HEX ON.
With the information you have provided we can see that the TSO has different
rules for parm processing that JCL. Neither the TSO or JCL rules apply to
program to program calls.
Regards,
Sam
- Yes, I'm clear on the difference between the restrictions imposed by PARM=
(one parm, 100 chars), TSO (a tendency to convert to U/C, and yes, I agree
with gil, over-compensating by converting to l/c when ASIS is specified is
just brain dead), ISPF (a tendency to convert to u/c), and C argv (only one
parm, possibly parsed into words).
- Thank you to Sam who suggested and was kind enough to send me a sample of
CEEPIPI. (Who names these things? I'm hanging out for the holidays with a
four-year-old granddaughter and all I can think of is how she would find
that name hilarious.) Unfortunately, the problem it solves is not the
problem I have. I have a "parm2" problem, not a "performance on multiple
assembler to C calls" problem. The assembler program would be calling the C
program once, or at most "a few" times. AND I have little control over the
assembler code, only the C code.
- Thank you for the suggestion of CEE3PRM which lets a "downstream" function
find the PARM= parameter. Unfortunately, that again is not the problem I
have. I've got a parm2 problem, and if necessary, I can pass it around
myself. It does, however, have the side benefit of making the 100 char
restriction in PARM= look generous. Who decided that 100 chars was too
generous and that 80 would be more than sufficient? (In fairness, there is a
version without that restriction.)
- Thank you especially for the suggestion of the __R1 macro. That seems to
do the job. It may have to go in the main program -- I had problems with
putting it in a downstream function, but I moved it to main() and did not
fully pursue getting it to work outside of main. Its companion __osplist or
whatever it was called looked promising also but I got the problem solved
with __R1. For anyone who is reading this thread and wants the solution,
here is what is working now. (I also am compiling with PLIST(OS) but I don't
*think* that is relevant.) This code could be shortened but this is what is
working at the moment:
// in the main() program
long *r1 = (long *)__R1; // declares r1 a pointer to a long (address)
char *pm1 = (char *)(*r1); // makes pm1 a char ptr for r1's 1st parm
r1++; // makes r1 point to next parm address
char *pm2 = (char *)(*r1); // makes pm2 a char ptr for r1's 2nd parm
Charles
>Were splitting hairs here. The original question related specifically to
>batch processing. (I took this to mean JCL/Converter/Interpreter.) The
>information from the link is related to tso and the tso call facility.
> There is no ASIS facility within a C/C++ program.
>
... even as there's no CAPS facility in JCL.
It's important that these hairs be split. The programmer must be
able to tell whether his data is being munged by ISPF, JCL, TSO,
LE, or ??? something else.
The document at:
>> http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/cbcug170/11.3.2
makes much mention of TSO, CALL, ASIS, etc. Yet it led me to believe it
was describing operation of LE -- that's the title of the document.
Better it should contain a cross reference to the TSO RM so the programmer
could read the description in its intuitive context.
However, in
http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/ikj4c590/1.10.3
I read:
1.10.3 "z/OS V1R10.0 TSO/E Command Reference"
ASIS | CAPS
ASIS prevents translation of a parameter list to uppercase
characters. Use ASIS for programs that accept mixed
case characters in a parameter list; the CALL
command will not alter the parameters in any way
when the ASIS option is specified.
The phrase "will not alter the parameters in any way" is pretty
emphatic. (We must infer a reasonable exception for doubled
apostrophes, etc. But that happens at a different layer.)
In fact, an experiment with a non-LE utility shows that TSO
CALL *(ASMA90) 'SYSPARM(ALLCAPS)' ASIS
passes the entirely uppercase PARM to the program in uppercase.
If the conversion to lowercase is performed it must be done by
another component. LE? C/C++? I haven't the resources to
perform that experiment.
>A C/C++ program will recieve parms as passed (subject to the PLIST(OS|HOST)
>setting) and will not change the case of the passed parameters. In fact you
>can send hex values (except x'00') in a parm from JCL by turing HEX ON.
>
More conflation of environments. In fact:
o I can send any character value in a parm from JCL without ever
turning HEX ON. HEX, like CAPS, is not a JCL facility, and belongs
in a discussion of some component other than JCL.
o I can pass the the value of the x'00' character in a parm from JCL.
Some other component (LE? C/C++ again?) may not accept it.
>With the information you have provided we can see that the TSO has different
>rules for parm processing that JCL. Neither the TSO or JCL rules apply to
>program to program calls.
>
... which is the reason we should be clear about which component we
are discussing.
-- gil
Try specifying the length as the 1st parm.
ATTACH EP=CPGM,ECB=STECB,PARAM=(PPARM)
PPARM DC H'17',C'PARM1,PARM2,PARM3'
Your results should be:
2 /* argc */
CPGM /* argv0 */
PARM1,PARM2,PARM3 /* argv1 */
hth,
Dave Waldman
On Sat, 26 Dec 2009 16:14:39 -0500, Charles Mills <char...@MCN.ORG>
wrote:
>Question: Does anyone know if a NOARGPARSE C++ program called via LINK or
>ATTACH would receive parm 2 - the second word pointed to by R1 -
anywhere?
>Is there a recommended way to do this?
>
>What I'd like to end up with is a C program that "did me no favors" - if
>invoked from JCL EXEC, then argv[1] would point to the PARM= string if any
>("as is") and if called via LINK or ATTACH would get the vector pointed to
>by the caller's R1 as argv[1, 2, 3 .].
>
>Anyone know the answer to this?
----------------------------------------------------------------------
From the 'Language Environment Programming Guide',
PLIST indicates in what form the invoked routine should expect the argument
list. You can specify PLIST with the following values under Language
Environment:
HOST The argument list is assumed to be a character string. The string is
located differently under various systems as follows:
Under TSO, if a CPPL is detected, Language Environment gets the
string from the command buffer.
Under TSO, if a CPPL is not detected, Language Environment assumes a
halfword-prefixed string in the MVS format.
Under MVS, Language Environment uses the halfword-prefixed string.
OS The inbound parameter list is assumed to be in an MVS linkage format in
which register 1 points to a parameter address list. No run-time options are
available. Register 1 is not interrogated by Language Environment.
The PLIST(HOST) setting allows the object to execute under MVS
(assuming a halfword-prefixed string), or under TSO (using the CPPL or the
MVS-format parameter list). Specify PLIST(HOST) to default to the
argument list format for the operating system under which your application
is running.
Another example using LINK and specifying a half-word prefixed length:
LINK EP=pgmname,PARAM=PPARM
PPARM DC H'17',C'PARM1 PARM2 PARM3'
With ARGPARSE and PLIST(HOST) the results should be:
4 /* argc */
pgmname /* argv0 */
PARM1 /* argv1 */
PARM2 /* argv2 */
PARM3 /* argv3 */
regards,
Dave Waldman
Charles
-----Original Message-----
From: IBM Mainframe Discussion List [mailto:IBM-...@bama.ua.edu] On Behalf
Of David Waldman
Sent: Tuesday, December 29, 2009 10:13 AM
To: IBM-...@bama.ua.edu
Subject: Re: argv for z/OS C++ batch
Blessedly, JCL is so antiquated that it makes no effort to implement
case-insensitivity. With luck, it may never happen, not in the brain
dead style of Binder.
>- Thank you especially for the suggestion of the __R1 macro. That seems to
>do the job. It may have to go in the main program -- I had problems with
>putting it in a downstream function, but I moved it to main() and did not
>fully pursue getting it to work outside of main. Its companion __osplist or
>whatever it was called looked promising also ...
>
I got curious:
user@3MVS:141$ grep __.*plist /usr/include/stdlib.h /dev/null
/usr/include/stdlib.h: #ifndef __sysplist
/usr/include/stdlib.h: #define __sysplist_i 12
/usr/include/stdlib.h: #define __sysplist ( (void * const *) \
/usr/include/stdlib.h: *((void ** const) (*(__gtab(__sysplist_i))) ) )
/usr/include/stdlib.h: #define __R1 ((void *) *((void **) (*(__gtab(__sysplist_i)))))
/usr/include/stdlib.h: #define __osplist ( (void **) __R1)
/usr/include/stdlib.h: #endif /* __sysplist */
user@MVS:138$ grep _Gtab `find /usr/include -print -name IBM -prune`
/usr/include/stdlib.h: #define __gtab(x) _Gtab(x)
/usr/include/stdlib.h: #pragma linkage(_Gtab, builtin)
/usr/include/stdlib.h: void **_Gtab(int);
So __osplist is merely a cast of __R1.
-- gil
>Actually, the linkage you describe is only 'standard' for a
>subroutine.
Part of the design of OS/360 is that a main program is just another
subroutine, except that it must accept the PARM passed by the Initiator or
TSO CALL.
>Standard linkage for a main program is to be passed a single parm,
>the address of a half-word prefixed string, pointed at by R1.
That's the standard was for the Initiator to invoke main programs, but the
same programs may, and do, accept other linkages as well.
>A main program cannot accept multiple parms, in the
>sense of a list of addresses longer than one entry.
I'm pretty sure that some of your courses include cases where they do
accept multiple parms, e.g., HLA. The IBM utilities test the end-of-list
bit to determine how long the list is.
--
Shmuel (Seymour J.) Metz, SysProg and JOAT
ISO position; see <http://patriot.net/~shmuel/resume/brief.html>
We don't care. We don't have to care, we're Congress.
(S877: The Shut up and Eat Your spam act of 2003)
>A C/C++ program will recieve parms as passed (subject to the
>PLIST(OS|HOST) setting) and will not change the case of the passed
>parameters.
What about argv[0]? The OP poster wrote
The C/C++ Language Reference on p. 207 says "Under z/OS batch .
argv[0] Returns the program name in uppercase
which, if true, is disastrous, since Unix file names are case dependent;
.\foo and .\Foo are different programs.
--
Shmuel (Seymour J.) Metz, SysProg and JOAT
ISO position; see <http://patriot.net/~shmuel/resume/brief.html>
We don't care. We don't have to care, we're Congress.
(S877: The Shut up and Eat Your spam act of 2003)
----------------------------------------------------------------------
I think that in this case, "batch" means "invoked via a JCL EXEC PGM=. I
hope it doesn't mean when invoked via BPXBATCH as a UNIX process. But,
then, you can't do a
//STEPNAME EXEC PGM=lcpgm
//STEPLIB DD PATH='/path/to/my/bin/directory'
//
Is there any way to invoke an HFS resident program via EXEC PGM=?
--
John McKown
Maranatha! <><
>In <4e2421a40912270056n1de...@mail.gmail.com>, on
>12/27/2009
> at 08:56 AM, Sam Siegel said:
>
>>A C/C++ program will recieve parms as passed (subject to the
>>PLIST(OS|HOST) setting) and will not change the case of the passed
>>parameters.
>
>What about argv[0]? The OP poster wrote
>
> The C/C++ Language Reference on p. 207 says "Under z/OS batch .
> argv[0] Returns the program name in uppercase
>
>which, if true, is disastrous, since Unix file names are case dependent;
>.\foo and .\Foo are different programs.
>
If by z/OS batch it refers to "// EXEC PGM=program-name", it must
be in upper case: I believe (not testing) that JCL won't even
permit quoting the name, and "in uppercase" should be regarded as
noise words.
-- gil
How would this help anyone? What benefits would it have over
BPXBATCH (or COZBATCH) ?
Kirk Wolf
Dovetailed Technologies
http://dovetail.com/products/cozbatch.html
o BPXBATCH: DD statements tend to evaporate.
o COZBATCH: The price is prohibitive to many sites. (I suppose
they could buy the service contract.)
>>>//STEPNAME EXEC PGM=lcpgm
>>>//STEPLIB DD PATH='/path/to/my/bin/directory'
-- gil
Just checking; I thought there was something in this question that
wasn't obvious.
It seems more likely that IBM would fix or replace BPXBATCH than to
change JCL and how EXEC PGM works.
(FWIW, COZBATCH is < 1 KLOC).
Besides - what you want in most cases for Unix binaries is to run the
user's default login shell and have input via "//STDIN DD *" (and have
it all run in the original address space). Changing "EXEC" to handle
Unix binaries would not necessarily address this aspect, nor the
problem that z/OS Unix standard files (fds) can't be automatically
redirected to/from MVS datasets.
Happy New Year,
Kirk Wolf
Dovetailed Technologies
http://dovetail.com
PS> Re: "Prohibitive"(?): COZBATCH is *free* to use but we offer paid
commercial support agreements if you require.
And I thought it unlikely that IBM would fix STDOUT and STDERR, but
they did that, but left STDIN broken.
>(FWIW, COZBATCH is < 1 KLOC).
>
>Besides - what you want in most cases for Unix binaries is to run the
>user's default login shell and have input via "//STDIN DD *" (and have
>it all run in the original address space). Changing "EXEC" to handle
>Unix binaries would not necessarily address this aspect, nor the
>problem that z/OS Unix standard files (fds) can't be automatically
>redirected to/from MVS datasets.
>
And when a C program run in batch with EXEC PGM= does fork(),
the child doesn't inherit stdin, stdout, or stderr. The language
of POSIX _almost_ makes this a violation, but it's slightly vague.
- Dave Rivers -
Charles Mills wrote:
--
riv...@dignus.com Work: (919) 676-0847
Get your mainframe programming tools at http://www.dignus.com