having trouble with my cd and history function - c

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.

Related

Trying to write numbers from a .txt to a binary file

I am currently reading a text file that is below:
New York,4:20,3:03
Kansas City,12:03,3:00
North Bay,16:00,0:20
Kapuskasing,10:00,4:02
Thunder Bay,0:32,0:31
I have the city names being fprintf to a new .txt file which works fine, however I am trying to take the times and print them to a binary file and am stuck as to where I am having an issue. Any help would be appreciated.I need to store the times as 04, 20 for "New York" in a 2 byte value and having issues parsing to have this specifically.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma warning(disable: 4996)
// a function to remove the trailing carraige return
void clearTrailingCarraigeReturn(char* buffer);
/* == FUNCTION PROTOTYPES == */
/* == CONSTANTS == */
// MAIN
typedef struct
{
char cityName[20];
short flightTime;
short layoverTime;
} Flight;
Flight parseFlight(char* line) {
char delimiter[2] = ",";
Flight flight;
char* token = strtok(line, delimiter);
int i = 0;
while (token != NULL)
{
if (i == 0)
{
strcpy(flight.cityName, token);
}
if (i == 1)
{
flight.flightTime = atoi(token);
}
if (i == 2)
{
flight.layoverTime = atoi(token);
}
token = strtok(NULL, delimiter);
i++;
}
return flight;
}
int main(int argc, char* argv[])
{
FILE *fpIn, *fpOut, *fbOut;
char line[80];
Flight flight;
fpIn = fopen(argv[1], "r");
fpOut = fopen("theCities.txt", "w+");
fbOut = fopen("theTimes.dat", "wb+");
while (fgets(line, 1024, fpIn) > 0)
{
clearTrailingCarraigeReturn(line);
printf(" >>> read record [%s]\n", line);
flight = parseFlight(line);
fprintf(fpOut, "%s\n", flight.cityName);
fwrite(&flight.flightTime, sizeof(short), 1, fbOut);
fwrite(&flight.layoverTime, sizeof(short), 1, fbOut);
}
fclose(fpIn);
fclose(fpOut);
fclose(fbOut);
}
// This function locates any carraige return that exists in a record
// and removes it ...
void clearTrailingCarraigeReturn(char* buffer)
{
char* whereCR = strchr(buffer, '\n');
if (whereCR != NULL)
{
*whereCR = '\0';
}
}
Perhaps something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Time_s
{
unsigned char hours;
unsigned char minutes;
} Time_t;
typedef struct Flight_s
{
char cityName[20];
Time_t flightTime;
Time_t layoverTime;
} Flight_t;
// a function to remove the trailing carraige return
void clearTrailingCarraigeReturn(char *buffer)
{
int more;
do {
size_t index;
index = strlen(buffer);
if(!index)
break;
--index;
switch(buffer[index])
{
case '\n':
case '\r':
buffer[index] = '\0';
more = 1;
break;
default:
more = 0;
break;
}
} while(more);
return;
}
int ParseTime(char *timeStr, Time_t *time)
{
int rCode=0;
char *next;
time->hours = (unsigned char)strtoul(timeStr, &next, 10);
if(':' == *next)
{
++next;
time->minutes = (unsigned char)strtoul(next, NULL, 10);
}
return(rCode);
}
Flight_t parseFlight(char* line)
{
char delimiter[2] = ",";
Flight_t flight;
char *token = strtok(line, delimiter);
int i = 0;
while(token)
{
switch(i)
{
case 0:
strcpy(flight.cityName, token);
break;
case 1:
ParseTime(token, &flight.flightTime);
break;
case 2:
ParseTime(token, &flight.layoverTime);
break;
}
token = strtok(NULL, delimiter);
i++;
}
return(flight);
}
int main(int argc, char* argv[])
{
int rCode=0;
FILE *fpIn=NULL, *fpOut=NULL, *fbOut=NULL;
char line[80+1];
Flight_t flight;
if(argc < 2)
{
fprintf(stderr, "ERROR: argc < 2\n");
goto CLEANUP;
}
fpIn = fopen(argv[1], "r");
if(!fpIn)
{
fprintf(stderr, "ERROR: fopen(\"%s\",\"r\")\n", argv[1]);
goto CLEANUP;
}
fpOut = fopen("theCities.txt", "w+");
if(!fpOut)
{
fprintf(stderr, "ERROR: fopen(\"theCities.txt\",\"w+\")\n");
goto CLEANUP;
}
fbOut = fopen("theTimes.dat", "wb+");
if(!fbOut)
{
fprintf(stderr, "ERROR: fopen(\"theTimes.dat\",\"wb+\")\n");
goto CLEANUP;
}
while(fgets(line, sizeof(line), fpIn) > 0)
{
clearTrailingCarraigeReturn(line);
flight = parseFlight(line);
printf("%s,%02hhu:%02hhu,%02hhu:%02hhu\n",
flight.cityName,
flight.flightTime.hours, flight.flightTime.minutes,
flight.layoverTime.hours, flight.layoverTime.minutes
);
fprintf(fpOut, "%s\n", flight.cityName);
fwrite(&flight.flightTime, sizeof(Time_t), 1, fbOut);
fwrite(&flight.layoverTime, sizeof(Time_t), 1, fbOut);
}
CLEANUP:
if(fpIn)
fclose(fpIn);
if(fpOut)
fclose(fpOut);
if(fbOut)
fclose(fbOut);
return(rCode);
}

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.

