Problems of History for my own Shell in C - 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.

Related

cronology feature to access the most recently commands inserted in a shell Linux in C

I'm trying to make a feature in my simple shell, which keeps track of the last 10 commands entered by the user. The problem is that when I enter commands in a circular array it is filled with with the last command entered. I can't understand why, thanks in advance.
in p[0] i have the command
main and fuction prompt
void prompt();
void history(char *p[]);
void showBuffer();
char* cbuffer[10] = {0};
int idx = 0;
int main (int argc, char* argv[])
{
//Set the PWD to the Home Directory
chdir(getenv("HOME"));
printf("Shell is running..\n");
printf("\n");
char com[MAX_STRING];
char *pars[MAX_ARGS],buff[MAX_ARGS];
int w, pid, s;
while (TRUE) {
prompt();
w = read_command(com, pars);
//check for the background or foreground implementation
//w=0 -> background
//w=1 foreground
printf("%d \n",w);
// check if no command was read
if (strlen(com) == 0)
continue;
// com are the commands.. /bin/cd..
//pars[0] it' the first token(command) .. pars[1] the second token
pid = fork();
if (pid < 0) { // fork FAILED!
printf("ERROR!: impossible to execute the command: %s", com);
continue;
}
if (pid != 0) // FATHER
if (w)
waitpid(-1, &s, 0);
else continue;
else execv(com, pars); // CHILD
}
printf("terminated");
return 0;
}
void prompt()
{
char hostname[MAX_STRING];
char buff[MAX_ARGS];
gethostname(hostname,MAX_STRING);
printf("#%s",hostname);
printf(": %s",getcwd(buff,MAX_STRING));
printf(" >> ");
}
fuctions that populates and show array
//function that populates the array
void history(char *p[])
{
cbuffer[idx] = p[0];
printf("comando nel BUFFER-------------->> %s \n", cbuffer[idx]);
printf("%d indice, idx \n", idx);
idx++;
if(idx == 10)
{
showBuffer();
idx = 0;
}
}
//show buffer
void showBuffer()
{
for(int i = 0; i < 10; i++) printf("%s e`il comando contenuto\n", cbuffer[i]);
}
fuctions read command and call history(char *p[])
int read_command(char *c, char *p[])
{
char tmp[MAX_STRING],copy_path[MAX_STRING], *s;
const char *path=getenv("PATH");
int i;
struct stat buf;
// it reads from the stdin in a SECURE way
get_string(tmp, MAX_STRING);
// the user just push the carriage return
if (strlen(tmp) == 0) {
c[0] = '\0';
return 0;
}
// extract the command name (first token)
s = strtok(tmp, " ");
strcpy(c,s);
//Pass a tmp path for don't change the getenv("PATH");
strcpy(copy_path,path);
// PARAMETER ARRANGEMENT
i=0;
while (s != NULL) {
if (p[i] == NULL)
p[i] = (char *) malloc(MAX_STRING); // MEMORY ALLOCATION
strcpy(p[i++], s);
s = strtok (NULL, " ");
}
p[i] = NULL;
/******* i try to save command in array************/
if(p[0]!=NULL && strcmp(p[0],"!!!") !=0)
{
history(p);
}
else if(strcmp(p[0], "!!!")==0)
{
for(int i = 0; i <= 10; i++){
printf("%d --> %s \n", i, cbuffer[i]);
}
showBuffer();
}
//Foreground
return 1;
}
OUTPUT :
comando nel BUFFER--------->> cd // last command insert, the above commands are different from "cd"
9 indice, idx
cd command
cd command
cd command
cd command
cd command
cd command
cd command
cd command
cd command
cd command

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.

Check if environment has passed to execv

I try to do some homework exercise about creating a process with execv in linux.
I need to take an input string from the user, and check if there is a program with same name on the machine.
I need to try to execute the given program string with the PATH variable directories
I have to use the execv function ONLY to execute the program.
The input seperated by space when the first word is the file of the program and the other words are the arguments.
And they also ask me to validate that the environment has passed to the execv.
How do i check that?
I found out that I need to use the environ variable and fill it
I Have tried this so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MYCOMMAND_LEN 1000
#define MYNUM_OF_PARAMS 500
extern char **environ;
int main()
{
int i = 0, j, pid, stat, amountOfLib;
char command[MYCOMMAND_LEN];
char *params[MYNUM_OF_PARAMS];
char *path, *lastStr;
char *libs[100];
int numberOflib = 0, numOfParams;
char *commandPath;
//cut path
path = getenv("PATH");
lastStr = strtok(path, ":");
libs[0] = (char*)malloc(sizeof(char)*strlen(lastStr) + 1);
strcpy(libs[0], lastStr);
i = 1;
while (lastStr = strtok(NULL, ":")) {
libs[i] = (char*)malloc(sizeof(char)*strlen(lastStr) + 1);
strcpy(libs[i], lastStr);
i++;
numberOflib = i;
}
numberOflib = i;
puts("Please Enter Command: ");
gets(commandPath);
//loop until leave {
while (strcmp(command, "leave") != 0) {
//cut command
lastStr = strtok(command, " ");
params[0] = (char*)malloc(sizeof(char)*(strlen(lastStr) + 1));
strcpy(params[0], lastStr);
i = 1;
while ((lastStr = strtok(NULL, " ")) != NULL)
{
params[i] = (char*)malloc(sizeof(char)*(strlen(lastStr) + 1));
strcpy(params[i], lastStr);
i++;
}
params[i] = NULL;
numOfParams = i;
//check if first is relative
if ((pid = fork()) == 0) {
if (params[0][0] == '/' ||
(strlen(params[0]) >= 2 &&
params[0][0] == '.' &&
params[0][1] == '/'
) ||
(strlen(params[0]) >= 3 &&
params[0][0] == '.' &&
params[0][1] == '.' &&
params[0][2] == '/'
)
) execv(params[0], params);
// if command like "man ls"
else {
for (i = 0; i < amountOfLib; i++) {
commandPath = libs[i];
strcat(commandPath, "/");
strcat(commandPath, params[0]);
for (j = 0; j < numOfParams; j++) {
environ[j] = params[j]; //last environ also get the null
}
execv(commandPath, NULL);
}
puts("command not found in PATH");
exit(1);
}
} else {
wait(&stat);
}
puts("Please Enter Command: ");
gets(commandPath);
}
//}
}
some inputs like 'ls' reply that the argv vector is empty.

