LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   [!] How to combine values in variable, text, int and other data in system(); (C). (http://www.linuxquestions.org/questions/programming-9/%5B-%5D-how-to-combine-values-in-variable-text-int-and-other-data-in-system-%3B-c-4175426819/)

suttiwit 09-12-2012 04:01 AM

[!] How to combine values in variable, text, int and other data in system(); (C).
 
Hello, I am a newbie to C. The system(); command is very useful for me. I used it so much in python. Now, i am learning C....

I was able to do this in python:
Code:

import os
editor = "nano"
file = "myfile.txt"
os.system(editor + " " + file) # This runs "nano myfile.txt".

But when i do something similar in C:
Code:

#include <stdio.h>
#include <stdlib.h>
#define EDITOR "nano"

int main()
{
char filename[9999] = "myfile.txt";
system("%s %s", EDITOR, filename);
return 0;
}

it gives me an error about "system(); can only take an argument" or something.

How do i do like in python in C? Help would be apreciated. :)

NevemTeve 09-12-2012 04:10 AM

sg like this:

Code:

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#define EDITOR "nano"

int systemf (const char *fmt, ...)
{
    char *cmdbuff= NULL;
    va_list ap;
    int rc;

    va_start (ap, fmt);
    rc= vasprintf (&cmdbuff, fmt, ap);
    va_end (ap);

    if (rc<0) {
        fprintf (stderr, "systemf: *** vasprintf error\n");
        goto RETURN;
    }

    rc= system (cmdbuff);

RETURN:
    if (cmdbuff) free (cmdbuff);
    return rc;
}

int main (void)
{
static const char filename[] = "myfile.txt";

    systemf ("%s %s", EDITOR, filename);
    return 0;
}


PS: you shouldn't hardcode "nano" into your program, instead ask environment variable $EDITOR to get the name of the user's preferred text-editor.

suttiwit 09-12-2012 04:13 AM

Hi, NevemTeve. Thanks for reply.. But, I don't understand much of it. Please give a more simpler code that only focuses on the system(); thanks.

414N 09-12-2012 04:15 AM

man system
And this settles the RTFM part ;)
system accepts only a char* as its only argument. What you've put in, however, is a format string followed by a list of variables in a printf/scanf fashion.
If you really want to use those variables you need to put them first inside a "buffer" string using sprintf, like:
Code:

char arg[9999];
sprintf(arg, "%s %s", EDITOR, filename);
system(arg);

Pay attention to the return values of those functions, especially the system calls like system().
EDIT: whoops, beaten on time!

suttiwit 09-12-2012 04:18 AM

414N, hi, thank you so much. :) also, i didn't know it has a man page :p

Celyr 09-12-2012 04:19 AM

1 Attachment(s)
Code:

#include <stdio.h>
#include <stdlib.h>
#define EDITOR "nano"

int main()
{
  char *buf[256];
  char *filename[128] = "myfile.txt";
 
  sprintf(buf, "%s %s", EDITOR, filename);

  return system(buf);
}

Please don't learn spaghetti code, every time you use a goto god kills a kitten.

EDIT: double beated on time -_-

suttiwit 09-12-2012 04:21 AM

what's sprintf(); ?

Celyr 09-12-2012 04:23 AM

Well, it's like printf but to a string instead of stdout.
Code:

man sprintf
:)

suttiwit 09-12-2012 04:34 AM

Quote:

Originally Posted by Celyr (Post 4778245)
Code:

#include <stdio.h>
#include <stdlib.h>
#define EDITOR "nano"

int main()
{
  string buf[256];
  string filename[128] = "myfile.txt";
 
  sprintf(buf, "%s %s", EDITOR, filename);

  return system(buf);
}

Please don't learn spaghetti code, every time you use a goto god kills a kitten.

EDIT: double beated on time -_-

Eh? What did u mean?

NevemTeve 09-12-2012 05:19 AM

Quote:

Originally Posted by suttiwit (Post 4778239)
But, I don't understand much of it. Please give a more simpler code that only focuses on the system(); thanks.

Either use the manual, or simply settle for the fact that now you have a 'systemf' function that works like 'sprintf' and 'system' combined. If you don't known what sprintf does, then... well, then get a basic textbook.

ntubski 09-12-2012 08:20 AM

Quote:

Originally Posted by NevemTeve
Code:

