Beispiel #1
0
void
file_dirscan( 
	char *dir,
	scanback func,
	void	*closure )
{
    PATHNAME f;
    string filespec[1];
    long handle;
    int ret;
    struct _find_t finfo[1];

    /* First enter directory itself */

    memset( (char *)&f, '\0', sizeof( f ) );

    f.f_dir.ptr = dir;
    f.f_dir.len = strlen(dir);

    dir = *dir ? dir : ".";

    /* Special case \ or d:\ : enter it */
    string_copy( filespec, dir );

    if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' )
 	    (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
    else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' )
 	    (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
    else
        string_push_back( filespec, '/' );

    string_push_back( filespec, '*' );

    /* Now enter contents of directory */

    if( DEBUG_BINDSCAN )
        printf( "scan directory %s\n", filespec->value );

    /* Time info in dos find_t is not very useful.  It consists */
    /* of a separate date and time, and putting them together is */
    /* not easy.  So we leave that to a later stat() call. */

    if( !_dos_findfirst( filespec->value, _A_NORMAL|_A_RDONLY|_A_SUBDIR, finfo ) )
    {
        string filename[1];
        string_new( filename );
        do
        {
            
            f.f_base.ptr = finfo->name;
            f.f_base.len = strlen( finfo->name );

            string_truncate( filename, 0 );
            path_build( &f, filename, 0 );
            (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 );
        }
        while( !_dos_findnext( finfo ) );
        string_free( filename );
    }
}
Beispiel #2
0
void file_build1( PATHNAME * f, string * file )
{
    if ( DEBUG_SEARCH )
    {
        printf("build file: ");
        if ( f->f_root.len )
            printf( "root = '%.*s' ", f->f_root.len, f->f_root.ptr );
        if ( f->f_dir.len )
            printf( "dir = '%.*s' ", f->f_dir.len, f->f_dir.ptr );
        if ( f->f_base.len )
            printf( "base = '%.*s' ", f->f_base.len, f->f_base.ptr );
        printf( "\n" );
    }

    /* Start with the grist.  If the current grist isn't */
    /* surrounded by <>'s, add them. */

    if ( f->f_grist.len )
    {
        if ( f->f_grist.ptr[0] != '<' )
            string_push_back( file, '<' );
        string_append_range(
            file, f->f_grist.ptr, f->f_grist.ptr + f->f_grist.len );
        if ( file->value[file->size - 1] != '>' )
            string_push_back( file, '>' );
    }
}
Beispiel #3
0
static void string_new_from_argv( string * result, char const * const * argv )
{
    assert( argv );
    assert( argv[ 0 ] );
    string_copy( result, *(argv++) );
    while ( *argv )
    {
        string_push_back( result, ' ' );
        string_push_back( result, '"' );
        string_append( result, *(argv++) );
        string_push_back( result, '"' );
    }
}
Beispiel #4
0
void path_build( PATHNAME * f, string * file )
{
    file_build1( f, file );

    /* Do not prepend root if it is '.' or the directory is rooted. */
    if ( f->f_root.len
        && !( f->f_root.len == 1 && f->f_root.ptr[ 0 ] == '.' )
        && !( f->f_dir.len && f->f_dir.ptr[ 0 ] == '/' )
#if PATH_DELIM == '\\'
        && !( f->f_dir.len && f->f_dir.ptr[ 0 ] == '\\' )
        && !( f->f_dir.len && f->f_dir.ptr[ 1 ] == ':' )
#endif
    )
    {
        string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len
            );
        /* If 'root' already ends with a path delimeter, do not add another one.
         */
        if ( !is_path_delim( f->f_root.ptr[ f->f_root.len - 1 ] ) )
            string_push_back( file, as_path_delim( f->f_root.ptr[ f->f_root.len
                ] ) );
    }

    if ( f->f_dir.len )
        string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );

    /* Put path separator between dir and file. */
    /* Special case for root dir: do not add another path separator. */
    if ( f->f_dir.len && ( f->f_base.len || f->f_suffix.len )
#if PATH_DELIM == '\\'
        && !( f->f_dir.len == 3 && f->f_dir.ptr[ 1 ] == ':' )
#endif
        && !( f->f_dir.len == 1 && is_path_delim( f->f_dir.ptr[ 0 ] ) ) )
        string_push_back( file, as_path_delim( f->f_dir.ptr[ f->f_dir.len ] ) );

    if ( f->f_base.len )
        string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len
            );

    if ( f->f_suffix.len )
        string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr +
            f->f_suffix.len );

    if ( f->f_member.len )
    {
        string_push_back( file, '(' );
        string_append_range( file, f->f_member.ptr, f->f_member.ptr +
            f->f_member.len );
        string_push_back( file, ')' );
    }
}
Beispiel #5
0
/**
 * Get one line from specific stream.
 */
