示例#1
0
/*
 * printerror
 *
 * format a nice and consistent error string using the errno to string
 * conversion utilities and the arguments supplied
 */
void printerror(const int ecode, char *(*error_itoa)(int),
		const char *func, const char *format, ...)
{
  char     message[512];
  char     err[128];
  char     ts[16];
  char     fs[64];
  va_list  ap;

  va_start(ap, format);
  vsnprintf(message, sizeof(message), format, ap);
  va_end(ap);

  error_str(ecode, error_itoa, err, sizeof(err));
  timestamp_str(ts, sizeof(ts));

  if(func != NULL) snprintf(fs, sizeof(fs), "%s: ", func);
  else             fs[0] = '\0';

  fprintf(stderr, "%s%s%s%s\n", ts, fs, message, err);
  fflush(stderr);

#ifndef WITHOUT_DEBUGFILE
  if(debugfile != NULL)
    {
      fprintf(debugfile, "%s%s%s%s\n", ts, fs, message, err);
      fflush(debugfile);
    }
#endif

  return;
}
示例#2
0
void scamper_debug(const char *func, const char *format, ...)
{
  char     message[512];
  va_list  ap;
  char     ts[16];
  char     fs[64];

#if !defined(WITHOUT_DEBUGFILE) && defined(NDEBUG)
  if(debugfile == NULL)
    return;
#endif

  assert(format != NULL);

  va_start(ap, format);
  vsnprintf(message, sizeof(message), format, ap);
  va_end(ap);

  timestamp_str(ts, sizeof(ts));

  if(func != NULL) snprintf(fs, sizeof(fs), "%s: ", func);
  else             fs[0] = '\0';

#ifndef NDEBUG
  fprintf(stderr, "%s%s%s\n", ts, fs, message);
  fflush(stderr);
#endif

#ifndef WITHOUT_DEBUGFILE
  if(debugfile != NULL)
    {
      fprintf(debugfile, "%s%s%s\n", ts, fs, message);
      fflush(debugfile);
    }
#endif

  return;
}
示例#3
0
void __scamper_assert(const char *file, int line, const char *func,
		      const char *expr, void *data)
{
  char ts[16];

  timestamp_str(ts, sizeof(ts));

  fprintf(stderr, "%s assertion failed: %s:%d %s `%s'\n",
	  ts, file, line, func, expr);
  fflush(stderr);

#ifndef WITHOUT_DEBUGFILE
  if(debugfile != NULL)
    {
      fprintf(debugfile, "%s assertion failed: %s:%d %s `%s'\n",
	      ts, file, line, func, expr);
      fflush(debugfile);
    }
#endif

  abort();
  return;
}
示例#4
0
OBJECT * outf_time( timestamp const * const time )
{
    return object_new( timestamp_str( time ) );
}
示例#5
0
文件: svn.cpp 项目: obarthel/Gource
bool SVNCommitLog::parseCommit(RCommit& commit) {

    //fprintf(stderr,"parsing svn log\n");

    std::string line;

    if(!getNextLine(line)) return false;

    //start of log entry
    if(!svn_logentry_start.match(line)) {

        //is this the start of the document
        if(!svn_xml_tag.match(line)) return false;

        //fprintf(stderr,"found xml tag\n");

        //if so find the first logentry tag

        bool found_logentry = false;

        while(getNextLine(line)) {
            if(svn_logentry_start.match(line)) {
                found_logentry = true;
                break;
            }
        }

        if(!found_logentry) return false;
    }

    //fprintf(stderr,"found logentry\n");

    logentry.clear();

    logentry.append(line);
    logentry.append("\n");

    //fprintf(stderr,"found opening tag\n");

    bool endfound = false;

    while(getNextLine(line)) {
        logentry.append(line);
        logentry.append("\n");
        if(svn_logentry_end.match(line)) {
            //fprintf(stderr,"found closing tag\n");
            endfound=true;
            break;
        }
    }

    //incomplete commit
    if(!endfound) return false;

    //fprintf(stderr,"read logentry\n");

    TiXmlDocument doc;

    if(!doc.Parse(logentry.c_str())) return false;

    //fprintf(stderr,"try to parse logentry: %s\n", logentry.c_str());

    TiXmlElement* leE = doc.FirstChildElement( "logentry" );

    std::vector<std::string> entries;

    if(!leE) return false;

    //parse date
    TiXmlElement* dateE = leE->FirstChildElement( "date" );

    if(!dateE) return false;

    std::string timestamp_str(dateE->GetText());

    if(!svn_logentry_timestamp.match(timestamp_str, &entries))
        return false;

    struct tm time_str;

    time_str.tm_year  = atoi(entries[0].c_str()) - 1900;
    time_str.tm_mon   = atoi(entries[1].c_str()) - 1;
    time_str.tm_mday  = atoi(entries[2].c_str());
    time_str.tm_hour  = atoi(entries[3].c_str());
    time_str.tm_min   = atoi(entries[4].c_str());
    time_str.tm_sec   = atoi(entries[5].c_str());
    time_str.tm_isdst = -1;

#ifdef HAVE_TIMEGM
    commit.timestamp = timegm(&time_str);
#else
    commit.timestamp = __timegm_hack(&time_str);
#endif

    //parse author
    TiXmlElement* authorE = leE->FirstChildElement("author");

    if(authorE != 0) {
		// GetText() may return NULL, causing author instantiation to crash.
        std::string author(authorE->GetText() ? authorE->GetText() : "Unknown");

        if(author.empty()) author = "Unknown";

        commit.username = author;
    }

    TiXmlElement* pathsE = leE->FirstChildElement( "paths" );

    //log entries sometimes dont have any paths
    if(!pathsE) return true;

    //parse changes

    for(TiXmlElement* pathE = pathsE->FirstChildElement("path"); pathE != 0; pathE = pathE->NextSiblingElement()) {
        //parse path

        const char* kind   = pathE->Attribute("kind");
        const char* action = pathE->Attribute("action");

        //check for action
        if(action == 0) continue;

        bool is_dir = false;

        //if has the 'kind' attribute (old versions of svn dont have this), check if it is a dir
        if(kind != 0 && strcmp(kind,"dir") == 0) {

            //accept only deletes for directories
            if(strcmp(action, "D") != 0) continue;

            is_dir = true;
        }

        std::string file(pathE->GetText());
        std::string status(action);

        if(file.empty()) continue;
        if(status.empty()) continue;

        //append trailing slash if is directory
        if(is_dir && file[file.size()-1] != '/') {
            file = file + std::string("/");
        }

        commit.addFile(file, status);
    }

    //fprintf(stderr,"parsed logentry\n");

    //read files

    return true;
}
示例#6
0
bool CVS2CLCommitLog::parseCommit(RCommit& commit) {

    //fprintf(stderr,"parsing cvs2cl log\n");

    std::string line;

    if(!getNextLine(line)) return false;

    //start of log entry
    if(!cvs2cl_logentry_start.match(line)) {

        //is this the start of the document
        if(!cvs2cl_xml_tag.match(line)) return false;

        //fprintf(stderr,"found xml tag\n");

        //if so find the first logentry tag

        bool found_logentry = false;
        
        while(getNextLine(line)) {
            if(cvs2cl_logentry_start.match(line)) {
                found_logentry = true;
                break;
            }
        }

        if(!found_logentry) return false;   
    }

    //fprintf(stderr,"found logentry\n");

    logentry.clear();

    logentry.append(line);
    logentry.append("\n");

    //fprintf(stderr,"found opening tag\n");

    bool endfound = false;
    
    while(getNextLine(line)) {
        logentry.append(line);
        logentry.append("\n");
        if(cvs2cl_logentry_end.match(line)) {
            //fprintf(stderr,"found closing tag\n");
            endfound=true;
            break;
        }
    }

    //incomplete commit
    if(!endfound) return false;

    //fprintf(stderr,"read logentry\n");

    TiXmlDocument doc;

    if(!doc.Parse(logentry.c_str())) return false;

    //fprintf(stderr,"try to parse logentry: %s\n", logentry.c_str());
    
    TiXmlElement* leE = doc.FirstChildElement( "entry" );
    
    std::vector<std::string> entries;
    
    if(!leE) return false;

    //parse date
    TiXmlElement* dateE = leE->FirstChildElement( "isoDate" );

    if(!dateE) return false;

    std::string timestamp_str(dateE->GetText());

    if(!cvs2cl_logentry_timestamp.match(timestamp_str, &entries))
        return false;
                    
    struct tm time_str;

    time_str.tm_year  = atoi(entries[0].c_str()) - 1900;
    time_str.tm_mon   = atoi(entries[1].c_str()) - 1;
    time_str.tm_mday  = atoi(entries[2].c_str());
    time_str.tm_hour  = atoi(entries[3].c_str());
    time_str.tm_min   = atoi(entries[4].c_str());
    time_str.tm_sec   = atoi(entries[5].c_str());
    time_str.tm_isdst = -1;

    commit.timestamp = mktime(&time_str);            
   
    //parse author
    TiXmlElement* authorE = leE->FirstChildElement("author");
    
    if(authorE != 0) {
    
        std::string author(authorE->GetText());

        if(author.empty()) author = "Unknown";
    
        commit.username = author;
    }

    //parse changes
    
    for(TiXmlElement* fileE = leE->FirstChildElement("file"); fileE != 0; fileE = fileE->NextSiblingElement()) {
        
        TiXmlElement* state = fileE->FirstChildElement("cvsstate");
        TiXmlElement* name  = fileE->FirstChildElement("name");

        //check for state
        if(name == 0 || state == 0) continue;

        std::string status = strcmp(state->GetText(), "dead") == 0 ? "D" : "M";
        std::string file(name->GetText());

        if(file.empty()) continue;
        
        commit.addFile(file, status);
    }
    
    //fprintf(stderr,"parsed logentry\n");

    //read files
    
    return true;
}
示例#7
0
void make0
(
    TARGET * t,
    TARGET * p,       /* parent */
    int      depth,   /* for display purposes */
    COUNTS * counts,  /* for reporting */
    int      anyhow,
    TARGET * rescanning
)  /* forcibly touch all (real) targets */
{
    TARGETS    * c;
    TARGET     * ptime = t;
    TARGET     * located_target = 0;
    timestamp    last;
    timestamp    leaf;
    timestamp    hlast;
    int          fate;
    char const * flag = "";
    SETTINGS   * s;

#ifdef OPT_GRAPH_DEBUG_EXT
    int savedFate;
    int oldTimeStamp;
#endif

    if ( DEBUG_MAKEPROG )
        out_printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );

    /*
     * Step 1: Initialize.
     */

    if ( DEBUG_MAKEPROG )
        out_printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );

    t->fate = T_FATE_MAKING;
    t->depth = depth;

    /*
     * Step 2: Under the influence of "on target" variables, bind the target and
     * search for headers.
     */

    /* Step 2a: Set "on target" variables. */
    s = copysettings( t->settings );
    pushsettings( root_module(), s );

    /* Step 2b: Find and timestamp the target file (if it is a file). */
    if ( ( t->binding == T_BIND_UNBOUND ) && !( t->flags & T_FLAG_NOTFILE ) )
    {
        OBJECT * another_target;
        object_free( t->boundname );
        t->boundname = search( t->name, &t->time, &another_target,
            t->flags & T_FLAG_ISFILE );
        /* If it was detected that this target refers to an already existing and
         * bound target, we add a dependency so that every target depending on
         * us will depend on that other target as well.
         */
        if ( another_target )
            located_target = bindtarget( another_target );

        t->binding = timestamp_empty( &t->time )
            ? T_BIND_MISSING
            : T_BIND_EXISTS;
    }

    /* INTERNAL, NOTFILE header nodes have the time of their parents. */
    if ( p && ( t->flags & T_FLAG_INTERNAL ) )
        ptime = p;

    /* If temp file does not exist but parent does, use parent. */
    if ( p && ( t->flags & T_FLAG_TEMP ) &&
        ( t->binding == T_BIND_MISSING ) &&
        ( p->binding != T_BIND_MISSING ) )
    {
        t->binding = T_BIND_PARENTS;
        ptime = p;
    }

