How to redesign this code to avoid goto - c

I have a programme that needs the user to input 4 files (no order require). Then I do something to the files differently. Now I used the goto statement, I want to replace the goto statement, but don't know how. And I want to know if these go to have some problem? Here is my code that using goto:
int main(int argc, char **argv){
char *tmp;
int i, flag1=0, flag2=0, flag3=0, flag4=0;
FILE *fp1;
FILE *fp2;
FILE *fp3;
FILE *fp4;
char file1[64];
char file2[64];
char file3[64];
char file4[64];
for( i=1; i<argc; i++){
tmp = argv[i];
if ( strcmp(tmp+8,"F1") == 0 ){
sprintf(file1,argv[i]);
flag1=1;
}
else if (strcmp(tmp+8,"F2") == 0 ){
sprintf(file2,argv[i]);
flag2=1;
}
else if (strcmp(tmp+8,"F3") == 0 ){
sprintf(file3,argv[i]);
flag3=1;
}
else if (strcmp(tmp+8,"F4") == 0 ){
sprintf(file4,argv[i]);
flag4=1;
}
}
if( !(flag1 && flag2 && flag3 && flag4) ){
printf("Must input four files!!\n");
exit(-1);
}
if (access(file1,0) != 0){
GOTO L1;
}
if((fp1 = fopen(file1,"r")) == NULL){
exit(-1);
}
do_file_1(fp1);
fclose(fp1);
L1: if (access(file2,0) != 0 ){
goto L2;
}
if((fp2 = fopen(file2,"r")) == NULL){
exit(-1);
}
do_file_2(fp2);
fclose(fp2);
L2: if (access(file3,0) != 0)
{
goto L3;
}
if((fp3=fopen(file3,"r"))==NULL)
{
exit(-1);
}
do_file_3(fp3);
fclose(fp3);
L3: if (access(file4,0) !=0)
{
goto end;
}
if((fp4=fopen(file4,"r"))==NULL)
{
exit(-1);
}
do_file_4(fp4);
fclose(fp4);
end:
return 0;
}

You have "if this condition is true, skip over some code". That's the only thing you're using goto for.
That's exactly what if does (except if skips the code if the condition is false).
You can replace:
L2: if (access(file3,0) != 0)
{
goto L3;
}
if((fp3=fopen(file3,"r"))==NULL)
{
exit(-1);
}
do_file_3(fp3);
fclose(fp3);
L3:
with:
if (access(file3,0) == 0)
{
if((fp3=fopen(file3,"r"))==NULL)
{
exit(-1);
}
do_file_3(fp3);
fclose(fp3);
}
and similarly for the other uses of goto.

You refactor in steps.
You can take the end label statement and put it directly where it is called. That's easy.
For the others, you can use else statements:
if (access(file1,0) != 0){
//GOTO L1;
}else{
if((fp1 = fopen(file1,"r")) == NULL){
exit(-1);
}
do_file_1(fp1);
fclose(fp1);
}
L1: if (access(file2,0) != 0 ){
//goto L2;
}else{
if((fp2 = fopen(file2,"r")) == NULL){
exit(-1);
}
do_file_2(fp2);
fclose(fp2);
}
L2: if (access(file3,0) != 0)
{
//goto L3;
}else{
if((fp3=fopen(file3,"r"))==NULL)
{
exit(-1);
}
do_file_3(fp3);
fclose(fp3);
}
L3: if (access(file4,0) !=0)
{
end:
return 0;
}
if((fp4=fopen(file4,"r"))==NULL)
{
exit(-1);
}
do_file_4(fp4);
fclose(fp4);
Of course, since there is no other statements in the if statements, the if else can be refactored to just be an if.
I have broken down more complex problems like this in the past.