bool_t string_getline(string_t* pstr_string, FILE* fp_stream)
{
    int n_char = EOF;
#ifdef _WIN32
    int n_prevchar = EOF;
#endif

    assert(pstr_string != NULL);
    assert(fp_stream != NULL);

    clearerr(fp_stream);
    string_clear(pstr_string);
    while (!feof(fp_stream) && !ferror(fp_stream) && n_char != '\n' &&
           string_size(pstr_string) < string_max_size(pstr_string)) {
        n_char = fgetc(fp_stream);
        if (n_char != '\n' && n_char != EOF) {
#ifdef _WIN32
            /* new line is '\r\n' in Windows */
            if (n_prevchar != EOF) {
                assert(n_prevchar == '\r');
                string_push_back(pstr_string, (char)n_prevchar);
                n_prevchar = EOF;
            }
            if (n_char == '\r') {
                assert(n_prevchar == EOF);
                n_prevchar = n_char;
            } else {
                string_push_back(pstr_string, (char)n_char);
            }
#else
            string_push_back(pstr_string, (char)n_char);
#endif
        }
    }

#ifdef _WIN32
    if (feof(fp_stream)) {
        if (n_prevchar != EOF) {
            assert(n_prevchar == '\r');
            string_push_back(pstr_string, (char)n_prevchar);
            n_prevchar = EOF;
        }

        return false;
    }
#endif

    return (char)n_char == '\n' ? true : false;
}
Beispiel #6
0
static void import_base_rule( void * r_, void * d_ )
{
    RULE * r = (RULE *)r_;
    RULE * ir1;
    RULE * ir2;
    struct import_base_data * d = (struct import_base_data *)d_;
    string qualified_name[ 1 ];
    OBJECT * qname;

    string_new      ( qualified_name               );
    string_append   ( qualified_name, object_str( d->base_name ) );
    string_push_back( qualified_name, '.'          );
    string_append   ( qualified_name, object_str( r->name ) );

    qname = object_new( qualified_name->value );

    ir1 = import_rule( r, d->class_module, r->name );
    ir2 = import_rule( r, d->class_module, qname );

    object_free( qname );

    /* Copy 'exported' flag. */
    ir1->exported = ir2->exported = r->exported;

    /* If we are importing a class method, localize it. */
    if ( ( r->module == d->base_module ) || ( r->module->class_module &&
        ( r->module->class_module == d->base_module ) ) )
        ir1->module = ir2->module = d->class_module;

    string_free( qualified_name );
}
Beispiel #7
0
/**
 * Get one line from specific stream with delimiter.
 */
