Question: Safe C memory programming The program below parses a given file path into a linked list of heap-allocated DirEntryName instances. A single heap-allocated PathName instance
Safe C memory programming
The program below parses a given file path into a linked list of heap-allocated DirEntryName instances. A single heap-allocated PathName instance owns this list.
Please write:
getPathText()
parseRestOfPath()
destroy()
Sample output:
$ ./dirPath / Start from the root directory / $ ./dirPath /hello Start from the root directory / hello $ ./dirPath /hello/there Start from the root directory / hello there $ ./dirPath hello/there Start from current directory hello there $ ./dirPath ~hello/there Start from the home directory of hello there $ ./dirPath ~hello/there.txt Start from the home directory of hello there.txt $ ./dirPath // Missing directory name! $ ./dirPath ~/hello/there Start from the root directory / home (the shell added this) instructor (the shell added this too) hello there $ ./dirPath ~/hello/the@re Illegal character @ in path!
/*-------------------------------------------------------------------------* *--- ---* *--- dirPath.c ---* *--- ---* *--- This file defines a program that parses a path into its ---* *--- component entries. ---* *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- ---* *-------------------------------------------------------------------------*/ #include#include #include #include #define LINE_LEN 256 struct DirEntryName { char* name_; struct DirEntryName* nextPtr_; }; struct PathName { int isRoot_; int isMyHome_; int isSomeonesHome_; struct DirEntryName* dirEntryNamePtr_; }; // PURPOSE: To return a non-zero value if 'c' is legal in a restricted Unix // directory entry name, or '0' otherwise. int isLegalDirEntryChar (char c ) { return( isalnum(c) || (c == '-') || (c == '_') || (c == '.') ); } // PURPOSE: To return 'argv[1]' if there is at least one argument on the // command line according to 'argc'. Otherwise: // (1) asks the user for a path, // (2) enters it into 'textSpace' of length 'textSpaceLen', // (3) removes the ending ' ' from 'textSpace', // (4) and returns 'textSpace'. const char* getPathText (int argc, char* argv[], char* textSpace, int textSpaceLen ) { // YOUR CODE HERE } // PURPOSE: To create and return a linked list of heap-allocated // struct DirEntryName instances that represent the path 'linePtr'. // (1) If 'linePtr' is empty (points to '\0') then returns 'NULL'. // (2) If 'linePtr' is not empty then it // (a) allocates a 'struct DirEntryName' instance from the heap, // (b) allocates a C-string to hold the directory entry 'linePtr' // points to. // (c) allocates a new 'struct DirEntryName' for the next directory // entry, etc. // // Directory entries are separated by the '/' char. // If the directory entry is empty (e.g. "//") then it does: // fprintf(stderr,"Missing directory name! "); // exit(EXIT_FAILURE); // If the directory entry has a character not accepted by // 'isLegalDirEntryChar()' then it does: // fprintf(stderr,"Illegal character %c in path! ",*linePtr); // exit(EXIT_FAILURE); struct DirEntryName* parseRestOfPath (const char* linePtr ) { // YOUR CODE HERE } // PURPOSE: To return the address of a heap-allocated 'struct PathName' // instance that encodes the path given by 'linePtr'. struct PathName* getPath (const char* linePtr ) { // I. Application validity check: if (linePtr == NULL) { fprintf(stderr,"NULL ptr to getPath()! "); exit(EXIT_FAILURE); } // II. Create 'struct PathName' object: // II.A. Obtain heap memory: struct PathName* toReturn = (struct PathName*) malloc(sizeof(struct PathName)); // II.B. Initialize flags of '*toReturn': toReturn->isRoot_ = 0; toReturn->isMyHome_ = 0; toReturn->isSomeonesHome_ = 0; switch (*linePtr) { case '/' : toReturn->isRoot_ = 1; linePtr++; break; case '~' : linePtr++; if (*linePtr == '\0') toReturn->isMyHome_ = 1; else if (*linePtr == '/') { toReturn->isMyHome_ = 1; linePtr++; } else toReturn->isSomeonesHome_ = 1; break; case '\0' : fprintf(stderr,"Empty path! "); exit(EXIT_FAILURE); } // II.B. Initialize 'dirEntryNamePtr_' of '*toReturn': toReturn->dirEntryNamePtr_ = parseRestOfPath(linePtr); // III. Finished: return(toReturn); } // PURPOSE: To print out the constructed path '*pathNamePtr'. No return // value. void print (struct PathName* pathNamePtr ) { // I. Application validity check: if (pathNamePtr == NULL) { fprintf(stderr,"NULL ptr to print()! "); exit(EXIT_FAILURE); } // II. Print path: // II.A. Print beginning of path: int sum = pathNamePtr->isRoot_ + pathNamePtr->isMyHome_ + pathNamePtr->isSomeonesHome_; if ( (sum < 0) || (sum > 1) ) { fprintf(stderr,"Inconsistent pathname! "); exit(EXIT_FAILURE); } struct DirEntryName* run = pathNamePtr->dirEntryNamePtr_; if (pathNamePtr->isRoot_) printf("Start from the root directory / "); else if (pathNamePtr->isMyHome_) printf("Start from your home directory ~ "); else if (pathNamePtr->isSomeonesHome_) { printf("Start from the home directory of %s ",run->name_); run = run->nextPtr_; } else printf("Start from current directory "); // II.B. Print rest of path: for ( ; run != NULL; run = run->nextPtr_) printf(" %s ",run->name_); // III. Finished: } // PURPOSE: To 'free()' the memory of 'pathNamePtr': all DirEntryName // 'name_' and 'nextPtr_' member vars, and the memory of 'pathNamePtr' // itself. No return value. void destroy (struct PathName* pathNamePtr ) { // YOUR CODE HERE } // PURPOSE: To do the high level work of this program. 'argc' tells the // number of command line arguments. 'argv[]' points to the arguments. // Returns 'EXIT_SUCCESS' to OS on success or 'EXIT_FAILURE' otherwise. int main (int argc, char* argv[] ) { char textSpace[LINE_LEN]; const char* linePtr = getPathText(argc,argv,textSpace,LINE_LEN); struct PathName* pathPtr = getPath(linePtr); print(pathPtr); destroy(pathPtr); return(EXIT_SUCCESS); }
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
