/**
	Finds all files matching [inPattern].  The wildcard expansion understands
	the following pattern constructs:

	- ?
		- Any single character.
	- *
		- Any character of which there are zero or more of them.
	- **
		- All subdirectories recursively.

	Additionally, if the pattern closes in a single slash, only directories
	are processed.  Forward slashes and backslashes may be used
	interchangeably.

	- *\
		- List all the directories in the current directory.  Can also be
		  *(forwardslash), but it turns off the C++ comment in this message.
	- **\
		- List all directories recursively.

	Wildcards may appear anywhere in the pattern, including directories.

	- *\*\*\*.c

	Note that *.* only matches files that have an extension.  This is different
	than standard DOS behavior.  Use * all by itself to match files, extension
	or not.

	Recursive wildcards can be used anywhere:

	c:/Dir1\**\A*\**\FileDirs*\**.mp3

	This matches all directories under c:\Dir1\ that start with A.  Under all
	of the directories that start with A, directories starting with FileDirs
	are matched recursively.  Finally, all files ending with an mp3 extension
	are matched.

	Any place that has more than two .. for going up a subdirectory is expanded
	a la 4DOS.

	...../StartSearchHere\**

	Expands to:

	../../../../StartSearchHere\**

	\param inPattern The pattern to use for matching.
**/
void fileglob_MatchPattern(fileglob* self, const char* inPattern) {
	BUFFER destBuff;
	const char* srcPtr;
	const char* lastSlashPtr;
	int numPeriods;

	buffer_initwithalloc(&destBuff, self->allocFunction, self->userData);

	if (inPattern == 0)
		inPattern = "*";

	// Give ourselves a local copy of the inPattern with all \ characters
	// changed to / characters and more than two periods expanded.
	srcPtr = inPattern;

	// Is it a Windows network path?   If so, don't convert the opening \\.
	if (srcPtr[0] == '\\'   &&   srcPtr[1] == '\\')
	{
		buffer_addchar(&destBuff, *srcPtr++);
		buffer_addchar(&destBuff, *srcPtr++);
	}

	lastSlashPtr = srcPtr - 1;
	numPeriods = 0;
	while (*srcPtr != '\0') {
		char ch = *srcPtr;

		///////////////////////////////////////////////////////////////////////
		// Check for slashes or backslashes.
		if (ch == '\\'  ||  ch == '/') {
			buffer_addchar(&destBuff, '/');

			lastSlashPtr = srcPtr;
			numPeriods = 0;
		}

		///////////////////////////////////////////////////////////////////////
		// Check for .
		else if (ch == '.') {
			if (srcPtr - numPeriods - 1 == lastSlashPtr) {
				numPeriods++;
				if (numPeriods > 2) {
					buffer_addchar(&destBuff, '/');
					buffer_addchar(&destBuff, '.');
					buffer_addchar(&destBuff, '.');
				} else {
					buffer_addchar(&destBuff, '.');
				}
			} else {
				buffer_addchar(&destBuff, '.');
			}
		}

		///////////////////////////////////////////////////////////////////////
		// Check for **
		else if (ch == '*'  &&  srcPtr[1] == '*') {
			if (srcPtr - 1 != lastSlashPtr) {
				// Something like this:
				//
				// /Dir**/
				//
				// needs to be translated to:
				//
				// /Dir*/**/
				buffer_addchar(&destBuff, '*');
				buffer_addchar(&destBuff, '/');
			}

			srcPtr += 2;

			buffer_addchar(&destBuff, '*');
			buffer_addchar(&destBuff, '*');

			// Did we get a double star this round?
			if (srcPtr[0] != '/'  &&  srcPtr[0] != '\\') {
				// Handle the case that looks like this:
				//
				// /**Text
				//
				// Translate to:
				//
				// /**/*Text
				buffer_addchar(&destBuff, '/');
				buffer_addchar(&destBuff, '*');
			}
			else if (srcPtr[1] == '\0'  ||  srcPtr[1] == MODIFIER_CHARACTER) {
				srcPtr++;

				buffer_addchar(&destBuff, '/');
				buffer_addchar(&destBuff, '*');
				buffer_addchar(&destBuff, '/');
			}

			// We added one too many in here... the compiler will optimize.
			srcPtr--;
		}

		///////////////////////////////////////////////////////////////////////
		// Check for @
		else if (ch == MODIFIER_CHARACTER) {
			// Gonna finish this processing in another loop.
			break;
		}

		///////////////////////////////////////////////////////////////////////
		// Check for +
		else if (ch == '+') {
			self->filesAndFolders = 1;
			if (srcPtr - 1 == lastSlashPtr)
				++lastSlashPtr;
		}

		///////////////////////////////////////////////////////////////////////
		// Everything else.
		else {
			buffer_addchar(&destBuff, *srcPtr);
		}

		srcPtr++;
	}

	buffer_addchar(&destBuff, 0);

	// Check for the @.
	if (*srcPtr == MODIFIER_CHARACTER) {
		_fileglob_Reset(self);
	}

	while (*srcPtr == MODIFIER_CHARACTER) {
		char ch;

		srcPtr++;

		ch = *srcPtr++;
		if (ch == '-'  ||  ch == '=') {
			BUFFER buff;
			buffer_initwithalloc(&buff, self->allocFunction, self->userData);
			while (*srcPtr != MODIFIER_CHARACTER  &&  *srcPtr != '\0') {
				buffer_addchar(&buff, *srcPtr++);
			}

			buffer_addchar(&buff, 0);

			if (ch == '-')
				fileglob_AddIgnorePattern(self, buffer_ptr(&buff));
			else if (ch == '=')
				fileglob_AddExclusivePattern(self, buffer_ptr(&buff));
			buffer_free(&buff);
		} else
			break;		// Don't know what it is.
	}

	// Start globbing!
	_fileglob_GlobHelper(self, buffer_ptr(&destBuff));
	buffer_free(&destBuff);
}
Beispiel #2
0
int main (int argc, char **argv) {
	int i, argn;
	int verbose = 0;

	if (argc == 1)
		Usage();

	for (argn = 1; argn < argc; ++argn) {
		char* arg = argv[argn];
		if (arg[0] != '-')
			break; // Filenames from here on.

		if (strcmp(arg, "-?") == 0) {
			Usage();
		}

		if (strcmp(arg, "-v") == 0) {
			verbose = 1;
		}

		if (strcmp(arg, "-vv") == 0) {
			verbose = 2;
		}
	}

	for (; argn < argc; ++argn) {
		fileglob* glob;
		char path[1000];
		char* startPath = path;
		strcpy(path, argv[argn]);
		if (*startPath == '\''  &&  startPath[strlen(startPath) - 1] == '\'') {
			startPath++;
			startPath[strlen(startPath) - 1] = 0;
		}
		glob = fileglob_Create(startPath);
        
		for (i = 1; i < argn; ++i) {
			char* arg = argv[i];

			if (strcmp(arg, "-e") == 0) {
				++i;
				fileglob_AddExclusivePattern(glob, argv[i]);
			}
			else if (strcmp(arg, "-i") == 0) {
				i++;
				fileglob_AddIgnorePattern(glob, argv[i]);
			}
		}

		while (fileglob_Next(glob)) {
			const char* filename = fileglob_FileName(glob);
			if (verbose) {
				fileglob_uint64 creationTime = fileglob_CreationTime(glob);
				fileglob_uint64 accessTime = fileglob_AccessTime(glob);
				fileglob_uint64 writeTime = fileglob_WriteTime(glob);
				fileglob_uint64 creationFILETIME = fileglob_CreationFILETIME(glob);
				fileglob_uint64 accessFILETIME = fileglob_AccessFILETIME(glob);
				fileglob_uint64 writeFILETIME = fileglob_WriteFILETIME(glob);
				fileglob_uint64 fileSize = fileglob_FileSize(glob);
				int isDirectory = fileglob_IsDirectory(glob);
				int isLink = fileglob_IsLink(glob);
				int isReadOnly = fileglob_IsReadOnly(glob);
				const char* permissions = fileglob_Permissions(glob);
				if (verbose == 1) {
					printf("%s - creationTime=%llu, accessTime=%llu, writeTime=%llu, creationFILETIME=%llu, accessFILETIME=%llu, writeFILETIME=%llu, fileSize=%llu, isDirectory=%s, isLink=%s, isReadOnly=%s, permissions=%s\n",
							filename, creationTime, accessTime, writeTime, creationFILETIME, accessFILETIME, writeFILETIME, fileSize, isDirectory ? "true" : "false", isLink ? "true" : "false", isReadOnly ? "true" : "false", permissions);
				} else {
					fileglob_uint64 numberOfLinks = fileglob_NumberOfLinks(glob);
					printf("%s - creationTime=%lld, accessTime=%lld, writeTime=%lld, creationFILETIME=%lld, accessFILETIME=%lld, writeFILETIME=%lld, fileSize=%lld, isDirectory=%s, isLink=%s, isReadOnly=%s, permissions=%s, numberOfLinks=%lld\n",
							filename, creationTime, accessTime, writeTime, creationFILETIME, accessFILETIME, writeFILETIME, fileSize, isDirectory ? "true" : "false", isLink ? "true" : "false", isReadOnly ? "true" : "false", permissions, numberOfLinks);
				}
			} else {
				printf("%s\n", filename);
			}
		}

		fileglob_Destroy(glob);
	}

	return EXIT_SUCCESS;
}