#include <stdio.h>
#include <string.h> /* for strcmp() strlen*/
//#include <unistd.h> /* for usleep() */
#include <Windows.h>
#include <ctype.h>
// argv MAX
#define MAX_CMD_NUM 10
// string MAX
#define BUF_LEN 128
int cmd_continue = 0;
typedef int cmd_func(int argc, char* argv[]);
struct Command_List
{
char* cmd;
cmd_func* func;
char* help_str;
};
int cmd_test1(int argc, char* argv[])
{
if (argv[1] == NULL) {
printf("test 1 command received. \n");
}
else {
printf("test 1 command received. argv[1] is %s. \n", argv[1]);
}
return 0;
}
int cmd_test2(int argc, char* argv[])
{
if (argv[1] == NULL) {
printf("test 1 command received. \n");
}
else {
printf("test 1 command received. argv[1] is %s. \n", argv[1]);
}
return 0;
}
int cmd_exit(int argc, char* argv[])
{
printf("exit command received \n");
cmd_continue = 0;
return 0;
}
struct Command_List CmdList[] =
{
{"test1", cmd_test1, "test1 command"},
{"test2", cmd_test2, "test2 command"},
{"exit", cmd_exit, "exit command"},
{0,0,0}
};
// string을 받아서 줄바꿈문자가 올 때 까지 띄어쓰기 단위로 파싱해 argv, argc에 담음
void parse_input_string(char* input_string, int* argc, char* argv[])
{
int found_arg = 1;
int argn = 0;
while (*input_string)
{
if (*input_string == '\n') {
*input_string = '\0';
break;
}
if (*input_string == ' ') {
found_arg = 1;
*input_string = '\0';
} else if (found_arg) {
argv[argn++] = input_string;
found_arg = 0;
}
input_string++;
}
*argc = argn;
}
void cmd_handler(char* cmd)
{
// 커맨드 목록 가리킬 포인터
struct Command_List* pCmdList = CmdList;
unsigned int i, command_found = 0;
int argc;
char* argv[MAX_CMD_NUM] = {0,};
char cmd_to_lowercase[BUF_LEN];
parse_input_string(cmd, &argc, argv);
// 커맨드명 대소문자 구분없이 처리하기 위해, 소문자로 담을 버퍼 초기화
memset((void*)cmd_to_lowercase, 0, sizeof(cmd_to_lowercase));
if (argc > 0)
{
for (i = 0; i < strlen((const char*)argv[0]); ++i)
cmd_to_lowercase[i] = (char)tolower(argv[0][i]);
}
if (argc)
{
// 커맨드리스트에서 순차확인하여
while (pCmdList->cmd)
{
// 입력된 커맨드와 일치하는 목록이 있으면 해당 커맨드 처리함수 호출
if (!strcmp((const char*)pCmdList->cmd, (const char*)cmd_to_lowercase))
{
command_found = 1;
pCmdList->func(argc, argv);
break;
}
++pCmdList;
}
}
if (command_found == 0) printf("command not found!\n");
}
int main(int argc, char* argv[])
{
char buf[BUF_LEN];
printf("=======================\n");
printf("Test program !\n");
printf("========================\n");
cmd_continue = 1;
while (cmd_continue)
{
printf("prompt>> ");
// 줄바꿈문자가 올때까지 읽기
fgets(buf, sizeof(buf), stdin);
// 프롬프트 핸들러 호출
cmd_handler(buf);
//usleep(1000);
Sleep(500);
}
return 0;
}
나중에 굉장히 유용하게 사용할 수 있을 것 같다.
fgets 함수는 스트림에서 num-1개의 문자를 입력 받을 때 까지 또는 개행문자나 EOF를 만날 때 까지 입력을 받아서 str 버퍼에 문자열로 저장한다. 개행문자 포함 입력받은 경우 \n 역시 str에 저장되고 마지막에는 NULL문자가 자동으로 저장된다.
3번째 인수로 stdin 을 전달하면 표준입력에서 입력을 받을 수 있다.
char* fgets(char* str, int num, FILE* stream);
parse_input_string 함수에서는 char* argv[] 에 띄어쓰기를 구분자로 문자열을 파싱해서 저장하고 인자의 개수만큼 argc를 카운트 한다.
cmd_handler 함수 아랫부분에서는 전역변수로 선언된 구조체 배열인 CmdList[]에서 strcmp로 일치하는 커맨드가 있는지 찾고 일치하는 커맨드를 찾은 경우 pCmdList->func(argc, argv); 로 함수 포인터를 호출한다.
두번째 이후 인자에 따라 디테일하게 명령을 처리하는 부분은 커맨드 함수 안에 써주면 된다.
나중에 UART 시리얼 커맨드를 처리하는 부분도 이런 방식으로 짜볼 수 있을 것 같다.
'프로그래밍 > C' 카테고리의 다른 글
C ] memset 함수 구현 (0) | 2022.10.09 |
---|---|
C, Linux ] pthread 사용해 보기 (0) | 2022.08.25 |
C ] 전처리기 (Preprocessor) (0) | 2022.08.24 |
C, Linux ] ls 명령어 구현 (0) | 2022.08.17 |
C, Linux ] main 함수의 매개변수 사용해서 파일 입출력 하기 (0) | 2022.08.17 |