void filecache_disable(TARGET *t) { BUFFER buff; LIST *filecache; pushsettings( t->settings ); filecache = var_get( "FILECACHE" ); if ( !filecache ) { popsettings( t->settings ); return; } buffer_init(&buff); buffer_addstring(&buff, filecache->string, strlen(filecache->string)); buffer_addstring(&buff, ".USE", 4); buffer_addchar(&buff, 0); var_set(buffer_ptr(&buff), list_new(L0, "0", 0), VAR_SET); buffer_free(&buff); buffer_init(&buff); buffer_addstring(&buff, filecache->string, strlen(filecache->string)); buffer_addstring(&buff, ".GENERATE", 9); buffer_addchar(&buff, 0); var_set(buffer_ptr(&buff), list_new(L0, "0", 0), VAR_SET); buffer_free(&buff); }
static int filecache_findlink(const char *cachedname, MD5SUM blobmd5sum) { int haveblobmd5sum = 0; /* Search for the appropriate .link file that matches the target. */ BUFFER linknamebuff; BUFFER wildbuff; buffer_init(&wildbuff); buffer_addstring(&wildbuff, cachedname, strlen(cachedname)); buffer_addstring(&wildbuff, "-*.link", 7); buffer_addchar(&wildbuff, 0); if (findfile(buffer_ptr(&wildbuff), &linknamebuff)) { const char* dashPtr = strrchr(buffer_ptr(&linknamebuff), '-'); const char* slashPtr = strrchr(buffer_ptr(&linknamebuff), '/'); #ifdef OS_NT const char* backslashPtr = strrchr(buffer_ptr(&linknamebuff), '\\'); if (backslashPtr > slashPtr) slashPtr = backslashPtr; #endif if (dashPtr > slashPtr) haveblobmd5sum = read_md5sum_string(dashPtr + 1, blobmd5sum); } buffer_free(&linknamebuff); buffer_free(&wildbuff); return haveblobmd5sum; }
LIST * builtin_usefilecache( PARSE *parse, LOL *args, int *jmp ) { LIST *l = lol_get( args, 0 ); LIST *l2 = lol_get( args, 1 ); const char* cachevar = l2 ? l2->string : "generic"; BUFFER buff; buffer_init( &buff ); buffer_addstring( &buff, "FILECACHE.", 10 ); buffer_addstring( &buff, cachevar, strlen( cachevar ) ); buffer_addchar( &buff, 0 ); for( ; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); t->settings = addsettings( t->settings, VAR_SET, "FILECACHE", list_new( L0, buffer_ptr( &buff ), 0 ) ); t->flags |= parse->num; } buffer_free( &buff ); return L0; }
/* * Get a filename in cache for given md5sum. */ const char *filecache_getfilename(TARGET *t, MD5SUM sum, const char* extension) { BUFFER buff; size_t pos; const char *cachedir; const char* result; cachedir = filecache_getpath(t); /* if no cachedir, no cachefiles */ if (cachedir==NULL) { return NULL; } /* put the cachedir in front of buffer */ buffer_init(&buff); buffer_addstring(&buff, cachedir, strlen(cachedir)); buffer_addchar(&buff, '/'); pos = buffer_pos(&buff); buffer_addstring(&buff, "000/", 4); /* add use md5 as filename */ buffer_addstring(&buff, md5tostring(sum), 32); if (extension) buffer_addstring(&buff, extension, strlen(extension)); buffer_addchar(&buff, 0); buffer_setpos(&buff, pos); buffer_putstring(&buff, buffer_ptr(&buff) + pos + 4, 3); result = newstr(buffer_ptr(&buff)); buffer_free(&buff); return result; }
void filecache_disable(TARGET *t) { BUFFER buff; LIST *filecache; char const* filecacheStr; pushsettings( t->settings ); filecache = var_get( "FILECACHE" ); if ( !list_first(filecache) ) { popsettings( t->settings ); return; } filecacheStr = list_value(list_first(filecache)); buffer_init(&buff); buffer_addstring(&buff, filecacheStr, strlen(filecacheStr)); buffer_addstring(&buff, ".USE", 4); buffer_addchar(&buff, 0); var_set(buffer_ptr(&buff), list_append(L0, "0", 0), VAR_SET); buffer_free(&buff); buffer_init(&buff); buffer_addstring(&buff, filecacheStr, strlen(filecacheStr)); buffer_addstring(&buff, ".GENERATE", 9); buffer_addchar(&buff, 0); var_set(buffer_ptr(&buff), list_append(L0, "0", 0), VAR_SET); buffer_free(&buff); }
LIST *filecache_fillvalues(TARGET *t) { LIST *filecache; if ( !( t->flags & T_FLAG_USEFILECACHE ) ) return 0; filecache = var_get( "FILECACHE" ); if ( filecache ) { LIST *l; BUFFER buff; buffer_init(&buff); buffer_addstring(&buff, filecache->string, strlen(filecache->string)); buffer_addstring(&buff, ".USE", 4); buffer_addchar(&buff, 0); l = var_get( buffer_ptr( &buff ) ); if ( l && atoi( l->string ) != 0) { t->filecache_use = 1; } buffer_free(&buff); buffer_init(&buff); buffer_addstring(&buff, filecache->string, strlen(filecache->string)); buffer_addstring(&buff, ".GENERATE", 9); buffer_addchar(&buff, 0); l = var_get( buffer_ptr( &buff ) ); if ( l && atoi( l->string ) != 0) { t->filecache_generate = 1; } buffer_free(&buff); } return filecache; }
/** \internal Simple path splicing (assumes no '/' in either part) \author Matthias Wandel ([email protected]) http://www.sentex.net/~mwandel/ **/ static void SplicePath(BUFFER* dest, const char * p1, const char * p2) { size_t l; buffer_reset(dest); l = strlen(p1); if (l == 0) { buffer_addstring(dest, p2, strlen(p2) + 1); } else { buffer_addstring(dest, p1, l + 1); if (buffer_ptr(dest)[l-1] != '/' && buffer_ptr(dest)[l-1] != ':') { buffer_ptr(dest)[l] = '/'; buffer_deltapos(dest, 1); } buffer_deltapos(dest, -1); buffer_addstring(dest, p2, strlen(p2) + 1); } }
int str_gsub (BUFFER *buff, const char *src, const char *p, const char *repl, int max_s) { int anchor; int n = 0; MatchState ms; size_t srcl = strlen(src); if (max_s == -1) max_s = srcl + 1; anchor = (*p == '^') ? (p++, 1) : 0; n = 0; ms.buff = buff; ms.src_init = src; ms.src_end = src+srcl; while (n < max_s) { const char *e; ms.level = 0; e = match(&ms, src, p); if (e) { n++; add_s(&ms, src, e, repl, strlen(repl)); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ else if (src < ms.src_end) { buffer_addchar(ms.buff, *src++); } else break; if (anchor) break; } buffer_addstring(ms.buff, src, ms.src_end-src); buffer_addchar(ms.buff, 0); return n; }
static void push_onecapture (MatchState *ms, int i, const char *s, const char *e) { if (i >= ms->level) { if (i == 0) { /* ms->level == 0, too */ buffer_addstring(ms->buff, s, e - s); /* add whole match */ } else gsub_error("invalid capture index"); } else { ptrdiff_t l = ms->capture[i].len; if (l == CAP_UNFINISHED) gsub_error("unfinished capture"); if (l == CAP_POSITION) { // lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); assert(0); } else buffer_addstring(ms->buff, ms->capture[i].init, l); } }
int findfile(const char* wildcard, BUFFER* foundfilebuff) { HANDLE handle; WIN32_FIND_DATA fd; const char* lastslash; buffer_init(foundfilebuff); handle = FindFirstFile(wildcard, &fd); if (handle == INVALID_HANDLE_VALUE) return 0; FindClose(handle); lastslash = max(strrchr(wildcard, '/'), strrchr(wildcard, '\\')); buffer_addstring(foundfilebuff, wildcard, lastslash - wildcard + 1); buffer_addstring(foundfilebuff, fd.cFileName, strlen( fd.cFileName )); buffer_addchar(foundfilebuff, 0); return 1; }
int findfile(const char* wildcard, BUFFER* foundfilebuff) { DIR* dirp; struct dirent* dp; const char* lastslash; const char* lastslash2; BUFFER pathbuff; lastslash = strrchr(wildcard, '/'); lastslash2 = strrchr(wildcard, '\\'); lastslash = lastslash > lastslash2 ? lastslash : lastslash2; buffer_init(&pathbuff); buffer_addstring(&pathbuff, wildcard, lastslash - wildcard); buffer_addchar(&pathbuff, 0); buffer_init(foundfilebuff); dirp = opendir(buffer_ptr(&pathbuff)); if (!dirp) { buffer_free(&pathbuff); return 0; } // Any files found? while ((dp = readdir(dirp)) != NULL) { if (wildmatch(lastslash + 1, dp->d_name, 1)) { buffer_addstring(foundfilebuff, wildcard, lastslash - wildcard + 1); buffer_addstring(foundfilebuff, dp->d_name, strlen(dp->d_name)); buffer_addchar(foundfilebuff, 0); closedir(dirp); return 1; } } closedir(dirp); return 0; }
LIST * builtin_match( PARSE *parse, LOL *args, int *jmp ) { LIST *l, *r; LIST *result = 0; /* For each pattern */ for( l = lol_get( args, 0 ); l; l = l->next ) { regexp *re = jam_regcomp( l->string ); /* For each string to match against */ for( r = lol_get( args, 1 ); r; r = r->next ) if( jam_regexec( re, r->string ) ) { int i, top; /* Find highest parameter */ for( top = NSUBEXP; top-- > 1; ) if( re->startp[top] ) break; /* And add all parameters up to highest onto list. */ /* Must have parameters to have results! */ for( i = 1; i <= top; i++ ) { BUFFER buff; size_t l; buffer_init( &buff ); l = re->endp[i] - re->startp[i]; buffer_addstring( &buff, re->startp[i], l ); buffer_addchar( &buff, 0 ); result = list_new( result, buffer_ptr( &buff ), 0 ); buffer_free( &buff ); } } free( (char *)re ); } return result; }
LIST *filecache_fillvalues(TARGET *t) { LIST *filecache; if ( !( t->flags & T_FLAG_USEFILECACHE ) ) return 0; filecache = var_get( "FILECACHE" ); if ( list_first(filecache) ) { LIST *l; BUFFER buff; char const* filecacheStr = list_value(list_first(filecache)); buffer_init(&buff); buffer_addstring(&buff, filecacheStr, strlen(filecacheStr)); buffer_addstring(&buff, ".USE", 4); buffer_addchar(&buff, 0); l = var_get( buffer_ptr( &buff ) ); if ( list_first(l) && atoi( list_value(list_first(l)) ) != 0) { t->filecache_use = 1; } buffer_free(&buff); buffer_init(&buff); buffer_addstring(&buff, filecacheStr, strlen(filecacheStr)); buffer_addstring(&buff, ".GENERATE", 9); buffer_addchar(&buff, 0); l = var_get( buffer_ptr( &buff ) ); if ( list_first(l) && atoi(list_value(list_first(l))) != 0) { t->filecache_generate = 1; } buffer_free(&buff); } return filecache; }
/* Based on code from ftjam by David Turner */ LIST * builtin_split( PARSE *parse, LOL *args, int *jmp ) { LIST* input = lol_get( args, 0 ); LIST* tokens = lol_get( args, 1 ); LIST* result = L0; char token[256]; BUFFER buff; buffer_init( &buff ); /* build token array */ memset( token, 0, sizeof( token ) ); for ( ; tokens; tokens = tokens->next ) { const char* s = tokens->string; for ( ; *s; s++ ) token[(unsigned char)*s] = 1; } /* now parse the input and split it */ for ( ; input; input = input->next ) { const char* ptr = input->string; const char* lastPtr = input->string; while ( *ptr ) { if ( token[(unsigned char) *ptr] ) { size_t count = ptr - lastPtr; if ( count > 0 ) { buffer_reset( &buff ); buffer_addstring( &buff, lastPtr, count ); buffer_addchar( &buff, 0 ); result = list_new( result, buffer_ptr( &buff ), 0 ); } lastPtr = ptr + 1; } ++ptr; } if ( ptr > lastPtr ) result = list_new( result, lastPtr, 0 ); } buffer_free( &buff ); return result; }
static void var_edit_file( const char *in, BUFFER *buff, VAR_EDITS *edits ) { PATHNAME pathname; char buf[ MAXJPATH ]; /* Parse apart original filename, putting parts into "pathname" */ path_parse( in, &pathname ); /* Replace any pathname with edits->f */ if( edits->f.f_grist.ptr ) pathname.f_grist = edits->f.f_grist; if( edits->f.f_root.ptr ) pathname.f_root = edits->f.f_root; if( edits->f.f_dir.ptr ) pathname.f_dir = edits->f.f_dir; if( edits->f.f_base.ptr ) pathname.f_base = edits->f.f_base; if( edits->f.f_suffix.ptr ) pathname.f_suffix = edits->f.f_suffix; if( edits->f.f_member.ptr ) pathname.f_member = edits->f.f_member; /* If requested, modify pathname to point to parent */ if( edits->parent ) path_parent( &pathname ); /* Put filename back together */ #ifdef OPT_ROOT_PATHS_AS_ABSOLUTE_EXT path_build( &pathname, buf, 0, 1 ); #else path_build( &pathname, buf, 0 ); #endif buffer_addstring( buff, buf, strlen( buf ) + 1 ); }
static void add_s (MatchState *ms, const char *s, const char *e, const char *news, size_t l) { size_t i; for (i = 0; i < l; i++) { if (news[i] != L_ESC) { buffer_addchar(ms->buff, news[i]); } else { i++; /* skip ESC */ if (!isdigit(uchar(news[i]))) { buffer_addchar(ms->buff, news[i]); } else if (news[i] == '0') { buffer_addstring(ms->buff, s, e - s); } else { push_onecapture(ms, news[i] - '1', s, e); // luaL_addvalue(b); /* add capture to accumulated result */ } } } }
void filecache_update(TARGET *t, MD5SUM buildmd5sum) { MD5SUM blobmd5sum; int haveblobmd5sum = 0; const char *cachedname; const char *blobname; int cacheerror; if (!t->filecache_generate) return; /* If the buildmd5sum is empty, then the file doesn't exist. */ cacheerror = ismd5empty(buildmd5sum); if (cacheerror) return; haveblobmd5sum = 0; cachedname = filecache_getfilename(t, buildmd5sum, NULL); if (!cachedname) return; /* Search for the appropriate .link file that matches the target. */ haveblobmd5sum = filecache_findlink(cachedname, blobmd5sum); /* If we weren't able to determine the target md5sum, do it now. */ if (!haveblobmd5sum) { getcachedmd5sum( t, 1 ); memcpy(blobmd5sum, t->contentchecksum->contentmd5sum, MD5_SUMSIZE); if (ismd5empty(t->contentchecksum->contentmd5sum)) return; } { /* Is the blob already there? */ time_t blobtime; blobname = filecache_getfilename(t, blobmd5sum, ".blob"); if (file_time(blobname, &blobtime) == -1) { time_t blobpartialtime; const char *blobpartialname; if(DEBUG_MD5HASH) printf("Caching %s as %s\n", t->name, cachedname); else printf("Caching %s\n", t->name); /* Write the new .blob to the cache. */ blobpartialname = filecache_getfilename(t, blobmd5sum, ".blob.partial"); if (file_time(blobpartialname, &blobpartialtime) == -1) { if (copyfile(blobpartialname, t->boundname, &blobmd5sum) == 0 || rename(blobpartialname, blobname) != 0) { printf("** Unable to write %s to cache.\n", t->name); filecache_disable(t); return; } } } } /* Write the new .link file to the cache. */ { FILE *file; BUFFER linknamebuff; buffer_init(&linknamebuff); buffer_addstring(&linknamebuff, cachedname, strlen(cachedname)); buffer_addchar(&linknamebuff, '-'); buffer_addstring(&linknamebuff, md5tostring(blobmd5sum), 32); buffer_addstring(&linknamebuff, ".link", 5); buffer_addchar(&linknamebuff, 0); file_mkdir(buffer_ptr(&linknamebuff)); file = fopen(buffer_ptr(&linknamebuff), "wb"); if (file) { write_md5sum(file, blobmd5sum); write_string(file, t->name); fclose(file); } buffer_free(&linknamebuff); } }
void filecache_update(TARGET *t) { MD5SUM blobmd5sum; int haveblobmd5sum = 0; const char *cachedname; const char *blobname; int cacheerror; if (!t->filecache_generate) return; /* If the buildmd5sum is empty, then the file doesn't exist. */ cacheerror = ismd5empty(t->buildmd5sum); if (cacheerror) return; haveblobmd5sum = 0; cachedname = filecache_getfilename(t, t->buildmd5sum, NULL); if (!cachedname) return; /* Search for the appropriate .link file that matches the target. */ haveblobmd5sum = filecache_findlink(cachedname, blobmd5sum); /* If we weren't able to determine the target md5sum, do it now. */ if (!haveblobmd5sum) { #ifdef OPT_BUILTIN_LUA_SUPPORT_EXT LIST *md5callback; pushsettings( t->settings ); md5callback = var_get( "MD5CALLBACK" ); popsettings( t->settings ); if ( md5callback ) { luahelper_md5callback(t->boundname, blobmd5sum, md5callback->string); } else { #endif md5file(t->boundname, blobmd5sum); #ifdef OPT_BUILTIN_LUA_SUPPORT_EXT } #endif memcpy(t->contentmd5sum, blobmd5sum, sizeof(MD5SUM)); if (ismd5empty(t->contentmd5sum)) return; } { /* Is the blob already there? */ time_t blobtime; blobname = filecache_getfilename(t, blobmd5sum, ".blob"); if (file_time(blobname, &blobtime) == -1) { time_t blobpartialtime; const char *blobpartialname; if(DEBUG_MD5HASH) printf("Caching %s as %s\n", t->name, cachedname); else printf("Caching %s\n", t->name); /* Write the new .blob to the cache. */ blobpartialname = filecache_getfilename(t, blobmd5sum, ".blob.partial"); if (file_time(blobpartialname, &blobpartialtime) == -1) { if (copyfile(blobpartialname, t->boundname, &blobmd5sum) == 0 || rename(blobpartialname, blobname) != 0) { printf("** Unable to write %s to cache.\n", t->name, cachedname); filecache_disable(t); return; } } } } /* Write the new .link file to the cache. */ { FILE *file; BUFFER linknamebuff; buffer_init(&linknamebuff); buffer_addstring(&linknamebuff, cachedname, strlen(cachedname)); buffer_addchar(&linknamebuff, '-'); buffer_addstring(&linknamebuff, md5tostring(blobmd5sum), 32); buffer_addstring(&linknamebuff, ".link", 5); buffer_addchar(&linknamebuff, 0); file_mkdir(buffer_ptr(&linknamebuff)); file = fopen(buffer_ptr(&linknamebuff), "wb"); if (file) { write_md5sum(file, blobmd5sum); write_string(file, t->name); fclose(file); } buffer_free(&linknamebuff); } }
int _fileglob_GlobHelper(fileglob* self, const char* inPattern) { fileglob_Context* context = self->context; int hasWildcard; int found; Setup: if (!context) { context = (fileglob_Context*)self->allocFunction(self->userData, NULL, sizeof(fileglob_Context)); context->prev = self->context; #if defined(WIN32) context->handle = INVALID_HANDLE_VALUE; #else context->dirp = NULL; context->hasattr = 0; context->statted = 0; #endif context->pattern = NULL; context->iterNode = NULL; context->directoryListHead = context->directoryListTail = 0; context->basePathLastSlashPos = 0; buffer_initwithalloc(&context->patternBuf, self->allocFunction, self->userData); buffer_addstring(&context->patternBuf, inPattern, strlen(inPattern) + 1); buffer_initwithalloc(&context->basePath, self->allocFunction, self->userData); buffer_initwithalloc(&context->matchPattern, self->allocFunction, self->userData); self->context = context; if (context->prev == NULL) return 1; } DoRecursion: found = 1; if (!context->pattern) { char* pattern; context->basePathEndPos = context->basePathLastSlashPos = 0; context->recurseAtPos = (size_t)-1; // Split the path into base path and pattern to match against. hasWildcard = 0; for (pattern = buffer_ptr(&context->patternBuf); *pattern != '\0'; ++pattern) { char ch = *pattern; // Is it a '?' ? if (ch == '?') hasWildcard = 1; // Is it a '*' ? else if (ch == '*') { hasWildcard = 1; // Is there a '**'? if (pattern[1] == '*') { // If we're just starting the pattern or the characters immediately // preceding the pattern are a drive letter ':' or a directory path // '/', then set up the internals for later recursion. if (pattern == buffer_ptr(&context->patternBuf) || pattern[-1] == '/' || pattern[-1] == ':') { char ch2 = pattern[2]; if (ch2 == '/') { context->recurseAtPos = pattern - buffer_ptr(&context->patternBuf); memcpy(pattern, pattern + 3, strlen(pattern) - 2); buffer_deltapos(&context->patternBuf, -3); } else if (ch2 == '\0') { context->recurseAtPos = pattern - buffer_ptr(&context->patternBuf); *pattern = '\0'; } } } } // Is there a '/' or ':' in the pattern at this location? if (ch == '/' || ch == ':') { if (hasWildcard) break; else { if (pattern[1]) context->basePathLastSlashPos = pattern - buffer_ptr(&context->patternBuf) + 1; context->basePathEndPos = pattern - buffer_ptr(&context->patternBuf) + 1; } } } context->pattern = pattern; // Copy the directory down. context->basePathLen = context->basePathEndPos; buffer_reset(&context->basePath); buffer_addstring(&context->basePath, buffer_ptr(&context->patternBuf), context->basePathLen); buffer_addchar(&context->basePath, 0); if (context->iterNode) { context->matchFiles = *context->pattern == 0; goto NextDirectory; } } #if defined(WIN32) if (context->handle == INVALID_HANDLE_VALUE) { #else if (!context->dirp && !context->statted) { #endif size_t matchLen; // Did we make it to the end of the pattern? If so, we should match files, // since there were no slashes encountered. context->matchFiles = *context->pattern == 0; // Copy the wildcard matching string. matchLen = (context->pattern - buffer_ptr(&context->patternBuf)) - context->basePathLen; buffer_reset(&context->matchPattern); buffer_addstring(&context->matchPattern, buffer_ptr(&context->patternBuf) + context->basePathLen, matchLen + 1); buffer_deltapos(&context->matchPattern, -1); if (*buffer_posptr(&context->matchPattern) == '/') { buffer_deltapos(&context->matchPattern, 1); buffer_addchar(&context->matchPattern, 0); } #if defined(WIN32) // Do the file search with *.* in the directory specified in basePattern. buffer_setpos(&context->basePath, context->basePathEndPos); buffer_addstring(&context->basePath, "*.*", 4); // Start the find. context->handle = FindFirstFile(buffer_ptr(&context->basePath), &context->fd); if (context->handle == INVALID_HANDLE_VALUE) { found = 0; } #else // Start the find. buffer_setpos(&context->basePath, context->basePathEndPos); buffer_addchar(&context->basePath, 0); context->dirp = opendir(buffer_ptr(&context->basePath)[0] ? buffer_ptr(&context->basePath) : "."); if (!context->dirp) { found = 0; } else { context->dp = readdir(context->dirp); found = context->dp != NULL; } #endif // Clear out the *.* so we can use the original basePattern string. buffer_setpos(&context->basePath, context->basePathEndPos); buffer_putchar(&context->basePath, 0); } else { goto NextFile; } // Any files found? #if defined(WIN32) if (context->handle != INVALID_HANDLE_VALUE) { #else if (context->dirp) { #endif for (;;) { #if defined(WIN32) char* filename = context->fd.cFileName; #else char* filename = context->dp->d_name; context->hasattr = 0; #endif // Is the file a directory? #if defined(WIN32) if (context->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { #else if (context->dp->d_type == DT_DIR) { #endif // Knock out "." or ".." int ignore = filename[0] == '.' && (filename[1] == 0 || (filename[1] == '.' && filename[2] == 0)); // Should this file be ignored? int matches = 0; if (!ignore) { size_t len = strlen(filename); filename[len] = '/'; filename[len + 1] = '\0'; matches = fileglob_WildMatch(buffer_ptr(&context->matchPattern), filename, 0); } // Do a wildcard match. if (!ignore && matches) { // It matched. Let's see if the file should be ignored. // See if this is a directory to ignore. ignore = _fileglob_MatchIgnoreDirectoryPattern(self, filename); // Should this file be ignored? if (!ignore) { _fileglob_list_append(self, &context->directoryListHead, &context->directoryListTail, filename); // Is this pattern exclusive? if (self->exclusiveDirectoryPatternsHead) { if (_fileglob_MatchExclusiveDirectoryPattern(self, filename)) break; } else { if ((!context->matchFiles && context->pattern[0] == '/' && context->pattern[1] == 0) || (self->filesAndFolders)) break; } } } } else { // Do a wildcard match. if (fileglob_WildMatch(buffer_ptr(&context->matchPattern), filename, 0)) { // It matched. Let's see if the file should be ignored. int ignore = _fileglob_MatchIgnoreFilePattern(self, filename); // Is this pattern exclusive? if (!ignore && self->exclusiveFilePatternsHead) { ignore = !_fileglob_MatchExclusiveFilePattern(self, filename); } // Should this file be ignored? if (!ignore) { if (context->matchFiles) break; } } } NextFile: // Look up the next file. #if defined(WIN32) found = FindNextFile(context->handle, &context->fd) == TRUE; #else if (context->dirp) { context->dp = readdir(context->dirp); found = context->dp != NULL; } else { found = 0; } #endif if (!found) break; } if (!found) { // Close down the file find handle. #if defined(WIN32) FindClose(context->handle); context->handle = INVALID_HANDLE_VALUE; #else if (context->dirp) { closedir(context->dirp); context->dirp = NULL; } #endif context->iterNode = context->directoryListHead; } } // Iterate the file list and either recurse or add the file as a found // file. if (!context->matchFiles) { if (found) { return 1; } NextDirectory: if (context->iterNode) { // Need more directories. SplicePath(&self->combinedName, buffer_ptr(&context->basePath), context->iterNode->buffer); buffer_deltapos(&self->combinedName, -2); buffer_addstring(&self->combinedName, context->pattern, strlen(context->pattern) + 1); context->iterNode = context->iterNode->next; context = NULL; inPattern = buffer_ptr(&self->combinedName); goto Setup; } } else { if (found) return 1; } // Do we need to recurse? if (context->recurseAtPos == (size_t)-1) { _fileglob_FreeContextLevel(self); context = self->context; if (!context) return 0; goto NextDirectory; } buffer_reset(&context->matchPattern); buffer_setpos(&context->patternBuf, context->recurseAtPos); buffer_addstring(&context->matchPattern, buffer_posptr(&context->patternBuf), strlen(buffer_posptr(&context->patternBuf))); buffer_addstring(&context->patternBuf, "*/**/", 5); buffer_addstring(&context->patternBuf, buffer_ptr(&context->matchPattern), buffer_pos(&context->matchPattern) + 1); inPattern = buffer_ptr(&context->patternBuf); context->pattern = NULL; if (context->matchFiles) { context->iterNode = context->directoryListHead; } else { _fileglob_list_clear(self, &context->directoryListHead, &context->directoryListTail); } goto DoRecursion; }
LIST * var_expand( LIST *prefix, const char *in, const char *end, LOL *lol, int cancopyin ) { BUFFER buff; const char *inp = in; int depth; size_t save_buffer_pos, ov_save_buffer_pos; int literal = 0; if( DEBUG_VAREXP ) printf( "expand '%.*s'\n", end - in, in ); /* This gets alot of cases: $(<) and $(>) */ if( end - in == 4 && in[0] == '$' && in[1] == leftParen && in[3] == rightParen ) { switch( in[2] ) { case '1': case '<': return list_copy( prefix, lol_get( lol, 0 ) ); case '2': case '>': return list_copy( prefix, lol_get( lol, 1 ) ); } } buffer_init( &buff ); /* Just try simple copy of in to out. */ while( in < end ) { char ch = *in++; buffer_addchar( &buff, ch ); if( ch == '$' && *in == leftParen ) goto expand; #ifdef OPT_EXPAND_LITERALS_EXT if( ch == '@' && *in == leftParen ) { literal = 1; goto expand; } if( ch == '@' && in[0] == '$' && in[1] == leftParen ) { ++in; literal = 1; goto expand; } #endif } /* No variables expanded - just add copy of input string to list. */ /* Cancopyin is an optimization: if the input was already a list */ /* item, we can use the copystr() to put it on the new list. */ /* Otherwise, we use the slower newstr(). */ buffer_putchar( &buff, 0 ); if( cancopyin ) { LIST *new_list = list_append( prefix, inp, 1 ); buffer_free( &buff ); return new_list; } else { LIST *new_list = list_append( prefix, buffer_ptr( &buff ), 0 ); buffer_free( &buff ); return new_list; } expand: /* * Input so far (ignore blanks): * * stuff-in-outbuf $(variable) remainder * ^ ^ * in end * Output so far: * * stuff-in-outbuf $ * ^ ^ * out_buf out * * * We just copied the $ of $(...), so back up one on the output. * We now find the matching close paren, copying the variable and * modifiers between the $( and ) temporarily into out_buf, so that * we can replace :'s with MAGIC_COLON. This is necessary to avoid * being confused by modifier values that are variables containing * :'s. Ugly. */ depth = 1; buffer_deltapos( &buff, -1 ); save_buffer_pos = buffer_pos( &buff ); in++; while( in < end && depth ) { char ch = *in++; buffer_addchar( &buff, ch ); if ( ch == leftParen ) { depth++; } else if ( ch == rightParen ) { depth--; } else { switch( ch ) { case ':': buffer_deltapos( &buff, -1 ); buffer_addchar( &buff, MAGIC_COLON ); break; case '[': buffer_deltapos( &buff, -1 ); buffer_addchar( &buff, MAGIC_LEFT ); break; case ']': buffer_deltapos( &buff, -1 ); buffer_addchar( &buff, MAGIC_RIGHT ); break; } } } /* Copied ) - back up. */ buffer_deltapos( &buff, -1 ); ov_save_buffer_pos = buffer_pos( &buff ); buffer_setpos( &buff, save_buffer_pos ); /* * Input so far (ignore blanks): * * stuff-in-outbuf $(variable) remainder * ^ ^ * in end * Output so far: * * stuff-in-outbuf variable * ^ ^ ^ * out_buf out ov * * Later we will overwrite 'variable' in out_buf, but we'll be * done with it by then. 'variable' may be a multi-element list, * so may each value for '$(variable element)', and so may 'remainder'. * Thus we produce a product of three lists. */ { LIST *variables = 0; LIST *remainder = 0; LISTITEM *vars; /* Recursively expand variable name & rest of input */ if( save_buffer_pos < ov_save_buffer_pos ) variables = var_expand( L0, buffer_posptr( &buff ), buffer_ptr( &buff ) + ov_save_buffer_pos, lol, 0 ); if( in < end ) remainder = var_expand( L0, in, end, lol, 0 ); /* Now produce the result chain */ /* For each variable name */ for( vars = list_first(variables); vars; vars = list_next( vars ) ) { LIST *value, *evalue = 0; LISTITEM* valueSliceStart = NULL; #ifdef OPT_EXPAND_LITERALS_EXT LIST *origvalue = 0; #endif char *colon; char *bracket; BUFFER varnamebuff; int sub1 = 0, sub2 = -1; VAR_EDITS edits; memset(&edits, 0, sizeof(VAR_EDITS)); if (leftParen == '{') { edits.empty.ptr = ""; edits.empty.len = 0; } /* Look for a : modifier in the variable name */ /* Must copy into varname so we can modify it */ buffer_init( &varnamebuff ); buffer_addstring( &varnamebuff, list_value(vars), strlen( list_value(vars) ) ); buffer_addchar( &varnamebuff, 0 ); if( ( colon = strchr( buffer_ptr( &varnamebuff ), MAGIC_COLON ) ) ) { *colon = '\0'; var_edit_parse( colon + 1, &edits ); } /* Look for [x-y] and [x-] subscripting */ /* sub1 is x (0 default) */ /* sub2 is length (-1 means forever) */ if( ( bracket = strchr( buffer_ptr( &varnamebuff ), MAGIC_LEFT ) ) ) { char *dash; if( ( dash = strchr( bracket + 1, '-' ) ) ) *dash = '\0'; sub1 = atoi( bracket + 1 ) - 1; if( !dash ) sub2 = 1; else if( !dash[1] || dash[1] == MAGIC_RIGHT ) sub2 = -1; else sub2 = atoi( dash + 1 ) - sub1; *bracket = '\0'; } /* Get variable value, specially handling $(<), $(>), $(n) */ #ifdef OPT_EXPAND_LITERALS_EXT if ( !literal ) #endif { const char* varname = buffer_ptr( &varnamebuff ); if( varname[0] == '<' && !varname[1] ) value = lol_get( lol, 0 ); else if( varname[0] == '>' && !varname[1] ) value = lol_get( lol, 1 ); else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] ) value = lol_get( lol, varname[0] - '1' ); else if ( edits.targetsetting ) { TARGET* t = bindtarget(edits.targetname.ptr); SETTINGS* settings = quicksettingslookup(t, varname); if (settings) value = list_copy(L0, settings->value); else value = L0; } else value = var_get( varname ); } #ifdef OPT_EXPAND_LITERALS_EXT else { origvalue = value = list_append( L0, buffer_ptr( &varnamebuff ), 0 ); } #endif /* The fast path: $(x) - just copy the variable value. */ /* This is only an optimization */ if( buffer_isempty( &buff ) && !bracket && !colon && in == end ) { prefix = list_copy( prefix, value ); buffer_free( &buff ); continue; } /* Handle start subscript */ valueSliceStart = list_first(value); while(sub1 > 0 && valueSliceStart) { sub1 -= 1; valueSliceStart = list_next(valueSliceStart); } /* Empty w/ :E=default? */ if( !valueSliceStart && (colon || leftParen == '{') && edits.empty.ptr ) { evalue = value = list_append( L0, edits.empty.ptr, 0 ); valueSliceStart = list_first(value); } #ifdef OPT_EXPAND_LITERALS_EXT if ( colon && edits.expandliteral ) { LOL lol; char const* string = list_value(list_first(value)); LIST *newvalue = var_expand( L0, string, string + strlen( string ), &lol, 0 ); if ( origvalue ) { list_free( origvalue ); origvalue = 0; } value = newvalue; valueSliceStart = list_first(value); sub2 = -1; } #endif #ifdef OPT_EXPAND_FILEGLOB_EXT if ( edits.wildcard ) { LIST *newl = L0; for( ; valueSliceStart; valueSliceStart = list_next( valueSliceStart ) ) { LIST *foundfiles = L0; fileglob* glob; /* Handle end subscript (length actually) */ if( sub2 >= 0 && --sub2 < 0 ) break; glob = fileglob_Create( list_value(valueSliceStart) ); while ( fileglob_Next( glob ) ) { foundfiles = list_append( foundfiles, fileglob_FileName( glob ) + edits.wildcard_remove_prepend.len, 0 ); } fileglob_Destroy( glob ); /* TODO: Efficiency: Just append to newl above? */ newl = list_copy( newl, foundfiles ); list_free( foundfiles ); } if ( origvalue ) { list_free( origvalue ); origvalue = 0; } value = newl; origvalue = value; valueSliceStart = list_first(value); } #endif /* For each variable value */ for( ; valueSliceStart; valueSliceStart = list_next( valueSliceStart ) ) { LISTITEM *rem; size_t save_buffer_pos; size_t end_buffer_pos; const char *valuestring; /* Handle end subscript (length actually) */ if( sub2 >= 0 && --sub2 < 0 ) break; /* Apply : mods, if present */ save_buffer_pos = buffer_pos( &buff ); valuestring = list_value(valueSliceStart); #ifdef OPT_EXPAND_BINDING_EXT if( colon && edits.expandbinding ) { SETTINGS *expandText; TARGET *t = bindtarget( valuestring ); expandText = quicksettingslookup( t, "EXPAND_TEXT" ); if ( expandText && list_first(expandText->value) ) { valuestring = list_value(list_first(expandText->value)); } else { if( t->binding == T_BIND_UNBOUND ) { t->boundname = search_using_target_settings( t, t->name, &t->time ); t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING; } valuestring = t->boundname; } } #endif if( colon && edits.filemods ) { var_edit_file( valuestring, &buff, &edits ); } else { buffer_addstring( &buff, valuestring, strlen( valuestring ) + 1 ); } buffer_setpos( &buff, save_buffer_pos ); if( colon && ( edits.upshift || edits.downshift ) ) var_edit_shift( buffer_posptr( &buff ), &edits ); #ifdef OPT_SLASH_MODIFIERS_EXT if( colon && ( edits.fslash || edits.bslash ) ) var_edit_slash( buffer_posptr( &buff ), &edits ); #endif #ifdef OPT_EXPAND_ESCAPE_PATH_EXT if ( colon && edits.escapepath ) { const char* ptr = buffer_posptr( &buff ); const char* endptr = ptr + strlen( ptr ); BUFFER escapebuff; buffer_init( &escapebuff ); save_buffer_pos = buffer_pos( &buff ); #ifdef NT while ( ptr != endptr && *ptr != ' ' && *ptr != '/' ) ++ptr; if (*ptr == ' ' || *ptr == '/' ) { buffer_addchar( &escapebuff, '"' ); buffer_addstring( &escapebuff, buffer_posptr( &buff ), endptr - buffer_posptr( &buff ) ); buffer_addchar( &escapebuff, '"' ); buffer_addchar( &escapebuff, 0 ); buffer_addstring( &buff, buffer_ptr( &escapebuff ), buffer_pos( &escapebuff ) ); } #else while ( ptr != endptr ) { if ( *ptr == ' ' || *ptr == '\\' || *ptr == leftParen || *ptr == rightParen || *ptr == '"' ) { buffer_addchar( &escapebuff, '\\' ); } buffer_addchar( &escapebuff, *ptr ); ++ptr; } buffer_addchar( &escapebuff, 0 ); buffer_addstring( &buff, buffer_ptr( &escapebuff ), buffer_pos( &escapebuff ) ); #endif buffer_setpos( &buff, save_buffer_pos ); buffer_free( &escapebuff ); } #endif /* Handle :J=joinval */ /* If we have more values for this var, just */ /* keep appending them (with the join value) */ /* rather than creating separate LIST elements. */ if( colon && edits.join.ptr && ( list_next( valueSliceStart ) || list_next( vars ) ) ) { buffer_setpos( &buff, buffer_pos( &buff ) + strlen( buffer_posptr( &buff ) ) ); buffer_addstring( &buff, edits.join.ptr, strlen( edits.join.ptr ) + 1 ); buffer_deltapos( &buff, -1 ); continue; } /* If no remainder, append result to output chain. */ if( in == end ) { prefix = list_append( prefix, buffer_ptr( &buff ), 0 ); continue; } /* For each remainder, append the complete string */ /* to the output chain. */ /* Remember the end of the variable expansion so */ /* we can just tack on each instance of 'remainder' */ save_buffer_pos = buffer_pos( &buff ); end_buffer_pos = strlen( buffer_ptr( &buff ) ); buffer_setpos( &buff, end_buffer_pos ); for( rem = list_first(remainder); rem; rem = list_next( rem ) ) { buffer_addstring( &buff, list_value(rem), strlen( list_value(rem) ) + 1 ); buffer_setpos( &buff, end_buffer_pos ); prefix = list_append( prefix, buffer_ptr( &buff ), 0 ); } buffer_setpos( &buff, save_buffer_pos ); } /* Toss used empty */ if( evalue ) list_free( evalue ); #ifdef OPT_EXPAND_LITERALS_EXT if ( origvalue ) list_free( origvalue ); #endif #ifdef OPT_EXPAND_INCLUDES_EXCLUDES_EXT if ( edits.includes_excludes ) { LIST *newl = L0; LISTITEM* l; LIST *origprefix = prefix; int hasInclude = 0; if ( !regexhash ) regexhash = hashinit( sizeof(regexdata), "regex" ); { LISTITEM *inex = list_first(edits.includes_excludes); while ( inex ) { char mod = list_value(inex)[0]; inex = list_next( inex ); if ( mod == 'I' ) { hasInclude = 1; } } } for (l = list_first(prefix) ; l; l = list_next( l ) ) { LISTITEM *inex = list_first(edits.includes_excludes); int remove = hasInclude; while ( inex ) { char mod = list_value(inex)[0]; regexp *re; regexdata data, *d = &data; inex = list_next( inex ); data.name = list_value(inex); if( !hashcheck( regexhash, (HASHDATA **)&d ) ) { d->re = jam_regcomp( list_value(inex) ); (void)hashenter( regexhash, (HASHDATA **)&d ); } re = d->re; inex = list_next( inex ); if ( mod == 'X' ) { if( jam_regexec( re, list_value(l) ) ) remove = 1; } else if ( mod == 'I' ) { if( jam_regexec( re, list_value(l) ) ) remove = 0; } } if ( !remove ) newl = list_append( newl, list_value(l), 1 ); } /* TODO: Efficiency: Just modify prefix? */ list_free( origprefix ); prefix = newl; } #endif //#ifdef OPT_EXPAND_LITERALS_EXT // buffer_free( &buff ); //#endif #ifdef OPT_EXPAND_INCLUDES_EXCLUDES_EXT list_free( edits.includes_excludes ); #endif } /* variables & remainder were gifts from var_expand */ /* and must be freed */ list_free( variables ); list_free( remainder ); if( DEBUG_VAREXP ) { printf( "expanded to " ); list_print( prefix ); printf( "\n" ); } buffer_free( &buff ); return prefix; } }