文字列を空白で分けて exec する

コマンド文字列を文字列の配列にわけてexecvp()する。Cで文字列扱うのは学生以来で思いのほか大変だった…。後execvpに渡す引数はちゃんとNULLクリアしておかないと思わぬ動きをする(かもしれない)ので注意。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

#define is_sep_char(c) ((c) == ' ' || (c) == '\t')
#define is_continue(c, bp, last) ((c) != '\0' && (bp) < (last))

int parse_command(char *cmd,
		char *buf, int buf_size, char *argv[], int n) {
	char *bp = buf;
	char *cp = cmd;
	char *last = buf + buf_size;
	int count = 0;
	int i;

	argv[count++] = bp;
	while (is_continue(*cp, bp, last)) {
		// 区切り文字じゃなかったらバッファに読み出す
		while ( ! is_sep_char(*cp) && is_continue(*cp, bp, last)) {
			*bp++ = *cp++;
		}
		*bp++ = (int)NULL;
		
		// 文字列配列に登録
		argv[count++] = bp;
		// argvの最大長
		if (count == n) { break; }
		
		// 区切り文字を読み飛ばす
		while (*cp != '\0') {
			if ( ! is_sep_char(*cp)) { break; }
			cp++;
		}
	}
	for (i=count-1; i<n; i++) { argv[i] = NULL; }

	return count;
}

int main(int argc, char *argv[]) {
	int pid, status;

	switch (pid = fork()) {
	case -1:
		perror("split");
		break;
	case 0: {
		char *argv[16];
		char buf[512];
		int i;
		
		// 15 は消える
		// char *cmd = "echo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15";
		char *cmd = "ls -l -a";
		parse_command(cmd, buf, 512, argv, 16);
		for (i=0; i<16; i++) {
			printf("main %d : %x, %s\n", i, &argv[i], argv[i]);
		}

		execvp(argv[0], argv);
		perror("execvp");
		_exit(1);
	} break;
	default:
		wait(&status);
		break;
	}

	return 0;
}

実行結果。

[ihiroky@puppypc:~]$ make str_execvp.c 
cc     str_execvp.c   -o str_execvp
[ihiroky@puppypc:~]$ make str_execvp
cc     str_execvp.c   -o str_execvp
[ihiroky@puppypc:~]$ ./str_execvp 
main 0 : bfde2594, ls
main 1 : bfde2598, -l
main 2 : bfde259c, -a
main 3 : bfde25a0, (null)
main 4 : bfde25a4, (null)
main 5 : bfde25a8, (null)
main 6 : bfde25ac, (null)
main 7 : bfde25b0, (null)
main 8 : bfde25b4, (null)
main 9 : bfde25b8, (null)
main 10 : bfde25bc, (null)
main 11 : bfde25c0, (null)
main 12 : bfde25c4, (null)
main 13 : bfde25c8, (null)
main 14 : bfde25cc, (null)
main 15 : bfde25d0, (null)
total 272
drwxr-xr-x 27 ihiroky users  4096 2009-03-11 00:46 .
drwxr-xr-x  5 ihiroky users  4096 2009-03-08 00:12 ..
drwx------  4 ihiroky users  4096 2008-03-21 00:24 .AbiSuite
drwxr-xr-x  3 ihiroky users  4096 2007-07-05 00:03 .TestGtkEmbed
…