Perhaps an approach like the following which uses loops with arrays would be shorter and more compact. This is a fairly straightforward transformation that consolidates separate variables into arrays. This does use an array of function pointers (see How do Function pointers in C work).
The do_file_1(), do_file_2(), etc. functions are just place holders for the actual functions you are using. This keeps the literal file names ("F1", "F2", etc.) that you specify though I am not sure why you are requiring certain, specific file names.
I also use the strcpy() function to copy the file name argument into the array of file names to open rather than using the sprintf() function.
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <string.h>
void do_file_1 (FILE *fp)
{
printf ("function do_file_1 called.\n");
}
void do_file_2 (FILE *fp)
{
printf ("function do_file_2 called.\n");
}
void do_file_3 (FILE *fp)
{
printf ("function do_file_3 called.\n");
}
void do_file_4 (FILE *fp)
{
printf ("function do_file_4 called.\n");
}
int main(int argc, char **argv)
{
int i;
char *fileArray[4] = { "F1", "F2", "F3", "F4"};
char fname[4][64] = {0};
void (*funcs[4]) (FILE *fp) = {do_file_1, do_file_2, do_file_3, do_file_4};
for( i = 1; i < argc; i++) {
int j;
for (j = 0; j < 4; j++) {
if ( strcmp(argv[i], fileArray[j]) == 0 ) {
strcpy(fname[j],argv[i]);
break;
}
}
}
if( !(fname[0][0] && fname[1][0] && fname[2][0] && fname[3][0]) ) {
printf("Must input four files!!\n");
exit(-1);
}
for (i = 0; i < 4; i++) {
if (access(fname[i],0) == 0) {
FILE *fp = fopen(fname[i],"r");
if (fp != NULL) {
funcs[i](fp);
fclose(fp);
} else {
break;
}
} else {
break;
}
}
if (i < 4) exit(-1);
return 0;
}

the obvious variant is to change if statements like this:
if (access(file1,0) == 0){
if((fp1 = fopen(file1,"r")) == NULL) exit(-1);
do_file_1(fp1);
fclose(fp1);
}
if (access(file2,0) == 0 ){
if((fp2 = fopen(file2,"r")) == NULL) exit(-1);
do_file_2(fp2);
fclose(fp2);
}
...

You're just using goto's as a way to reverse the if clauses. Reverse them directly and indent what lies between:
if (access(file1,0) != 0){
GOTO L1;
}
if((fp1 = fopen(file1,"r")) == NULL){
exit(-1);
}
do_file_1(fp1);
fclose(fp1);
L1: ...
Becomes:
if (access(file1,0) == 0)
{
if((fp1 = fopen(file1,"r")) == NULL){
exit(-1);
}
do_file_1(fp1);
fclose(fp1);
}
//L1:

int main(int argc, char **argv){
char *tmp;
int i, flag1=0, flag2=0, flag3=0, flag4=0;
FILE *fp1;
FILE *fp2;
FILE *fp3;
FILE *fp4;
char file1[64];
char file2[64];
char file3[64];
char file4[64];
for( i=1; i<argc; i++){
tmp = argv[i];
if ( strcmp(tmp,"F1") == 0 ){
sprintf(file1,argv[i]);
flag1=1;
}
else if (strcmp(tmp,"F2") == 0 ){
sprintf(file2,argv[i]);
flag2=1;
}
else if (strcmp(tmp,"F3") == 0 ){
sprintf(file3,argv[i]);
flag3=1;
}
else if (strcmp(tmp,"F4") == 0 ){
sprintf(file4,argv[i]);
flag4=1;
}
}
if( !(flag1 && flag2 && flag3 && flag4) ){
printf("Must input four files!!\n");
return -1;
}
if (access(file1,0) == 0) {
if((fp1 = fopen(file1,"r")) == NULL){
return -1;
}
do_file_1(fp1);
fclose(fp1);
}
/*L1:*/
if (access(file2,0) == 0 ) {
if((fp2 = fopen(file2,"r")) == NULL){
return -1;
}
do_file_2(fp2);
fclose(fp2);
}
/*L2:*/
if (access(file3,0) == 0) {
if((fp3=fopen(file3,"r"))==NULL) {
return -1;
}
do_file_3(fp3);
fclose(fp3);
}
/* L3: */
if (access(file4,0) == 0) {
if((fp4=fopen(file4,"r"))==NULL) {
return -1;
}
do_file_4(fp4);
fclose(fp4);
}
return 0;
}
But really, no one programer will not do so.

