コード例 #1
0
ファイル: builtins.c プロジェクト: larus/jamplus
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;
}
コード例 #2
0
ファイル: hcache.c プロジェクト: brkpt/jamplus
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);
}
コード例 #3
0
ファイル: hcache.c プロジェクト: brkpt/jamplus
/*
 * 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;
}
コード例 #4
0
ファイル: builtins.c プロジェクト: larus/jamplus
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;
}
コード例 #5
0
ファイル: hcache.c プロジェクト: larus/jamplus
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;
}
コード例 #6
0
ファイル: luagsub.c プロジェクト: alenl/jamplus
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 */
      }
    }
  }
}
コード例 #7
0
ファイル: fileunix.c プロジェクト: arventwei/jamplus
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;
}
コード例 #8
0
ファイル: headers.c プロジェクト: arventwei/jamplus
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;
}
コード例 #9
0
ファイル: builtins.c プロジェクト: larus/jamplus
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;
}
コード例 #10
0
ファイル: hcache.c プロジェクト: r1chi3x/jamplus
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;
}
コード例 #11
0
ファイル: builtins.c プロジェクト: larus/jamplus
/* 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;
}
コード例 #12
0
ファイル: filent.c プロジェクト: caryhaynie/jamplus
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;
}
コード例 #13
0
ファイル: expand.c プロジェクト: arventwei/jamplus
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;
	}
}
コード例 #14
0
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;
}
コード例 #15
0
/**
	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);
}
コード例 #16
0
ファイル: hcache.c プロジェクト: larus/jamplus
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);
	}
}
コード例 #17
0
ファイル: hcache.c プロジェクト: caryhaynie/jamplus
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);
	}
}