#ifdef OPT_SEMAPHORE
    {
        LIST * var = var_get( root_module(), constant_JAM_SEMAPHORE );
        if ( !list_empty( var ) )
        {
            TARGET * const semaphore = bindtarget( list_front( var ) );
            semaphore->progress = T_MAKE_SEMAPHORE;
            t->semaphore = semaphore;
        }
    }
#endif

    /* Step 2c: If its a file, search for headers. */
    if ( t->binding == T_BIND_EXISTS )
        headers( t );

    /* Step 2d: reset "on target" variables. */
    popsettings( root_module(), s );
    freesettings( s );

    /*
     * Pause for a little progress reporting.
     */

    if ( DEBUG_BIND )
    {
        if ( !object_equal( t->name, t->boundname ) )
            out_printf( "bind\t--\t%s%s: %s\n", spaces( depth ),
                object_str( t->name ), object_str( t->boundname ) );

        switch ( t->binding )
        {
        case T_BIND_UNBOUND:
        case T_BIND_MISSING:
        case T_BIND_PARENTS:
            out_printf( "time\t--\t%s%s: %s\n", spaces( depth ),
                object_str( t->name ), target_bind[ (int)t->binding ] );
            break;

        case T_BIND_EXISTS:
            out_printf( "time\t--\t%s%s: %s\n", spaces( depth ),
                object_str( t->name ), timestamp_str( &t->time ) );
            break;
        }
    }

    /*
     * Step 3: Recursively make0() dependencies & headers.
     */

    /* Step 3a: Recursively make0() dependencies. */
    for ( c = t->depends; c; c = c->next )
    {
        int const internal = t->flags & T_FLAG_INTERNAL;

        /* Warn about circular deps, except for includes, which include each
         * other alot.
         */
        if ( c->target->fate == T_FATE_INIT )
            make0( c->target, ptime, depth + 1, counts, anyhow, rescanning );
        else if ( c->target->fate == T_FATE_MAKING && !internal )
            out_printf( "warning: %s depends on itself\n", object_str(
                c->target->name ) );
        else if ( c->target->fate != T_FATE_MAKING && rescanning )
            make0rescan( c->target, rescanning );
        if ( rescanning && c->target->includes && c->target->includes->fate !=
            T_FATE_MAKING )
            make0rescan( target_scc( c->target->includes ), rescanning );
    }

    if ( located_target )
    {
        if ( located_target->fate == T_FATE_INIT )
            make0( located_target, ptime, depth + 1, counts, anyhow, rescanning
                );
        else if ( located_target->fate != T_FATE_MAKING && rescanning )
            make0rescan( located_target, rescanning );
    }

    /* Step 3b: Recursively make0() internal includes node. */
    if ( t->includes )
        make0( t->includes, p, depth + 1, counts, anyhow, rescanning );

    /* Step 3c: Add dependencies' includes to our direct dependencies. */
    {
        TARGETS * incs = 0;
        for ( c = t->depends; c; c = c->next )
            if ( c->target->includes )
                incs = targetentry( incs, c->target->includes );
        t->depends = targetchain( t->depends, incs );
    }

    if ( located_target )
        t->depends = targetentry( t->depends, located_target );

    /* Step 3d: Detect cycles. */
    {
        int cycle_depth = depth;
        for ( c = t->depends; c; c = c->next )
        {
            TARGET * scc_root = target_scc( c->target );
            if ( scc_root->fate == T_FATE_MAKING &&
                ( !scc_root->includes ||
                  scc_root->includes->fate != T_FATE_MAKING ) )
            {
                if ( scc_root->depth < cycle_depth )
                {
                    cycle_depth = scc_root->depth;
                    t->scc_root = scc_root;
                }
            }
        }
    }

    /*
     * Step 4: Compute time & fate.
     */

    /* Step 4a: Pick up dependencies' time and fate. */
    timestamp_clear( &last );
    timestamp_clear( &leaf );
    fate = T_FATE_STABLE;
    for ( c = t->depends; c; c = c->next )
    {
        /* If we are in a different strongly connected component, pull
         * timestamps from the root.
         */
        if ( c->target->scc_root )
        {
            TARGET * const scc_root = target_scc( c->target );
            if ( scc_root != t->scc_root )
            {
                timestamp_max( &c->target->leaf, &c->target->leaf,
                    &scc_root->leaf );
                timestamp_max( &c->target->time, &c->target->time,
                    &scc_root->time );
                c->target->fate = max( c->target->fate, scc_root->fate );
            }
        }

        /* If LEAVES has been applied, we only heed the timestamps of the leaf
         * source nodes.
         */
        timestamp_max( &leaf, &leaf, &c->target->leaf );
        if ( t->flags & T_FLAG_LEAVES )
        {
            timestamp_copy( &last, &leaf );
            continue;
        }
        timestamp_max( &last, &last, &c->target->time );
        fate = max( fate, c->target->fate );

#ifdef OPT_GRAPH_DEBUG_EXT
        if ( DEBUG_FATE )
            if ( fate < c->target->fate )
                out_printf( "fate change %s from %s to %s by dependency %s\n",
                    object_str( t->name ), target_fate[ (int)fate ],
                    target_fate[ (int)c->target->fate ], object_str(
                    c->target->name ) );
#endif
    }

    /* Step 4b: Pick up included headers time. */

    /*
     * If a header is newer than a temp source that includes it, the temp source
     * will need building.
     */
    if ( t->includes )
        timestamp_copy( &hlast, &t->includes->time );
    else
        timestamp_clear( &hlast );

    /* Step 4c: handle NOUPDATE oddity.
     *
     * If a NOUPDATE file exists, mark it as having eternally old dependencies.
     * Do not inherit our fate from our dependencies. Decide fate based only on
     * other flags and our binding (done later).
     */
    if ( t->flags & T_FLAG_NOUPDATE )
    {
#ifdef OPT_GRAPH_DEBUG_EXT
        if ( DEBUG_FATE )
            if ( fate != T_FATE_STABLE )
                out_printf( "fate change  %s back to stable, NOUPDATE.\n",
                    object_str( t->name ) );
#endif

        timestamp_clear( &last );
        timestamp_clear( &t->time );

        /* Do not inherit our fate from our dependencies. Decide fate based only
         * upon other flags and our binding (done later).
         */
        fate = T_FATE_STABLE;
    }

    /* Step 4d: Determine fate: rebuild target or what? */

    /*
        In English:
        If can not find or make child, can not make target.
        If children changed, make target.
        If target missing, make it.
        If children newer, make target.
        If temp's children newer than parent, make temp.
        If temp's headers newer than parent, make temp.
        If deliberately touched, make it.
        If up-to-date temp file present, use it.
        If target newer than non-notfile parent, mark target newer.
        Otherwise, stable!

        Note this block runs from least to most stable: as we make it further
        down the list, the target's fate gets more stable.
    */

