void check_collisions() { unsigned nx = snake->x, ny = snake->y; if(ground[nx][ny] == WALL) die_and_score(); else if(ground[nx][ny] == BONUS) { no_pop++; score += BONUS_PTS; ground[nx][ny] = GROUND; timeout[nx][ny] = 0; find_empty(&nx, &ny); ground[nx][ny] = BONUS; timeout[nx][ny] = rnd_max(45) + 5; } else if(ground[nx][ny] == MALUS) { no_pop += 4; score -= MALUS_PTS; ground[nx][ny] = GROUND; timeout[nx][ny] = 0; find_empty(&nx, &ny); ground[nx][ny] = MALUS; timeout[nx][ny] = rnd_max(45) + 5; } }
//================================================================================== vAddr allocateNewInt(){ vAddr virtual_addr; vAddr ram_empty; sem_wait(&ram_lock); ram_empty=find_empty(RAM); //printf("ram_empty index %d\n",ram_empty); if(ram_empty==-1){//if no empty slot in ram ram_empty=find_evict(RAM); //find a slot to swap out sem_post(&ram_lock); //printf("after sem_post &ram_lock\n"); sem_wait(&ssd_lock); //printf("begin searching ssd\n"); vAddr ssd_empty=find_empty(SSD);//find an empty slot to take in the swapped out RAM if (ssd_empty==-1){//if no empty slot in ssd to take in ssd_empty=find_evict(SSD);//find a slot to evict sem_post(&ssd_lock); sem_wait(&disk_lock); vAddr disk_empty=find_empty(DISK);//find a slot in disk to take in if(disk_empty==-1){//if no place in disk virtual_addr=-1; //return false value printf("no space avaible\n"); } else{//if find a slot in disk sem_post(&disk_lock); swap(SSD,ssd_empty,DISK,disk_empty); disk_info[disk_empty].lock=0; swap(RAM,ram_empty,SSD,ssd_empty); ssd_info[ssd_empty].lock=0; } } else{//if there is empty slot in ssd sem_post(&ssd_lock); swap(RAM,ram_empty,SSD,ssd_empty); ssd_info[ssd_empty].lock=0; } } else{ sem_post(&ram_lock); } virtual_addr=find_in_pt(0,-9999); if(virtual_addr!=-1){ pageTable[virtual_addr].address=ram_empty; pageTable[virtual_addr].array=RAM; ram_info[ram_empty].lock=0; }else{ virtual_addr=-1; printf("page table is full\n"); } //mark as selected //store in pageTable printf("recorded in pagetable: %d \n",virtual_addr); return virtual_addr; }
void load_level(int lvl_nb) { char fname[100]; FILE *lev; unsigned iLin, iCol, x, y; char c; sprintf(fname, PATH"lvls/level-%d.lvl", lvl_nb); lev = fopen(fname, "r"); if(lev == NULL) { printf("Cannot open %s\n", fname); fflush(stdout); quit_stuff(); } for(iCol = 0; iCol < MAX_HEI; iCol++) { for(iLin = 0; iLin < MAX_LEN; iLin++) { c = getc(lev); if(c == '#') ground[iCol][iLin] = WALL; else ground[iCol][iLin] = GROUND; } getc(lev); /* This should be a \n */ } find_empty(&x, &y); ground[x][y] = BONUS; timeout[x][y] = rnd_max(45) + 5; find_empty(&x, &y); ground[x][y] = MALUS; timeout[x][y] = rnd_max(45) + 5; find_empty(&x, &y); ground[x][y] = MALUS; timeout[x][y] = rnd_max(45) + 5; find_empty(&x, &y); ground[x][y] = MALUS; timeout[x][y] = rnd_max(45) + 5; fclose(lev); free_snake(); /* Then the snake */ snake = malloc(sizeof(Snake)); snake->x = 9; snake->y = 13; snake->next = NULL; add_head(10, 13); add_head(11, 13); add_head(12, 13); add_head(13, 13); }
/** * Allocates a single random object in the dungeon. * \param c the current chunk * \param set where the entity is placed (corridor, room or either) * \param typ what is placed (rubble, trap, gold, item) * \param depth generation depth * \param origin item origin (if appropriate) * * 'set' controls where the object is placed (corridor, room, either). * 'typ' conrols the kind of object (rubble, trap, gold, item). */ bool alloc_object(struct chunk *c, int set, int typ, int depth, byte origin) { int x = 0, y = 0; int tries = 0; /* Pick a "legal" spot */ while (tries < 2000) { tries++; find_empty(c, &y, &x); /* If we are ok with a corridor and we're in one, we're done */ if (set & SET_CORR && !square_isroom(c, y, x)) break; /* If we are ok with a room and we're in one, we're done */ if (set & SET_ROOM && square_isroom(c, y, x)) break; } if (tries == 2000) return false; /* Place something */ switch (typ) { case TYP_RUBBLE: place_rubble(c, y, x); break; case TYP_TRAP: place_trap(c, y, x, -1, depth); break; case TYP_GOLD: place_gold(c, y, x, depth, origin); break; case TYP_OBJECT: place_object(c, y, x, depth, false, false, origin, 0); break; case TYP_GOOD: place_object(c, y, x, depth, true, false, origin, 0); break; case TYP_GREAT: place_object(c, y, x, depth, true, true, origin, 0); break; } return true; }
void insert(tw_event ** hash_t, tw_event * event, int hash_size) { int key = 0; key = find_empty(hash_t, event, hash_size); hash_t[key] = event; }
int CondorFileTable::install_special( int real_fd, char *kind ) { int fd = find_empty(); if(fd<0) return -1; CondorFileInfo *i= make_info(kind); i->already_warned = 1; i->open_count++; CondorFileSpecial *s = new CondorFileSpecial(); s->attach( real_fd ); pointers[fd] = new CondorFilePointer( s, i, O_RDWR, kind ); return fd; }
static int register_thread(void) { struct sigaction actions; int i; if ((i=find_empty(pthread_self())) >= 0) { threads[i].state = PTHREAD_CANCEL_ENABLE; threads[i].exit = 0; } memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = sigusr1_handler; sigaction(SIGUSR1, &actions, NULL); return i; }
void check_timeouts() { Tile type; int i, j; unsigned x, y; for(i = 0; i < MAX_LEN; i++) for(j = 0; j < MAX_HEI; j++) { if(ground[i][j] == WALL || ground[i][j] == GROUND) break; timeout[i][j]--; if(!timeout[i][j]) { type = ground[i][j]; ground[i][j] = GROUND; find_empty(&x, &y); ground[x][y] = type; timeout[x][y] = rnd_max(45) + 5; } } }
int CondorFileTable::open( const char *logical_name, int flags, int mode ) { char *full_logical_name = NULL; CondorFile *file=0; CondorFileInfo *info=0; // Convert a relative path into a complete path complete_path( logical_name, &full_logical_name ); // Find a fresh file descriptor int fd = find_empty(); if(fd<0) { errno = EMFILE; free( full_logical_name ); return -1; } file = open_file_unique( full_logical_name, flags, mode ); if(!file) { free( full_logical_name ); return -1; } info = make_info( full_logical_name ); info->open_count++; // Flags that should be applied once only are now removed flags &= ~(O_TRUNC); flags &= ~(O_CREAT); // Install the pointer and return! pointers[fd] = new CondorFilePointer(file,info,flags,full_logical_name); free( full_logical_name ); return fd; }
/** * Place some staircases near walls. * \param c the current chunk * \param feat the stair terrain type * \param num number of staircases to place * \param walls number of walls to surround the stairs (negotiable) */ void alloc_stairs(struct chunk *c, int feat, int num, int walls) { int y, x, i, j, done; /* Place "num" stairs */ for (i = 0; i < num; i++) { /* Place some stairs */ for (done = FALSE; !done; ) { /* Try several times, then decrease "walls" */ for (j = 0; !done && j <= 1000; j++) { find_empty(c, &y, &x); if (next_to_walls(c, y, x) < walls) continue; place_stairs(c, y, x, feat); done = TRUE; } /* Require fewer walls */ if (walls) walls--; } } }
/* * map_ioctl: * process the supported ioctls */ static int map_ioctl(RP rp) { PARAM far *p = (PARAM far*)IOPARAM(rp); DATA far *d; int idx; ULONG addr, lock, temp; ULONG far *ud; /* only accept class XFREE86_PMAP */ if (IOCAT(rp) != XFREE86_PMAP) return RP_EBAD; switch (IOFUNC(rp)) { case PMAP_MAP: /* test: Parameter packet is readable and has correct size * get a free slot */ if (Verify(p,sizeof(PARAM),0)==0 && (idx = find_empty()) != -1) { /* map the requested region */ addr = Pmap(p->u.physaddr,p->size); /* was okay? */ if (addr) { /* get the return packet of ioctl */ d = (DATA far*)IODATA(rp); /* writable ? */ if (Verify(d,sizeof(DATA),1)==0) { /* set the mapping address in * process address space */ d->addr = addr; d->sel = 0; /* registrate stuff in mapping table */ maps[idx].phys = p->u.physaddr; maps[idx].vmaddr = addr; maps[idx].sfnum = IOSFN(rp); maps[idx].lockhan = 0; return RPDONE; } } } /* come here for error condition */ break; case PMAP_UNMAP: /* test: parameter packet readable and correct size * entry found in table * unmapping okay? */ if (Verify(p,sizeof(PARAM),0)==0 && (idx = find_map(IOSFN(rp),p->u.vmaddr)) != -1 && Punmap(p->u.vmaddr)==0) { /* get the return packet of ioctl */ ud = (ULONG far*)IODATA(rp); /* writable ? */ if (Verify(d,sizeof(ULONG),1)==0) { /* set the vmaddress just invalidated * into data packet */ *ud = maps[idx].vmaddr; /* remove entry from table */ maps[idx].phys = 0; maps[idx].vmaddr = 0; maps[idx].sfnum = -1; maps[idx].lockhan = 0; return RPDONE; } } /* arrive here for error condition */ break; case PMAP_UNMAP2: /* test: parameter packet readable and correct size * entry found in table * unmapping okay? */ if (Verify(p,sizeof(PARAM),0)==0 && (idx = find_mapphys(IOSFN(rp),p->u.physaddr,p->size)) != -1 && Punmap(maps[idx].vmaddr)==0) { /* remove entry from table */ maps[idx].phys = 0; maps[idx].vmaddr = 0; maps[idx].sfnum = -1; maps[idx].lockhan = 0; return RPDONE; } /* arrive here for error condition */ break; case PMAP_NAME: if (Verify(d,14,1) == 0) { bmove((char far*)d,"\\dev\\pmap$\0",11); return RPDONE; } break; case PMAP_DRVID: return drvid(d,IODLEN(rp),PMAPDRV_ID); case PMAP_READROM: /* testcfg.sys replacement function */ if (Verify(p,sizeof(ROMPARAM),0) == 0) { ROMPARAM far *p1 = (ROMPARAM*)p; USHORT n = p1->numbytes; ULONG ad = p1->physaddr + n; if (p1->command == 0 && p1->physaddr >= 0xc0000 && p1->physaddr <= 0xfffff && ad >= 0xc0000 && ad <= 0xfffff) { char far *d1 = (char far*)IODATA(rp); if (Verify(d1,n,1) == 0) { char far *addr; if (P2V(p1->physaddr,n,&addr)==0) { bmove(d1,addr,n); /*UnPhysToVirt == NOOP in OS/2 2.x */ return RPDONE; } } } } break; case PMAP_LOCKBUF: /* test: Parameter packet is readable and has correct size * */ lock = 0; if (Verify(p,sizeof(PARAM),0)==0 && (idx = find_empty()) != -1) { /* lock the requested region */ lock = Vlock(p->u.vmaddr,p->size); temp = (p->u.vmaddr << 3) | 0x070000; /* Make sel */ /* was okay? */ if ((lock) && (Verify((FPVOID)temp, (USHORT)p->size, 0) ==0)) { /* get the return packet of ioctl */ d = (DATA far*)IODATA(rp); /* writable ? */ if (Verify(d,sizeof(DATA),1)==0) { /* set the mapping address in * process address space */ /* This is where things crash: VtoP does not like our addr */ d->addr = VtoP(p->u.vmaddr); d->sel = 0; maps[idx].phys = addr; maps[idx].vmaddr = p->u.vmaddr; maps[idx].sfnum = IOSFN(rp); maps[idx].lockhan = lock; return RPDONE; } } if(lock) Vunlock(lock); /* In case Verify failed */ } /* come here for error condition */ break; default: return RP_EBAD; } /* break from case */ return RP_EINVAL; }
/** * Generate a random level. * * Confusingly, this function also generate the town level (level 0). * \param c is the level we're going to end up with, in practice the global cave * \param p is the current player struct, in practice the global player */ void cave_generate(struct chunk **c, struct player *p) { const char *error = "no generation"; int y, x, tries = 0; struct chunk *chunk; assert(c); /* Generate */ for (tries = 0; tries < 100 && error; tries++) { struct dun_data dun_body; error = NULL; /* Mark the dungeon as being unready (to avoid artifact loss, etc) */ character_dungeon = FALSE; /* Allocate global data (will be freed when we leave the loop) */ dun = &dun_body; dun->cent = mem_zalloc(z_info->level_room_max * sizeof(struct loc)); dun->door = mem_zalloc(z_info->level_door_max * sizeof(struct loc)); dun->wall = mem_zalloc(z_info->wall_pierce_max * sizeof(struct loc)); dun->tunn = mem_zalloc(z_info->tunn_grid_max * sizeof(struct loc)); /* Choose a profile and build the level */ dun->profile = choose_profile(p->depth); chunk = dun->profile->builder(p); if (!chunk) { error = "Failed to find builder"; mem_free(dun->cent); mem_free(dun->door); mem_free(dun->wall); mem_free(dun->tunn); continue; } /* Ensure quest monsters */ if (is_quest(chunk->depth)) { int i; for (i = 1; i < z_info->r_max; i++) { monster_race *r_ptr = &r_info[i]; int y, x; /* The monster must be an unseen quest monster of this depth. */ if (r_ptr->cur_num > 0) continue; if (!rf_has(r_ptr->flags, RF_QUESTOR)) continue; if (r_ptr->level != chunk->depth) continue; /* Pick a location and place the monster */ find_empty(chunk, &y, &x); place_new_monster(chunk, y, x, r_ptr, TRUE, TRUE, ORIGIN_DROP); } } /* Clear generation flags. */ for (y = 0; y < chunk->height; y++) { for (x = 0; x < chunk->width; x++) { sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_INNER); sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_OUTER); sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_SOLID); sqinfo_off(chunk->squares[y][x].info, SQUARE_MON_RESTRICT); } } /* Regenerate levels that overflow their maxima */ if (cave_monster_max(chunk) >= z_info->level_monster_max) error = "too many monsters"; if (error) ROOM_LOG("Generation restarted: %s.", error); mem_free(dun->cent); mem_free(dun->door); mem_free(dun->wall); mem_free(dun->tunn); } if (error) quit_fmt("cave_generate() failed 100 times!"); /* Free the old cave, use the new one */ if (*c) cave_free(*c); *c = chunk; /* Place dungeon squares to trigger feeling (not in town) */ if (player->depth) place_feeling(*c); /* Save the town */ else if (!chunk_find_name("Town")) { struct chunk *town = chunk_write(0, 0, z_info->town_hgt, z_info->town_wid, FALSE, FALSE, FALSE); town->name = string_make("Town"); chunk_list_add(town); } (*c)->feeling = calc_obj_feeling(*c) + calc_mon_feeling(*c); /* Validate the dungeon (we could use more checks here) */ chunk_validate_objects(*c); /* The dungeon is ready */ character_dungeon = TRUE; /* Free old and allocate new known level */ if (cave_k) cave_free(cave_k); cave_k = cave_new(cave->height, cave->width); if (!cave->depth) cave_known(); (*c)->created_at = turn; }
int main( int argc, char ** argv) { int loaded; int target = -1; int oldtarget; command com; /* a little DOS joke */ /* * drive_num really should be something from the config file, but.. * for now, it is set to zero, since most of the common changers * used by amanda only have one drive ( until someone wants to * use an EXB60/120, or a Breece Hill Q45.. ) */ int drive_num = 0; int need_eject = 0; /* Does the drive need an eject command ? */ unsigned need_sleep = 0; /* How many seconds to wait for the drive to get ready */ int clean_slot = -1; int maxclean = 0; char *clean_file=NULL; char *time_file=NULL; int use_slots; int slot_offset; int confnum; int fd, slotcnt, drivecnt; int endstatus = 0; char *changer_dev = NULL; char *tape_device = NULL; char *changer_file = NULL; char *scsitapedevice = NULL; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); set_pname("chg-scsi"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_SERVER); parse_args(argc,argv,&com); changer = alloc(SIZEOF(changer_t)); config_init(CONFIG_INIT_USE_CWD, NULL); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } changer_dev = getconf_str(CNF_CHANGERDEV); changer_file = getconf_str(CNF_CHANGERFILE); tape_device = getconf_str(CNF_TAPEDEV); /* Get the configuration parameters */ if (strlen(tape_device)==1){ read_config(changer_file, changer); confnum=atoi(tape_device); use_slots = changer->conf[confnum].end-changer->conf[confnum].start+1; slot_offset = changer->conf[confnum].start; drive_num = changer->conf[confnum].drivenum; need_eject = changer->eject; need_sleep = changer->sleep; clean_file = stralloc(changer->conf[confnum].cleanfile); clean_slot = changer->conf[confnum].cleanslot; maxclean = changer->cleanmax; if (NULL != changer->conf[confnum].timefile) time_file = stralloc(changer->conf[confnum].timefile); if (NULL != changer->conf[confnum].slotfile) changer_file = stralloc(changer->conf[confnum].slotfile); else changer_file = NULL; if (NULL != changer->conf[confnum].device) tape_device = stralloc(changer->conf[confnum].device); if (NULL != changer->device) changer_dev = stralloc(changer->device); if (NULL != changer->conf[confnum].scsitapedev) scsitapedevice = stralloc(changer->conf[confnum].scsitapedev); if (NULL != changer->conf[confnum].tapestatfile) tapestatfile = stralloc(changer->conf[confnum].tapestatfile); dump_changer_struct(changer); /* get info about the changer */ fd = OpenDevice(INDEX_CHANGER , changer_dev, "changer_dev", changer->conf[confnum].changerident); if (fd == -1) { int localerr = errno; g_fprintf(stderr, _("%s: open: %s: %s\n"), get_pname(), changer_dev, strerror(localerr)); g_printf(_("%s open: %s: %s\n"), "<none>", changer_dev, strerror(localerr)); dbprintf(_("open: %s: %s\n"), changer_dev, strerror(localerr)); return 2; } if (tape_device == NULL) { tape_device = stralloc(changer_dev); } if (scsitapedevice == NULL) { scsitapedevice = stralloc(tape_device); } if ((changer->conf[confnum].end == -1) || (changer->conf[confnum].start == -1)){ slotcnt = get_slot_count(fd); use_slots = slotcnt; slot_offset = 0; } free_changer_struct(&changer); } else { /* get info about the changer */ confnum = 0; fd = OpenDevice(INDEX_CHANGER , changer_dev, "changer_dev", changer->conf[confnum].changerident); if (fd == -1) { int localerr = errno; g_fprintf(stderr, _("%s: open: %s: %s\n"), get_pname(), changer_dev, strerror(localerr)); g_printf(_("%s open: %s: %s\n"), _("<none>"), changer_dev, strerror(localerr)); dbprintf(_("open: %s: %s\n"), changer_dev, strerror(localerr)); return 2; } slotcnt = get_slot_count(fd); use_slots = slotcnt; slot_offset = 0; drive_num = 0; need_eject = 0; need_sleep = 0; } drivecnt = get_drive_count(fd); if (drive_num > drivecnt) { g_printf(_("%s drive number error (%d > %d)\n"), _("<none>"), drive_num, drivecnt); g_fprintf(stderr, _("%s: requested drive number (%d) greater than " "number of supported drives (%d)\n"), get_pname(), drive_num, drivecnt); dbprintf(_("requested drive number (%d) greater than " "number of supported drives (%d)\n"), drive_num, drivecnt); CloseDevice("", fd); return 2; } loaded = drive_loaded(fd, drive_num); switch(com.command_code) { case COM_SLOT: /* slot changing command */ if (is_positive_number(com.parameter)) { if ((target = atoi(com.parameter))>=use_slots) { g_printf(_("<none> no slot `%d'\n"),target); close(fd); endstatus = 2; break; } else { target = target+slot_offset; } } else target=get_relative_target(fd, use_slots, com.parameter, loaded, changer_file,slot_offset,slot_offset+use_slots); if (loaded) { if (changer_file != NULL) { oldtarget=get_current_slot(changer_file); } else { oldtarget = GetCurrentSlot(fd, drive_num); } if ((oldtarget)!=target) { if (need_eject) eject_tape(scsitapedevice, need_eject); (void)unload(fd, drive_num, oldtarget); if (ask_clean(scsitapedevice)) clean_tape(fd,tape_device,clean_file,drive_num, clean_slot,maxclean,time_file); loaded=0; } } if (changer_file != NULL) { put_current_slot(changer_file, target); } if (!loaded && isempty(fd, target)) { g_printf(_("%d slot %d is empty\n"),target-slot_offset, target-slot_offset); close(fd); endstatus = 1; break; } if (!loaded) if (load(fd, drive_num, target) != 0) { g_printf(_("%d slot %d move failed\n"),target-slot_offset, target-slot_offset); close(fd); endstatus = 2; break; } if (need_sleep) Tape_Ready1(scsitapedevice, need_sleep); g_printf(_("%d %s\n"), target-slot_offset, tape_device); break; case COM_INFO: if (changer_file != NULL) { g_printf("%d ", get_current_slot(changer_file)-slot_offset); } else { g_printf("%d ", GetCurrentSlot(fd, drive_num)-slot_offset); } g_printf("%d 1\n", use_slots); break; case COM_RESET: if (changer_file != NULL) { target=get_current_slot(changer_file); } else { target = GetCurrentSlot(fd, drive_num); } if (loaded) { if (!isempty(fd, target)) target=find_empty(fd,0 ,0); if (need_eject) eject_tape(scsitapedevice, need_eject); (void)unload(fd, drive_num, target); if (ask_clean(scsitapedevice)) clean_tape(fd,tape_device,clean_file,drive_num,clean_slot, maxclean,time_file); } if (isempty(fd, slot_offset)) { g_printf(_("0 slot 0 is empty\n")); close(fd); endstatus = 1; break; } if (load(fd, drive_num, slot_offset) != 0) { g_printf(_("%d slot %d move failed\n"),slot_offset, slot_offset); close(fd); endstatus = 2; break; } if (changer_file != NULL) { put_current_slot(changer_file, slot_offset); } if (need_sleep) Tape_Ready1(scsitapedevice, need_sleep); if (changer_file != NULL) { g_printf("%d %s\n", get_current_slot(changer_file), tape_device); } else { g_printf("%d %s\n", GetCurrentSlot(fd, drive_num), tape_device); } break; case COM_EJECT: if (loaded) { if (changer_file != NULL) { target=get_current_slot(changer_file); } else { target = GetCurrentSlot(fd, drive_num); } if (need_eject) eject_tape(scsitapedevice, need_eject); (void)unload(fd, drive_num, target); if (ask_clean(scsitapedevice)) clean_tape(fd,tape_device,clean_file,drive_num,clean_slot, maxclean,time_file); g_printf("%d %s\n", target, tape_device); } else { g_printf(_("%d drive was not loaded\n"), target); endstatus = 1; } break; case COM_CLEAN: if (loaded) { if (changer_file != NULL) { target=get_current_slot(changer_file); } else { target = GetCurrentSlot(fd, drive_num); } if (need_eject) eject_tape(scsitapedevice, need_eject); (void)unload(fd, drive_num, target); } clean_tape(fd,tape_device,clean_file,drive_num,clean_slot, maxclean,time_file); g_printf(_("%s cleaned\n"), tape_device); break; }; CloseDevice("", 0); dbclose(); return endstatus; }