The Notebook Review forums were hosted by TechTarget, who shut down them down on January 31, 2022. This static read-only archive was pulled by NBR forum users between January 20 and January 31, 2022, in an effort to make sure that the valuable technical information that had been posted on the forums is preserved. For current discussions, many NBR forum users moved over to NotebookTalk.net after the shutdown.
Problems? See this thread at archive.org.

    Any C coders here?

    Discussion in 'Linux Compatibility and Software' started by system_159, Oct 11, 2007.

  1. system_159

    system_159 Notebook Deity

    Reputations:
    363
    Messages:
    794
    Likes Received:
    0
    Trophy Points:
    30
    I have an issue I need resolved, so I thought I'd throw up the problem here. It goes as such.

    I want to use the system() function to change directories, and run a few programs based on user input.

    Code so far:
    Code:
    #include <stdio.h>
    
    
    int main()
    {
    	int MAX_PATH = 100;
    	int i;
    	char path[MAX_PATH];
    	char cd_cmd[MAX_PATH + 3];
    	printf("Please enter sox src directory: ");
    	fgets(path,MAX_PATH,stdin);
    	for(i = 0; i < MAX_PATH; i++)
    	{
        	if(path[i] == '\n')
        	{
        	    path[i] = '\0';
        	    break;
        	}
    	}
    	cd_cmd[0] = 'c';
    	cd_cmd[1] = 'd';
    	cd_cmd[2] = ' ';
    	for(i = 0; i < MAX_PATH; i++)
    	{
    		cd_cmd[i+3] = path[i];
    	}
    	printf("cd_cmd is now %s \n", cd_cmd);
    	system("ls -l");
    	system(cd_cmd);
    	system("ls -l");
    		 
     	return(0);
    }
    
    I also tried omitting the whole cd_cmd array and doing this:
    Code:
    system("cd ", path);
    
    that compiled, but didn't change the directory like I wanted it to.

    So how do I get a path from a user and change the current directory to that?

    Thanks!
     
  2. AKAJohnDoe

    AKAJohnDoe Mime with Tourette's

    Reputations:
    1,163
    Messages:
    3,017
    Likes Received:
    0
    Trophy Points:
    105
    You might need to establish the drive the directory is on first.
     
  3. Jalf

    Jalf Comrade Santa

    Reputations:
    2,883
    Messages:
    3,468
    Likes Received:
    0
    Trophy Points:
    105
    Not when I can avoid it, no... ;)
    Is there any vital reason why it can't be C++? Save a little sanity in the world... :)

    Before I get into the actual code, it might be helpful if you describe what error you get, exactly. Does your code compile? If so, what does it do?
    If it doesn't, which error do you get?

    Code:
    	for(i = 0; i < MAX_PATH; i++)
    	{
    		cd_cmd[i+3] = path[i];
    	}
    
    That seems a bad idea, at least. You're going through the array, from 0 to MAX_PATH-1, and in each iteration, you overwrite the char 3 bytes further ahead. Which means that your array will end up containing "cd cd cd cd cd cd cd cd cd ", and so on, as far as I can see. You'll also end up writing 3 bytes past the end of the array, and there won't be a terminating \0.
    But then again, this is C code, buffer overflows are expected. It probably isn't a proper C program if it doesn't contain one of those... ;)

    If you want to do it this way, you should run the loop backwards (for i = MAX_PATH-4; i >= 0; --i))

    or you could replace your fgets line with something like this:
    Code:
    fgets(cd_cmd+3, MAX_PATH, stdin);
    
    Then you'd avoid having to move everything 3 chars. (And you could ditch the path array)

    And just for fun, here's an equivalent C++ version:

    Code:
    #include <string>
    #include <iostream>
    
    int main(){
      std::string path;
      std::getline( std::cin, path );
      std::string cmd = "cd " + path;
      system("ls -l");
      system(cmd);
      system("ls -l");
    }
    
    If you ask me, that's a bit more readable (and *a lot* less error-prone)

    (Note, I haven't actually compiled and tested either version. Mine should work as far as I can see, and with yours, I'd like a bit more information about what's wrong with it)
     
  4. system_159

    system_159 Notebook Deity

    Reputations:
    363
    Messages:
    794
    Likes Received:
    0
    Trophy Points:
    30
    I'm using C because a lot of the code is directly reused in an embedded system, which is running an RTOS that requires code to be in C.

    The code does compile, and I've found an answer that negates the need for the stupid loop ;).

    new code:
    Code:
    #include <stdio.h>
    
    
    int main()
    {
    	int MAX_PATH = 100;
    	int i;
    	char path[MAX_PATH];
    	printf("Please enter sox src directory: ");
    	fgets(path,MAX_PATH,stdin);
    	for(i = 0; i < MAX_PATH; i++)
    	{
        	if(path[i] == '\n')
        	{
        	    path[i] = '\0';
        	    break;
        	}
    	}
    
    	system("ls -l");
            chdir(path);
    	system("ls -l");
     	return(0);
    }
    
    The original problem still stands, though, as I need to get a file name from the user and enter it into the middle of a command ala: /sox chimes.wav -r 8000 -c 1 -u -1 cchimes.wav where chimes.wav and cchimes.wav are user defined.

    edit: the problem with the original code was that it didn't actually change directories
     
  5. Jalf

    Jalf Comrade Santa

    Reputations:
    2,883
    Messages:
    3,468
    Likes Received:
    0
    Trophy Points:
    105
    Any particular reason why you can't just call the command with the path in one go?

    (Instead of "cd ../foo/bar; /sox chimes.wav -r 8000 -c 1 -u -1 cchimes.wav", you could just do "../foo/bar/sox chimes.wav -r 8000 -c 1 -u -1 cchimes.wav")
    Which, now I come to think about it, shows another solution. Instead of multiple system() calls, just use one with all the commands separated by semicolons)

    As for getting the wav filename from the user, and inserting it into the middle of the command, that sounds like sprintf() to me.
     
  6. gorn

    gorn Notebook Enthusiast

    Reputations:
    14
    Messages:
    23
    Likes Received:
    0
    Trophy Points:
    5
    When you call system() a new instance of bash is created, and executes whatever you tell it. This means if you do system("cd /") it opens bash, changes to /, then exits bash. Then you run system again and it opens a new bash, no longer at /. As you found, chdir will change the directory of your program, so then when bash is called, it's in the correct directory to begin with.

    As the C-hater ( ;) ) pointed out, system("cd foo; ls -l") would work, as it'd be one bash instance. He also was correct in sprintf being useful for what you want to do:

    Code:
    #include <stdio.h>
    #define MAX_FILENAME 20
    #define MAX_CMD 50
    main() {
            char a[MAX_FILENAME];
            char b[MAX_CMD];
    
            fgets(a, MAX_FILENAME, stdin);
            if(a[strlen(a)-1] == 0x0a) /* Our capture included the "enter" key */
                    a[strlen(a)-1] = 0x00; // kill it
    
            /* Create a command string including the user data */
            snprintf(b, MAX_CMD, "sox foo bar -l -asdf -fdsa %s -o %s.sox", a, a);
            printf("Command would be: [%s]\n", b);
    }
    
    I kept the buffer sizes pretty small to show what happens when you overflow (only truncation because snprintf is used, rather than sprintf.)

    If security is an issue keep in mind that someone could enter "filename `rm -rf /`". If security is not an issue then you should be okay, but you still might want to do sanity checks on the data. execl() is one way of doing this.
     
  7. Insane

    Insane Notebook Evangelist

    Reputations:
    62
    Messages:
    506
    Likes Received:
    0
    Trophy Points:
    30
    You'll need the #include <string.h> header for strlen() Gorn... ^^ ... though it may be different under Unix...
     
  8. chimpanzee

    chimpanzee Notebook Virtuoso

    Reputations:
    683
    Messages:
    2,561
    Likes Received:
    0
    Trophy Points:
    55
    you need more background knowledge beyond C.

    If your program just need to construct a string of 'shell script' then run it through system(), there is a scripting language LUA which is small(about 100K for the VM) that is very embedd friendly and you can do it at a much higher abstract level than C.

    And LUA can be compiled on almost any OS, so long there is a C compiler available. It relies nothing other than a C89 compliant C compiler.
     
  9. Jalf

    Jalf Comrade Santa

    Reputations:
    2,883
    Messages:
    3,468
    Likes Received:
    0
    Trophy Points:
    105
    100kb can be quite a lot on some embedded systems. And in an RTOS, I'm not sure Lua would be a particularly good idea. You generally want something much more deterministic there.
     
  10. chimpanzee

    chimpanzee Notebook Virtuoso

    Reputations:
    683
    Messages:
    2,561
    Likes Received:
    0
    Trophy Points:
    55
    I believe we are not talking about some multi-thread situation so I am lost on the deterministic point. As it is just a way to execute some program in linear fashion, be it a native executable or a python/lua/tcl/ruby script. Can you elaborate that ?

    As for 100kB is a lot, I have no idea the targetting environment but I believe it would be a point about how many native apps(even a very basic helloworld C program may need 5-10K) and how complex the app is. So while one C program compiled may be smaller than the lua VM, 10 such thing may not be.