OpenBSD 5.9 header with C99 inline function

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

Circuit Simulator in C input

I have to create a circuit based off the inputs of a text file i read.
The first text file I use has the circuit description and then the next has the actual binary values of the circuit you end up creating.
Example:
INPUTVAR 3 A B C
OUTPUTVAR 1 Q
AND A B w
AND A C x
OR w x Q
the format of this example means that there are 3 input variables called A, B , C. There is also 1 output variable called Q. The And creates an expression called w= A.B. along with x=A.C. and the or is Q = w.x. My problem is that I do not know how to read in this input since it isnt the same format every time. The amount of variables after the INPUTVAR depends on what that first number says. I am confused on how I can interpret this in code, I know how to read in data that is formatted. Any hints or help provided will be appreciated.
I believe I need to use fgets() to do it line by line.
with help I have came up with the following code
FILE *circuit;
circuit = fopen(argv[1],"r");
char line[50];
char *str;
while (fgets(line,sizeof(line),circuit) != NULL)
{
str = strtok(line," "); //space is DELIM
printf("str is: %s\n",str);
}
I am geting the following outputs from the text file that I included as an example:
str is: INPUTVAR
str is: OUTPUTVAR
str is: AND
str is: AND
str is: OR
How do I go about getting the characters after the first word of each line?
I adjusted your code [please pardon any gratuitous style cleanup]:
FILE *circuit;
circuit = fopen(argv[1], "r");
char line[50];
char *str;
char *cp;
while (1) {
cp = fgets(line, sizeof(line), circuit);
if (cp == NULL)
break;
cp = strchr(line,'\n');
if (cp != NULL)
*cp = 0;
cp = line;
while (1) {
str = strtok(cp, " ");
cp = NULL;
if (str == NULL)
break;
printf("str is: %s\n", str);
}
}
UPDATE: Per your request, here is a more generalized solution that gets you closer. This compiles but is untested. But, it should give you the idea.
// circuit -- circuit simulator
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// command parsing control
// NOTE: this can be build up if desired
struct cmd {
const char *cmd_str; // command string
const char *(*cmd_parse)(struct cmd *); // command parse function
};
// forward declarations
const char *parse_inputvar(struct cmd *cmd);
const char *parse_outputvar(struct cmd *cmd);
const char *parse_and(struct cmd *cmd);
const char *parse_or(struct cmd *cmd);
// list of supported commands
struct cmd cmdlist[] = {
{ .cmd_str = "INPUTVAR", .cmd_parse = parse_inputvar },
{ .cmd_str = "OUTPUTVAR", .cmd_parse = parse_outputvar },
{ .cmd_str = "AND", .cmd_parse = parse_and },
{ .cmd_str = "OR", .cmd_parse = parse_or },
{ .cmd_str = NULL }
};
int
main(int argc,char **argv)
{
FILE *circuit;
char line[5000];
char *cp;
struct cmd *cmd;
const char *err;
--argc;
++argv;
circuit = fopen(*argv, "r");
while (1) {
cp = fgets(line, sizeof(line), circuit);
if (cp == NULL)
break;
cp = strchr(line,'\n');
if (cp != NULL)
*cp = 0;
cp = strtok(line," ");
err = NULL;
for (cmd = cmdlist; cmd->cmd_str != NULL; ++cmd) {
if (strcmp(cp,cmd->cmd_str) == 0) {
err = cmd->cmd_parse(cmd);
break;
}
}
if (cmd->cmd_str == NULL)
printf("unknown command -- '%s'\n",cp);
if (err != NULL)
printf("error in %s command -- %s\n",cmd->cmd_str,err);
}
fclose(circuit);
}
const char *
parse_inputvar(struct cmd *cmd)
{
char *cp;
char *sym;
int cnt;
int idx;
const char *err = NULL;
do {
// get the count string
cp = strtok(NULL," ");
if (cp == NULL) {
err = "missing count";
break;
}
// decode count string into number
cnt = atoi(cp);
if (cnt <= 0) {
err = "bad count";
break;
}
for (idx = 0; idx < cnt; ++idx) {
sym = strtok(NULL," ");
if (sym == NULL) {
err = "missing symbol";
break;
}
// NOTE: sym will be invalid after we return so we need to preserve
// it now
sym = strdup(sym);
// do whatever ...
}
} while (0);
return err;
}
const char *
parse_outputvar(struct cmd *cmd)
{
const char *err = NULL;
return err;
}
const char *
parse_and(struct cmd *cmd)
{
const char *err = NULL;
return err;
}
const char *
parse_or(struct cmd *cmd)
{
const char *err = NULL;
return err;
}
You can read the line of input, using fgets(), as a string and them do a split() function on it to parse it into numbers. The split creates an array of strings using spaces as delimiters. The first string will be INPUTVAR in string format, then you can do an atoi() on that to convert to a number.

Resources