Beispiel #1
0
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;
}
Beispiel #2
0
// 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;
		}
	}
}