これが私が組み立ててテストしたコードです。argv
アセンブル時に、引数リストと各引数の両方に動的メモリ割り当てを使用します。この関数release_cmd()
は、割り当てられたスペースを解放します。この関数cleanup()
は内部的なものであり、失敗すると割り当てられた領域を解放してから、null 二重ポインターを返します。これにより、エラー処理が簡素化されます。prompt()
関数とには最小限のテスト ハーネスがありますmain()
。の下で実行したことはありませんvalgrind
が、MacOS X の実装ではmalloc()
問題が頻繁に検出されるため、重大なメモリの乱用はないとある程度確信していますが、オフバイワン リークが発生する可能性があります。cleanup()
割り当ての失敗を偽ってコードをテストしていません。
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void release_cmd(char **argv)
{
for (size_t i = 0; argv[i] != 0; i++)
free(argv[i]);
free(argv);
}
static char **cleanup(size_t argc, char **argv)
{
argv[argc] = 0;
release_cmd(argv);
return 0;
}
char **parse_cmd(const char* cmdline)
{
size_t argc = 2;
char **argv = malloc(argc * sizeof(char *));
if (argv == 0)
return 0;
size_t j = 0; // Index into argv
size_t len = strlen(cmdline);
for (size_t i = 0; i < len; i++)
{
while (isspace(cmdline[i]))
i++;
if (cmdline[i] == '\0')
break;
if (j > argc - 2)
{
size_t newc = (argc * 2);
char **newv = realloc(argv, newc * sizeof(char *));
if (newv == 0)
return cleanup(argc, argv);
argv = newv;
argc = newc;
}
size_t argl = 2; // Length of argument string
argv[j] = malloc(argl);
size_t k = 0; // Index into argv[j]
while (cmdline[i] != '\0' && !isspace(cmdline[i]))
{
if (k > argl - 2)
{
size_t newl = argl * 2;
char *news = realloc(argv[j], newl);
if (news == 0)
return cleanup(argc, argv);
argv[j] = news;
argl = newl;
}
argv[j][k++] = cmdline[i++];
}
argv[j][k] = '\0';
argv[j] = realloc(argv[j], k+1); // Shrink to fit!
j++;
}
argv[j] = 0;
argv = realloc(argv, (j+1)*sizeof(*argv)); // Shrink to fit!
return argv;
}
static int prompt(const char *prompt, char *buffer, size_t bufsiz)
{
printf("%s", prompt);
return (fgets(buffer, bufsiz, stdin) != 0);
}
int main(void)
{
char line[1024];
while (prompt("cmd? ", line, sizeof(line)) != 0)
{
char **argv = parse_cmd(line);
char **args = argv;
while (*args)
puts(*args++);
release_cmd(argv);
}
putchar('\n');
return 0;
}