Problems with Implementing Mutex in C

I am implementing a program to read filenames with room names, connections, and room types. Ex:
ROOM NAME: chicago
CONNECTION 1: sarasota
CONNECTION 2: columbus
CONNECTION 3: miami
CONNECTION 4: boston
ROOM TYPE: END_ROOM
The program is designed to show the user the room they are starting in, ask for input from the user, check to see if the input is the end room or another connection. If it is another connection, the prompt will display again. If the user reaches the end room, the game ends. However, I am required to implement a mutex that, if the user enters "time", a file is created, the time is written to it, and it is displayed on the screen. After that, prompt is displayed again for the user. My code works fine when the mutex implementation is stripped out. Here is what I am seeing when the mutex is in the code. I appear to reach the time function and the program seems to recognize incorrect rooms but when a "correct" room is entered the cursor just returns and does nothing. Any clue on why I am getting this behavior only on mutex implementation?
The program is below, do you see anything that would cause this issue?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
//Read in the room data
//Perform the stat() function on the rooms directory in the same directory
//and open the file with the most recent st_mtime component of the returned stat struct
#define NUM_USED_ROOMS 7
char usedRooms[NUM_USED_ROOMS][256];
char roomFilePath[75];
char timeFilePath[75];
char* connections[NUM_USED_ROOMS];
int end = 0;
char input[20];
int numberOfSteps = -1;
char *steps[75];
int file_descriptor;
char timeText[100];
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;
void * getTime() {
pthread_mutex_lock(&myMutex);
printf("You asked for the time!\n");
pthread_mutex_unlock(&myMutex);
return NULL;
}
//Check if the room number passed is the end
void isEnd(int roomNumber, char *dirName){
//Counting the number of steps for the end of the program
numberOfSteps++;
steps[numberOfSteps - 1] = usedRooms[roomNumber];
//Getting the name of the proper file
sprintf(roomFilePath, "%s/%s", dirName, usedRooms[roomNumber]);
char substring[20];
int numLine = 1;
FILE * filePointer;
filePointer = fopen(roomFilePath, "r");
int lines = 0;
char buffer[256];
while(fgets(buffer, sizeof(buffer), filePointer) != NULL){
lines = lines + 1;
}
fclose(filePointer);
//Opening the file to read to see if it is the end. If it is, assign end = 1.
filePointer = fopen(roomFilePath, "r");
while(fgets(buffer, sizeof(buffer), filePointer) != NULL) {
if (numLine == lines)
{
strcpy(substring, buffer+11);
}
numLine = numLine + 1;
}
if(strstr(substring, "END" ) != NULL) {
end = 1;
}
}
//Get the user input
void getInput() {
fflush(stdin);
scanf("%s", input);
fflush(stdin);
fflush(stdout);
}
void readFile(char *dirName){
DIR *dir;
struct dirent *ent;
int i = 0;
if ((dir = opendir (dirName)) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
if (strncmp(ent->d_name,".",sizeof(ent->d_name)) == 0 ||
strncmp(ent->d_name,"..",sizeof(ent->d_name)) == 0 )
{
} else {
strcpy(usedRooms[i],ent->d_name);
i++;
}
}
closedir (dir);
} else {
/* could not open directory */
perror ("");
}
}
void playGame(int roomNumber, char * dirName){
int i;
printf("usedRooms is %s", usedRooms[roomNumber]);
pthread_mutex_lock(&myMutex);
pthread_t secondThread;
pthread_create(&secondThread, NULL, getTime,NULL);
//Check if the user guessed the end room
if(end == 1) {
fflush(stdout);
return;
}
else{
isEnd(roomNumber, dirName);
if (end == 1)
{
fflush(stdout);
return;
}
}
int move = 1;
while(move == 1) {
//Open the file of the path of the room passed in
sprintf(roomFilePath, "%s/%s", dirName, usedRooms[roomNumber]);
FILE * filePointer;
filePointer = fopen(roomFilePath, "r");
int fileLines = 0;
char line[256];
//Count the lines in the file so I know how to traverse it
while(fgets(line, sizeof line, filePointer) != NULL) {
fileLines = fileLines + 1;
}
fclose(filePointer);
filePointer = fopen(roomFilePath, "r");
int currentLine = 0;
//Create the array for the rooms that can be navigated to
char gameRooms[6][30];
while(fgets(line, sizeof line, filePointer) != NULL) {
char *pos;
if((pos = strchr(line, '\n')) != NULL)
{
*pos = '\0';
}
//Print out the current room
if (currentLine == 0)
{
char substring[20];
strcpy(substring, line+11);
printf("CURRENT LOCATION: %s\n", substring);
}
//Print the first connection from this room
else if (currentLine == 1){
printf("POSSIBLE CONNECTIONS: ");
fflush(stdout);
char substring[20];
strcpy(substring, line+14);
printf("%s", substring);
fflush(stdout);
strcpy(gameRooms[currentLine - 1], substring);
}
//Print the rest of the connections, comma separated
else if (currentLine > 1 && currentLine < fileLines - 1) {
printf(",");
fflush(stdout);
char substring[20];
strcpy(substring, line+14);
printf("%s", substring);
fflush(stdout);
strcpy(gameRooms[currentLine - 1], substring);
//gameRooms[currentLine - 1] = substring;
}
else {
printf(".");
fflush(stdout);
}
currentLine = currentLine + 1;
}
fclose(filePointer);
printf("\nWHERE TO?>");
//Get the user input
getInput();
if(strcmp("time", input) == 0){
pthread_mutex_unlock(&myMutex);
pthread_join(secondThread, NULL);
pthread_mutex_lock(&myMutex);
pthread_create(&secondThread, NULL, getTime, NULL);
}
//Loop through the file to see if the input matches a room name in the array
for(i = 0; i < fileLines - 2; i++) {
if (strcmp(gameRooms[i], input) == 0)
{
int j;
for(j = 0; j < NUM_USED_ROOMS; j++) {
//If there is a match, play the game starting at the room entered
if(strcmp(usedRooms[j], input) == 0) {
printf("THE STRINGS MATCH usedRooms is %s "
"and input is %s\n",usedRooms[j],input);
playGame(j,dirName);
}
}
move = 0;
}
}
//If the user's input didn't match the list of rooms
if (move == 1) {
printf("\nHUH? I DON'T UNDERSTAND THAT ROOM. TRY AGAIN. \n\n");
fflush(stdout);
fflush(stdin);
}
}
}
int main() {
int newestDirTime = -1; // Modified timestamp of newest subdir examined
char targetDirPrefix[32] = "walterer.rooms."; // Prefix we're looking for
char newestDirName[256]; // Holds the name of the newest dir that contains prefix
memset(newestDirName, '\0', sizeof(newestDirName));
DIR* dirToCheck; // Holds the directory we're starting in
struct dirent *fileInDir; // Holds the current subdir of the starting dir
struct stat dirAttributes; // Holds information we've gained about subdir
dirToCheck = opendir("."); // Open up the directory this program was run in
if (dirToCheck > 0) // Make sure the current directory could be opened
{
while ((fileInDir = readdir(dirToCheck)) != NULL) // Check each entry in dir
{
if (strstr(fileInDir->d_name, targetDirPrefix) != NULL) // If entry has prefix
{
//printf("Found the prefex: %s\n", fileInDir->d_name);
stat(fileInDir->d_name, &dirAttributes); // Get attributes of the entry
if ((int)dirAttributes.st_mtime > newestDirTime) // If this time is bigger
{
newestDirTime = (int)dirAttributes.st_mtime;
memset(newestDirName, '\0', sizeof(newestDirName));
strcpy(newestDirName, fileInDir->d_name);
}
}
}
}
closedir(dirToCheck);
//Read the file at the specified directory
readFile(newestDirName);
int start;
int i;
for (i = 0; i < NUM_USED_ROOMS; i++)
{
memset(roomFilePath, '\0', sizeof(roomFilePath));
sprintf(roomFilePath,"%s/%s", newestDirName, usedRooms[i]);
char output[256];
memset(output, '\0', sizeof(output));
char* token;
char* connectRoom;
FILE *filePointer;
filePointer = fopen(roomFilePath,"r");
//Find the starting room and pass that into the playGame function
if (filePointer == NULL)
{
printf("Unable to open file!\n");
} else {
while(!feof(filePointer)) {
fgets(output, 256, filePointer);
token = strtok(output, "\n");
if(strstr(token, "START") != NULL){
start = i;
}
}
fclose(filePointer);
}
}
//Play the game with the starting room at the directory name
playGame(start, newestDirName);
printf("YOU HAVE FOUND THE END ROOM. CONGRATULATIONS!\n");
printf("YOU TOOK %d STEPS. YOUR PATH TO VICTORY WAS: \n", numberOfSteps);
for(i = 0; i < numberOfSteps; i++){
printf("%s\n", steps[i]);
}
return 0;
}
As a rule, you should lock a mutex for the shortest time possible. Violation of this rule is a severe anti-pattern called "asking for trouble" which is usually punished with deadlocks. Remove that anti-pattern from your code.