#ifdef OPT_GRAPH_DEBUG_EXT
    savedFate = fate;
    oldTimeStamp = 0;
#endif

    if ( fate >= T_FATE_BROKEN )
    {
        fate = T_FATE_CANTMAKE;
    }
    else if ( fate >= T_FATE_SPOIL )
    {
        fate = T_FATE_UPDATE;
    }
    else if ( t->binding == T_BIND_MISSING )
    {
        fate = T_FATE_MISSING;
    }
    else if ( t->binding == T_BIND_EXISTS && timestamp_cmp( &last, &t->time ) >
        0 )
    {
#ifdef OPT_GRAPH_DEBUG_EXT
        oldTimeStamp = 1;
#endif
        fate = T_FATE_OUTDATED;
    }
    else if ( t->binding == T_BIND_PARENTS && timestamp_cmp( &last, &p->time ) >
        0 )
    {
#ifdef OPT_GRAPH_DEBUG_EXT
        oldTimeStamp = 1;
#endif
        fate = T_FATE_NEEDTMP;
    }
    else if ( t->binding == T_BIND_PARENTS && timestamp_cmp( &hlast, &p->time )
        > 0 )
    {
        fate = T_FATE_NEEDTMP;
    }
    else if ( t->flags & T_FLAG_TOUCHED )
    {
        fate = T_FATE_TOUCHED;
    }
    else if ( anyhow && !( t->flags & T_FLAG_NOUPDATE ) )
    {
        fate = T_FATE_TOUCHED;
    }
    else if ( t->binding == T_BIND_EXISTS && ( t->flags & T_FLAG_TEMP ) )
    {
        fate = T_FATE_ISTMP;
    }
    else if ( t->binding == T_BIND_EXISTS && p && p->binding != T_BIND_UNBOUND
        && timestamp_cmp( &t->time, &p->time ) > 0 )
    {
#ifdef OPT_GRAPH_DEBUG_EXT
        oldTimeStamp = 1;
#endif
        fate = T_FATE_NEWER;
    }
    else
    {
        fate = T_FATE_STABLE;
    }