bool_t string_getline_delimiter(string_t* pstr_string, FILE* fp_stream, char c_delimiter)
{
    int n_char = EOF;

    assert(pstr_string != NULL);
    assert(fp_stream != NULL);

    if(c_delimiter == '\n')
    {
        return string_getline(pstr_string, fp_stream);
    }
    else
    {
        clearerr(fp_stream);
        string_clear(pstr_string);
        while(!feof(fp_stream) && !ferror(fp_stream) && (char)n_char != c_delimiter &&
              string_size(pstr_string) < string_max_size(pstr_string))
        {
            n_char = fgetc(fp_stream);
            if((char)n_char != c_delimiter && n_char != EOF)
            {
                string_push_back(pstr_string, (char)n_char);
            }
        }

        if((char)n_char == c_delimiter)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}
Beispiel #8
0
void err_msg_adding(char* msg, char* sname, int line)
{
    char* tmp = MALLOC(strlen(sname) + 128 + strlen(msg));
    snprintf(tmp, strlen(sname) + 128 + strlen(msg), "%s %d: %s\n", sname,  line, msg);

    string_push_back(gErrMsg, tmp);
    FREE(tmp);
}
LIST *property_set_create( PARSE *parse, FRAME *frame )
{
    LIST* properties = lol_get( frame->args, 0 );    
    LIST* sorted = 0;
    LIST* order_sensitive = 0;
    LIST* unique;
    LIST* tmp;
    LIST* val;
    string var[1];

#if 0
    /* Sort all properties which are not order sensitive */
    for(tmp = properties; tmp; tmp = tmp->next) {
        LIST* g = get_grist(tmp->string);
        LIST* att = call_rule("feature.attributes", frame, g, 0);
        if (list_in(att, "order-sensitive")) {
            order_sensitive = list_new( order_sensitive, tmp->string);
        } else {
            sorted = list_new( sorted, tmp->string);
        }
        list_free(att);
    }
    
    sorted = list_sort(sorted);
    sorted = list_append(sorted, order_sensitive);
    unique = list_unique(sorted);
#endif
    sorted = list_sort(properties);
    unique = list_unique(sorted);

    string_new(var);
    string_append(var, ".ps.");
    
    for(tmp = unique; tmp; tmp = tmp->next) {
        string_append(var, tmp->string);
        string_push_back(var, '-');
    }
    val = var_get(var->value);
    if (val == 0) 
    {          
        val = call_rule("new", frame, 
                        list_append(list_new(0, "property-set"), unique), 0);                
        
        var_set(newstr(var->value), list_copy(0, val), VAR_SET);
    }
    else
    {
        val = list_copy(0, val);
    }
    
    string_free(var);
    /* The 'unique' variable is freed in 'call_rule'. */
    list_free(sorted);

    return val;

}
Beispiel #10
0
const char * path_tmpfile(void)
{
    const char * result = 0;

    string file_path;
    string_copy(&file_path,path_tmpdir());
    string_push_back(&file_path,PATH_DELIM);
    string_append(&file_path,path_tmpnam());
    result = newstr(file_path.value);
    string_free(&file_path);

    return result;
}
Beispiel #11
0
void string_unit_test()
{
    {
        string s[ 1 ];
        int i;
        int const limit = sizeof( s->opt ) * 2 + 2;
        string_new( s );
        assert( s->value == s->opt );
        for ( i = 0; i < limit; ++i )
        {
            string_push_back( s, (char)( i + 1 ) );
            assert( s->size == i + 1 );
        }
        assert( s->size == limit );
        assert( s->value != s->opt );
        for ( i = 0; i < limit; ++i )
            assert( s->value[ i ] == (char)( i + 1 ) );
        string_free( s );
    }

    {
        char * const original = "  \n\t\v  Foo \r\n\v \tBar\n\n\r\r\t\n\v\t \t";
        string copy[ 1 ];
        string_copy( copy, original );
        assert( !strcmp( copy->value, original ) );
        assert( copy->size == strlen( original ) );
        string_free( copy );
    }

    {
        char * const foo = "Foo    ";
        string foo_copy[ 1 ];
        string_copy( foo_copy, foo );
        string_rtrim( foo_copy );
        assert( !strcmp( foo_copy->value, "Foo" ) );

        string_rtrim( foo_copy );
        assert( !strcmp( foo_copy->value, "Foo" ) );
    }
    {
        char * const bar = "Bar\0\0\0";
        string bar_copy[ 1 ];
        string_copy( bar_copy, bar );
        string_rtrim( bar_copy );
        assert( !strcmp( bar_copy->value, "Bar" ) );

        string_rtrim( bar_copy );
        assert( !strcmp( bar_copy->value, "Bar" ) );
    }
}
Beispiel #12
0
/** LyricsWiki parsing strategy:
 * - start from first hit of "<div class='lyricbox'>"
 * - search until first html entity
 * - start converting entities to utf-32 and <br />s to newlines
 * - if over 48 characters without html entity (allows up to 8 <br />s, for
 *   instance), stop
 */
static char *parse_lyrics_page(char *page)
{
  char *p;
  int gap = 0;
  uint32_t chr;
  char *tmp;
  string_t *string, *result;
  
  p = strstr(page, "<div class='lyricbox'>");
  
  if (!p) {
    return NULL;
  }
  
  string = string_new();

  for (; *p != '\0'; ++p) {
    if (string_size(string) > 0 && gap > 48) {
      break;
    }
    
    ++gap;
    
    if (!strncmp(p, "&#", 2)) {
      if (sscanf(p + 2, "%d;", &chr) < 1) {
        continue;
      }
      
      gap = 0;
      
      tmp = (char *)&chr;
      string_push_back(string, tmp[0]);
      string_push_back(string, tmp[1]);
      string_push_back(string, tmp[2]);
      string_push_back(string, tmp[3]);
    } else if (!strncmp(p, "<br />", 6)) {
      string_push_back(string, '\n');
      string_push_back(string, '\0');
      string_push_back(string, '\0');
      string_push_back(string, '\0');
    }
  }
  
  result = string_iconv(string, "UTF-8", "UTF-32");
  string_free(string);
  return string_release(result);
}
Beispiel #13
0
/**
 * Read the character string from specific stream.
 */
void string_input(string_t* pstr_string, FILE* fp_stream)
{
    int n_char = EOF;

    assert(pstr_string != NULL);
    assert(fp_stream != NULL);

    clearerr(fp_stream);
    string_clear(pstr_string);
    while (!feof(fp_stream) && !ferror(fp_stream) && string_size(pstr_string) < string_max_size(pstr_string)) {
        if ((n_char = fgetc(fp_stream)) != EOF) {
            string_push_back(pstr_string, (char)n_char);
        }
    }
}
Beispiel #14
0
OBJECT * path_tmpfile(void)
{
    OBJECT * result = 0;
    OBJECT * tmpnam;

    string file_path;
    string_copy(&file_path,path_tmpdir());
    string_push_back(&file_path,PATH_DELIM);
    tmpnam = path_tmpnam();
    string_append(&file_path,object_str(tmpnam));
    object_free(tmpnam);
    result = object_new(file_path.value);
    string_free(&file_path);

    return result;
}
Beispiel #15
0
void query_filter(query_t *query, query_field_t field,
                      const char *filter)
{
  string_t *string;
  if (!filter) {
    query->filters[field] = NULL;
    return;
  }
  if (!id_fields[field]) {
    query->filters[field] = stringf("%%%s%%", filter);
    return;
  }

  /* The field is an id field. Ensure the filter is a comma-separated list of
   * decimal numbers. */
  string = string_new();
  for (; *filter != '\0'; ++filter) {
    if (*filter == ',' || (*filter >= '0' && *filter <= '9')) {
      string_push_back(string, *filter);
    }
  }
  query->filters[field] = string_release(string);
}
Beispiel #16
0
void string_unit_test()
{
    string s[1];
    int i;
    char buffer[sizeof(s->opt) * 2 + 2];
    int limit = sizeof(buffer) > 254 ? 254 : sizeof(buffer);

    string_new(s);
    
    for (i = 0; i < limit; ++i)
    {
        string_push_back( s, (char)(i + 1) );
    };

    for (i = 0; i < limit; ++i)
    {
        assert( i < s->size );
        assert( s->value[i] == (char)(i + 1));
    }

    string_free(s);
    
}
Beispiel #17
0
void exec_cmd
(
    char * command,
    void (* func)( void * closure, int status, timing_info *, char * invoked_command, char * command_output ),
    void * closure,
    LIST * shell,
    char * action,
    char * target
)
{
    int      slot;
    int      raw_cmd = 0 ;
    char   * argv_static[ MAXARGC + 1 ];  /* +1 for NULL */
    char * * argv = argv_static;
    char   * p;
    char   * command_orig = command;

    /* Check to see if we need to hack around the line-length limitation. Look
     * for a JAMSHELL setting of "%", indicating that the command should be
     * invoked directly.
     */
    if ( shell && !strcmp( shell->string, "%" ) && !list_next( shell ) )
    {
        raw_cmd = 1;
        shell = 0;
    }

    /* Find a slot in the running commands table for this one. */
    for ( slot = 0; slot < MAXJOBS; ++slot )
        if ( !cmdtab[ slot ].pi.hProcess )
            break;
    if ( slot == MAXJOBS )
    {
        printf( "no slots for child!\n" );
        exit( EXITBAD );
    }

    /* Compute the name of a temp batch file, for possible use. */
    if ( !cmdtab[ slot ].tempfile_bat )
    {
        char const * tempdir = path_tmpdir();
        DWORD procID = GetCurrentProcessId();

        /* SVA - allocate 64 bytes extra just to be safe. */
        cmdtab[ slot ].tempfile_bat = BJAM_MALLOC_ATOMIC( strlen( tempdir ) + 64 );

        sprintf( cmdtab[ slot ].tempfile_bat, "%s\\jam%d-%02d.bat",
            tempdir, procID, slot );
    }

    /* Trim leading, -ending- white space */
    while ( *( command + 1 ) && isspace( *command ) )
        ++command;

    /* Write to .BAT file unless the line would be too long and it meets the
     * other spawnability criteria.
     */
    if ( raw_cmd && ( can_spawn( command ) >= MAXLINE ) )
    {
        if ( DEBUG_EXECCMD )
            printf("Executing raw command directly\n");
    }
    else
    {
        FILE * f = 0;
        int tries = 0;
        raw_cmd = 0;

        /* Write command to bat file. For some reason this open can fail
         * intermitently. But doing some retries works. Most likely this is due
         * to a previously existing file of the same name that happens to be
         * opened by an active virus scanner. Pointed out and fixed by Bronek
         * Kozicki.
         */
        for ( ; !f && ( tries < 4 ); ++tries )
        {
            f = fopen( cmdtab[ slot ].tempfile_bat, "w" );
            if ( !f && ( tries < 4 ) ) Sleep( 250 );
        }
        if ( !f )
        {
            printf( "failed to write command file!\n" );
            exit( EXITBAD );
        }
        fputs( command, f );
        fclose( f );

        command = cmdtab[ slot ].tempfile_bat;

        if ( DEBUG_EXECCMD )
        {
            if ( shell )
                printf( "using user-specified shell: %s", shell->string );
            else
                printf( "Executing through .bat file\n" );
        }
    }

    /* Formulate argv; If shell was defined, be prepared for % and ! subs.
     * Otherwise, use stock cmd.exe.
     */
    if ( shell )
    {
        int i;
        char jobno[ 4 ];
        int gotpercent = 0;

        sprintf( jobno, "%d", slot + 1 );

        for ( i = 0; shell && ( i < MAXARGC ); ++i, shell = list_next( shell ) )
        {
            switch ( shell->string[ 0 ] )
            {
                case '%': argv[ i ] = command; ++gotpercent; break;
                case '!': argv[ i ] = jobno; break;
                default : argv[ i ] = shell->string;
            }
            if ( DEBUG_EXECCMD )
                printf( "argv[%d] = '%s'\n", i, argv[ i ] );
        }

        if ( !gotpercent )
            argv[ i++ ] = command;

        argv[ i ] = 0;
    }
    else if ( raw_cmd )
    {
        argv = string_to_args( command );
    }
    else
    {
        argv[ 0 ] = "cmd.exe";
        argv[ 1 ] = "/Q/C";  /* anything more is non-portable */
        argv[ 2 ] = command;
        argv[ 3 ] = 0;
    }

    /* Catch interrupts whenever commands are running. */
    if ( !cmdsrunning++ )
        istat = signal( SIGINT, onintr );

    /* Start the command. */
    {
        SECURITY_ATTRIBUTES sa
            = { sizeof( SECURITY_ATTRIBUTES ), 0, 0 };
        SECURITY_DESCRIPTOR sd;
        STARTUPINFO si
            = { sizeof( STARTUPINFO ), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        string cmd;

        /* Init the security data. */
        InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION );
        SetSecurityDescriptorDacl( &sd, TRUE, NULL, FALSE );
        sa.lpSecurityDescriptor = &sd;
        sa.bInheritHandle = TRUE;

        /* Create the stdout, which is also the merged out + err, pipe. */
        if ( !CreatePipe( &cmdtab[ slot ].pipe_out[ 0 ],
            &cmdtab[ slot ].pipe_out[ 1 ], &sa, 0 ) )
        {
            perror( "CreatePipe" );
            exit( EXITBAD );
        }

        /* Create the stdout, which is also the merged out+err, pipe. */
        if ( globs.pipe_action == 2 )
        {
            if ( !CreatePipe( &cmdtab[ slot ].pipe_err[ 0 ],
                &cmdtab[ slot ].pipe_err[ 1 ], &sa, 0 ) )
            {
                perror( "CreatePipe" );
                exit( EXITBAD );
            }
        }

        /* Set handle inheritance off for the pipe ends the parent reads from. */
        SetHandleInformation( cmdtab[ slot ].pipe_out[ 0 ], HANDLE_FLAG_INHERIT, 0 );
        if ( globs.pipe_action == 2 )
            SetHandleInformation( cmdtab[ slot ].pipe_err[ 0 ], HANDLE_FLAG_INHERIT, 0 );

        /* Hide the child window, if any. */
        si.dwFlags |= STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_HIDE;

        /* Set the child outputs to the pipes. */
        si.dwFlags |= STARTF_USESTDHANDLES;
        si.hStdOutput = cmdtab[ slot ].pipe_out[ 1 ];
        if ( globs.pipe_action == 2 )
        {
            /* Pipe stderr to the action error output. */
            si.hStdError = cmdtab[ slot ].pipe_err[ 1 ];
        }
        else if ( globs.pipe_action == 1 )
        {
            /* Pipe stderr to the console error output. */
            si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
        }
        else
        {
            /* Pipe stderr to the action merged output. */
            si.hStdError = cmdtab[ slot ].pipe_out[ 1 ];
        }

        /* Let the child inherit stdin, as some commands assume it's available. */
        si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);

        /* Save the operation for exec_wait() to find. */
        cmdtab[ slot ].func = func;
        cmdtab[ slot ].closure = closure;
        if ( action && target )
        {
            string_copy( &cmdtab[ slot ].action, action );
            string_copy( &cmdtab[ slot ].target, target );
        }
        else
        {
            string_free( &cmdtab[ slot ].action );
            string_new ( &cmdtab[ slot ].action );
            string_free( &cmdtab[ slot ].target );
            string_new ( &cmdtab[ slot ].target );
        }
        string_copy( &cmdtab[ slot ].command, command_orig );

        /* Put together the command we run. */
        {
            char * * argp = argv;
            string_new( &cmd );
            string_copy( &cmd, *(argp++) );
            while ( *argp )
            {
                string_push_back( &cmd, ' ' );
                string_append( &cmd, *(argp++) );
            }
        }

        /* Create output buffers. */
        string_new( &cmdtab[ slot ].buffer_out );
        string_new( &cmdtab[ slot ].buffer_err );

        /* Run the command by creating a sub-process for it. */
        if (
            ! CreateProcess(
                NULL                    ,  /* application name               */
                cmd.value               ,  /* command line                   */
                NULL                    ,  /* process attributes             */
                NULL                    ,  /* thread attributes              */
                TRUE                    ,  /* inherit handles                */
                CREATE_NEW_PROCESS_GROUP,  /* create flags                   */
                NULL                    ,  /* env vars, null inherits env    */
                NULL                    ,  /* current dir, null is our       */
                                           /* current dir                    */
                &si                     ,  /* startup info                   */
                &cmdtab[ slot ].pi         /* child process info, if created */
                )
            )
        {
            perror( "CreateProcess" );
            exit( EXITBAD );
        }

        /* Clean up temporary stuff. */
        string_free( &cmd );
    }

    /* Wait until we are under the limit of concurrent commands. Do not trust
     * globs.jobs alone.
     */
    while ( ( cmdsrunning >= MAXJOBS ) || ( cmdsrunning >= globs.jobs ) )
        if ( !exec_wait() )
            break;

    if ( argv != argv_static )
        free_argv( argv );
}
Beispiel #18
0
int var_string( const char * in, char * out, int outsize, LOL * lol )
{
    char * out0 = out;
    char * oute = out + outsize - 1;

    while ( *in )
    {
        char * lastword;
        int    dollar = 0;

        /* Copy white space. */
        while ( isspace( *in ) )
        {
            if ( out >= oute )
                return -1;
            *out++ = *in++;
        }

        lastword = out;

        /* Copy non-white space, watching for variables. */
        while ( *in && !isspace( *in ) )
        {
            if ( out >= oute )
                return -1;

            if ( ( in[ 0 ] == '$' ) && ( in[ 1 ] == '(' ) )
            {
                ++dollar;
                *out++ = *in++;
            }
            #ifdef OPT_AT_FILES
            else if ( ( in[ 0 ] == '@' ) && ( in[ 1 ] == '(' ) )
            {
                int depth = 1;
                const char * ine = in + 2;
                const char * split = 0;

                /* Scan the content of the response file @() section. */
                while ( *ine && ( depth > 0 ) )
                {
                    switch ( *ine )
                    {
                    case '(': ++depth; break;
                    case ')': --depth; break;
                    case ':':
                        if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '=' ) )
                            split = ine;
                        break;
                    }
                    ++ine;
                }

                if ( !split )
                {
                    /*  the @() reference doesn't match the @(foo:E=bar) format.
                        hence we leave it alone by copying directly to output. */
                    int l = 0;
                    if ( out + 2 >= oute ) return -1;
                    *( out++ ) = '@';
                    *( out++ ) = '(';
                    l = var_string( in + 2, out, oute - out, lol );
                    if ( l < 0 ) return -1;
                    out += l;
                    if ( out + 1 >= oute ) return -1;
                    *( out++ ) = ')';
                }
                else if ( depth == 0 )
                {
                    string file_name_v;
                    OBJECT * file_name = 0;
                    int file_name_l = 0;
                    const char * file_name_s = 0;

                    /* Expand the temporary file name var inline. */
                    #if 0
                    string_copy( &file_name_v, "$(" );
                    string_append_range( &file_name_v, in + 2, split );
                    string_push_back( &file_name_v, ')' );
                    #else
                    string_new( &file_name_v );
                    string_append_range( &file_name_v, in + 2, split );
                    #endif
                    file_name_l = var_string( file_name_v.value, out, oute - out + 1, lol );
                    string_free( &file_name_v );
                    if ( file_name_l < 0 ) return -1;
                    file_name_s = out;

                    /* For stdout/stderr we will create a temp file and generate
                     * a command that outputs the content as needed.
                     */
                    if ( ( strcmp( "STDOUT", out ) == 0 ) ||
                        ( strcmp( "STDERR", out ) == 0 ) )
                    {
                        int err_redir = strcmp( "STDERR", out ) == 0;
                        out[ 0 ] = '\0';

                        file_name = path_tmpfile();
                        file_name_s = object_str(file_name);
                        file_name_l = strlen(file_name_s);
                        #ifdef OS_NT
                        if ( ( out + 7 + file_name_l + ( err_redir ? 5 : 0 ) ) >= oute )
                            return -1;
                        sprintf( out,"type \"%s\"%s", file_name_s,
                            err_redir ? " 1>&2" : "" );
                        #else
                        if ( ( out + 6 + file_name_l + ( err_redir ? 5 : 0 ) ) >= oute )
                            return -1;
                        sprintf( out,"cat \"%s\"%s", file_name_s,
                            err_redir ? " 1>&2" : "" );
                        #endif
                        /* We also make sure that the temp files created by this
                         * get nuked eventually.
                         */
                        file_remove_atexit( file_name );
                    }

                    /* Expand the file value into the file reference. */
                    var_string_to_file( split + 3, ine - split - 4, file_name_s,
                        lol );

                    if ( file_name )
                    {
                        object_free( file_name );
                    }

                    /* Continue on with the expansion. */
                    out += strlen( out );
                }

                /* And continue with the parsing just past the @() reference. */
                in = ine;
            }
            #endif
            else
            {
                *out++ = *in++;
            }
        }

        /* Add zero to 'out' so that 'lastword' is correctly zero-terminated. */
        if ( out >= oute )
            return -1;
        /* Do not increment, intentionally. */
        *out = '\0';

        /* If a variable encountered, expand it and and embed the
         * space-separated members of the list in the output.
         */
        if ( dollar )
        {
            LIST * l = var_expand( L0, lastword, out, lol, 0 );
            LIST * saved = l;

            out = lastword;

            while ( l )
            {
                int so = strlen( object_str( l->value ) );

                if ( out + so >= oute )
                    return -1;

                strcpy( out, object_str( l->value ) );
                out += so;
                l = list_next( l );
                if ( l ) *out++ = ' ';
            }

            list_free( saved );
        }
    }

    if ( out >= oute )
        return -1;

    *out++ = '\0';

    return out - out0;
}
Beispiel #19
0
void path_build( PATHNAME * f, string * file, int binding )
{
    struct dirinf root;
    struct dirinf dir;
    int g;

    file_build1( f, file );

    /* Get info on root and dir for combining. */
    dir_flags( f->f_root.ptr, f->f_root.len, &root );
    dir_flags( f->f_dir.ptr, f->f_dir.len, &dir );

    /* Combine. */
    switch ( g = grid[ root.flags ][ dir.flags ] )
    {
    case G_DIR:
        /* take dir */
        string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len  );
        break;

    case G_ROOT:
        /* take root */
        string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len  );
        break;

    case G_VAD:
        /* root's dev + abs directory */
        string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len  );
        string_append_range( file, dir.dir.ptr, dir.dir.ptr + dir.dir.len  );
        break;

    case G_DRD:
    case G_DDD:
        /* root's dev:[dir] + rel directory */
        string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len  );

        /* sanity checks: root ends with ] */

        if ( file->value[file->size - 1] == ']' )
            string_pop_back( file );

        /* Add . if separating two -'s */

        if ( g == G_DDD )
            string_push_back( file, '.' );

        /* skip [ of dir */
        string_append_range( file, dir.dir.ptr + 1, dir.dir.ptr + 1 + dir.dir.len - 1  );
        break;

    case G_VRD:
        /* root's dev + rel directory made abs */
        string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len  );
        string_push_back( file, '[' );
        /* skip [. of rel dir */
        string_append_range( file, dir.dir.ptr + 2, dir.dir.ptr + 2 + dir.dir.len - 2  );
        break;
    }