int systemf (const char *fmt, ...)
{
    char *cmdbuff= NULL;
...
    if (rc<0) {
        fprintf (stderr, "systemf: *** vasprintf error\n");
        goto RETURN;
    }
...
RETURN:
    if (cmdbuff) free (cmdbuff);
    return rc;
}


Quote:

Originally Posted by Celyr
Please don't learn spaghetti code, every time you use a goto god kills a kitten.

That is a perfectly reasonable non-spaghetti use of goto, don't be a fanatic. The "if (cmdbuff)" is not needed though:
Code:

$ man 3 free
...
      The free() function frees the memory space pointed to by ptr...
      If ptr is NULL, no operation is performed.

I'd say the real problems here would be passing computed strings (which I guess will eventually be coming from user input) to system() which leads to possible security bugs. Also @Celyr: you should be using snprintf in that situation.

Celyr 09-12-2012 08:29 AM

I don't think so, it's perfectly safe even this way without snprintf. But well you can use it if you like.
I don't get why use goto when you can use else and make the code more readable. There is no need to use goto and it should not be used.

johnsfine 09-12-2012 09:27 AM

Quote:

Originally Posted by suttiwit (Post 4778233)
I am a newbie to C.

Something important to learn in any programming language, but even more important in C:

Figure out what basic functions you will need and write them, then use them.
Quote:

Code:

system("%s %s", EDITOR, filename);

You obviously want a function that is a combination of system and sprintf. The actual system function in C is not that.

Quote:

Originally Posted by Celyr (Post 4778245)
Code:

int main()
{
...
  sprintf(buf, "%s %s", EDITOR, filename);

  return system(buf);
}


That is the beginner approach to such problems. A combination of sprintf and system is needed, with clear evidence that it will be needed multiple times. The beginner answer is to use sprintf and system where the combination is needed. That grows into using sprintf and system each time the combination is needed.

NevemTeve gave the better answer earlier. Write a general purpose function (once) that combines sprintf and system. Then use that function in each place where you want the combination.

We aren't just talking about sprintf+system here. We are talking about the difference between real programming and slapping stuff together in a programming language.

Quote:

Please don't learn spaghetti code, every time you use a goto god kills a kitten.
I'm with NevemTeve on that one as well. Highly improbable exceptions in a language without exception handling are much cleaner using goto rather than nesting else.

Quote:

Originally Posted by suttiwit (Post 4778239)
Hi, NevemTeve. Thanks for reply.. But, I don't understand much of it. Please give a more simpler code that only focuses on the system(); thanks.

I'm writing this big reply because you are apparently rejecting the very good answer you got.

There are some complications in writing a general purpose sprintf+system function, because variable arg lists are tricky in C and because C traditionally didn't have good solutions to the risk of buffer overrun when using char buffers (because of the lack of a built in string type).

So NevemTeve used a GNU extension to C (be aware of that if you will be using a non GNU C compiler) and used C features too advanced for a beginner.

So

Quote:

Originally Posted by NevemTeve (Post 4778277)
Either use the manual

A short function that is too advanced for a C beginner to write is simple enough for a C beginner to understand by reading the man pages of the constructs used.

Quote:

or simply settle for the fact that now you have a 'systemf' function that works like 'sprintf' and 'system' combined.
You don't need to understand the function he gave you. It does exactly what you seemed to want the system function to do. So you can include that in your code and then use it and not worry about why it works.

NevemTeve 09-12-2012 09:29 AM

1. sprintf (unlike snprintf and asprintf) may lead to buffer-overflow
2. free (NULL) might be problematic on some old/exotic platforms, so it is wise to make a habit of checking
3. goto's often can be eliminated with nested if's or other hard-to-read constructions, but that's not my cup of tea

Celyr 09-12-2012 09:53 AM

Quote:

Originally Posted by NevemTeve (Post 4778475)
1. sprintf (unlike snprintf and asprintf) may lead to buffer-overflow
2. free (NULL) might be problematic on some old/exotic platforms, so it is wise to make a habit of checking
3. goto's often can be eliminated with nested if's or other hard-to-read constructions, but that's not my cup of tea

You can freely make an example on how that source can produce a buffer overflow. How can 128+6 add up more that 256 will be a miracle I suppose?
Then again show me the proof that it will be needed more times, come on you are discussing on nothing and that goto still be awful


All times are GMT -5. The time now is 01:43 PM.