Aztec C: Execute external program with parameters

,

Hi there,
I am currently writing a small C program to start Microsoft Basic directly with a Basic program on a C128 in CP/M.
Unfortunately I only manage to start Basic but without the Basic program to be loaded.
I am using Aztech C version 1.06. To compile the finished program I use the attached compiler. As an intermediate step I have to use the assembler and it reports “8080 assembler”. The 8080 is an Intel. Is it possible that the error can be found here?

To test all this I use the emulator MYZ80 for MS-DOS which also emulates the Z80.
I wrote another program to see which parameters are passed. It shows that Basic is called normally, but the desired program only consists of confused characters.
Unfortunately I can only find Aztech C version 1.06 on the internet.

My C program to run the start looks like this:

main()
{
	execv("mbasic","GAME.BAS",0);
  
}

Welcome! I’m not familiar with all details of your setup, but it looks like the second parameter to execv should be an array of string pointers: the zeroth element should be the filename and the first element is the first parameter.

Try using execl instead of execv.

1 Like

Thank you for the answers.
I am an absolute beginner in C programming.
In the meantime I have found a code that I put together for my needs.
The problem now is that I have to enter e.g. G or 1 eight times (GAME.BAS = 8 ), but then the program to be loaded is actually started.
A bit confusing but it works.
How do I have to change the code so that I no longer have to enter a parameter.

main(argv)
  char ** argv;
{
  char ** _getargs();
  argv = _getargs(0, "GAME.BAS");
  execv("mbasic",argv,0);
}

I can’t do it on my own and ask for help with the small change. I just want to type a command to load mbasic with the game.
8 times pressing a key is not so nice.
Unfortunately it doesn’t work with execl.
Only the getargs would have to be removed but I don’t know what command to use to replace getargs.

Hi,

first a disclaimer: I’m neither a C-wizard nor do I have any idea of Aztec C and its specifics.

That said, i you want to use execv(), on UNIX/Linux this has the following signature:

int execv( const char * path, char * const argv[] );

Meaning, it takes a pointer to an array of char(acters) as the first argument for the path of the program to be called, and a second pointer to an array for the arguments.
So the first argument is your command, like mbasic (or rather the full path to this program).
The second agrument is used as the ARGV for this program, i.e., first the program name, then any options and/or any “normal” arguments for this program, etc. This array is NULL terminated, meaning it MUST have NULL as the last element. (Otherwise, there will be a run-away at the attempt to parse the ARGV.) The first argument must always be the program name (which is always provided in ARGV[0].) Otherwise, this array may consist of multiple strings, e.g., for providing options and/or arguments (much like on the command line, where you use space-separated strings).

Your problem is that you attempt to re-use the ARGV of your C prorgam, rather than providing an array of its own for the called program. (This is also, why you have to type 8 random charactwers, as you need 8 characters for “GAME.BAS” to fit.)

So, how do we define such an array and how do we pass a pointer?
An array is defined by the variable name followed immediately by square brackets [], and the value part is provided in curly brackets ‘{}’. A pointer to a variable is denoted by an asterisk in front (*).
We can do this in a single definition (mind the program name as the first and NULL as last element of the array.)

main()
{
   char * arr[] = { "mbasic", "GAME.BAS", NULL };
   execv("mbasic", arr);
}

to understand the mechanism, consider this example (equivalent to “ls -aF” on the command line):

char * arr[] = { "ls", "-a", "-F", NULL };
execv("/bin/ls", arr);

(The first argument, “ls” in our array “arr” is the call name passed to the program. If we set it to “dir”, bin/ls would behave, as if we had set an alias in the shell and called it by this.)

Another – and probably simpler – way to do this is using execl(), where you just provide these arguments without packing them into arrays:

execl( "/bin/ls", "ls", "-a", "-F", NULL );

Mind how we do not have to define an array at all, since the call constructs one for us in order to pass the arguments.

In your case (on UNIX/Linux):

main()
{
   execl( "mbasic", "mbasic", "GAME.BAS", NULL );
}

Mind that the first "mbasic" should be the full path.


Edit, I had a look at Aztec C 1.06 for C/PM [1].
[1] Aztec_C_CPM_1.06_User_Manual_Mar84 Aztec C CPM 1.06 User Manual Mar84

The sigature of our call is:

execl(name, arg0, arg1, ..., argN, 0)

(The terminating 0 is equivalent to NULL in the above examples.)

Mind that CP/M has no directories, so the path is equal to the program name on Unix. But what is the program name on Unix (arg0) is never passed to the called program (and thus a dummy).
From the manual:

For execl (…) the arguments are arg1 arg1, … , argn. For execv (…) the arguments are argv[1], argv[2], … , argv[n]. Note that arg0 and argv[0] aren’t passed to the new program: on Unix these strings are conventionally the name 'of the program being executed.

So, I guess, it’s still:

main()
{
   execl( "mbasic", "mbasic", "GAME.BAS", 0 );
}
3 Likes

Having a fresh look at the quote from the manual, I think, we’re meant to repeat “GAME.BAS”:

main()
{
   execl( "mbasic", "GAME.BAS", "GAME.BAS", 0 );
}

That way, it’s arg1, arg1, … argN. (Mind that the second “mbasic” would have been arg0.)
However, if arg0 (between the pathname and the first argument) isn’t passed forward anyway, it shouldn’t matter much.

1 Like

Nice explanation, @NoLand! I think “arg1, arg1” might be a typo in the manual text. Earlier in the function prototype it has:

SYNOPSIS
	execl(name, arg0, arg1, ..., argn, 0)
	char *name, *arg0, *arg1, ..., *argn;

And the subsequent sentence describing execv has what you would normally expect:

For execv and execvp the arguments are argv[1], argv[2], ..., argv[n].

Which makes me think your original version is the logically correct one, although, like you say, I suppose it doesn’t technically matter what you put into arg0 if the call ignores it…

Anyway I found this nice clean scan of the manual: http://www.clipshop.ca/Aztec/docs/Aztec_C_1.06_User_Manual_Mar84.pdf

2 Likes
main()
{
   execl( "mbasic", "GAME.BAS", "GAME.BAS", 0 );
}

It works!!! :flushed:

WOW, I’m totally happy! :smile:

I’ve been trying to solve this for 12 days. :sweat_smile:

Thanks alot!!! :upside_down_face:

2 Likes

Thank you very much for all the replies and help!!!

Thorougly needed! The one I found is full of OCR scan artifacts.
Thanks for digging up a better one!

Actually, I’m not so sure about execv(). Both signatures include arg0, with the note specifying a preferred dummy argument (2 × arg1) for execl. So I would expect the argv-array for execv to start with a dummy argument, as well. To say the least, the two calls are not in sync, as far as this note is concerned. (I’m too lazy to install the required environment and software to test this in order to find out more about this.)

Me too. Maybe @Mr.Jones will follow up and tell us how it goes!

Manuals (including the same clean one found by Paganini) are at Wonderfully Ancient Aztec C Manuals and Documentation
Edit: Hm, why does the forum software replace the link with the title from the page? When I see random links I prefer to see the actual link… anyway, it’s https://www.aztecmuseum.ca/docs/

`

1 Like

Well, because. The remedy: select the link, click the link icon at the top of the editor and paste the URL (again) as the title. Or in markdown: [title](https://www.example.com)

Thank you very much for that link. It’s a great read, and it even hints that its floating point internal representation is base 256, which @IsaacKuo had mentioned favorably in another thread.

2 Likes