Issue with libreadline when completing an upper case directory

this is a piece of a shell that I'm creating. I'm having some trouble using libreadline, because when the shell gets loaded and I try to cd in a directory using autocompletion (so pressing TAB), after I press enter I access the directory but I get some strange output before another prompt is printed. I noticed that this happens only when the name of the directory starts with an upper case letter.
Example: "user:: ~ % cd Github" <-- written pressing tab to autocomplete Github
Next prompt is: "8b�/�user :: Github %"
I really cannot understand why, this is something really strange for me.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>
#include <readline/history.h>
#include <readline/readline.h>
#include "flush.h"
#include "env.h"
#include "fget.h"
char * flush_builtins[] =
{
"cd",
"help",
"exit",
"ver",
"fget"
};
int flush_num_builtins() {
return sizeof(flush_builtins) / sizeof(char *);
}
int (*flush_func[]) (char **) =
{
&flush_cd,
&help,
&exit_flush,
&ver,
&fget
};
static int flush_startp(char **args)
{
pid_t pid;
int status;
pid = fork();
if (pid == 0)
{
if (execvp(args[0], args) == -1)
{
fprintf(stderr, "flush: command not found\n");
}
exit(1);
}
else if (pid < 0)
{
fprintf(stderr, "flush: command not found\n");
}
else
{
do
{
waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 1;
}
static int flush_exec(char **args)
{
int i;
if (args[0] == NULL)
{
return 1;
}
for (i = 0; i < flush_num_builtins(); i++)
{
if (strcmp(args[0], flush_builtins[i]) == 0) {
return (*flush_func[i])(args);
}
}
return flush_startp(args);
}
static char * flush_read(void)
{
fflush(stdout);
char *line_read = malloc(sizeof(char) * LINE_BUF);
char *prompt = malloc(sizeof(char) * LINE_BUF);
char *current, buffer[TOK_BUF];
current = getcwd(buffer, TOK_BUF);
strcat(prompt, get_user());
strcat(prompt, " :: ");
if (strcmp(current, get_home()) == 0)
{
strcat(prompt, "~");
}
else
{
strcat(prompt, get_cwd());
}
strcat(prompt, " % ");
line_read = readline(prompt);
if (line_read && *line_read)
{
add_history(line_read);
}
return line_read;
free(prompt);
free(line_read);
free(current);
}
static char **flush_getargs(char * line)
{
int bufsize = TOK_BUF;
int i = 0;
char **tokens = malloc(bufsize * sizeof(char *));
char **token;
if (!tokens)
{
fprintf(stderr, "allocation error\n");
exit(1);
}
token = strtok(line, DELIM);
while (token != NULL)
{
tokens[i] = token;
i++;
token = strtok(NULL, DELIM);
}
tokens[i] = NULL;
return tokens;
}
static void flush_loop(void)
{
char *line;
char **args;
int status;
do
{
line = flush_read();
args = flush_getargs(line);
status = flush_exec(args);
free(line);
free(args);
} while (status);
}
static void handler(int num)
{
signal(SIGINT, handler);
flush_loop();
fflush(stdout);
}
int main()
{
init();
signal(SIGINT, handler);
flush_loop();
return 0;
}
You can not use strcat with a non \0 terminated string:
char *prompt = malloc(sizeof(char) * LINE_BUF);
char *current, buffer[TOK_BUF];
current = getcwd(buffer, TOK_BUF);
strcat(prompt, get_user());
Use strcpy instead of strcat, or calloc instead of malloc

Trying to recursively loop the folder contents

I'm trying to create a function which recursively returns the contents of a folder. While testing it, I encounter some problems. With some folders it works, With others it gives me an EXC_BAD_ACCESS, and sometimes it just stops.
I have been trying to debug it with GDB for a long time, but I just can't find a solution to my problem. The function is not quit short an goes as follows.
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
/* THIS IS AN EXTRACT FROM A LARGER FILE
THERE MAY BE TO MUCH INCLUDE STATEMENTS
*/
struct Directory {
DIR *handle;
const char *filename;
};
typedef struct Directory Directory;
int DirectoryCreate(const char *n, Directory *d) {
DIR *dh;
char *str;
dh = opendir(n);
if(dh == NULL) {
return -1;
}
d->handle = dh;
str = malloc(strlen(n) + 1);
if(str == NULL) {
errno = ENOMEM;
closedir(d->handle);
return -1;
}
strcpy(str, n);
d->filename = (const char *)str;
return 0;
}
void DirectoryFree(Directory *s) {
if(s->handle) {
closedir(s->handle);
}
if(s->filename) {
free((void *)s->filename);
}
}
void FreeDirectoryArray(Directory *array, size_t size) {
register size_t i;
for(i = 0; i < size; i++) {
DirectoryFree(&(array[i]));
}
free(array);
}
Directory *ReadFolders = NULL;
size_t ReadFoldersSize = 0;
const char *ReadFolderFilename = NULL;
const char *ReadNextRecursiveItemInFolder(const char *folder) {
struct dirent *entry;
struct stat fileStatus;
int status;
mode_t mode;
const char *newFilename;
char *fullName;
char *ptr;
size_t strLen;
if(folder == NULL && ReadFolders == NULL) {
errno = 0;
return NULL;
}
if(folder != NULL) {
/* free the previous directory list */
FreeDirectoryArray(ReadFolders, ReadFoldersSize);
ReadFolders = NULL;
ReadFoldersSize = 0;
/* open the new directory */
ReadFolders = (Directory *)realloc(ReadFolders, sizeof(Directory));
ReadFoldersSize++;
status = DirectoryCreate(folder, ReadFolders);
if(status != 0) {
FreeDirectoryArray(ReadFolders, ReadFoldersSize-1);
ReadFolders = NULL;
return NULL;
}
}
entry = readdir(ReadFolders[ReadFoldersSize - 1].handle);
/* If NULL, go to previous folder */
if(entry == NULL) {
DirectoryFree(&(ReadFolders[ReadFoldersSize - 1]));
--ReadFoldersSize;
/* if it's empty, we've reached the end */
if(ReadFoldersSize == 0) {
free(ReadFolders);
ReadFolders = NULL;
errno = 0;
return NULL;
}
newFilename = ReadNextRecursiveItemInFolder(NULL);
return newFilename;
}
/* Make sure the entry name is not . or .. */
if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
newFilename = ReadNextRecursiveItemInFolder(NULL);
return newFilename;
}
/* we've got an entry, now construct the full path */
strLen =
strlen(ReadFolders[ReadFoldersSize - 1].filename) +
1 +
strlen(entry->d_name);
fullName = malloc(strLen + 1);
ptr = fullName;
strcpy(ptr, ReadFolders[ReadFoldersSize - 1].filename);
ptr += strlen(ReadFolders[ReadFoldersSize - 1].filename);
strcpy(ptr, "/");
ptr++;
strcpy(ptr, entry->d_name);
newFilename = fullName;
/* no recurse on symbolic links */
status = lstat(newFilename, &fileStatus);
if(status != 0) {
FreeDirectoryArray(ReadFolders, ReadFoldersSize);
ReadFolders = NULL;
ReadFoldersSize = 0;
return NULL;
}
mode = fileStatus.st_mode;
/* if not readable for file or not searchable for folder, get next */
/* if folder and not link, recursively continue */
/* else return the new name */
if((((mode & S_IFDIR) == S_IFDIR) && (mode & S_IXUSR) != S_IXUSR) ||
(mode & S_IRUSR) != S_IRUSR) {
free((void *)newFilename);
newFilename = ReadNextRecursiveItemInFolder(NULL);
return newFilename;
} else if((mode & S_IFDIR) && (mode & S_IFLNK) != S_IFLNK) {
ReadFolders = realloc(ReadFolders, ReadFoldersSize + 1);
ReadFoldersSize++;
errno = 0;
status = DirectoryCreate(newFilename, &(ReadFolders[ReadFoldersSize - 1]));
if(status != 0) {
FreeDirectoryArray(ReadFolders, ReadFoldersSize - 1);
ReadFolders = NULL;
ReadFoldersSize = 0;
return NULL;
}
if(newFilename != ReadFolderFilename) {
free((void *)ReadFolderFilename);
ReadFolderFilename = newFilename;
}
} else {
if(newFilename != ReadFolderFilename) {
free((void *)ReadFolderFilename);
ReadFolderFilename = newFilename;
}
errno = 0;
}
return ReadFolderFilename;
}
int main() {
const char *filename = "/Users/";
const char *entry;
while(1) {
entry = ReadNextRecursiveItemInFolder(filename);
filename = NULL;
if(entry == NULL) {
if(errno == 0) {
printf("End reached\n");
} else {
printf("Error: %s\n", strerror(errno));
}
break;
}
printf("Entry: %s\n", entry);
}
return 0;
}
I'll give a brief explanation how the code works. To start looping a directory, you have to give the full directory path to the function. All subsequent calls have to pass NULL to get the next item in line, unless they want to process another directory.
The code counts every file and folder in a folder, recursively. It does not follow symbolic links, and it only counts readable files and executable directories. To keep track of its 'flow', the function uses 3 global variables:
ReadFolders: an array of Directory structures used to keep track of different levels of folders. The last one at the back.
ReadFoldersSize: the amount of Directory structures in ReadFolders.
ReadFolderFilename: the string that contains the last item processed.
I hope I can find some help around here,
ief2.
The realloc size is wrong : it not "n" but "n*size".
So the line 153 should be :
ReadFolders = realloc(ReadFolders, (ReadFoldersSize + 1)*sizeof(Directory));

Resources