# ifdef DEBUG
    if ( DEBUG_SEARCH && ( root.flags || dir.flags ) )
        printf( "%d x %d = %d (%s)\n", root.flags, dir.flags,
                grid[ root.flags ][ dir.flags ], file->value );
# endif

    /*
     * Now do the special :P modifier when no file was present.
     *  (none)      (none)
     *  [dir1.dir2] [dir1]
     *  [dir]       [000000]
     *  [.dir]      (none)
     *  []      []
     */

    if ( ( file->value[ file->size - 1 ] == ']' ) && f->parent )
    {
        char * p = file->value + file->size;
        while ( p-- > file->value )
        {
            if ( *p == '.' )
            {
                /* If we've truncated everything and left with '[',
                   return empty string. */
                if ( p == file->value + 1 )
                    string_truncate( file, 0 );
                else
                {
                    string_truncate( file, p - file->value );
                    string_push_back( file, ']' );
                }
                break;
            }
            
            if ( *p == '-' )
            {
                /* handle .- or - */
                if ( ( p > file->value ) && ( p[ -1 ] == '.' ) )
                    --p;

                *p++ = ']';
                break;
            }
            
            if ( *p == '[' )
            {
                if ( p[ 1 ] == ']' )
                {
                    /* CONSIDER: I don't see any use of this code. We immediately
                       break, and 'p' is a local variable. */
                    p += 2;
                }
                else
                {
                    string_truncate( file, p - file->value );
                    string_append( file, "[000000]" );
                }
                break;
            }
        }
    }

    /* Now copy the file pieces. */
    if ( f->f_base.len )
    {
        string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len  );
    }

    /* If there is no suffix, we append a "." onto all generated names. This
     * keeps VMS from appending its own (wrong) idea of what the suffix should
     * be.
     */
    if ( f->f_suffix.len )
        string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len  );
    else if ( binding && f->f_base.len )
        string_push_back( file, '.' );

    if ( f->f_member.len )
    {
        string_push_back( file, '(' );
        string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len  );
        string_push_back( file, ')' );
    }

