c语言字符串拼接——snprintf
获取可执行文件绝对路径的时候遇到了一个问题,比如给了可执行文件的名字 “ls”,要求在/bin和/usr/bin里面找存在的可执行的名叫ls的可执行文件,返回绝对路径比如/bin/ls,如果高效拼接“/bin”、“/”、“ls”。
借鉴上面的回答,得到代码:
char *pathSet[] = {"/bin", "/usr/bin", NULL};
#define BUFF_SIZE 256
int searchPath(char *execute, char *path) {
for (int i = 0; pathSet[i] != NULL; i++) {
snprintf(path, BUFF_SIZE, "%s/%s", pathSet[i], execute);
if (access(path, X_OK) == 0) return 0;
}
return -1;
}
答案(未实现并行指令)
#include <ctype.h> // isspace
#include <regex.h> // regcomp, regexec, regfree
#include <stdio.h> // fopen, fclose, fileno, getline, feof
#include <stdlib.h> // exit
#include <sys/types.h>
#include <sys/wait.h> // waitpid
#include <string.h> // strlen, strsep, strcat, strdup, strcmp
#include <unistd.h> // STDERR_FILENO, fork, exec, access, exit, chdir
#define INTERACTIVE_MODE 1
#define BATCH_MODE 2
#define BUFF_SIZE 256
char *pathSet[BUFF_SIZE] = {"/bin", "/usr/bin", NULL};
char *line = NULL;
FILE *in;
void printError() {
char error_message[30] = "An error has occurred\n";
write(STDERR_FILENO, error_message, strlen(error_message));
}
void parseInputAndExecute(char *arg);
void executeCommands(char *args[], int argsNum, FILE *out);
int searchPath(char *execute, char *path);
void redirect(FILE *out);
char *trim(char *s);
int main(int argc, char *argv[]) {
size_t len = 0;
ssize_t readlen = 0;
char *command = NULL;
//int commandsNum = 0;
if (argc == 1) {
while (1) {
printf("wish> ");
if ((readlen = getline(&line, &len, stdin)) != -1) {
if (line[readlen - 1] == '\n') line[readlen - 1] = '\0';
while ((command = strsep(&line, "&")) != NULL) {
//printf("cmd:%s--line:%s--|", command, line);
if (command[0] == '\0') continue;
parseInputAndExecute(command);
}
} else {
free(line);
printError();
exit(1);
}
}
} else if (argc == 2){
in = fopen(argv[1], "r");
if (in == NULL) {
free(line);
printError();
exit(1);
}
while ((readlen = getline(&line, &len, in)) != -1) {
if (line[readlen - 1] == '\n') line[readlen - 1] = '\0';
while ((command = strsep(&line, "&")) != NULL) {
//printf("cmd:%s--line:%s--|", command, line);
if (command[0] == '\0') continue;
parseInputAndExecute(command);
}
}
fclose(in);
free(line);
exit(0);
} else {
printError();
exit(1);
}
return 0;
}
void parseInputAndExecute(char *arg) {
FILE *out = stdout;
int argsNum = 0;
char *args[BUFF_SIZE];
char *token;
char *command = strsep(&arg, ">");
if (command == NULL || *command == '\0') {
printError();
return;
}
if (arg != NULL) {
// contain white space in the middle or ">"
char *file = trim(arg);
token = strsep(&file, " \t");
//printf("file:%s---token:%s", file, token);
if (file != NULL) {
printError();
return;
}
if ((out = fopen(token, "w")) == NULL) {
printError();
return;
}
}
//printf("command:%s--arg:%s\n", line, arg);
char *const delim = " \t";
command = trim(command);
while (command && *command != '\0') {
token = strsep(&command, delim);
if (token != NULL && *token != '\0') args[argsNum++] = token;
if (argsNum >= BUFF_SIZE) break;
}
// for (int i = 0; i < argsNum; i++) {
// printf("token:%s--argsNum:%d\n", args[i], argsNum);
// }
if (argsNum < BUFF_SIZE) args[argsNum] = NULL;
else args[BUFF_SIZE - 1] = NULL;
if (argsNum > 0) {
executeCommands(args, argsNum, out);
}
}
void executeCommands(char *args[], int argsNum, FILE *out) {
// check built-in command: exit, cd, path
if (strcmp(args[0], "exit") == 0) {
if (argsNum > 1) printError();
else {
free(line);
exit(EXIT_SUCCESS); //exit(0);
}
} else if (strcmp(args[0], "cd") == 0) {
if (argsNum != 2) printError();
else {
if (chdir(args[1]) == -1) {
printError();
}
}
} else if (strcmp(args[0], "path") == 0) {
int i = 0;
// while (args[i]) {
// printf("args:%s\n", args[i]);
// i++;
// }
// i = 0;
while (pathSet[i] != NULL) i++;
int j = 0;
while (j < argsNum - 1) {
pathSet[i] = strdup(args[j + 1]);
i++;
j++;
}
pathSet[i] = NULL;
if (argsNum == 1) pathSet[0] = NULL;
// i = 0;
// while (pathSet[i]) {
// printf("pathset:%s\n", pathSet[i]);
// i++;
// }
} else {
// not built-in command
char path[BUFF_SIZE];
int rc = searchPath(args[0], path);
if (rc == -1) {
printError(); // not fond in path
return;
}
//printf("path: %s,args: %s", path, args[0]);
pid_t pid = fork();
if (pid < 0) {
printError();
exit(1);
} else if (pid == 0) {
redirect(out);
execv(path, args);
printError();
} else {
waitpid(pid, NULL, 0); // parent process waits child
}
}
}
int searchPath(char *execute, char *path) {
for (int i = 0; pathSet[i] != NULL; i++) {
snprintf(path, BUFF_SIZE, "%s/%s", pathSet[i], execute);
int rc = access(path, X_OK);
//printf("path:%s---rc:%d\n", path, rc);
if (rc == 0) {
return 0;
}
}
return -1;
}
void redirect(FILE *out) {
int outFileno = fileno(out);
if (outFileno == -1) {
printError();
exit(1);
}
if (outFileno != STDOUT_FILENO) {
// redirect output
if (dup2(outFileno, STDOUT_FILENO) == -1) {
printError();
return;
}
if (dup2(outFileno, STDERR_FILENO) == -1) {
printError();
return;
}
fclose(out);
}
}
char *trim(char *s) {
// trim leading spaces
while (isspace(*s)) s++;
if (*s == '\0') return s; //empty string
// trim trailing spaces
char *end = s + strlen(s) - 1;
while (end > s && isspace(*end)) end--;
*(end + 1) = '\0';
return s;
}