#ifdef OPT_GRAPH_DEBUG_EXT
    if ( DEBUG_FATE && ( fate != savedFate ) )
	{
        if ( savedFate == T_FATE_STABLE )
            out_printf( "fate change  %s set to %s%s\n", object_str( t->name ),
                target_fate[ fate ], oldTimeStamp ? " (by timestamp)" : "" );
        else
            out_printf( "fate change  %s from %s to %s%s\n", object_str( t->name ),
                target_fate[ savedFate ], target_fate[ fate ], oldTimeStamp ?
                " (by timestamp)" : "" );
	}
#endif

    /* Step 4e: Handle missing files. */
    /* If it is missing and there are no actions to create it, boom. */
    /* If we can not make a target we do not care about it, okay. */
    /* We could insist that there are updating actions for all missing */
    /* files, but if they have dependencies we just pretend it is a NOTFILE. */

    if ( ( fate == T_FATE_MISSING ) && !t->actions && !t->depends )
    {
        if ( t->flags & T_FLAG_NOCARE )
        {
#ifdef OPT_GRAPH_DEBUG_EXT
            if ( DEBUG_FATE )
                out_printf( "fate change %s to STABLE from %s, "
                    "no actions, no dependencies and do not care\n",
                    object_str( t->name ), target_fate[ fate ] );
#endif
            fate = T_FATE_STABLE;
        }
        else
        {
            out_printf( "don't know how to make %s\n", object_str( t->name ) );
            fate = T_FATE_CANTFIND;
        }
    }

    /* Step 4f: Propagate dependencies' time & fate. */
    /* Set leaf time to be our time only if this is a leaf. */

    timestamp_max( &t->time, &t->time, &last );
    timestamp_copy( &t->leaf, timestamp_empty( &leaf ) ? &t->time : &leaf );
    /* This target's fate may have been updated by virtue of following some
     * target's rebuilds list, so only allow it to be increased to the fate we
     * have calculated. Otherwise, grab its new fate.
     */
    if ( fate > t->fate )
        t->fate = fate;
    else
        fate = t->fate;

    /*
     * Step 4g: If this target needs to be built, make0 all targets
     * that are updated by the same actions used to update this target.
     * These have already been marked as REBUILDS, and make1 has
     * special handling for them.  We just need to make sure that
     * they get make0ed.
     */
    if ( ( fate >= T_FATE_BUILD ) && ( fate < T_FATE_BROKEN ) )
    {
        ACTIONS * a;
        TARGETS * c;
        for ( a = t->actions; a; a = a->next )
        {
            for ( c = a->action->targets; c; c = c->next )
            {
                if ( c->target->fate == T_FATE_INIT )
                {
                    make0( c->target, ptime, depth + 1, counts, anyhow, rescanning );
                }
            }
        }
    }

    /* Step 4h: If this target needs to be built, force rebuild everything in
     * its rebuilds list.
     */
    if ( ( fate >= T_FATE_BUILD ) && ( fate < T_FATE_BROKEN ) )
        force_rebuilds( t );

    /*
     * Step 5: Sort dependencies by their update time.
     */

    if ( globs.newestfirst )
        t->depends = make0sort( t->depends );

    /*
     * Step 6: A little harmless tabulating for tracing purposes.
     */

    /* Do not count or report interal includes nodes. */
    if ( t->flags & T_FLAG_INTERNAL )
        return;

    if ( counts )
    {
#ifdef OPT_IMPROVED_PATIENCE_EXT
        ++counts->targets;
#else
        if ( !( ++counts->targets % 1000 ) && DEBUG_MAKE )
        {
            out_printf( "...patience...\n" );
            out_flush();
        }
#endif

        if ( fate == T_FATE_ISTMP )
            ++counts->temp;
        else if ( fate == T_FATE_CANTFIND )
            ++counts->cantfind;
        else if ( ( fate == T_FATE_CANTMAKE ) && t->actions )
            ++counts->cantmake;
        else if ( ( fate >= T_FATE_BUILD ) && ( fate < T_FATE_BROKEN ) &&
            t->actions )
            ++counts->updating;
    }

    if ( !( t->flags & T_FLAG_NOTFILE ) && ( fate >= T_FATE_SPOIL ) )
        flag = "+";
    else if ( t->binding == T_BIND_EXISTS && p && timestamp_cmp( &t->time,
        &p->time ) > 0 )
        flag = "*";

    if ( DEBUG_MAKEPROG )
        out_printf( "made%s\t%s\t%s%s\n", flag, target_fate[ (int)t->fate ],
            spaces( depth ), object_str( t->name ) );
}