static uio_DirList * uio_getDirListMulti(uio_PDirHandle **pDirHandles, int numPDirHandles, const char *pattern, match_MatchType matchType) { int pDirI; // physical dir iterator uio_DirBufferLink **links; // array of bufferLinks for each physical dir uio_DirBufferLink *linkPtr; int *numNames; // number of entries in each physical dir int totalNumNames; const char **bigNameBuffer; // buffer where all names will end up together const char **destPtr; uio_DirList *result; match_Result matchResult; match_MatchContext *matchContext; matchResult = match_prepareContext(pattern, &matchContext, matchType); if (matchResult != match_OK) { #ifdef DEBUG fprintf(stderr, "Error compiling match function: %s.\n", match_errorString(matchContext, matchResult)); #endif match_freeContext(matchContext); errno = EIO; // I actually want to signal an internal error. // EIO comes closes return NULL; } // first get the directory listings for all seperate relevant dirs. totalNumNames = 0; links = uio_malloc(numPDirHandles * sizeof (uio_DirBufferLink *)); numNames = uio_malloc(numPDirHandles * sizeof (int)); for (pDirI = 0; pDirI < numPDirHandles; pDirI++) { uio_collectDirEntries(pDirHandles[pDirI], &links[pDirI], &numNames[pDirI]); totalNumNames += numNames[pDirI]; } bigNameBuffer = uio_malloc(totalNumNames * sizeof (uio_DirBufferLink *)); // Fill the bigNameBuffer with all the names from all the DirBufferLinks // of all the physical dirs. destPtr = bigNameBuffer; totalNumNames = 0; for (pDirI = 0; pDirI < numPDirHandles; pDirI++) { for (linkPtr = links[pDirI]; linkPtr != NULL; linkPtr = linkPtr->next) { int numNewNames; uio_filterNames((const char * const *) linkPtr->buffer, linkPtr->numEntries, destPtr, &numNewNames, matchContext); totalNumNames += numNewNames; destPtr += numNewNames; } } match_freeContext(matchContext); // Sort the bigNameBuffer // Necessary for removing doubles. // Not really necessary if the big list was the result of only one // physical dir, but let's output a sorted list anyhow. qsort((void *) bigNameBuffer, totalNumNames, sizeof (char *), (int (*)(const void *, const void *)) strPtrCmp); // remove doubles // (unnecessary if the big list was the result of only one physical dir) if (numPDirHandles > 1) { uio_filterDoubleNames(bigNameBuffer, totalNumNames, bigNameBuffer, &totalNumNames); } // resize the bigNameBuffer bigNameBuffer = uio_realloc((void *) bigNameBuffer, totalNumNames * sizeof (char *)); // put the lot in a DirList, copying the strings themselves result = uio_makeDirList(bigNameBuffer, bigNameBuffer, totalNumNames); // free the old junk for (pDirI = 0; pDirI < numPDirHandles; pDirI++) uio_DirBufferChain_free(links[pDirI]); uio_free(links); uio_free(numNames); return result; }
// The result should be freed using uio_free(). // NB. POSIX allows errno to be set for vsprintf(), but does not require it: // "The value of errno may be set to nonzero by a library function call // whether or not there is an error, provided the use of errno is not // documented in the description of the function in this International // Standard." The latter is the case for vsprintf(). char * uio_vasprintf(const char *format, va_list args) { // TODO: If there is a system vasprintf, use that. // XXX: That would mean that the allocation would always go through // malloc() or so, instead of uio_malloc(), which may not be // desirable. char *buf; size_t bufSize = 128; // Start with enough for one screen line, and a power of 2, // which might give faster result with allocations. buf = uio_malloc(bufSize); if (buf == NULL) { // errno is set. return NULL; } for (;;) { int printResult = vsnprintf(buf, bufSize, format, args); if (printResult < 0) { // This means the buffer was not large enough, but vsnprintf() // does not give us any clue on how large it should be. // Note that this does not happen with a C'99 compliant // vsnprintf(), but it will happen on MS Windows, and on // glibc before version 2.1. bufSize *= 2; } else if ((unsigned int) printResult >= bufSize) { // The buffer was too small, but printResult contains the size // that the buffer needs to be (excluding the '\0' character). bufSize = printResult + 1; } else { // Success. if ((unsigned int) printResult + 1 != bufSize) { // Shorten the resulting buffer to the size that was // actually needed. char *newBuf = uio_realloc(buf, printResult + 1); if (newBuf == NULL) { // We could have returned the (overly large) original // buffer, but the unused memory might not be // acceptable, and the program would be likely to run // into problems sooner or later anyhow. int savedErrno = errno; uio_free(buf); errno = savedErrno; return NULL; } return newBuf; } return buf; } { char *newBuf = uio_realloc(buf, bufSize); if (newBuf == NULL) { int savedErrno = errno; uio_free(buf); errno = savedErrno; return NULL; } buf = newBuf; } } }