# ifdef DEBUG
    if ( DEBUG_SEARCH )
        printf( "built %.*s + %.*s / %.*s suf %.*s mem %.*s -> %s\n",
               f->f_root.len, f->f_root.ptr,
               f->f_dir.len, f->f_dir.ptr,
               f->f_base.len, f->f_base.ptr,
               f->f_suffix.len, f->f_suffix.ptr,
               f->f_member.len, f->f_member.ptr,
               file->value );
# endif
}
Beispiel #20
0
static void canonicWindowsPath( char const * const path, int const path_length,
    string * const out )
{
    char const * last_element;
    unsigned long saved_size;
    char const * p;

    /* This is only called via path_key(), which initializes the cache. */
    assert( path_key_cache );

    if ( !path_length )
        return;

    if ( path_length == 1 && path[ 0 ] == '\\' )
    {
        string_push_back( out, '\\' );
        return;
    }

    if ( path[ 1 ] == ':' &&
        ( path_length == 2 ||
        ( path_length == 3 && path[ 2 ] == '\\' ) ) )
    {
        string_push_back( out, toupper( path[ 0 ] ) );
        string_push_back( out, ':' );
        string_push_back( out, '\\' );
        return;
    }

    /* Find last '\\'. */
    for ( p = path + path_length - 1; p >= path && *p != '\\'; --p );
    last_element = p + 1;

    /* Special case '\' && 'D:\' - include trailing '\'. */
    if ( p == path ||
        p == path + 2 && path[ 1 ] == ':' )
        ++p;

    if ( p >= path )
    {
        char const * const dir = path;
        int const dir_length = p - path;
        OBJECT * const dir_obj = object_new_range( dir, dir_length );
        int found;
        path_key_entry * const result = (path_key_entry *)hash_insert(
            path_key_cache, dir_obj, &found );
        if ( !found )
        {
            result->path = dir_obj;
            canonicWindowsPath( dir, dir_length, out );
            result->key = object_new( out->value );
        }
        else
        {
            object_free( dir_obj );
            string_append( out, object_str( result->key ) );
        }
    }

    if ( out->size && out->value[ out->size - 1 ] != '\\' )
        string_push_back( out, '\\' );

    saved_size = out->size;
    string_append_range( out, last_element, path + path_length );

    {
        char const * const n = last_element;
        int const n_length = path + path_length - n;
        if ( !( n_length == 1 && n[ 0 ] == '.' )
            && !( n_length == 2 && n[ 0 ] == '.' && n[ 1 ] == '.' ) )
        {
            WIN32_FIND_DATA fd;
            HANDLE const hf = FindFirstFileA( out->value, &fd );
            if ( hf != INVALID_HANDLE_VALUE )
            {
                string_truncate( out, saved_size );
                string_append( out, fd.cFileName );
                FindClose( hf );
            }
        }
    }
}
Beispiel #21
0
void
path_build(
    PATHNAME *f,
    string  *file,
    int binding )
{
    file_build1( f, file );

    /* Don't prepend root if it's . or directory is rooted */
# if PATH_DELIM == '/'

    if ( f->f_root.len
        && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
        && !( f->f_dir.len && f->f_dir.ptr[0] == '/' ) )

# else /* unix */

    if ( f->f_root.len
        && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
        && !( f->f_dir.len && f->f_dir.ptr[0] == '/' )
        && !( f->f_dir.len && f->f_dir.ptr[0] == '\\' )
        && !( f->f_dir.len && f->f_dir.ptr[1] == ':' ) )

# endif /* unix */

    {
        string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len  );
        /* If 'root' already ends with path delimeter,
           don't add yet another one. */
        if ( ! is_path_delim( f->f_root.ptr[f->f_root.len-1] ) )
            string_push_back( file, as_path_delim( f->f_root.ptr[f->f_root.len] ) );
    }

    if ( f->f_dir.len )
        string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len  );

    /* UNIX: Put / between dir and file */
    /* NT:   Put \ between dir and file */

    if ( f->f_dir.len && ( f->f_base.len || f->f_suffix.len ) )
    {
        /* UNIX: Special case for dir \ : don't add another \ */
        /* NT:   Special case for dir / : don't add another / */

# if PATH_DELIM == '\\'
        if ( !( f->f_dir.len == 3 && f->f_dir.ptr[1] == ':' ) )
# endif
            if ( !( f->f_dir.len == 1 && is_path_delim( f->f_dir.ptr[0] ) ) )
                string_push_back( file, as_path_delim( f->f_dir.ptr[f->f_dir.len] ) );
    }

    if ( f->f_base.len )
    {
        string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len  );
    }

    if ( f->f_suffix.len )
    {
        string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len  );
    }

    if ( f->f_member.len )
    {
        string_push_back( file, '(' );
        string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len  );
        string_push_back( file, ')' );
    }
}
Beispiel #22
0
static void reportWindowsError( char const * const apiName, int slot )
{
    char * errorMessage;
    char buf[24];
    string * err_buf;
    timing_info time;
    DWORD const errorCode = GetLastError();
    DWORD apiResult = FormatMessageA(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |  /* __in      DWORD dwFlags       */
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,                             /* __in_opt  LPCVOID lpSource    */
        errorCode,                        /* __in      DWORD dwMessageId   */
        0,                                /* __in      DWORD dwLanguageId  */
        (LPSTR)&errorMessage,             /* __out     LPTSTR lpBuffer     */
        0,                                /* __in      DWORD nSize         */
        0 );                              /* __in_opt  va_list * Arguments */
    
    /* Build a message as if the process had written to stderr. */
    if ( globs.pipe_action )
        err_buf = cmdtab[ slot ].buffer_err;
    else
        err_buf = cmdtab[ slot ].buffer_out;
    string_append( err_buf, apiName );
    string_append( err_buf, "() Windows API failed: " );
    sprintf( buf, "%d", errorCode );
    string_append( err_buf, buf );

    if ( !apiResult )
        string_append( err_buf, ".\n" );
    else
    {
        string_append( err_buf, " - " );
        string_append( err_buf, errorMessage );
        /* Make sure that the buffer is terminated with a newline */
        if( err_buf->value[ err_buf->size - 1 ] != '\n' )
            string_push_back( err_buf, '\n' );
        LocalFree( errorMessage );
    }

    /* Since the process didn't actually start, use a blank timing_info. */
    time.system = 0;
    time.user = 0;
    timestamp_current( &time.start );
    timestamp_current( &time.end );

    /* Invoke the callback with a failure status. */
    (*cmdtab[ slot ].func)( cmdtab[ slot ].closure, EXEC_CMD_FAIL, &time,
        cmdtab[ slot ].buffer_out->value, cmdtab[ slot ].buffer_err->value,
        EXIT_OK );
    
    /* Clean up any handles that were opened. */
    closeWinHandle( &cmdtab[ slot ].pi.hProcess );
    closeWinHandle( &cmdtab[ slot ].pi.hThread );
    closeWinHandle( &cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_READ ] );
    closeWinHandle( &cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_WRITE ] );
    closeWinHandle( &cmdtab[ slot ].pipe_err[ EXECCMD_PIPE_READ ] );
    closeWinHandle( &cmdtab[ slot ].pipe_err[ EXECCMD_PIPE_WRITE ] );
    string_renew( cmdtab[ slot ].buffer_out );
    string_renew( cmdtab[ slot ].buffer_err );
}
Beispiel #23
0
int
var_string(
	char	*in,
	char	*out,
	int	outsize,
	LOL	*lol )
{
	char 	*out0 = out;
	char	*oute = out + outsize - 1;

	while( *in )
	{
	    char	*lastword;
	    int		dollar = 0;

	    /* Copy white space */

	    while( isspace( *in ) )
	    {
		if( out >= oute )
		    return -1;

		*out++ = *in++;
	    }

	    lastword = out;

	    /* Copy non-white space, watching for variables */

	    while( *in && !isspace( *in ) )
	    {
	        if( out >= oute )
		    return -1;

		if( in[0] == '$' && in[1] == '(' )
		    dollar++;
                #ifdef OPT_AT_FILES
                else if ( in[0] == '@' && in[1] == '(' )
                {
                    int depth = 1;
                    char *ine = in + 2;
                    char *split = 0;
                    
                    /* Scan the content of the response file @() section. */
                    
                    while( *ine && depth > 0 )
                    {
                        switch( *ine )
                        {
                        case '(':
                            ++depth;
                            break;
                        case ')':
                            --depth;
                            break;
                        case ':':
                            if( depth == 1 && ine[1] == 'E' && ine[2] == '=' )
                            {
                                split = ine;
                            }
                           break;
                        }
                        ++ine;
                    }
                    
                    if (!split)
                    {
                        printf( "no file specified!\n" );
                        exit( EXITBAD );
                    }
                    
                    if ( depth == 0 )
                    {
                        string file_name_v;
                        int file_name_l = 0;
                        const char * file_name_s = 0;
                        
                        /* expand the temporary file name var inline */
                        #if 0
                        string_copy(&file_name_v,"$(");
                        string_append_range(&file_name_v,in+2,split);
                        string_push_back(&file_name_v,')');
                        #else
                        string_new(&file_name_v);
                        string_append_range(&file_name_v,in+2,split);
                        #endif
                        file_name_l = var_string(file_name_v.value,out,oute-out+1,lol);
                        string_free(&file_name_v);
                        if ( file_name_l < 0 ) return -1;
                        file_name_s = out;
                        
                        /* for stdout/stderr we will create a temp file and generate
                           a command that outputs the content as needed. */
                        if ( strcmp( "STDOUT", out ) == 0 || strcmp( "STDERR", out ) == 0 )
                        {
                            int err_redir = strcmp( "STDERR", out ) == 0;
                            out[0] = '\0';
                            file_name_s = path_tmpfile();
                            file_name_l = strlen(file_name_s);
                            #ifdef OS_NT
                            if ( (out+7+file_name_l+(err_redir?5:0)) >= oute ) return -1;
                            sprintf( out,"type \"%s\"%s",
                                file_name_s,
                                err_redir ? " 1>&2" : "" );
                            #else
                            if ( (out+6+file_name_l+(err_redir?5:0)) >= oute ) return -1;
                            sprintf( out,"cat \"%s\"%s",
                                file_name_s,
                                err_redir ? " 1>&2" : "" );
                            #endif
                            /* we also make sure that the temp files created by this
                               get nuked eventually. */
                            file_remove_atexit( file_name_s );
                        }
                        
                        /* expand the file value into the file reference */
                        if ( !globs.noexec )
                            var_string_to_file( split+3, ine-split-4, file_name_s, lol );
                        
                        /* continue on with the expansion */
                        out += strlen(out);
                    }
                    
                    /* and continue with the parsing just past the @() reference */
                    in = ine;
                }
                #endif

		*out++ = *in++;
	    }

        /* Add zero to 'out' so that 'lastword' is correctly zero-terminated. */
        if (out >= oute)
            return -1;
        /* Don't increment, intentionally. */
        *out= '\0';
           
	    /* If a variable encountered, expand it and and embed the */
	    /* space-separated members of the list in the output. */

	    if( dollar )
	    {
		LIST	*l;

		l = var_expand( L0, lastword, out, lol, 0 );

		out = lastword;

		while ( l )
		{
		    int so = strlen( l->string );

		    if( out + so >= oute )
			return -1;

		    strcpy( out, l->string );
		    out += so;
		    l = list_next( l );
		    if ( l ) *out++ = ' ';
		}

		list_free( l );
	    }
	}

	if( out >= oute )
	    return -1;

	*out++ = '\0';

	return out - out0;
}
Beispiel #24
0
void
path_build(
	PATHNAME *f,
	string* file,
	int	binding )
{
    int dflag, rflag, act;

    file_build1( f, file );
	
    /* Combine root & directory, according to the grid. */
	
    dflag = file_flags( f->f_dir.ptr, f->f_dir.len );
    rflag = file_flags( f->f_root.ptr, f->f_root.len );
	
    switch( act = grid[ rflag ][ dflag ] )
    {
    case G_DTDR:
        {
            /* :: of rel dir */
            string_push_back( file, DELIM );
        }
        /* fall through */
		
    case G_DIR: 	
        /* take dir */
        string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len  );
        break;
		
    case G_ROOT:	
        /* take root */
        string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len  );
        break;
	    
    case G_CAT:	
        /* prepend root to dir */
        string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len  );
        if( file->value[file->size - 1] == DELIM )
            string_pop_back( file );
        string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len  );
        break;
	
    case G_DDDD:	
        /* make it ::: (../..) */
        string_append( file, ":::" );
        break;
    }

    /* Put : between dir and file (if none already) */
	
    if( act != G_MT && 
        file->value[file->size - 1] != DELIM && 
        ( f->f_base.len || f->f_suffix.len ) )
    {
        string_push_back( file, DELIM );
    }

    if( f->f_base.len )
    {
        string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len  );
    }

    if( f->f_suffix.len )
    {
        string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len  );
    }

    if( f->f_member.len )
    {
        string_push_back( file, '(' );
        string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len  );
        string_push_back( file, ')' );
    }
	
    if( DEBUG_SEARCH )
        printf(" -> '%s'\n", file->value);
}
Beispiel #25
0
void ShortPathToLongPath( char * short_path, string * out )
{
    const char * new_element;
    unsigned long saved_size;
    char * p;

    if ( short_path[0] == '\0' )
    {
        return;
    }

    if ( short_path[0] == '\\' && short_path[1] == '\0')
    {
        string_push_back( out, '\\' );
        return;
    }

    if ( short_path[1] == ':' &&
        ( short_path[2] == '\0' ||
        ( short_path[2] == '\\' && short_path[3] == '\0' ) ) )
    {
        string_push_back( out, toupper( short_path[0] ) );
        string_push_back( out, ':' );
        string_push_back( out, '\\' );
        return;
    }
    
    /* '/' already handled. */
    if ( ( p = strrchr( short_path, '\\' ) ) )
    {
        char saved;
        new_element = p + 1;

        /* special case \ */
        if ( p == short_path )
            ++p;
        
        /* special case D:\ */
        if ( p == short_path + 2  && short_path[1] == ':' )
            ++p;

        saved = *p;
        *p = '\0';
        path_write_key( short_path, out );
        *p = saved;
    }
    else
    {
        new_element = short_path;
    }

    if ( out->size && out->value[ out->size - 1 ] != '\\' )
    {
        string_push_back( out, '\\' );
    }
    
    saved_size = out->size;
    string_append( out, new_element );

    if ( ! ( new_element[0] == '.' && new_element[1] == '\0' ||
        new_element[0] == '.' && new_element[1] == '.'
        && new_element[2] == '\0' ) )
    {
        WIN32_FIND_DATA fd;
        HANDLE hf = 0;
        hf = FindFirstFile( out->value, &fd );

        /* If the file exists, replace the name. */
        if ( hf != INVALID_HANDLE_VALUE )
        {
            string_truncate( out, saved_size );
            string_append( out, fd.cFileName );
            FindClose( hf );
        }
    }
}