Related

How to skip NULL file

My code traverses through command line arguments. if the command line contains "alice.txt" index zero of an empty array is filled with "alice.txt" This also applies to "anh.txt" if it is present, then index 1 is filled with "anh.txt". When i type in the command line ./wc alice.txt anh.txt it will print out words line and characters of both files. however if I just do /wc anh.txt i will get "NULL FILE" I suspect this is because of index zero being NULL, I wrote it so it would print "NULL FILE" and then exit the program. How can I modify my code so it doesn't exit, rather skips to the next index? This is what I have for code:
int main(int argc, char **argv)
{
int argArray[argc];
char *nameArray[argc];
for (int i = 1; i < argc; i ++)
{
if (strcmp(argv[i], "-l") == 0)
{
argArray[0] = 1;
}
if (strcmp(argv[i], "-w") == 0)
{
argArray[1] = 1;
}
if (strcmp(argv[i], "-c") == 0)
{
argArray[2] = 1;
}
if (strcmp(argv[i], "alice.txt") == 0)
{
nameArray[0] = "alice.txt";
}
if (strcmp(argv[i], "anh.txt") == 0)
{
nameArray[1] = "anh.txt";
}
if ((strcmp(argv[i], "-l") != 0) && (strcmp(argv[i], "-c") != 0 ) && (strcmp(argv[i], "-w") != 0 ) && (strcmp(argv[i], "-w") != 0) && (strcmp(argv[i], "alice.txt") != 0) && (strcmp(argv[i], "anh.txt") != 0))
{
printf("%s is an invalid argument or file\n", argv[i]);
}
}
if ((argArray[0] != 1) && (argArray[1] != 1) && (argArray[2] != 1))
{
argArray[0] = 1;
argArray[1] = 1;
argArray[2] = 1;
}
int *myArrayAlice = get_counts2(nameArray[0]);
print_counts(argArray, myArrayAlice, *nameArray);
printf(" alice.txt\n");
int *myArrayAnh = get_counts(nameArray[1]);
print_counts(argArray,myArrayAnh, *nameArray);
printf(" anh.txt\n");
int *myArrayTotal2 = get_counts2(nameArray[1]);
print_counts(argArray, myArrayTotal2, *nameArray);
printf(" total\n");
return 0;
}
int *get_counts(char *filename)
{
FILE *file = fopen(filename, "r");
if (file == NULL)
{
printf("NULL FILE");
//exit(1);
}
int c;
bool whitespace = true;
int *arr = calloc(3,sizeof(int));
for(;;)
{
c = fgetc(file);
if (c == EOF)
{
break;
}
else if (c == '\n')
{
arr[0]++;
}
else if (whitespace && !isspace(c))
{
arr[1]++;
whitespace = false;
}
else if (!whitespace && isspace(c))
{
whitespace = true;
}
arr[2]++;
}
fclose(file);
return arr;
}
int *get_counts2(char *filename)
{
FILE *file = fopen(filename, "r");
if (file == NULL)
{
printf("NULL FILE");
//exit(1);
}
int c;
bool whitespace = true;
static int arr[3] = {0,0,0};
for(;;)
{
c = fgetc(file);
if (c == EOF)
{
break;
}
else if (c == '\n')
{
arr[0]++;
}
else if (whitespace && !isspace(c))
{
arr[1]++;
whitespace = false;
}
else if (!whitespace && isspace(c))
{
whitespace = true;
}
arr[2]++;
}
fclose(file);
return arr;
}

My array does not reset to zero after I recall the function

