0

I wrote a code below

#include<stdio.h>

int main(int argc, char *argv[]) {
    char cmd[50]="dir";
    if (argc == 2) {
        sprintf(cmd,"dir %s",argv[1]);
    }
    if (argc == 3) {
        sprintf(cmd,"dir %s %s", argv[1], argv[2]);
    }
    printf("%s\n",cmd);
    system(cmd);
    return 0;
}

when I executed like below

enter image description here

I think can't pass '*' by *argv[]

How can I pass something like "*.c" ?

update

code

#include<stdio.h>

int main(int argc, char *argv[]) {
    char cmd[50]="dir";
    if (argc == 2) {
        sprintf(cmd,"dir %s",argv[1]);
    }
    if (argc == 3) {
        sprintf(cmd,"dir %s %s", argv[1], argv[2]);
    }
    if (argc > 3) {
        sprintf(cmd,"dir %s %s", argv[1], argv[2]);
    }
    printf("%s\n",cmd);
    system(cmd);
    return 0;
}

changing is below enter image description here

what..... @.@ ?

Updated code again

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

int main(int argc, char *argv[]) {
    int i;
    char sp[2]=" ", cmd[250]="dir";
    if (argc > 1) {
        sprintf(cmd,"dir /d ");
        for (i =1 ; i < argc; i ++)  {
            strcat(cmd,sp);
            strcat(cmd,argv[i]);
        }
    }
    printf("%s\n",cmd);
    system(cmd);
    return 0;
}

see what happen when I executed

enter image description here

kind of ugly.... any decent idea?

alexparkjw
  • 113
  • 1
  • 6
  • I tried this on my Windows system (compiled with gcc from MinGW) and `*.c` is passed correctly. – nnn Nov 22 '15 at 21:08
  • edit your code to include `if (argc > 3)` case. Probably shell expansion is occurring – M.M Nov 22 '15 at 21:11
  • @nnn but mine don't correctly. :( – alexparkjw Nov 22 '15 at 21:22
  • @M.M I add if (argc > 3) case. ls *.c converting to dir cat.c copycon.c what ....what's going on? – alexparkjw Nov 22 '15 at 21:32
  • @alexparkjw post your updated code and screenshot, make sure you are running the updated code – M.M Nov 22 '15 at 21:33
  • 1
    What shell are you using? Can you try `ls "*.c"` – chqrlie Nov 22 '15 at 21:34
  • @chqrlie the shell is cmd.exe (windows 10) – alexparkjw Nov 22 '15 at 21:39
  • What happens if you quote `"*.c"` ? – chqrlie Nov 22 '15 at 21:41
  • @M.M I think buffer holds all of *.c strings. what do you think? – alexparkjw Nov 22 '15 at 21:42
  • 1
    @alexparkjw the updated version shows that the `argc > 3` case is actually happening – M.M Nov 22 '15 at 21:43
  • try `echo *.c`. Does it display `*.c` or the list of C files? – chqrlie Nov 22 '15 at 21:44
  • @chqrlie echo *.c shows that *.c the same. – alexparkjw Nov 22 '15 at 21:55
  • So it seems that cmd.exe is doing shell expansion on Windows 10, this doesn't happen on my system Windows 8.1 – nnn Nov 22 '15 at 21:56
  • It would be surprising that Microsoft would introduce such a drastic change in Windows 10. That would cause endless headaches as so many batch and command files rely on the previous behavior. I suspect the C runtime is doing the expansion. See this question: http://stackoverflow.com/questions/3995493/gnuwin32-find-exe-expands-wildcard-before-performing-search – chqrlie Nov 22 '15 at 22:01
  • @chqrlie "*.c" ... this is working well what I expected. but ugly – alexparkjw Nov 22 '15 at 22:06
  • This will complicate your quick and dirty implementation of `ls`. Especially since the stupid `dir` command cannot handle multiple arguments gracefully. – chqrlie Nov 22 '15 at 22:12
  • The ugly output is that of `dir`. You cannot implement a decent `ls` as a wrapper on top of such a braindead CMD.EXE built-in command. You will need to write some substantial amount of non trivial code to implement the `ls` unix utility. If you just care about a single filespec, try to find a different toolchain that does not expand wildcards, such as Microsoft Visual Studio (I never thought I would ever give such advice!) – chqrlie Nov 22 '15 at 23:00

2 Answers2

3

This issue is not related to the C runtime, but to the shell behaviour. If you use Windows CMD.EXE, the * is passed unchanged to the programs, whereas if you use Cygwin's bash, the shell expands * to the list of files and passes this expansion as individual arguments to your program. You can prevent this expansion by quoting the wildcards with "*" or '*'.

Note that you should not use sprintf, but snprintf to avoid buffer overflows. If you link to the non standard Microsoft C library, you may need to use _snprintf instead.

EDIT: CMD.EXE does not seem to expand wildcards, but the C runtime you link your program with might do it at startup. See this question: Gnuwin32 find.exe expands wildcard before performing search

The solution is to quote the argument.

Community
  • 1
  • 1
chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

I'm afraid the accepted answer is not correct as the edit courteously admits. What is happening here is that globbing behaviour is provided in the C runtime but the default behaviour differs between compilers.

Yes, it's a major pain if you do not know what is happening. Worse the globbing does not occur if the glob does not match any files. I was pretty surprised myself.

Under Visual Studio, by default, wildcards are not expanded in command-line arguments. You can enable this feature by linking with setargv.obj or wsetargv.obj:

cl example.c /link setargv.obj

Under MinGW, by default, wildcards are expanded in command line arguments. To prevent this you can link with CRT_noglob.o or, much more easily, add the global variable:

int _CRT_glob = 0; 

in your own source in the file which defines main() or WinMain().

carveone
  • 889
  • 9
  • 16