예제 #1
0
파일: async.c 프로젝트: Elohim/FGmud
void *dbexecthread(struct request *req){
	pthread_mutex_lock(db_mut);
	db_t *db = find_db_conn((int)req->buf);
	int ret = -1;
	if (db->type->execute) {
		if (db->type->cleanup) {
			db->type->cleanup(&(db->c));
		}

		ret = db->type->execute(&(db->c), req->tmp.u.string);
		if (ret == -1){
			if(db->type->error) {
				char *tmp;
				strncpy(req->path, tmp = db->type->error(&(db->c)), MAXPATHLEN-1);
				FREE_MSTR(tmp);
			} else {
				strcpy(req->path, "Unknown error");
			}
		}
	} else {
		strcpy(req->path, "No database exec function!");
	}
	pthread_mutex_unlock(db_mut);

	req->ret = ret;
	req->status = DONE;
	return NULL;
}
예제 #2
0
파일: file.c 프로젝트: Elohim/FGmud
char *read_bytes (const char * file, int start, int len, int * rlen)
{
    struct stat st;
    FILE *fptr;
    char *str;
    int size;

    if (len < 0)
        return 0;
    file = check_valid_path(file, current_object,
                            "read_bytes", 0);
    if (!file)
        return 0;
    fptr = fopen(file, "rb");
    if (fptr == NULL)
        return 0;
    if (fstat(fileno(fptr), &st) == -1)
        fatal("Could not stat an open file.\n");
    size = st.st_size;
    if (start < 0)
        start = size + start;

    if (len == 0)
        len = size;
    if (len > MAX_BYTE_TRANSFER) {
        fclose(fptr);
        error("Transfer exceeded maximum allowed number of bytes.\n");
        return 0;
    }
    if (start >= size) {
        fclose(fptr);
        return 0;
    }
    if ((start + len) > size)
        len = (size - start);

    if ((size = fseek(fptr, start, 0)) < 0) {
        fclose(fptr);
        return 0;
    }
    
    str = new_string(len, "read_bytes: str");

    size = fread(str, 1, len, fptr);

    fclose(fptr);

    if (size <= 0) {
        FREE_MSTR(str);
        return 0;
    }
    /*
     * The string has to end to '\0'!!!
     */
    str[size] = '\0';

    *rlen = size;
    return str;
}
예제 #3
0
파일: file.c 프로젝트: Elohim/FGmud
int file_size (const char * file)
{
    struct stat st;
    long ret;
#ifdef WIN32
    char *t;
    int needs_free = 0, len;
    const char *p;
#endif

    file = check_valid_path(file, current_object, "file_size", 0);
    if (!file)
        return -1;

#ifdef WIN32
    len = strlen(file);
    p = file + len - 1;
    if (*p == '/') {
        needs_free = 1;
        p = file;
        t = new_string(len - 1, "file_size");
        memcpy(t, p, len - 1);
        t[len-1] = 0;
        file = t;
    }
#endif

    if (stat(file, &st) == -1)
        ret = -1;
    else if (S_IFDIR & st.st_mode)
        ret = -2;
    else 
        ret = st.st_size;

#ifdef WIN32
    if (needs_free) FREE_MSTR(file);
#endif
    
    return ret;
}
예제 #4
0
static void pop_sprintf_state (void) {
    sprintf_state_t *state;

    state = sprintf_state;
    sprintf_state = sprintf_state->next;

    if (state->obuff.buffer) {
        FREE_MSTR(state->obuff.buffer);
    }
    while (state->csts) {
        cst *next = state->csts->next;
        if (!(state->csts->info & INFO_COLS) && state->csts->d.tab) {
            FREE(state->csts->d.tab);
        }
        FREE(state->csts);
        state->csts = next;
    }
    if (state->clean.type != T_NUMBER) {
        free_svalue(&(state->clean), "pop_sprintf_state");
    }

    FREE(state);
}
예제 #5
0
파일: dwlib.c 프로젝트: Yuffster/fluffOS
/* Hideous mangling of C code by Taffyd. */ 
void query_multiple_short(svalue_t * arg, const char * type, int no_dollars, int quiet, int dark, int num_arg) { 
    char m[] = "$M$";
    char s[] = "_short";
    char default_function[] = "a_short";
    char separator[] = ", ";
    char andsep[] = " and ";
    int mlen = strlen(m);
    int slen = strlen(s);
    int seplen = strlen( separator );
    int andlen = strlen( andsep );

    array_t *arr = arg->u.arr;
    svalue_t *sv;
    svalue_t *v;
    int size = arr->size;
    int i;
    int len;
    int total_len;
    char *str, *res;
    object_t *ob;
    char *fun; 

    if (!size) {
        str = new_string(0, "f_query_multiple_short");
        str[0] = '\0';
        pop_n_elems(num_arg);
        push_malloced_string(str);
        return; 
    }
    
    /* 
    if (no_dollars && sizeof(args) && objectp(args[0]) && undefinedp(dark) && 
        this_player() && environment(this_player())) {
        dark = this_player()->check_dark(environment(this_player())->query_light());
        if (dark) {
        return "some objects you cannot make out";
        }
    } */ 

    if (no_dollars && arr->item->type == T_OBJECT && !dark && command_giver &&
        command_giver->super) { 
        call_origin = ORIGIN_EFUN;
        if(!apply_low("query_light", command_giver->super, 0))
            push_number(0);
        v = apply("check_dark", command_giver, 1, ORIGIN_EFUN);
        
        if (v && v->type == T_NUMBER && v->u.number) {
            pop_n_elems(num_arg);
            copy_and_push_string("some objects you cannot make out"); 
            return;
        }
    }

    /* If we don't have a type parameter, then use default_function */ 
    /* We need to free this value with FREE_MSTR() */ 

    if ( !type ) { 
        len = strlen( default_function );
        fun = new_string( len, "f_query_multiple_short");
        fun[len] = '\0';
        strncpy( fun, default_function, len );
    }
    else { 
        len = strlen( type ) + slen;
        fun = new_string( len, "f_query_multiple_short");
        fun[len] = '\0';
        strncpy( fun, type, len );
        strncpy( fun + strlen( type ), s, slen);
    }
   
    /* Check to see if there are any non-objects in the array. */ 
    for (i = 0; i < size; i++) {
        if ((arr->item + i)->type != T_OBJECT) {
            break;
        }
    }

    /* The array consists only of objects, and will use the $M$ 
       expansion code. */ 
    if (i == size && !no_dollars) {
        str = new_string(max_string_length, "f_query_multiple_short");
        str[max_string_length]= '\0';
        strncpy(str, m, mlen);
        total_len = mlen;

        for ( i = 0; i < size; i++ ) {
            sv = (arr->item + i);
            push_number(quiet);
            v = apply(fun, sv->u.ob, 1, ORIGIN_EFUN);

            if (!v || v->type != T_STRING) {
                continue;                
            }
            if(total_len + SVALUE_STRLEN(v) > max_string_length - mlen)
                continue;
            strncpy(str + total_len, v->u.string, (len = SVALUE_STRLEN(v)));
            total_len += len;
        }

        strncpy(str + total_len, m, mlen);
        total_len += mlen;

        res = new_string( total_len, "f_query_multiple_short" );
        res[ total_len ] = '\0';
        memcpy(res, str, total_len);

        /* Clean up our temporary buffer. */ 

        FREE_MSTR(str);
        FREE_MSTR(fun);

        pop_n_elems(num_arg);
        push_malloced_string(res);
        return;
    }

    /* This is a mixed array, so we don't use $M$ format.  Instead, we 
       do as much $a_short$ conversion as we can etc.  */ 

    str = new_string(max_string_length, "f_query_multiple_short");
    str[max_string_length]= '\0';
    total_len = 0;

    for ( i = 0; i < size; i++ ) {
        sv = (arr->item + i);
    
        switch(sv->type) {
            case T_STRING:
                len = SVALUE_STRLEN(sv);
                if(total_len + len < max_string_length){
                    strncpy(str + total_len, sv->u.string, len);
                    total_len += len;
                }
                break;
            case T_OBJECT:
                push_number(quiet);
                v = apply(fun, sv->u.ob, 1, ORIGIN_EFUN);

                if (!v || v->type != T_STRING) {
                    continue;                
                }

                if(total_len + SVALUE_STRLEN(v) < max_string_length){
                    strncpy(str + total_len, v->u.string, 
                            (len = SVALUE_STRLEN(v)));
                    total_len += len;
                }

                break;
            case T_ARRAY:
              /* Does anyone use this? */ 
              /* args[ i ] = "$"+ type +"_short:"+ file_name( args[ i ][ 1 ] ) +"$"; */ 
            default:    
                /* Get the next element. */ 
                continue;            
                break;
        }
        
        if ( len && size > 1 ) {
            if ( i < size - 2 ) {
                if(total_len+seplen < max_string_length){
                    strncpy( str + total_len, separator, seplen );
                    total_len += seplen;
                }
            }
            else { 
                if ( i < size - 1 ) {    
                    if(total_len+andlen < max_string_length){
                        strncpy( str + total_len, andsep, andlen );
                        total_len += andlen;
                    }
                }
            }
        }
    }

    FREE_MSTR(fun);

    res = new_string(total_len, "f_query_multiple_short");
    res[total_len] = '\0';
    memcpy(res, str, total_len);

    FREE_MSTR(str);

    /* Ok, now that we have cleaned up here we have to decide what to do
       with it. If nodollars is 0, then we need to pass it to an object
       for conversion. */ 

    if (no_dollars) { 
        if (command_giver) { 
            /* We need to call on this_player(). */ 
            push_malloced_string(res);
            v = apply("convert_message", command_giver, 1, ORIGIN_EFUN);
            
            if (v && v->type == T_STRING) { 
                pop_n_elems(num_arg);
                share_and_push_string(v->u.string);
            }
            else { 
                pop_n_elems(num_arg);
                push_undefined();
            }
            
        }
        else {
            /* We need to find /global/player. */ 
            /* Does this work? Seems not to. */ 
            ob = find_object("/global/player");
            
            if (ob) {
                push_malloced_string(res);
                v = apply("convert_message", ob, 1, ORIGIN_EFUN);
                
                /* Return the result! */ 
                if (v && v->type == T_STRING) { 
                    pop_n_elems(num_arg);
                    share_and_push_string(v->u.string);
                }
                else { 
                    pop_n_elems(num_arg);
                    push_undefined();
                }
            }
            else { 
                pop_n_elems(num_arg);
                push_undefined();
            }
        }

    }
    else { 
        pop_n_elems(num_arg);
        push_malloced_string(res);
    }
} /* query_multiple_short() */
예제 #6
0
파일: chinese.c 프로젝트: ViKingIX/NtOS
void f_cwrap ()
{
	register int i, j;
	int width, slen, blanks;
	register char *istr, *ostr, *ret;

	if(st_num_arg >= 2)
	{
		if(st_num_arg == 3)
		{
			blanks = sp->u.number;
			pop_stack();
	
			if(blanks < 0)
				blanks = 0;
		}
		else
			blanks = 4;
	
		width = sp->u.number;
		pop_stack();
	
		if(width < 2)
			width = 64;
	
		if(width - blanks < 2)
		{
			width = 64;
			blanks = 4;
		}
	}
	else
	{
		blanks = 4;
		width = 64;
	}

	istr = (char *)sp->u.string;
	slen = SVALUE_STRLEN(sp);
	
	if(slen < blanks)
		blanks = 0;
	
	i = blanks;
	
	ostr = ret = new_string(slen+slen/width+blanks, "f_cwrap");
	
	while(blanks--)
		*ostr++ = ' ';
	
	while(*istr)
	{
		if(*istr == '\n')
		{
			istr++;
			continue;
		}
	
		if(istr[0] == 27 && istr[1] == '[')
		{
			j=2;
	
			while(istr[j] && (isdigit(istr[j]) || istr[j]==';'))
				j++;
	
			if(istr[j++] == 'm')
			{
				while(j--)
					*ostr++ = *istr++;
	
				continue;
			}
		}
	
		i++;
		*ostr++ = *istr++;
	
		if(is_B51((unsigned char)*(istr-1)))
		{
			i++;
			*ostr++ = *istr++;
		}
		else if((unsigned char)*(istr-1) == '\t')
			i += 4;
	
		if(i >= width)
		{
			*ostr++ = '\n';
			i = 0;
		}
	}
	
	*ostr = '\0';
	
	ostr = string_copy(ret, "f_cwrap");
	FREE_MSTR(ret);
	
	free_string_svalue(sp);
	put_malloced_string(ostr);
}
예제 #7
0
파일: file.c 프로젝트: Elohim/FGmud
char *read_file(const char * file, int start, int len) {
	struct stat st;
#ifndef PACKAGE_COMPRESS
	FILE *f;
#else
	gzFile f;
#endif
	int chunk;
	char *str, *p, *p2;

	if (len < 0)
		return 0;

	file = check_valid_path(file, current_object, "read_file", 0);

	if (!file)
		return 0;

	/*
	 * file doesn't exist, or is really a directory
	 */
	if (stat(file, &st) == -1 || (st.st_mode & S_IFDIR))
		return 0;
#ifndef PACKAGE_COMPRESS
	f = fopen(file, FOPEN_READ);
#else
	f = gzopen(file, "rb");
#endif
	if (f == 0)
		return 0;

	if (start < 1)
		start = 1;
	if (len == 0)
		len = 2*READ_FILE_MAX_SIZE;

	str = new_string(2*READ_FILE_MAX_SIZE, "read_file: str");
	if (st.st_size== 0) {
		/* zero length file */
		str[0] = 0;
#ifndef PACKAGE_COMPRESS
		fclose(f);
#else
		gzclose(f);
#endif
		str = extend_string(str, 0); /* fix string length */
		return str;
	}

	do {
#ifndef PACKAGE_COMPRESS
		chunk = fread(str, 1, 2*READ_FILE_MAX_SIZE, f);
#else 
		chunk = gzread(f, str, 2*READ_FILE_MAX_SIZE);
#endif
		if (chunk < 1)
			goto free_str;
		p = str;
		while (start > 1) {
			/* skip newlines */
			p2 = (char *)memchr(p, '\n', 2*READ_FILE_MAX_SIZE+str-p);
			if (p2) {
				p = p2 + 1;
				start--;
			} else
				break;
		}
	} while (start > 1);

	p2 = str;
	while (1) {
		char c;

		c = *p++;
		if (p-str > chunk) {
			if (chunk == 2*READ_FILE_MAX_SIZE) {
				goto free_str;	//file too big
			} else
				break; //reached the end
		}
		
		if (p2-str > READ_FILE_MAX_SIZE)
			goto free_str;  //file too big
		
		if (c == '\0') {
			FREE_MSTR(str);
#ifndef PACKAGE_COMPRESS
			fclose(f);
#else
			gzclose(f);
#endif
			error("Attempted to read '\\0' into string!\n");
		}
		if (c != '\r' || *p != '\n') {
			*p2++ = c;
			if (c == '\n' && --len == 0)
				break; /* done */
		}
	}

	*p2 = 0;
	str = extend_string(str, p2 - str); /* fix string length */

#ifndef PACKAGE_COMPRESS
	fclose(f);
#else
	gzclose(f);
#endif

	return str;

	/* Error path: unwind allocated resources */

free_str: 
	FREE_MSTR(str);
#ifndef PACKAGE_COMPRESS
	fclose(f);
#else
	gzclose(f);
#endif
	return 0;
}
예제 #8
0
파일: file.c 프로젝트: Yuffster/fluffOS
char *read_file (const char * file, int start, int len) {
    struct stat st;
    FILE *f;
    int lastchunk, chunk, ssize, fsize;
    char *str, *p, *p2;

    if (len < 0)
        return 0;

    file = check_valid_path(file, current_object, "read_file", 0);

    if (!file)
        return 0;

    /*
     * file doesn't exist, or is really a directory
     */
    if (stat(file, &st) == -1 || (st.st_mode & S_IFDIR))
        return 0;

    f = fopen(file, FOPEN_READ);
    if (f == 0)
        return 0;

#ifndef LATTICE
    if (fstat(fileno(f), &st) == -1)
        fatal("Could not stat an open file.\n");
#endif

    /* lastchunk = the size of the last chunk we read
     * chunk = size of the next chunk we will read (always < fsize)
     * fsize = amount left in file
     */
    lastchunk = chunk = ssize = fsize = st.st_size;
    if (fsize > READ_FILE_MAX_SIZE)
        lastchunk = chunk = ssize = READ_FILE_MAX_SIZE;

    /* Can't shortcut out if size > max even if start and len aren't
       specified, since we still need to check for \0, and \r's may pull the
       size into range */

    if (start < 1) start = 1;
    if (len == 0) len = READ_FILE_MAX_SIZE;

    str = new_string(ssize, "read_file: str");
    if (fsize == 0) {
        /* zero length file */
        str[0] = 0;
        fclose(f);
        return str;
    }

    do {
        /* read another chunk */
        if (fsize == 0 || fread(str, chunk, 1, f) != 1)
            goto free_str;
        p = str;
        lastchunk = chunk;
        fsize -= chunk;
        if (chunk > fsize) chunk = fsize;

        while (start > 1) {
            /* skip newlines */
            p2 = memchr(p, '\n', str + lastchunk - p);
            if (p2) {
                p = p2 + 1;
                start--;
            } else
                break; /* get another chunk */
        }
    } while (start > 1); /* until we've skipped enough */

    p2 = str;
    while (1) {
        char c;

        if (p == str + lastchunk) {
            /* need another chunk */
            if (chunk > ssize - (p2 - str))
                chunk = ssize - (p2 - str); /* space remaining */
            if (fsize == 0) break; /* nothing left */
            if (chunk == 0 || fread(p2, chunk, 1, f) != 1)
                goto free_str;
            p = p2;
            lastchunk = chunk + (p2 - str); /* fudge since we didn't
                                               start at str */
            fsize -= chunk;
            if (chunk > fsize) chunk = fsize;
        }

        c = *p++;
        if (c == '\0') {
            FREE_MSTR(str);
            fclose(f);
            error("Attempted to read '\\0' into string!\n");
        }
        if (c != '\r' || *p != '\n') {
            *p2++ = c;
            if (c == '\n' && --len == 0)
                break; /* done */
        }
    }

    *p2 = 0;
    str = extend_string(str, p2 - str); /* fix string length */
    fclose(f);

    return str;

    /* Error path: unwind allocated resources */

free_str:
    FREE_MSTR(str);
    fclose(f);
    return 0;
}
예제 #9
0
파일: compress.c 프로젝트: Yuffster/fluffOS
void f_compress_file (void)
{
   int readb;
   int len;
   int num_arg = st_num_arg;
   const char* input_file;
   const char* output_file;
   const char* real_input_file;
   const char* real_output_file;
   char* tmpout;
   gzFile out_file;
   FILE* in_file;
   char buf[4096];
   char outname[1024];

   // Not a string?  Error!
   if ((sp - num_arg + 1)->type != T_STRING) {
      pop_n_elems(num_arg);
      push_number(0);
      return ;
   }

   input_file = (sp - num_arg + 1)->u.string;
   if (num_arg == 2) {
      if (((sp - num_arg + 2)->type != T_STRING)) {
         pop_n_elems(num_arg);
         push_number(0);
         return ;
      }
      output_file = (sp - num_arg + 2)->u.string;
   } else {
      len = strlen(input_file);
      if (!strcmp(input_file + len - strlen(GZ_EXTENSION), GZ_EXTENSION)) {
         // Already compressed...
         pop_n_elems(num_arg);
         push_number(0);
         return ;
      }
      tmpout = new_string(strlen(input_file) + strlen(GZ_EXTENSION),
                            "compress_file");
      strcpy(tmpout, input_file);
      strcat(tmpout, GZ_EXTENSION);
      output_file = tmpout;
   }

   real_output_file = check_valid_path(output_file, current_object, "compress_file", 1);
   if (!real_output_file) {
      pop_n_elems(num_arg);
      push_number(0);
      return ;
   }
   // Copy it into our little buffer.
   strcpy(outname, real_output_file);
   // Free the old file.
   if (num_arg != 2) {
      FREE_MSTR(output_file);
   }
   output_file = outname;

   real_input_file = check_valid_path(input_file, current_object, "compress_file", 0);
   if (!real_input_file) {
      pop_n_elems(num_arg);
      push_number(0);
      return ;
   }

   in_file = fopen(real_input_file, "rb");
   if (!in_file) {
      pop_n_elems(num_arg);
      push_number(0);
      return ;
   }

   out_file = gzopen(output_file, "wb");
   if (!out_file) {
      fclose(in_file);
      pop_n_elems(num_arg);
      push_number(0);
      return ;
   }

   do {
      readb = fread(buf, 1, 4096, in_file);
      gzwrite(out_file, buf, readb);
   } while (readb == 4096);
   fclose(in_file);
   gzclose(out_file);

   unlink(real_input_file);

   pop_n_elems(num_arg);
   push_number(1);
}
예제 #10
0
파일: array.c 프로젝트: quixadhal/discworld
void
filter_array P2(svalue_t *, arg, int, num_arg)
{
    array_t *vec = arg->u.arr, *r;
    int size;

    if ((size = vec->size) < 1) {
	pop_n_elems(num_arg - 1);
	return;
    }
    else {
	funptr_t *fp;
	object_t *ob = 0;
	char *func;

	char *flags = new_string(size, "TEMP: filter: flags");
	svalue_t *extra, *v;
	int res = 0, cnt, numex = 0;

	push_malloced_string(flags);

	if ((arg+1)->type == T_FUNCTION){
	    fp = (arg+1)->u.fp;
	    if (num_arg > 2) extra = arg+2, numex = num_arg - 2;
	} else {    
	    func = (arg+1)->u.string;
	    if (num_arg < 3) ob = current_object;
	    else {
		if ((arg+2)->type == T_OBJECT) ob = (arg+2)->u.ob;
		else if ((arg+2)->type == T_STRING){
		    if ((ob = find_object(arg[2].u.string)) && !object_visible(ob)) ob = 0;
		}
		if (!ob) bad_argument(arg+2, T_STRING | T_OBJECT, 3, F_FILTER);
		if (num_arg > 3) extra = arg + 3, numex = num_arg - 3;
	    }
	}

	for (cnt = 0; cnt < size; cnt++){
	    push_svalue(vec->item + cnt);
	    if (numex) push_some_svalues(extra, numex);
	    v = ob ? apply(func, ob, 1 + numex, ORIGIN_EFUN)
		: call_function_pointer(fp, 1 + numex);
	    if (!IS_ZERO(v)){
		flags[cnt] = 1;
		res++;
	    } else flags[cnt] = 0;
	}
	r = allocate_empty_array(res);
	if (res){
	    while (cnt--) {
		if (flags[cnt])
		    assign_svalue_no_free(&r->item[--res], vec->item+cnt);
	    }
	}

	FREE_MSTR(flags);
	sp--;
	pop_n_elems(num_arg - 1);
	free_array(vec);
	sp->u.arr = r;
    }
}
예제 #11
0
void replace_programs (void)
{
    replace_ob_t *r_ob, *r_next;
    int i, num_fewer, offset;
    svalue_t *svp;

    debug(d_flag, ("start of replace_programs"));

    for (r_ob = obj_list_replace; r_ob; r_ob = r_next) {
	program_t *old_prog;

	if (r_ob->ob->flags & O_SWAPPED)
	    load_ob_from_swap(r_ob->ob);
	num_fewer = r_ob->ob->prog->num_variables_total - r_ob->new_prog->num_variables_total;

	debug(d_flag, ("%d less variables\n", num_fewer));

	tot_alloc_object_size -= num_fewer * sizeof(svalue_t[1]);
	if ((offset = r_ob->var_offset)) {
	    svp = r_ob->ob->variables;
	    /* move our variables up to the top */
	    for (i = 0; i < r_ob->new_prog->num_variables_total; i++) {
		free_svalue(svp, "replace_programs");
		*svp = *(svp + offset);
		*(svp + offset) = const0u;
		svp++;
	    }
	    /* free the rest */
	    for (i = 0; i < num_fewer; i++) {
		free_svalue(svp, "replace_programs");
		*svp++ = const0u;
	    }
	} else {
	    /* We just need to remove the last num_fewer variables */
	    svp = &r_ob->ob->variables[r_ob->new_prog->num_variables_total];
	    for (i = 0; i < num_fewer; i++) {
		free_svalue(svp, "replace_programs");
		*svp++ = const0u;
	    }
	}

        if (r_ob->ob->replaced_program) {
            FREE_MSTR(r_ob->ob->replaced_program);
            r_ob->ob->replaced_program = 0;
        }
        r_ob->ob->replaced_program = string_copy(r_ob->new_prog->name, "replace_programs");

	reference_prog(r_ob->new_prog, "replace_programs");
	old_prog = r_ob->ob->prog;
	r_ob->ob->prog = r_ob->new_prog;
	r_next = r_ob->next;
	free_prog(old_prog, 1);

	debug(d_flag, ("program freed."));
#ifndef NO_SHADOWS
	if (r_ob->ob->shadowing) {
	    /*
	     * The master couldn't decide if it's a legal shadowing before
	     * the program was actually replaced. It is possible that the
	     * blueprint to the replacing program is already destructed, and
	     * it's source changed. On the other hand, if we called the
	     * master now, all kind of volatile data structures could result,
	     * even new entries for obj_list_replace. This would eventually
	     * require to reference it, and all the lrpp's , in
	     * check_a_lot_ref_counts() and garbage_collection() . Being able
	     * to use replace_program() in shadows is hardly worth this
	     * effort. Thus, we simply stop the shadowing.
	     */
	    r_ob->ob->shadowing->shadowed = r_ob->ob->shadowed;
	    if (r_ob->ob->shadowed) {
		r_ob->ob->shadowed->shadowing = r_ob->ob->shadowing;
		r_ob->ob->shadowed = 0;
	    }
	    r_ob->ob->shadowing = 0;
	}
#endif
	FREE((char *) r_ob);
    }
    obj_list_replace = (replace_ob_t *) 0;
    debug(d_flag, ("end of replace_programs"));
}