I'm writing a word, character, line counter for files in C. Im using a function get_counts to get these numbers. Right now I'm trying to get these values for two files. However, when I call it twice, the values don't reset to zero. I don't understand why because I declare the array to be {0,0,0} before I do any counting when I call the function. Here is my code. Currently just trying to get the line counter to work in print_counts. i'm sending it two files, one file has 3735 lines and the other file has 21. I keep getting an output of 3756.
int *get_counts(char *filename)
{
FILE *file = fopen(filename, "r");
if (file == NULL)
{
printf("NULL FILE");
exit(1);
}
int c;
bool whitespace = true;
static int arr[3] = {0,0,0};
for(;;)
{
c = fgetc(file);
if (c == EOF)
{
break;
}
else if (c == '\n')
{
arr[0]++;
}
else if (whitespace && !isspace(c))
{
arr[1]++;
whitespace = false;
}
else if (!whitespace && isspace(c))
{
whitespace = true;
}
arr[2]++;
}
fclose(file);
return arr;
}
void print_counts(int* show, int *count, char *name)
{
if (name[0] != '\0')
{
//int *myArray1 = get_counts(&name[0]);
if (show[0] == 1)
{
printf("%d", count[0]);
}
}
if (name[1] != '\0')
{
if (show[0] == 1)
{
printf("%d", count[0]);
}
}
}
int main(int argc, char **argv)
{
int argArray[argc];
char *nameArray[argc];
for (int i = 1; i < argc; i ++)
{
if (strcmp(argv[i], "-l") == 0)
{
argArray[0] = 1;
}
if (strcmp(argv[i], "-w") == 0)
{
argArray[1] = 1;
}
if (strcmp(argv[i], "-c") == 0)
{
argArray[2] = 1;
}
if (strcmp(argv[i], "alice.txt") == 0)
{
nameArray[0] = "alice.txt";
}
if (strcmp(argv[i], "anh.txt") == 0)
{
nameArray[1] = "anh.txt";
}
if ((strcmp(argv[i], "-l") != 0) && (strcmp(argv[i], "-c") != 0 ) && (strcmp(argv[i], "-w") != 0 ) && (strcmp(argv[i], "-w") != 0) && (strcmp(argv[i], "alice.txt") != 0) && (strcmp(argv[i], "anh.txt") != 0))
{
printf("error");
exit(1);
}
}
int *myArrayAlice = get_counts(nameArray[0]);
print_counts(argArray, myArrayAlice, *nameArray);
int *myArrayAnh = get_counts(nameArray[1]);
print_counts(argArray, myArrayAnh, *nameArray);
return 0;
}
I don't understand why because I declare the array to be {0,0,0}
before I do any counting when I call the function.
Because is defined as static, remove the static keyword switching to int *arr = calloc(3, sizeof(int); or passing arr[3] from main and calling memset(arr, 0, 3 * sizeof(int)); in the function if you prefer to avoid dynamic memory.

How to test if a file is open/closed in different functions in C

I need to write separate functions for opening/closing the file and working with it. Was recommended to not use global variables in it.
I have a function where I need to open the file and print what's in it(open_file), a second to work with the data in it(do_stuff_in_file), and a third to only close the file and exit the program(close_file).
When I try to call do_stuff_in_file or close_file the program just crashes.
I know I'm supposed to use pointers, but I just can't get it right and I don't know where's the mistake.
int open_file(FILE **fr) {
if ((fr = fopen("soldcars.txt", "r")) == NULL) {
printf("File was not opened\n");
return 1;
}
else {
char testchar;
while ((testchar = fgetc(fr)) != EOF) {
ungetc(testchar, fr);
//just printing whats in the file
}
}
return 0;
}
int do_stuff_in_file(FILE **fr, int date) {
if (fr==NULL) {
printf("File not open yet\n");
return 1;
}
else{ fseek(fr, 0, SEEK_SET); } //doing stuff
return 0;
}
int close_file(FILE **fr) {
if (fr==NULL) {
printf("It was not even open yet\n");
return 1;
}
else{
if (fclose(fr) == EOF) {
printf("File was not successfully closed");
return 1;
}
else{
printf("Adios");
exit(1);
}
}
}
int main() {
char input;
int date;
FILE* fr;
fr = NULL;
while ((input = getchar()) != 'c') {
if (input == 'o') open_file(&fr);
else if (input == 'd') {
scanf("%d", &date);
do_stuff_in_file(&fr, date);
}
}
if (input == 'c') {
close_file(&fr);
}
return 0;
}
You need to dereference properly. eg
int open_file(FILE **fr) {
if ((*fr = fopen("soldcars.txt", "r")) == NULL) {
perror( "soldcars.txt" );
return 1;
}
Note *fr = open instead of fr = open. And, in that function, always use *fr, as in fgetc(*fr) vice fgetc(fr). Similarly in the other functions. Because fr is not a FILE *, but *fr is.

C program which counts lines and operators wrong

This program should read rows and count operators, but counts wrong and can not find out where the errors are.
Help me find out the bugs and fix the program to be able to count rows and operators correctly.I've already tried several ways to fix it and it still counts wrong.
Current output:Broqt na operatorite e:1
Broqt na redovete e:1119
Expected output: Broqt na operatorite e:11
Broqt na redovete e:221
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
void cycleOperatorsCounter(FILE* inputStream, FILE* outputStream);
void counter(FILE* inputStream, FILE* outputStream);
int fileToFile(void);
int fileToScreen(void);
int screenToFile(void);
int screenToScreen(void);
void getFileName(char* fileName, int mode);
int menu() {
int i;
printf("----1. FILE TO FILE \n");
printf("----2. FILE TO SCREEN \n");
printf("----3. KBRD TO FILE \n");
printf("----4. KBRD TO SCREEN \n");
printf("----0. EXIT \n");
do {
printf("SELECT OPTION: ");
fflush(stdin);
scanf("%i", &i);
} while (i < 0 || i> 4);
return i;
}
int main(void) {
while (1) {
system("cls");
switch (menu()) {
case 1: fileToFile();
break;
case 2: fileToScreen();
break;
case 3: screenToFile();
break;
case 4: screenToScreen();
break;
default:
return 0;
}
system("pause");
}
}
void getFileName(char* fileName, int mode) {
while (1) {
fflush(stdin);
if (mode == 1) {
printf("Input file name(.C): ");
gets(fileName);
if (fileName[strlen(fileName) - 2] == '.' && toupper(fileName[strlen(fileName) - 1]) == 'C') {
return;
}
}
else {
printf("Output File: ");
gets(fileName);
return;
}
}
}
int fileToFile(void) {
char inputFileName[256], outputFileName[256];
FILE *inputStream, *outputStream;
getFileName(inputFileName, 1);
if (!(inputStream = fopen(inputFileName, "r"))) {
fprintf(stderr, "Error opening file!\n");
return -1;
}
getFileName(outputFileName, 2);
if (!(outputStream = fopen(outputFileName, "w"))) {
fprintf(stderr, "Error opening file!\a\n");
return -1;
}
cycleOperatorsCounter(inputStream, outputStream);
rewind(inputStream);
counter(inputStream, outputStream);
fclose(inputStream);
fclose(outputStream);
printf("Results saved to \"%s\".\n", outputFileName);
return 0;
}
int fileToScreen(void) {
char inputFileName[256];
FILE* inputStream;
getFileName(inputFileName, 1);
if (!(inputStream = fopen(inputFileName, "r"))) {
fprintf(stderr, "Error opening file!\n");
return -1;
}
cycleOperatorsCounter(inputStream, stdout);
rewind(inputStream);
counter(inputStream, stdout);
fclose(inputStream);
return 0;
}
int screenToFile(void) {
char outputFileName[256];
FILE *outputStream, *tempStream;
char str[999];
tempStream = fopen("temp.tmp", "w");
fflush(stdin);
printf("Napishete \"KRAI\" na nov red, kogato vuvedete teksta\n");
while (1) {
gets(str);
if (!strcmp(str, "KRAI")) {
fclose(tempStream);
tempStream = fopen("temp.tmp", "r");
break;
}
fprintf(tempStream, "%s\n", str);
}
getFileName(outputFileName, 2);
if (!(outputStream = fopen(outputFileName, "w"))) {
fprintf(stderr, "Error opening file!\a\n");
return -1;
}
cycleOperatorsCounter(tempStream, outputStream);
rewind(tempStream);
counter(tempStream, outputStream);
fclose(tempStream);
fclose(outputStream);
printf("Results saved to \"%s\".\n", outputFileName);
return 0;
}
int screenToScreen(void) {
FILE *tempStream;
char str[999];
tempStream = fopen("temp.tmp", "w");
fflush(stdin);
printf("Napishete \"KRAI\" na nov red, kogato vuvedete teksta\n");
while (1) {
gets(str);
if (!strcmp(str, "KRAI")) {
fclose(tempStream);
tempStream = fopen("temp.tmp", "r");
break;
}
fprintf(tempStream, "%s\n", str);
}
cycleOperatorsCounter(tempStream, stdout);
rewind(tempStream);
counter(tempStream, stdout);
fclose(tempStream);
return 0;
}
void cycleOperatorsCounter(FILE* inputStream, FILE* outputStream) {
char str[1000];
int cycleCounter = 0;
unsigned i;
while (fgets(str, sizeof(str), inputStream) != NULL) {
for (i = 0; i < strlen(str); i++) {
if ((str[i-1] == ' ' || str[i-1] == '\n' || str[i-1] == '\t' || i==0) &&
(str[i] == 'i') && (str[i + 1] == 'f') && (str[i+3] == ' ' || str[i+3] ==
'\n' || str[i+3] == '\t')) {
cycleCounter++;
}
if ((str[i-1] == ' ' || str[i-1] == '\n' || str[i-1] == '\t' ||
i==0)
&& (str[i] == 'e') && (str[i + 1] == 'l') && (str[i + 2] == 's')
&& (str[i + 3] == 'e')
&& (str[i+5] == ' ' || str[i+6] == '\n' || str[i+7] ==
'\t')) {
cycleCounter++;
}
}
}
fprintf(outputStream, "Broqt na operatorite za cikul e: %d\n",
cycleCounter);
}
void counter(FILE* inputStream, FILE* outputStream) {
char str[1000];
int Counter = 0;
unsigned i;
while (fgets(str, sizeof(str), inputStream) != NULL) {
for (i = 0; i < strlen(str); i++) {
{
if ((str[i-1] == ' ' || str[i-1] == '\n' || str[i-1] == '\t' || i==0))
{
Counter++;
}
}
}
}
fprintf(outputStream, "Broqt na redovete e: %d\n", Counter);
}
This is prefaced by my top comments.
That is, finding the if and the else is more easily done with strtok and strcmp.
And, to count rows/lines, simply doing fgets and counting or doing fgetc and counting the \n will work.
Hopefully, this will get you farther:
void
cycleOperatorsCounter(FILE *inputStream, FILE *outputStream)
{
char *bp;
char *tok;
char str[1000];
int cycleCounter = 0;
while (fgets(str, sizeof(str), inputStream) != NULL) {
bp = str;
while (1) {
tok = strtok(bp," \t\n");
if (tok == NULL)
break;
bp = NULL;
if (strcmp(tok,"if") == 0) {
cycleCounter++;
continue;
}
if (strcmp(tok,"else") == 0) {
cycleCounter++;
continue;
}
}
}
fprintf(outputStream, "Broqt na operatorite za cikul e: %d\n",
cycleCounter);
}
void
counter(FILE *inputStream, FILE *outputStream)
{
int Counter = 0;
// count number of lines
// NOTE: either of these should work:
#if 1
char str[1000];
while (fgets(str, sizeof(str), inputStream) != NULL)
++Counter;
#else
while (1) {
int chr = fgetc(inputStream);
if (chr == EOF)
break;
if (chr == '\n')
++Counter;
}
#endif
fprintf(outputStream, "Broqt na redovete e: %d\n", Counter);
}

minishell malloc error with EXC_BAD_ACCESS

Hi I've recently started learning unix system programming.
I'm trying to create a minishell in c but when I run my code,
I always get:
EXC_BAD_ACCESS (code=EXC_I386_GPFLT
Don't really know what's wrong here. Searched online they say it's something wrong with malloc, but I don't see what's wrong.
Can someone help me with this problem?
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include "minishell.h"
char promptString[] = "mysh>";
struct command_t command;
int enviromentlength;
int commandlength;
char *pathv[MAX_PATHS];
//to display the prompt in the front of every line
void printPrompt()
{
printf("%s", promptString);
}
//get the user's command
void readCommand(char *buffer)
{
gets(buffer);
}
//get the environment variable and store in a pathEnvVar
int parsePath( char* dirs[] )
{
char* pathEnvVar;
char* thePath;
int i;
for(i = 0; i < MAX_ARGS; i++)
{
dirs[i] = NULL;
}
i = 0;
//use system call to get the environment variable
pathEnvVar = (char*) getenv("PATH");
//printf("%s\n", pathEnvVar);
thePath = (char*) malloc(strlen(pathEnvVar) + 1);
strcpy(thePath, pathEnvVar);
//splict the variable and store in the pathv
char *temp = strtok(thePath, ":");
dirs[i] = temp;
while(temp != NULL)
{
i++;
temp = strtok(NULL, ":");
if(temp == NULL)
{
break;
}
else
{
dirs[i] = temp;
}
}
dirs[i+1] = NULL;
return i;
}
//get the user's command and parameters
int parseCommand(char * commandline)
{
int i = 0;
char* temp;
temp = strtok(commandline, " ");
while(temp != NULL)
{
command.argv[i] = temp;
i++;
temp = strtok(NULL, " ");
}
command.argv[i] = NULL;
return i;
}
//input the user's command to
//fix the absolute path of the command
char* lookupPath(char* dir[], char* command[])
{
char* result = NULL;
int i;
//printf("%c\n", *command.argv[0]);
//if the command is already an absolute path
if(*command[0] == '/')
{
result = command[0];
//printf("test\n");
if( access(result, X_OK) == 0)
{
return result;
}
else
{
fprintf(stderr, "%s: command not found\n", result);
return NULL;
}
}
//if the command is not an absolute path
else
{
for(i = 0; i < enviromentlength; i++)
{
char *temp = (char *) malloc (30);
strcpy(temp, dir[i]);
strcat(temp, "/");
strcat(temp, command[0]);
result = temp;
if( access(result, X_OK) == 0)
{
return result;
}
}
fprintf(stderr, "%s: command not found\n", result);
return NULL;
}
}
//to change the directory and
//display the absolute path of the current directory
void do_cd(char* dir[])
{
char currentdirectory[MAX_PATHS];
if(dir[1] == NULL || (strcmp(dir[1], ".") == 0))
{
printf("director does not change\n");
//printf("The current directory is:%s", currentdirectory);
}
else
{
if(chdir(dir[1]) < 0)
{
printf("change director error\n");
}
else
{
printf("change director success\n");
}
}
getcwd(currentdirectory, MAX_PATHS);
printf("The current directory is:%s\n", currentdirectory);
}
//redirection the result to file
void redirection(char* command, char* commandcontent[], int position, pid_t thisChPID)
{
char* content[commandlength - 1];
char* filename = (char *) malloc(MAX_PATH_LEN);
FILE* fid;
int i = 0;
int stat;
strcpy(filename, commandcontent[position + 1]);
//printf("%s\n", commandcontent[position + 1]);
for(i = 0; i < position; i++)
{
content[i] = commandcontent[i];
//printf("content: %s\n", content[i]);
}
content[i + 1] = NULL;
for(i = 0; i< position + 1; i++)
{
printf("%s\n", content[i]);
}
printf("%s\n", command);
if((thisChPID=fork()) < 0)
{
fprintf(stderr, "fork failed\n");
}
else if(thisChPID == 0)
{
fid = open(filename, O_WRONLY || O_CREAT);
close(1);
dup(fid);
close(fid);
execve(command, content, pathv);
}
else
{
wait(&stat);
}
}
//use pipe to run the program
void piperun(char* command, char* commandcontent[], int position, pid_t thisChPID)
{
printf("%s\n%d\n", command, position);
char* firstcommand[position+1];
char* secondcommand[commandlength-position];
char* result = (char *) malloc(MAX_PATH_LEN);
pid_t child;
//the pipe name
int pipeID[2];
int j;
for(j = 0; j< position; j++)
{
firstcommand[j] = commandcontent[j];
printf("%s\n", firstcommand[j]);
}
firstcommand[j] = NULL;
printf("length: %d\n", commandlength-position);
for(j = 0; j < (commandlength-position); j++)
{
secondcommand[j] = commandcontent[position + 1 + j];
printf("second:%s\n",secondcommand[j]);
}
//secondcommand[j+1] = NULL;
result = lookupPath(pathv, secondcommand);
//printf("%s\n", secondcommand[0]);
printf("%s\n", result);
//create pipe "pipeID"
if(pipe(pipeID)==-1)
{
printf("Fail to creat pipe.\n");
}
if((thisChPID=fork())==-1)
{
printf("Fail to creat child process.\n");
}
if(thisChPID==0)
{
printf("in the child\n");
close(1);
dup(pipeID[1]);
close(pipeID[0]);
close(pipeID[1]);
if(execve(command, firstcommand, pathv)==-1)
{
printf("Child process can't exec command %s.\n",firstcommand[0]);
}
}
else
{
child = fork();
if((child=fork())==-1)
{
printf("Fail to creat child process.\n");
}
if(child==0)
{
close(0);
dup(pipeID[0]);
close(pipeID[1]);
close(pipeID[0]);
if(execve(result, secondcommand, pathv)==-1)
{
printf("Child process can't exec command %s.\n",secondcommand[0]);
}
}
else
{
wait(NULL);
}
}
}
int main()
{
char commandLine[LINE_LEN];
int child_pid; //child process id
int stat; //used by parent wait
pid_t thisChPID;
char *arg[MAX_ARGS];
//the flag of redirection, piping and background running
int redirectionsituation = 0;
int pipesituation = 0;
int background = 0;
char * tempchar;
//Command initialization
int i;
for(i = 0; i < MAX_ARGS; i++ )
{
command.argv[i] = (char *) malloc(MAX_ARG_LEN);
}
//get all directories from PATH env var
enviromentlength = parsePath(pathv);
//Main loop
while(TRUE)
{
redirectionsituation = 0;
pipesituation = 0;
background = 0;
//Read the command line
printPrompt();
readCommand(commandLine);
//input nothing
if(commandLine[0] == '\0')
{
continue;
}
//quit the shell?
if((strcmp(commandLine, "exit") == 0) || (strcmp(commandLine, "quit") == 0))
{
break;
}
//if it is background running
if(commandLine[strlen(commandLine) - 1] == '&')
{
printf("backgrond\n");
tempchar = strtok (commandLine, "&");
//strcpy(commandLine, tempchar);
printf("%s\n", tempchar);
background = 1;
}
//Parse the command line
commandlength = parseCommand(commandLine);
//if the command is "cd"
if(strcmp(command.argv[0], "cd") == 0)
{
do_cd(command.argv);
continue;
}
//Get the full path name
command.name = lookupPath(pathv, command.argv);
printf("command name %s\n", command.name);
//report error
if( command.name == NULL)
{
continue; //non-fatal
}
//if redirection is required
for(i = 0; i < commandlength; i++)
{
if(strcmp(command.argv[i], ">") == 0)
{
redirectionsituation = 1;
break;
}
}
if(redirectionsituation == 1)
{
redirection(command.name, command.argv, i, thisChPID);
continue;
}
//if pipe is required
for(i = 0; i < commandlength; i++)
{
if(strcmp(command.argv[i], "|") == 0)
{
pipesituation = 1;
break;
}
}
if(pipesituation == 1)
{ //run pipe
piperun(command.name, command.argv, i, thisChPID);
continue;
}
//normal running
if((thisChPID=fork()) < 0)
{
fprintf(stderr, "fork failed\n");
}
else if(thisChPID == 0)
{
//printf("run again\n");
execve(command.name, command.argv, pathv);
}
else
{
//do not put the process in the background, wait until the child process terminates
if(background == 0)
{
wait(&stat);
}
}
}
return 0;
}
Run it in a debugger and see where you are dereferencing a null.

Resources