OpenBSD 5.9 header with C99 inline function - c
I'm building a custom shell and see when I compile that usr/include/ctype.h:92 seem to require c99 inline function but the compiler says that C99 inline functions are not supported. The warning can be disabled with a parameter to the compiler but is it a bug that needs a fix?
This is my main.c
#define _XOPEN_SOURCE 500
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include "openshell.h"
#include "errors.h"
#include <errno.h>
#include <locale.h>
#include <readline/readline.h>
#include <getopt.h>
#include <unistd.h>
#include <assert.h>
#include <readline/history.h>
#ifdef SIGDET
#if SIGDET == 1
int isSignal = 1; /*Termination detected by signals*/
#endif
#endif
static int sourceCount = 0;
static FILE *sourcefiles[MAX_SOURCE];
/*
* The special maximum argument value which means that there is
* no limit to the number of arguments on the command line.
*/
#define INFINITE_ARGS 0x7fffffff
/*
* The table of built-in commands.
* A command is terminated wih an entry containing NULL values.
*/
static const CommandEntry commandEntryTable[] =
{
{
"checkenv", do_checkenv, 1, INFINITE_ARGS,
"Check environment variables",
""
},
{
"add2path", do_add2path, 3, INFINITE_ARGS,
"do_add2path",
"[txp]v arFileName fileName ..."
},
{
"cd", do_cd, 1, 2,
"Change current directory",
"[dirName]"
},
{
"exit", do_exit, 1, 2,
"Exit from shell",
"[exit value]"
},
{
"help", do_help, 1, 2,
"Print help about a command",
"[word]"
},
{
"kill", do_kill, 2, INFINITE_ARGS,
"Send a signal to the specified process",
"[-sig] pid ..."
},
{
NULL, 0, 0, 0,
NULL,
NULL
}
};
struct command {
char *const *argv;
};
char** str_split(char* a_str, const char a_delim)
{
char** result = 0;
size_t count = 0;
char* tmp = a_str;
char* last_comma = 0;
char delim[2];
delim[0] = a_delim;
delim[1] = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (a_delim == *tmp)
{
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = malloc(sizeof(char*) * count);
if (result)
{
size_t idx = 0;
char* token = strtok(a_str, delim);
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, delim);
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
char ** stripped;
char ** create_pipeline(int argc, char ** argv) {
if(!strstr(argv[argc], "|")) { /* && ! isBetweenquotes*/
stripped = argv;
return stripped;
}
else {
stripped = argv;
return create_pipeline(argc, argv);
}
}
static int runCmd(const char *cmd) {
const char *cp;
pid_t pid;
int status;
struct command shellcommand[4];
char **argv = 0;
int argc = 1;
bool pipe = false;
char *command[40];
char *cmd2[20] = {"cmd2", 0};
int numberofpipelines = 0;
unsigned long i3 = 0;
unsigned long i2 = 0;
unsigned long i1 = 0;
unsigned long n = 0;
char *string;
char *string1;
int max_args = 1; /* there's at least one argument or we wouldn't reach this */
cmd2[0] = NULL;
cmd2[1] = NULL;
cmd2[2] = NULL;
command[0] = NULL;
command[1] = NULL;
command[3] = NULL;
char *string2 = NULL;
char** tokens;
for (cp = cmd; *cp; cp++) {
if ((*cp >= 'a') && (*cp <= 'z')) {
continue;
}
if ((*cp >= 'A') && (*cp <= 'Z')) {
continue;
}
if (isDecimal(*cp)) {
continue;
}
if (isBlank(*cp)){
continue;
}
if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
(*cp == '+') || (*cp == '=') || (*cp == '_') ||
(*cp == ':') || (*cp == ',') || (*cp == '\'') ||
(*cp == '"')) {
continue;
}
}
makeArgs(cmd, &argc, (const char ***) &argv, pipe);
char a[20] = {0};
if (sscanf(cmd, "%*[^']'%[^']'", a) == 1) {
printf("<undefined>");
}
char cmdtmp[75];
strcpy(cmdtmp, cmd);
tokens = str_split( cmdtmp, '|');
if (tokens)
{
int i;
for (i = 0; *(tokens + i); i++)
{
printf("month=[%s]\n", *(tokens + i));
free(*(tokens + i));
}
printf("\n");
free(tokens);
}
for (int i = 0; i < argc; i++) {
if (argv[i] != NULL && strstr(argv[i], "|")) {
numberofpipelines++;
char subbuff[40];
i1 = 0;
i2 = 0;
i3 = 0;
subbuff[0]='\0';
string = strstr(argv[i], "|");
if (string != NULL) {
i3 = string - argv[i];
printf("**** is null ***");
cmd2[1] = argv[argc - 1];
}
string1 = strstr(&argv[i][i3 + 2], "|");
if (string1 != NULL) {
i2 = string1 - argv[i3 + 1];
printf("i2: %lu", i2);
} else {
char *found3 = strstr(&argv[i][i3 + 1], " ");
if (found3 != NULL) {}
string2 = strstr(argv[1], "|");
if (string2 != NULL) {
i1 = string2 - argv[1];
}
n = strlen(argv[1]) - i1;
if (argc > 2) {
memcpy(subbuff, &argv[i][i3 + 1], n - 1);
subbuff[n - 1] = '\0';
cmd2[0] = subbuff;
cmd2[1] = argv[argc - 1];
} else {
memcpy(subbuff, &argv[i][i3 + 1], n);
subbuff[n] = '\0';
cmd2[0] = subbuff;
cmd2[1] = argv[argc - 1];
}
argc++;
argv[i + 1] = subbuff;
command[i] = "<undefined>";
argv[i + 2] = NULL;
max_args = i;
}
}
if (argv[i] != NULL) {
if (i < max_args) {
command[i] = argv[i];
command[i+1] = 0;
max_args++;
cmd2[1] = argv[argc - 1];
} else {
command[max_args] = argv[max_args];
command[max_args+1] = 0;
cmd2[1] = argv[argc - 1];
}
}
if (argv[i] != NULL) {
char *p = strchr(argv[i], '|');
if (!p) {
/* deal with error: / not present" */;
} else {
*p = 0;
}
}
}
dump_argv((const char *) "d", argc, argv);
/* makeArgs(cmd, &argc, &argv, pipe);*/
/* command[2]= 0;*/
shellcommand[0].argv = command;
shellcommand[1].argv = cmd2;
pid = fork();
if (pid < 0) {
perror("fork failed");
return -1;
}
/* If we are the child process, then go execute the program.*/
if (pid == 0) {
/* spawn(cmd);*/
fork_pipes(numberofpipelines, shellcommand);
}
/*
* We are the parent process.
* Wait for the child to complete.
*/
status = 0;
while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
if (pid < 0) {
fprintf(stderr, "Error from waitpid: %s", strerror(errno));
return -1;
}
if (WIFSIGNALED(status)) {
fprintf(stderr, "pid %ld: killed by signal %d\n",
(long) pid, WTERMSIG(status));
return -1;
}
return WEXITSTATUS(status);
}
/* The shell performs wildcard expansion on each token it extracts while parsing the command line.
* Oftentimes, globbing will obviously not do anything (for example, ls just returns ls).
* When you want nullglob behavior you'll have to know whether the glob function actually found any glob characters, though
*/
static void expandVariable(char *shellcommand) {
char mystring[CMD_LEN];
char *cp;
char *ep;
strcpy(mystring, shellcommand);
cp = strstr(mystring, "$(");
if (cp) {
*cp++ = '\0';
strcpy(shellcommand, mystring);
ep = ++cp;
while (*ep && (*ep != ')')) ep++;
if (*ep == ')') *ep++ = '\0';
cp = getenv(cp);
if (cp) strcat(shellcommand, cp);
strcat(shellcommand, ep);
}
return;
}
int do_help(int argc, const char **argv) {
const CommandEntry *entry;
const char *str;
str = NULL;
if (argc == 2)
str = argv[1];
/*
* Check for an exact match, in which case describe the program.
*/
if (str) {
for (entry = commandEntryTable; entry->name; entry++) {
if (strcmp(str, entry->name) == 0) {
printf("%s\n", entry->description);
printf("usage: %s %s\n", entry->name,
entry->usage);
return 0;
}
}
}
/*
* Print short information about commands which contain the
* specified word.
*/
for (entry = commandEntryTable; entry->name; entry++) {
if ((str == NULL) || (strstr(entry->name, str) != NULL) ||
(strstr(entry->usage, str) != NULL)) {
printf("%-10s %s\n", entry->name, entry->usage);
}
}
return 0;
}
/*
* Try to execute a built-in command.
* Returns TRUE if the command is a built in, whether or not the
* command succeeds. Returns FALSE if this is not a built-in command.
*/
bool exec_builtin(const char *cmd) {
const char *endCmd;
const CommandEntry *entry;
int argc;
const char **argv;
char cmdName[CMD_LEN];
/*
* Look for the end of the command name and then copy the
* command name to a buffer so we can null terminate it.
*/
endCmd = cmd;
while (*endCmd && !isBlank(*endCmd))
endCmd++;
memcpy(cmdName, cmd, endCmd - cmd);
cmdName[endCmd - cmd] = '\0';
/*
* Search the command table looking for the command name.
*/
for (entry = commandEntryTable; entry->name != NULL; entry++) {
if (strcmp(entry->name, cmdName) == 0)
break;
}
/*
* If the command is not a built-in, return indicating that.
*/
if (entry->name == NULL) {
return false;
}
bool bo = false;
/*
* The command is a built-in.
* Break the command up into arguments and expand wildcards.
*/
if (!makeArgs(cmd, &argc, &argv, bo)) {
return true;
}
/*
* Give a usage string if the number of arguments is too large
* or too small.
*/
if ((argc < entry->minArgs) || (argc > entry->maxArgs)) {
fprintf(stderr, "usage: %s %s\n", entry->name, entry->usage);
return true;
}
/*
* Call the built-in function with the argument list.
*/
entry->func(argc, argv);
return true;
}
/*
* Parse and execute one null-terminated command line string.
* This breaks the command line up into words, checks to see if the
* command is an alias, and expands wildcards.
*/
int command(const char *cmd) {
const char *endCmd;
char cmdName[CMD_LEN];
freeChunks();
/*
* Skip leading blanks.
*/
while (isBlank(*cmd))
cmd++;
/*
* If the command is empty or is a comment then ignore it.
*/
if ((*cmd == '\0') || (*cmd == '#'))
return 0;
/*
* Look for the end of the command name and then copy the
* command name to a buffer so we can null terminate it.
*/
endCmd = cmd;
while (*endCmd && !isBlank(*endCmd))
endCmd++;
memcpy(cmdName, cmd, endCmd - cmd);
cmdName[endCmd - cmd] = '\0';
/*
* Expand simple environment variables
*/
while (strstr(cmd, "$(")) expandVariable((char *) cmd);
/*
* Now look for the command in the builtin table, and execute
* the command if found.
*/
if (exec_builtin(cmd)) {
return 0;
}
/*
* The command is not a built-in, so run the program along
* the PATH list.
*/
return runCmd(cmd);
}
/*
* Execute the specified file or program
* A null name pointer indicates to read from stdin.
*/
int exec_program(const char *name) {
FILE *fp;
int r = 0;
char *input, shell_prompt[100];
if (sourceCount >= MAX_SOURCE) {
fprintf(stderr, "Too many source files\n");
return 1;
}
fp = stdin;
if (name) {
fp = fopen(name, "r");
if (fp == NULL) {
perror(name);
return 1;
}
}
sourcefiles[sourceCount++] = fp;
setlocale(LC_CTYPE, "");
/*Configure readline to auto-complete paths when the tab key is hit.*/
rl_bind_key('\t', rl_complete);
/*stifle_history(7);*/
for (; ;) {
/* Create prompt string from user name and current working directory.*/
snprintf(shell_prompt, sizeof(shell_prompt), "%s:%s $ ", getenv("USER"), getcwd(NULL, 1024));
// Display prompt and read input (NB: input must be freed after use)...
input = readline(shell_prompt);
// Check for EOF.
if (!input)
break;
add_history(input);
r = command(input);
free(input);
}
return r;
}
static struct option long_options[] = {
{"with_param", 1, 0, 'p'},
{"version", 0, 0, 'v'},
{"help", 0, 0, 'h'},
{0, 0, 0, 0}
};
char s[] = "Interrupt\n";
void int_handler(int signum) {
if (write(fileno(stdin), s, sizeof s - 1)) { } else { }
if (signum) { if (false); } else { }
}
int main(int argc, char *argv[]) {
struct sigaction sh;
sh.sa_handler = int_handler;
sigemptyset(&sh.sa_mask);
sh.sa_flags = 0;
sigaction(SIGINT, &sh, NULL);
sourceCount = 0;
const char *commandFile;
commandFile = NULL;
char *pathValue;
int option;
sh.sa_handler = int_handler;
sigemptyset(&sh.sa_mask);
sh.sa_flags = 0;
sigaction(SIGINT, &sh, NULL);
int option_index = 0;
while (1) {
option_index = 0;
option = getopt_long(argc, argv, "p:vh",
long_options, &option_index);
if (option == -1)
break;
switch (option) {
case 'p': {
/* store_parameter(optarg); */
break;
}
case 'v': {
printf("OpenShell version 0.1(a)\n");
printf("Version: %s\n", VERSION);
exit(EXIT_SUCCESS);
}
case 'h': {
printf("Usage: ./shell\n");
/*print_help();*/
exit(EXIT_SUCCESS);
}
default: {
/* fprintf(stderr, "Error (%s): unrecognized option.\n", __FUNCTION__);*/
/* print_help();*/
return 1;/*RETURN_FAILURE;*/
}
} /* end switch */
}
/* get the PATH environment to find if less is installed */
pathValue = getenv("PATH");
if (!pathValue || getenv("PATH") == NULL) {
printf("'%s' is not set.\n", "PATH");
/* Default our path if it is not set. */
putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc");
}
else {
printf("'%s' is set to %s.\n", "PATH", pathValue);
}
exec_program(commandFile);
return (0);
}
My makefile:
CC = gcc
GIT_VERSION := $(shell git describe --abbrev=4 --dirty --always --tags)
CFLAGS := $(CFLAGS) -L/usr/local/include/ -L/usr/include -pedantic -std=c99 -Wall -O3 -g -DVERSION=\"$(GIT_VERSION)\" -ledit -lncurses
LDIRS = -L/usr/local/lib -L/usr/lib
LIBS =su -lcurses
shell: main.o
$(CC) -o shell main.o errors.c util.c pipeline.c -ledit -lncurses -lcurses
main.o: main.c errors.c util.c
USERNAME := $(shell whoami >> username.txt)
GIT:= $(shell head -n -1 openshell.h > temp.txt ; mv temp.txt openshell.h;git describe --abbrev=4 --dirty --always --tags > VERSION; echo "\#define VERSION \"$(GIT_VERSION)\"" >> openshell.h)
.PHONY: clean
clean:
rm -f *.o
You should compile with c99 or c11, and the flags to gcc:
gcc -std=c99
or
gcc -std=c11
Related
Get_next_line : Abort when BUFFER_SIZE between 8 and 15 on Mac
I am currently completing my "Get_next_line" project. It is a function that reads a file and allows you to read a line ending with a newline character from a file descriptor. When you call the function again on the same file, it grabs the next line. This project deals with memory allocation and when to free and allocate memory to prevent leaks. The value (-1) is returned if an error occurred, (0) is returned if the file is finished reading, and (1) is returned if a line is read. However, while testing my final code I encounter an abort when BUFFER_SIZE is between 8 and 15. This error only appears on Mac. Does anyone have an idea of what might be the issue? Compile with : gcc -Wall -Wextra -Werror -D BUFFER_SIZE=32 get_next_line.c get_next_line_utils.c The get_next_line() function and some support code; #include "get_next_line.h" int ft_backslash(const char *s) { int i; i = -1; while (s[++i]) if (s[i] == '\n') return (1); if (s[i] == '\n') return (1); return (0); } int ft_read_buffer(int fd, char *buf) { int ret; ret = 0; ret = read(fd, buf, BUFFER_SIZE); if (ret < 0) return (-1); buf[ret] = '\0'; return (ret); } char *ft_treat_save(char *save, char *buf) { char *tmp; if (save == NULL) save = ft_strdup(buf); else { tmp = ft_strdup(save); free (save); save = ft_strjoin(tmp, buf); free (tmp); } return (save); } char *ft_treat_tmp(char *save) { char *tmp; tmp = ft_strdup(save); free (save); return (tmp); } int get_next_line(int fd, char **line) { int ret; char buf[BUFFER_SIZE]; char *tmp; static char *save; ret = 1; if (fd < 0 || fd > 255 || BUFFER_SIZE <= 0 || line == NULL) return (-1); *line = NULL; tmp = NULL; while (ret > 0) { if ((ret = ft_read_buffer(fd, buf)) < 0) return (-1); save = ft_treat_save(save, buf); if (ft_backslash(save) == 1) { tmp = ft_treat_tmp(save); *line = ft_strcut_front(tmp); save = ft_strcut_back(tmp); return (1); } } tmp = ft_treat_tmp(save); save = NULL; *line = ft_strdup(tmp); free (tmp); return (0); } Other support code: size_t ft_strlen(char *str) { size_t i; i = 0; if (str) while (str[i]) i++; return (i); } char *ft_strdup(char *str) { int i; char *dst; dst = malloc(sizeof(char) * ((ft_strlen(str) + 1))); if (!(dst)) { free (dst); return (NULL); } i = -1; while (str[++i]) dst[i] = str[i]; dst[i] = '\0'; return (dst); } char *ft_strjoin(char *s1, char *s2) { int i; int j; char *join; i = -1; j = 0; if (!s1 && !s2) return (NULL); join = malloc(sizeof(char) * (ft_strlen(s1) + ft_strlen(s2) + 2)); if (!(join)) return (NULL); if (BUFFER_SIZE == 1) while (s1[++i + 1] != '\0') join[i] = s1[i]; else while (s1[++i] != '\0') join[i] = s1[i]; while (s2[j]) join[i++] = s2[j++]; join[i] = '\0'; return (join); } char *ft_strcut_front(char *str) { int i; char *front; i = 0; while (str[i] != '\n') i++; front = malloc(sizeof(char) * (i + 1)); if (!(front)) return (NULL); i = 0; while (str[i] != '\n') { front[i] = str[i]; i++; } front[i] = '\0'; return (front); } char *ft_strcut_back(char *str) { int i; int j; char *back; i = 0; while (str[i] != '\n') i++; i++; back = malloc(sizeof(char) * ((ft_strlen(str) - i) + 1)); if (!(back)) return (NULL); j = 0; while (str[i] != '\0') back[j++] = str[i++]; back[j] = '\0'; free (str); return (back); } The main() function: int main(void) { int fd, ret, line_count; char *line; line_count = 1; ret = 0; line = NULL; fd = open("baudelaire.txt", O_RDONLY); while ((ret = get_next_line(fd, &line)) > 0) { printf(" \n [ Return: %d ] | A line has been read #%d => |%s|\n", ret, line_count, line); line_count++; } printf(" \n [ Return: %d ] A line has been read #%d: |%s\n", ret, line_count++, line); printf("\n"); if (ret == -1) printf("-----------\n An error happened\n"); else if (ret == 0) { printf("-----------\n EOF has been reached\n"); } close(fd); }
Problem solved. I forgot to add + 1 to my buf size... stupid error ! Thank you
C program that executes command fails with sleep
I wrote a program that read a bash file line by line and execute its command written inside. It seems to execute standard command normally (albeit there is not output on the terminal), but when it reads the sleep command, there is an error: sleep 3: missing operand Try 'sleep 3 --help' for more information. char** string_separator(char* string, const char a_delim) { char** result = 0; size_t count = 0; char* tmp = string; char* last_dot = 0; char delimiter[2]; delimiter[0] = a_delim; delimiter[1] = 0; while (*tmp) { if (a_delim == *tmp) { count++; last_dot = tmp; } tmp++; } count += last_dot < (string + strlen(string) - 1); count++; result = malloc(sizeof(char*) * count); if (result) { size_t idx = 0; char* token = strtok(string,delimiter); while (token) { assert(idx < count); *(result + idx++) = strdup(token); token = strtok(0, delimiter); } assert(idx == count - 1); *(result + idx) = 0; } return result; } int main(int argc, char *argv[]) { for (int i = 1; i < argc; i++) { FILE * fp; fp = fopen(argv[i], "r"); char buf[100]; int bytes_read = 0; char * inputCopy = malloc(255 * sizeof(char)); const char delim[] = " "; while (fgets(buf, sizeof buf, fp) != NULL) { if (strstr(buffer, "#!/")) { } else { char ** strtoken = string_separator(buf, '\n'); char * firstWord = getFirstWord(buf, inputCopy, delim); pid_t pid; pid = fork(); if (pid == 0) { execvpe(firstWord, strtoken, NULL); exit(1); } else { int status; waitpid(pid, & status, 0); } } } } return 0; } Why is the program not working with the sleep command? EDIT: Made the modification in the code such as function definition and indentation, I think the problem might be with the string_separator function, it might not separate the string into char array as expected.
Problems of History for my own Shell in C
As a project, I have to make my own shell. I did it but I have some problems with the history feature. Here's piece of my code: int main(int argc, char* argv[]) { char saisie[300], cwd[1024]; char* nom = getenv("USER"); char* backup[MAXCMD]; int boucle = 1, n = 0, i, u = 0, b = 0; for(i = 0; i < MAXCMD; i++) { backup[i] = NULL; } for(i = 0; i < MAX_INPUT_SZ; i++) { saisie[i] = 0; } char* cmd[MAXPARAMS]; //MAXPARAMS is 20 while( boucle == 1) { printf("%s#sam:~ %s> ", nom, (getcwd(cwd, sizeof(cwd)))); fgets(saisie,MAX_INPUT_SZ,stdin); printf("\n"); split_input(saisie, cmd); free(backup[u]); backup[u] = strdup(saisie); u = (u + 1) % MAXCMD; b = switchcmd(cmd,backup,b,u); start(cmd,b); b = 0; //débloquage fonction start } return 0; } I print the history with this fonction: int historique(char* backup[], int u) { int i = u; int place = 1; do { if (backup[i]) { printf("%4d: %s\n", place, backup[i]); place++; } i = (i + 1) % MAXCMD; } while (i != u); return 0; } B is used to block the execution fonction (start) when user enter "cd" or "history", because it will generate an error. Here's the fonction triggered when user enters "cd", "history", or "exit": int switchcmd(char** cmd,char** backup, int b,int u) { int i, n = 3, switch_value = 0; char* error; char* listcmd[n]; listcmd[0] = "cd"; listcmd[1] = "exit"; listcmd[2] = "history"; for (i = 0; i < n; ++i) { if(strcmp(cmd[0], listcmd[i]) == 0) { switch_value = i + 1; break; } } switch (switch_value) { case 1: chdir(cmd[1]); b = 1; error = strerror(errno); if (*error != 0) { printf("sam: %s: %s\n", cmd[0], error); } break; case 2: printf("Bye bye\n"); exit(0); case 3: historique((char**)backup,u); b = 1; break; } return b; } When I execute my shell, and enter these commands successively, they work. °i1 > clear > ls -a -l > ls -a > cd .. > man chdir Then "history" for printing the history, I have this : °i2 1: clear 2: ls 3: ls 4: cd 5: man 6: history and I want this output, with all parameters: °i3 1: clear 2: ls -a -l 3: ls -a 4: cd .. 5: man chdir 6: history` I dont know why, and I don't understand why strdup does not duplicate my cmd in backup at it should. Any help please?
When the user command is store in ' saisie ', this command is duplicate and split in array of parameters. And I use ' cmd ' in the execution fonction, with execvp. Then there is your big problem, cmd has a fixed length of 1, if you use that to stored the command arguments for execvp, then you can only store one thing: NULL. You have two options: Use a large fixed size, for example char *cmd[100] where you can store up to 99 arguments and no more. This is the easiest solution but it is not flexible enough. Although some systems have a limit on the number of arguemnts you can pass to a new process, I don't know if there is a limit for all systems, this and this might help you there. Dynamically create an array of char pointers depending on the command line. This is more work but this is also the more flexible solution. Assuming that your command line does not have support for pipes (|) and redirections (<, <<, >, >>), then split_input could look like this: char **split_input(const char *cmd) { if(cmd == NULL) return NULL; char **argv = NULL, **tmp; char *line = strdup(cmd); if(line == NULL) return NULL; const char *delim = " \t\n"; char *token = strtok(line, delim); if(token == NULL) { free(line); return NULL; } size_t len = 0; do { char *arg = strdup(token); if(arg == NULL) { free_argv(argv); free(line); return NULL; } tmp = realloc(argv, (len + 2) * sizeof *argv); if(tmp == NULL) { free_argv(argv); free(line); return NULL; } argv = tmp; argv[len++] = arg; argv[len] = NULL; // argv must be NULL terminated } while(token = strtok(NULL, delim)); free(line); return argv; } void free_argv(char **argv) { if(argv == NULL) return; for(size_t i = 0; argv[i]; ++i) free(argv[i]); free(argv); } Now you can use it like this: while( boucle == 1) { printf("%s#sam:~ %s> ", nom, (getcwd(cwd, sizeof(cwd)))); fgets(saisie,MAX_INPUT_SZ,stdin); printf("\n"); char **argv = split_input(saisie); if(argv == NULL) { fprintf(stderr, "Cannot split command line, not enough memory\n"); continue; } free(backup[u]); backup[u] = strdup(argv[0]); // <-- passing argv[0], not argv // but perhaps what you really want // is strdup(saisie) u = (u + 1) % MAXCMD; b = switchcmd(argv,backup,b,u); start(argv,b); b = 0; //débloquage fonction start free_argv(argv); } You are also doing backup[u] = strdup(cmd); but the problem is that cmd is an array of char pointers, strdup expects a const char*, you are passing the wrong type. It should be strdup(cmd[0]) or strdup(saisie) if you want to store the whole command.
Vigenere cipher in C
I am having trouble debugging my implementation of Vigenere's cipher in C. The error arises when using file input (-f flag) where the file contains fewer than 6 chars (+ 1 EOF), it spits out some number of random characters as well as the expected input and I cannot figure out why this is, although I suspect it has something to do with the second part of my question which is, when using fread(), I noticed that this if( fread(fcontents, fsize, sizeof(char), file) != 1 ) {...} will run with no issues, whereas this if( fread(fcontents, sizeof(char), fsize, file) != 1 ) {...} doesn't work (i.e. causes fread() to return 1 and trigger the error handling code beneath it), which I would expect to be the other way around according to answers from here, but I may just be misinterpreting something. My complete code is as follows: #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <unistd.h> #define ENC 0 //Encrypt mode #define DEC 1 //Decrypt mode #define INP 0 //Commandline input mode #define FLE 1 //File input mode typedef struct { char *password; char *file_name; char *input; int edmode; int ifmode; } options; void string_clean(char *source) { char *i = source; char *j = source; while(*j != 0) { *i = *j++; if( *i != ' ' && (isupper(*i) || islower(*i)) ) i++; } *i = 0; } char *ftostr(char *file_name) //Takes a file name as input and returns a char* to the files contents, returns NULL pointer on faliure. Allocated string must be freed after use by parent function to prevent memory leaks. { FILE *file; long int fsize; char *fcontents; if( !(file = fopen(file_name, "r")) ) { fprintf(stderr, "Error opening file \"%s\"!\n", file_name); return NULL; } fseek(file, 0L, SEEK_END); fsize = ftell(file); rewind(file); if( !(fcontents = malloc((fsize + 1) * sizeof(char))) ) { fclose(file); fprintf(stderr, "Error allocating memory!"); return NULL; } if( fread(fcontents, fsize, sizeof(char), file) != 1 ) { //suspected buggy line fclose(file); free(fcontents); fprintf(stderr, "Error copying file to memory!\n"); return NULL; } fclose(file); return fcontents; } options parse_opts(int argc, char *argv[]) { int c; options args; args.edmode = ENC; //enable encrypt mode by default args.ifmode = INP; //enable commandline input mode by default args.file_name = NULL; args.password = NULL; args.input = NULL; opterr = 0; while((c = getopt(argc, argv, "dep:i:f:")) != -1) { switch(c) { case 'e': args.edmode = ENC; break; case 'd': args.edmode = DEC; break; case 'p': args.password = optarg; break; case 'i': args.input = optarg; args.ifmode = INP; break; case 'f': args.file_name = optarg; args.ifmode = FLE; break; case '?': if(optopt == 'f' || optopt == 'p' || optopt == 'i') fprintf(stderr, "Option -%c requires an argument.\n", optopt); else if(isprint(optopt)) fprintf(stderr, "Unknown option `-%c'.\n", optopt); else fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); fprintf(stderr, "Usage: %s (-f file_name || -i input) -p password [options]\n" "Optional: -e -d\n", argv[0]); exit(-1); } } return args; } char *vigenere_dec(char cipher_text[], char cipher[]) { char *plain_text; string_clean(cipher_text); string_clean(cipher); int plain_text_len = strlen(cipher_text); int cipher_len = strlen(cipher); if( !(plain_text = malloc((plain_text_len + 1) * sizeof(char))) ) return 0; for(int i = 0; i < cipher_len; i++) { if(isupper(cipher[i])) cipher[i] -= 'A'; else if(islower(cipher[i])) cipher[i] -= 'a'; } for(int i = 0, j = 0; i < plain_text_len; i++, j++) { if(j == cipher_len) j = 0; if(isupper(cipher_text[i])) cipher_text[i] -= 'A'; else if(islower(cipher_text[i])) cipher_text[i] -= 'a'; plain_text[i] = ((cipher_text[i] - cipher[j]) % 26); if(plain_text[i] < 0) plain_text[i] += 26; plain_text[i] += 'A'; } return plain_text; } char *vigenere_enc(char plain[], char cipher[]) { char *cipher_text; string_clean(plain); string_clean(cipher); int plain_len = strlen(plain); int cipher_len = strlen(cipher); if(plain_len == 0 || cipher_len == 0) return NULL; if( !(cipher_text = malloc((plain_len + 1) * sizeof(char))) ) return NULL; for(int i = 0; i < cipher_len; i++) { if(isupper(cipher[i])) cipher[i] -= 'A'; else if(islower(cipher[i])) cipher[i] -= 'a'; } for(int i = 0, j = 0; i < plain_len; i++, j++) { if(j == cipher_len) j = 0; if(isupper(plain[i])) plain[i] -= 'A'; else if(islower(plain[i])) plain[i] -= 'a'; cipher_text[i] = ((plain[i] + cipher[j]) % 26) + 'A'; } return cipher_text; } int main(int argc, char *argv[]) { options args; char *output_text = NULL; args = parse_opts(argc, argv); if(args.password == NULL) { fprintf(stderr, "Password uninitialised!\n"); exit(-1); } if(args.input == NULL && args.file_name == NULL) { fprintf(stderr, "Input stream uninitialised!\n"); exit(-1); } if(args.ifmode == INP) { if(args.edmode == ENC) output_text = vigenere_enc(args.input, args.password); else if(args.edmode == DEC) output_text = vigenere_dec(args.input, args.password); } else if(args.ifmode == FLE) { if( !(args.input = ftostr(args.file_name)) ) return -1; if(args.edmode == ENC) output_text = vigenere_enc(args.input, args.password); else if(args.edmode == DEC) output_text = vigenere_dec(args.input, args.password); free(args.input); } puts(output_text); free(output_text); return 0; }
The fault is unterminated strings. You allowed room for the termination char with if( !(plain_text = malloc(plain_text_len + 1)) ) // (simplified) but after you have set, for example plain_text[i] += 'A'; you need to end the string with plain_text[i+1] = '\0'; or when the string is complete. For the second part, you quoted another question, but failed to see that fread() returns the number of items read. So if you swap its size and count arguments, expect a different result (unless fsize == 1). So you can either use if( fread(fcontents, fsize, 1, file) != 1 ) {...} or this if( fread(fcontents, 1, fsize, file) != fsize ) {...} Note I changed sizeof(char) to 1 since by definition, it is.
having trouble with my cd and history function
My results for cd and history: sgraham#myshell:/home/class/sgraham/proj1>cd .. (works fine) sgraham#myshell:/home/class/sgraham>cd .. (not working) sgraham#myshell:/home/class/sgraham>cd .. (not working) cd: Too many arguments sgraham#myshell:/home/class/sgraham>history sgraham#myshell:/home/class/sgraham> (not printing out history) #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <fcntl.h> #define MAX_COMMAND_SIZE 80 #define MAX_ARGS 9 #define HIS_SIZE 100 typedef struct { int argument; // userCom arguments char *arg[MAX_ARGS + 1]; // userCom arguments array char *history[HIS_SIZE]; //history array char *input; // hold input file char *output; // hold output file } Command; int main() { Command userCom = {0}; //holds userCom struct const char *whitespace = " \n\r\t\v\f"; // userCom delimiting chars char* username = getenv("USER"); //Get user name char* curDirect = getenv("HOME"); //get cwd char* token[MAX_ARGS]; char* cwd; char* buf; char* cmd; char buffer[MAX_COMMAND_SIZE + 1]; //hold userCom line //char history[HIS_SIZE][MAX_ARGS +1]; //2D array for history int tok = 0; int new; int i; int limit; int last = 0; int hist = 0; //initialize history size to 0 long size; struct stat buff; //holds file information //gets current working directory and also changes buffer if necessary size = pathconf(".", _PC_PATH_MAX); if ((buf = (char *)malloc((size_t)size)) != NULL) cwd = getcwd(buf, (size_t)size); while(1){ //prints users prompt printf("\n%s#myshell:%s>", username,cwd); //gets string from userCom line fgets(buffer, MAX_COMMAND_SIZE + 1, stdin); buffer[strlen(buffer)-1] = 0 ;//set null //set-up history function userCom.history[last% HIS_SIZE] = cmd; last++; //parses tokens and looks for delimiters token[tok] = strtok(buffer,whitespace); while(token[tok]) { ++tok; if(tok == MAX_ARGS) printf("Reached MAX userCom arguments"); break; token[tok] = strtok(NULL, whitespace); } i =0; //sort tokens based on special characters for (;i<tok;++i) { if(!strcmp(token[i], "<")) { userCom.output = token[++i]; } else if(!strcmp(token[i], ">")) { userCom.input = token[++i]; } else if (token[i][0] == '$') { char* toktok = getenv((const char*)&token[i][1]); if (!toktok) { printf("%s: ERROR: variable.\n", token[i]); return 0; } else { userCom.arg[userCom.argument] = toktok; ++(userCom.argument); } } else { userCom.arg[userCom.argument] = token[i]; ++(userCom.argument); } } tok = 0; userCom.arg[userCom.argument] = 0; //handles the "cd" command if((strcmp(userCom.arg[0],"cd") == 0)) { if (userCom.argument > 2) printf("cd: Too many arguments\n"); // change directories if valid target and update cwd else if (userCom.argument == 1) { new = chdir(cwd); if (new != 0) printf("%s: No such file or directory\n"); // if no argument is given, new directory should be $HOME else { new = chdir(curDirect); // get the new current working directory size = pathconf(".", _PC_PATH_MAX); if ((buf = (char *)malloc((size_t)size)) != NULL) cwd = getcwd(buf, (size_t)size); } } }//end "cd" function //handles the echo command else if(strcmp(userCom.arg[0], "echo") == 0) { int p; for(p=1;p < userCom.argument; ++p) printf("%s ", userCom.arg[p]); }//ends echo function //handles exit else if(strcmp(userCom.arg[0], "exit") == 0) { exit(0); } //handles history functions else if(strcmp(userCom.arg[0], "history") == 0) { int j; for(j = last, limit = 0; userCom.history[j] != NULL && limit != HIS_SIZE ; j = (j -1)% HIS_SIZE, limit++) printf(" %s ",userCom.history[j]); } else { break; } }//end while 1 loop return 0; }//End int main
while(token[tok]) { ++tok; if(tok == MAX_ARGS) printf("Reached MAX userCom arguments"); break; token[tok] = strtok(NULL, whitespace); } This loop breaks at the first time. Probably the if should be like if(tok == MAX_ARGS) { printf("Reached MAX userCom arguments"); break; } Also userCom.argument is never set back to zero, which causes the cd .. to work first time.