Prev: Reading /proc/<pid>/maps
Next: Code and Creation 73169
From: frank on 27 Jan 2010 02:21 Hello again comp.unix.programer,gnu.gcc.help I would like to develop a small C utility that does something that a mortensen child can use. If I don't get it done before the end of january, then it's not a x-mas gift. I bought _Crossing the Threshold of Hope_ for Alan and have a thumbdrive of music for Robyn. So this is to make a source listing and not much else. I'll do that after the sig so you won't have to read it unless you want to. What follows is the readdir() I understand best and then working code from unleashed that has a 2-d resizable array. Jens Thoerring has given me the best design idea that I have right now, but if you think you have a better one given the source below, then I'm all ears. Thanks for your constructive comment and cheers, -- frank #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <unistd.h> #define PATH_SIZE 300 unsigned process_directory (char *theDir) { DIR *dir = NULL; struct dirent entry; struct dirent *entryPtr = NULL; int retval = 0; unsigned count = 0; char pathName[PATH_SIZE + 1]; /* Open the given directory, if we can. */ dir = opendir (theDir); if (dir == NULL) { printf ("Error opening %s: %s", theDir, strerror (errno)); return 0; } retval = readdir_r (dir, &entry, &entryPtr); while (entryPtr != NULL) { struct stat entryInfo; if ((strncmp (entry.d_name, ".", PATH_SIZE) == 0) || (strncmp (entry.d_name, "..", PATH_SIZE) == 0)) { /* Short-circuit the . and .. entries. */ retval = readdir_r (dir, &entry, &entryPtr); continue; } (void) strncpy (pathName, theDir, PATH_SIZE); (void) strncat (pathName, "/", PATH_SIZE); (void) strncat (pathName, entry.d_name, PATH_SIZE); if (lstat (pathName, &entryInfo) == 0) { /* stat() succeeded, let's party */ count++; if (S_ISDIR (entryInfo.st_mode)) { /* directory */ printf ("processing %s/\n", pathName); count += process_directory (pathName); } else if (S_ISREG (entryInfo.st_mode)) { /* regular file */ printf ("\t%s has %lld bytes\n", pathName, (long long) entryInfo.st_size); } else if (S_ISLNK (entryInfo.st_mode)) { /* symbolic link */ char targetName[PATH_SIZE + 1]; if (readlink (pathName, targetName, PATH_SIZE) != -1) { printf ("\t%s -> %s\n", pathName, targetName); } else { printf ("\t%s -> (invalid symbolic link!)\n", pathName); } } } else { printf ("Error statting %s: %s\n", pathName, strerror (errno)); } retval = readdir_r (dir, &entry, &entryPtr); } /* Close the directory and return the number of entries. */ (void) closedir (dir); return count; } int main (void) { process_directory ("/etc/"); return EXIT_SUCCESS; } // gcc -D_GNU_SOURCE -Wall -Wextra rd3.c -o out end rd3.c. strarr2.h: // strarr2.h - header for string array demo #ifndef STRARR_H__ #define STRARR_H__ void FreeStrArray(char **, size_t ); char **AllocStrArray(size_t , size_t); int ResizeOneString(char **, size_t , size_t ); int AddFilesToStrArray(char ***, size_t , int , size_t ); int ConsolidateStrArray(char **, size_t ); #endif end strarr2.h begin strarr2.c: #include <stdlib.h> #include <string.h> #include <assert.h> #include "strarr2.h" void FreeStrArray(char **Array, size_t NumFiles) { size_t index; if(Array != NULL) { for(index = 0; index < NumFiles; index++) { if(Array[index] != NULL) { free(Array[index]); } } free(Array); } } char **AllocStrArray(size_t NumFiles, size_t Width) { char **Array = NULL; size_t index; int Success = 1; /* allocating 0 bytes is not a great idea, and * represents a logic error. */ assert(NumFiles > 0); assert(Width > 0); /* Just in case the zero allocation is NOT caught * in testing, we'll check for it here. */ if(NumFiles > 0 && Width > 0) { Array = malloc(NumFiles * sizeof *Array); if(Array != NULL) { for(index = 0; index < NumFiles; index++) { Array[index] = malloc(Width * sizeof *Array[index]); if(NULL == Array[index]) { Success = 0; } else { /* Making this into an empty string is a quick * op which will almost invariably be The Right * Thing and can never be The Wrong Thing, so * we might as well do it. */ Array[index][0] = '\0'; } } /* If any inner allocation failed, * we should clean up. */ if(1 != Success) { FreeStrArray(Array, NumFiles); Array = NULL; } } } return Array; } int ResizeOneString(char **Array, size_t index, size_t NewSize) { char *p; int Success = 1; assert(Array != NULL); p = realloc(Array[index], NewSize); if(p != NULL) { Array[index] = p; } else { Success = 0; } return Success; } int AddFilesToStrArray(char ***ArrayPtr, size_t OldNumFiles, int NumFilesToAdd, size_t InitWidth) { char **p; int Success = 1; int index; int OldFiles; OldFiles = (int)OldNumFiles; if(NumFilesToAdd < 0) { for(index = OldFiles - 1; index >= OldFiles + NumFilesToAdd; index--) { free((*ArrayPtr)[index]); } } p = realloc(*ArrayPtr, (OldFiles + NumFilesToAdd) * sizeof(**ArrayPtr)); if(p != NULL) { *ArrayPtr = p; for(index = OldFiles; Success && index < OldFiles + NumFilesToAdd; index++) { (*ArrayPtr)[index] = malloc(InitWidth); if((*ArrayPtr)[index] != NULL) { (*ArrayPtr)[index][0] = '\0'; } else { Success = 0; } } } else { Success = 0; } return Success; } int ConsolidateStrArray(char **ArrayPtr, size_t NumFiles) { size_t index; size_t Len; int NumFailures = 0; for(index = 0; index < NumFiles; index++) { /* If the library has been correctly used, no * index pointer will ever be NULL, so we should * assert that this is the case. */ assert(ArrayPtr[index] != NULL); Len = 1 + strlen(ArrayPtr[index]); if(0 == ResizeOneString(ArrayPtr, index, Len)) { ++NumFailures; } } return NumFailures; } /* end of strarr.c */ /* gcc -Wall -Wextra -c -o string2.o strarr2.c */ end source listings
From: Moi on 27 Jan 2010 07:03 On Wed, 27 Jan 2010 00:21:30 -0700, frank wrote: > Hello again comp.unix.programer,gnu.gcc.help > > I would like to develop a small C utility that does something that a > mortensen child can use. If I don't get it done before the end of > january, then it's not a x-mas gift. I bought _Crossing the Threshold > of Hope_ for Alan and have a thumbdrive of music for Robyn. > > So this is to make a source listing and not much else. I'll do that > after the sig so you won't have to read it unless you want to. > > What follows is the readdir() I understand best and then working code > from unleashed that has a 2-d resizable array. > > Jens Thoerring has given me the best design idea that I have right now, > but if you think you have a better one given the source below, then I'm > all ears. > > Thanks for your constructive comment and cheers, A few points: 0) you need to include a few headers. The code as you posted it did not even compile. 1) I don't understand your use of readdir_r(). readdir() seems good enough, IMO. 2) IIRC Jens Thoerring said something about your choice of "API" / and use of return value. It is crucial if you design a function that "returns" a collection (list) of things, that you make choices of how and what to return. 3) I did not look at the string-stuff it is too messy for me, and I think you could put what you need into less lines. Also: you realloc to often, causing a 1/2(N*N) amount of "memory operations". 4) I compacted your process_directory() function for you. **************************/ #define MOI 1 #if MOI #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #endif #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <unistd.h> #define PATH_SIZE 300 #if MOI unsigned process_directory (char *theDir) { DIR *dir = NULL; struct dirent entry; struct dirent *entryPtr = NULL; int retval = 0; unsigned count = 0; char pathName[PATH_SIZE + 1]; size_t dirlen, namelen; /* Open the given directory, if we can. */ dir = opendir (theDir); if (dir == NULL) { fprintf (stderr, "Error opening %s: %s\n", theDir, strerror (errno)); return 0; } dirlen = strlen(theDir); for( retval = readdir_r (dir, &entry, &entryPtr); entryPtr != NULL; retval = readdir_r (dir, &entry, &entryPtr)) { struct stat entryInfo; if (!strcmp (entry.d_name, ".") || !strcmp (entry.d_name, "..") ) continue; namelen = strlen(entry.d_name); if (dirlen+1+namelen+1 >= sizeof pathName) { fprintf(stderr,"Name too long: %u+1+%u+1 %s/%s\n" , (unsigned) dirlen, (unsigned) namelen,theDir,entry.d_name ); continue; } memcpy (pathName, theDir, dirlen); pathName[dirlen] = '/'; memcpy (pathName+dirlen+1, entry.d_name, namelen +1); if (lstat (pathName, &entryInfo) == -1) { /* stat() failed, let's party */ fprintf (stderr, "Error statting %s: %s\n", pathName, strerror (errno)); continue; } count++; if (S_ISDIR (entryInfo.st_mode)) { /* directory */ printf ("processing %s/\n", pathName); count += process_directory (pathName); continue; } if (S_ISREG (entryInfo.st_mode)) { /* regular file */ printf ("\t%s has %lld bytes\n" , pathName, (long long) entryInfo.st_size); continue; } if (S_ISLNK (entryInfo.st_mode)) { /* symbolic link */ char targetName[PATH_SIZE + 1]; if (readlink (pathName, targetName, PATH_SIZE) == -1) { printf ("\t%s -> (invalid symbolic link!)\n", pathName); continue; } printf ("\t%s -> %s\n", pathName, targetName); continue; } printf ("\t%s (Strange Mode: 0x%x)\n", pathName, entryInfo.st_mode); } /* Close the directory and return the number of entries. */ (void) closedir (dir); return count; } /*************** HTH, AvK
From: John Gordon on 27 Jan 2010 10:36 In <7sa7rrFg81U1(a)mid.individual.net> frank <frank(a)example.invalid> writes: > Jens Thoerring has given me the best design idea that I have right now, > but if you think you have a better one given the source below, then I'm > all ears. If you really want help it's best to give a short description of what the code is intended to do and perhaps mention some specific ways you'd like to see the code improve, rather than just dumping the code and asking us to "make it better." -- John Gordon A is for Amy, who fell down the stairs gordon(a)panix.com B is for Basil, assaulted by bears -- Edward Gorey, "The Gashlycrumb Tinies"
From: Ben Bacarisse on 27 Jan 2010 10:45 frank <frank(a)example.invalid> writes: > Hello again comp.unix.programer,gnu.gcc.help I can't see the relevance to gnu.gcc.help so I've removed that NG. > I would like to develop a small C utility that does something that a > mortensen child can use. If I don't get it done before the end of > january, then it's not a x-mas gift. You've pre-decided that this is a C learning exercise which is not obviously a goal that is compatible with getting something working in a few days time. I don't know what you intend (a short description of the purpose would help) but the code you posted is equivalent to a few lines of bash script (or Perl or Python...). If you don't know any of these, learning enough bash to do what the C code does would not take long (a day or so). <snip> -- Ben.
From: Andrew Poelstra on 27 Jan 2010 19:06
On 2010-01-27, Moi <root(a)invalid.address.org> wrote: > On Wed, 27 Jan 2010 00:21:30 -0700, frank wrote: > >> Hello again comp.unix.programer,gnu.gcc.help >> >> I would like to develop a small C utility that does something that a >> mortensen child can use. If I don't get it done before the end of >> january, then it's not a x-mas gift. I bought _Crossing the Threshold >> of Hope_ for Alan and have a thumbdrive of music for Robyn. >> >> So this is to make a source listing and not much else. I'll do that >> after the sig so you won't have to read it unless you want to. >> >> What follows is the readdir() I understand best and then working code >> from unleashed that has a 2-d resizable array. >> >> Jens Thoerring has given me the best design idea that I have right now, >> but if you think you have a better one given the source below, then I'm >> all ears. >> >> Thanks for your constructive comment and cheers, > > A few points: > 0) you need to include a few headers. The code as you posted it did not even compile. I changed #include "strarr2.h" to #include "strarr.h" and it compiled. I think he just made a typo giving the filename of the string header. |