tags:

views:

205

answers:

4

How can I call two C applications from within another C application?

e.g. :

pg1.c can be run as ./a.out pg1_args

pg2.c can be run as ./a.out pg2_args

I would like to write a program that can be run as:

./a.out pg1_args pg2_args

With the result being equivalent to :

./a.out pg1_args

./a.out pg2_args

./a.out pg1_args

./a.out pg2_args

the pg1 here is svm_scale and pg2 here is svm_predict , both taken from libsvm : http://www.csie.ntu.edu.tw/~cjlin/libsvm/

[ edit ]

@Jonathan ,

I wrote these programs for trying out this concept..

pg1.c

#include <stdio.h>
#include <string.h>

int main(int argc,char **argv)
{
    FILE *fin;
    fin=fopen("pg1file.txt","a");
    fprintf(fin,"%s",argv[1]);
    fflush(fin);
    fclose(fin);
}

pg2.c

#include <stdio.h>
#include <string.h>

int main(int argc,char **argv)
{
    FILE *fin;
    fin=fopen("pg2file.txt","a");
    fprintf(fin,"%s",argv[1]);
    fflush(fin);
    fclose(fin);
}

pg3.c :

#include<stdio.h>
#include<string.h>
int main(int argc,char **argv)
{
int i;
const char *cmd1 = strcat("./pg1 ",argv[1]);
const char *cmd2 = strcat("./pg2 ",argv[2]);
for(i=0;i<4;i++)
{
if (system(cmd1) != 0)
    printf("\n error executing pg 1"); 
if (system(cmd2) != 0)
    printf("\n error executing pg 2");
}
}

[root@localhost trinity]# ./a.out first second
Segmentation fault (core dumped)
[root@localhost trinity]# 

Could somebody explain what I've done wrong?

+4  A: 

A very simple solution is to use the system() function. Pass a program's command line to it to run the program.

Max Shawabkeh
+1  A: 

Probably the simplest technique is to build the two calls (are the two 'different' programs really both called a.out?) as a string and then use the system() function:

const char *cmd1 = "./a.out pg1_args";
const char *cmd2 = "./a.out pg2_args";

if (system(cmd1) != 0)
    ...report trouble...
if (system(cmd2) != 0)
    ...report trouble...

Clearly, you would normally build those command lines from the arguments passed to your program, rather than hard-wiring them as shown. Just be wary of buffer overflows and unexpected characters when you build the command lines.

Jonathan Leffler
okay , i'll try this , thanks.
trinity
@trinity: R Samuel Klatchko shows what I had in mind; I was flying at the wrong time and couldn't provide that answer. In C, it is always crucial to understand where string data is stored. Your code was trying to attach an argument after a constant string - which was in read-only memory, hence leading to the core dump.
Jonathan Leffler
+4  A: 

From your latest code, here is your problem:

const char *cmd1 = strcat("./pg1 ",argv[1]);
const char *cmd2 = strcat("./pg2 ",argv[2]);

That's bad for a couple of reasons (string literals are usually put in read only memory and they to do not have memory allocated for concatenating new data at the end).

Change that to:

size_t len = snprintf(NULL, 0, "./pg1 %s", argv[1]);
char *cmd1 = malloc(len + 1);
snprintf(cmd1, len, "./pg1 %s", argv[1]);

size_t len = snprintf(NULL, 0, "./pg2 %s", argv[2]);
char *cmd2 = malloc(len + 1);
snprintf(cmd2, len, "./pg2 %s", argv[2]);
R Samuel Klatchko
+1  A: 
const char *cmd1 = strcat("./pg1 ",argv[1]);
const char *cmd2 = strcat("./pg2 ",argv[2]);

is wrong. "./pg1 " is a read-only string. You can't append anything to it. You haven't got access to the memory after the string "./pg1 " ends anyway. So, you need to get access to memory where you can write your strings.

Try:

char *cmd1 = malloc(strlen("./pg1 ") + strlen(argv[1]) + 1);
char *cmd2 = malloc(strlen("./pg2 ") + strlen(argv[2]) + 1);

if (cmd1 == NULL || cmd2 == NULL) { /* deal with error */ }
sprintf(cmd1, "./pg1 %s", argv[1]);
sprintf(cmd1, "./pg1 %s", argv[1]);

and then remember to free the memory when you're done. Or you can declare them as arrays with a big enough size:

char cmd1[32] = "./pg1 ";
char cmd1[32] = "./pg2 ";
strcat(cmd1, argv[1]);
strcat(cmd1, argv[2]);

but the above will be bad if there is not enough space in cmd1 or cmd2.

Alok
thanks , it s working.
trinity