LIST *builtin_subst_literalize( PARSE *parse, LOL *args, int *jmp ) { LIST *pattern; LIST *result = L0; for( pattern = lol_get( args, 0 ); pattern; pattern = pattern->next ) { const char* patternString; BUFFER patternBuff; buffer_init( &patternBuff ); for ( patternString = pattern->string; *patternString; ++patternString ) { if ( *patternString == '(' || *patternString == ')' || *patternString == '.' || *patternString == '%' || *patternString == '+' || *patternString == '-' || *patternString == '*' || *patternString == '?' || *patternString == '[' || *patternString == ']' || *patternString == '^' || *patternString == '$' ) { buffer_addchar( &patternBuff, '%' ); } buffer_addchar( &patternBuff, *patternString ); } buffer_addchar( &patternBuff, 0 ); result = list_new( result, buffer_ptr( &patternBuff ), 0 ); } 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); }
/* * 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; }
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; }
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; }
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 */ } } } }
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 * headers1( const char *file, LIST *hdrscan ) { FILE *f; LIST *result = 0; LIST *hdrpipe; LIST *hdrpipefile; if ( list_first(hdrpipe = var_get( "HDRPIPE" )) ) { LOL args; BUFFER buff; lol_init( &args ); lol_add( &args, list_append( L0, file, 0 ) ); buffer_init( &buff ); if ( var_string( list_value(list_first(hdrpipe)), &buff, 0, &args, ' ') < 0 ) { printf( "Cannot expand HDRPIPE '%s' !\n", list_value(list_first(hdrpipe)) ); exit( EXITBAD ); } buffer_addchar( &buff, 0 ); if ( !( f = file_popen( (const char*)buffer_ptr( &buff ), "r" ) ) ) { buffer_free( &buff ); return result; } buffer_free( &buff ); lol_free( &args ); } else { if( !( f = fopen( file, "r" ) ) ) return result; } result = headers1helper( f, hdrscan ); if ( list_first(hdrpipe) ) file_pclose( f ); else fclose( f ); if ( list_first(hdrpipefile = var_get( "HDRPIPEFILE" )) ) { if( !( f = fopen( list_value(list_first(hdrpipefile)), "r" ) ) ) return result; result = headers1helper( f, hdrscan ); fclose( f ); } return result; }
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; }
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; }
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; } }
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; }
/** 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); }
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); } }
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); } }