/* fd, is a user file descriptor. */ PRIVILEGED_FUNCTION int _close_r(struct _reent *ptr, int fd) { int res; struct fdent *pfd; pfd = findslot(fd); if (pfd == NULL) { ptr->_errno = EBADF; return -1; } /* Handle stderr == stdout. */ if ((fd == 1 || fd == 2) && (openfiles[1].handle == openfiles[2].handle)) { pfd->handle = -1; return 0; } /* Attempt to close the handle. */ res = checkerror(do_AngelSWI (AngelSWI_Reason_Close, &f(pfd->handle))); /* Reclaim handle? */ if (res == 0) pfd->handle = -1; return res; }
int rc_open( unsigned long ip_net ,unsigned short port_net ) { int fd; if( (fd = findslot())< 0 ) return -2; slot[fd].ip_net = ip_net; slot[fd].port_net = port_net; if(addsendp( fd , SEQ_NOUSE , COMMAND_OPEN , LEN_NOUSE , fd , RFD_NOUSE , BUF_NOUSE )<0){ return -100; } slot[fd].open_send = 1; while(1){ rc_proc(); if( slot[fd].open_ack){ break; } } return fd; }
static int findfreeslot(void) { int slot; if ((slot = findslot(NOPID)) < 0) errx(1, "internal error: no free pid slot"); return (slot); }
static int Xslot (char *ttys_file, char *servers_file, char *tty_line, char *host_name, int addp) { FILE *ttys, *servers; int c; int slot = 1; int column0 = 1; char servers_line[1024]; char disp_name[512]; int len; char *pos; /* remove screen number from the display name */ memset(disp_name, 0, sizeof(disp_name)); strncpy(disp_name, host_name ? host_name : tty_line, sizeof(disp_name)-1); pos = strrchr(disp_name, ':'); if (pos) { pos = strchr(pos, '.'); if (pos) *pos = '\0'; } sysnerr ((int)(long)(ttys = fopen (ttys_file, "r")), ttys_file); while ((c = getc (ttys)) != EOF) if (c == '\n') { ++slot; column0 = 1; } else column0 = 0; if (!column0) ++slot; (void) fclose (ttys); sysnerr ((int)(long)(servers = fopen (servers_file, "r")), servers_file); len = strlen (disp_name); column0 = 1; while (fgets (servers_line, sizeof (servers_line), servers)) { if (column0 && *servers_line != '#') { if (!strncmp (disp_name, servers_line, len) && (servers_line[len] == ' ' || servers_line[len] == '\t')) return slot; ++slot; } if (servers_line[strlen(servers_line)-1] != '\n') column0 = 0; else column0 = 1; } /* * display not found in Xservers file - allocate utmp entry dinamically */ return findslot (tty_line, host_name, addp, slot); }
static int pids_remove(pid_t pid) { int slot; if ((slot = findslot(pid)) < 0) return (0); clearslot(slot); curprocs--; return (1); }
bool StateManager::save(const char *filename, uint8 slot, serializer &s, const char *description) { //if no state archive exists ... if(file::exists(filename) == false) { //try and create one if(create(filename) == false) return false; } //if we cannot load the existing state archive ... if(load(filename) == false) { //it's probably an older version, try and create a new one if(create(filename) == false) return false; //it still needs to be loaded before we can write to it if(load(filename) == false) return false; } uint8 index = findslot(slot); if(index == SlotInvalid) { //create new slot instead of over-writing existing slot if(info.slotcount >= 255) return false; index = info.slotcount; slot = info.slotcount; } file fp; if(fp.open(filename, file::mode_readwrite) == false) return false; fp.seek(SlotIndex + index); fp.write(slot); time_t current = time(0); tm *ts = localtime(¤t); char timestamp[32]; sprintf(timestamp, "%.4u-%.2u-%.2u %.2u:%.2u:%.2u", 1900 + ts->tm_year, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, (ts->tm_hour < 12 ? "AM" : "PM") ); fp.seek(DateTimeIndex + index * DateTimeSize); fp.write((uint8*)×tamp[0], DateTimeSize); char desc[DescriptionSize]; memset(&desc, 0, DescriptionSize); strlcpy(desc, description, DescriptionSize); fp.seek(DescIndex + index * DescriptionSize); fp.write((uint8*)&desc[0], DescriptionSize); fp.seek(HeaderSize + index * system.serialize_size); fp.write(s.data(), s.size()); for(unsigned n = 0; n < system.serialize_size - s.size(); n++) fp.write(0x00); fp.close(); return true; }
serializer StateManager::load(const char *filename, uint8 slot) { if(load(filename) == false) throw; if(info.slotcount <= slot) throw; uint8 index = findslot(slot); if(index == SlotInvalid) throw; file fp; if(fp.open(filename, file::mode_read) == false) throw; fp.seek(HeaderSize + system.serialize_size * index); uint8 *data = new uint8[system.serialize_size]; fp.read(data, system.serialize_size); serializer s(data, system.serialize_size); delete[] data; fp.close(); return s; }
bool StateManager::set_description(const char *filename, uint8 slot, const char *description) { if(load(filename) == false) return false; if(info.slotcount <= slot) return false; file fp; if(fp.open(filename, file::mode_readwrite) == false) return false; uint8 index = findslot(slot); if(index == SlotInvalid) { fp.close(); return false; } char desc[DescriptionSize]; memset(&desc, 0, DescriptionSize); strlcpy(desc, description, DescriptionSize); fp.seek(DescIndex + index * DescriptionSize); fp.write((uint8*)&desc[0], DescriptionSize); fp.close(); return true; }
bool StateManager::erase(const char *filename, uint8 slot) { if(load(filename) == false) return false; uint8 index = findslot(slot); if(index == SlotInvalid) return false; file fp; if(fp.open(filename, file::mode_readwrite) == false) return false; if(info.slotcount <= slot) return false; //copy the very last state to the slot that is to be erased uint8 lastslot = info.slotcount - 1; info.slot[index] = info.slot[lastslot]; info.slot[lastslot] = SlotInvalid; fp.seek(DateTimeIndex + index * DateTimeSize); fp.write((uint8*)&info.datetime[lastslot * DateTimeSize], DateTimeSize); fp.seek(DescIndex + index * DescriptionSize); fp.write((uint8*)&info.description[lastslot * DescriptionSize], DescriptionSize); fp.seek(HeaderSize + system.serialize_size * lastslot); uint8 *data = new uint8[system.serialize_size]; fp.read(data, system.serialize_size); fp.seek(HeaderSize + system.serialize_size * index); fp.write(data, system.serialize_size); delete[] data; //decrement all IDs after the deleted one (removes empty slot ID from deletion) for(unsigned n = 0; n < lastslot; n++) { if(info.slot[n] > slot) info.slot[n]--; } fp.seek(SlotIndex); fp.write(info.slot, 256); unsigned size = fp.size(); fp.truncate(size - system.serialize_size); return true; }
int rc_proc(void) { int i; int ll; double now_time = getUTimeDouble(); if( ( now_time - lasttime ) < (INTERVAL_MS*1000)) return 0; lasttime = now_time; fprintf(stderr , "!"); for(ll=0;ll<rc.maxslot;ll++){ int j; struct sendp *sq; /* 誰を処理するのか */ do_first++; if( do_first == rc.maxslot ) do_first = 0; if( slot[do_first].use == 0 ) continue; sq = slot[do_first].sendq; /* 書きこみ不可になるか、全部のスロットを処理しきるまで書きつづける */ if( ! select_writable()) break; for(j=0;j<SENDQSIZE;j++){ if( sq[j].state == SENDP_SENDWAIT ){ /* 送信まちになっているぞ */ if(sender( slot[do_first].ip_net , slot[do_first].port_net , sq[j].seq , sq[j].cmd , sq[j].len, sq[j].sfd , sq[j].rfd ,sq[j].buf )<=0){ /* 送信できなかったらとりあえずやめる */ break; } else { } sq[j].sendtime = now_time; sq[j].nexttime = now_time + timetable[0]; switch( sq[j].cmd ){ case COMMAND_DATA: case COMMAND_OPEN: case COMMAND_CLOSE: sq[j].state = SENDP_ACKWAIT; break; case COMMAND_DATAACK: case COMMAND_OPENACK: case COMMAND_CLOSEACK: deletesendp( &sq[j] ); break; default: /* ERROR!!!!!!*/ break; } if( select_writable() ) continue; else break; } else if( sq[j].state == SENDP_ACKWAIT){ /* 1回送信して、ACKをまっているのだ。時間次第で再送 */ if( sq[j].nexttime < now_time ){ sq[j].retrytimes++; if( sq[j].retrytimes == sizeof( timetable)/sizeof(timetable[0])){ closeslot( do_first ); fprintf( stderr, "TIMEOUT on slot %d\n" , do_first); } else { fprintf( stderr, "RETRY Qi:%d fd:%d\n" ,j , do_first ); if( sender( slot[do_first].ip_net , slot[do_first].port_net , sq[j].seq , sq[j].cmd , sq[j].len, sq[j].sfd , sq[j].rfd ,sq[j].buf )<=0){ break; } sq[j].nexttime = sq[j].sendtime + timetable[sq[j].retrytimes]; } } } else { /* 何もせん */ } } } /* while */ while(1){ struct sockaddr_in sin; int clilen = sizeof( sin ); int n; int ret; char buf[MTU]; int seq , cmd , len , sfd , rfd; char *data; unsigned long ip_net; unsigned short port_net; /* 読みこみ可能なら永久に読みつづける */ if( select_readable()){ n = recvfrom( rc.sockfd , buf , sizeof( buf ), 0 , ( struct sockaddr*)&sin , &clilen ); if( n <= 0 )break; } else { break; } getheader( buf , n , &seq , &cmd, &len , &sfd , &rfd , &data ); ip_net = sin.sin_addr.s_addr; port_net = sin.sin_port; fprintf( stderr ,"PACKET! SEQ:%x CMD:%x LEN:%x SFD:%x RFD:%x\n", seq,cmd,len,sfd,rfd); /* COMMANDによってわける */ if( cmd == COMMAND_DATA ){ if( FDINVALID( rfd ) ) continue; /* 2重チェックをここでする */ for(i=0;i<RECVQSIZE;i++){ if( slot[rfd].recvq[i].seq == seq && slot[rfd].recvq[i].state == RECVP_SENDACK )break; } if( i != RECVQSIZE ){ fprintf( stderr, "Ignored datapacket. seq:%d\n" , seq ); continue; } addrecvp( rfd , seq , cmd , len , sfd , rfd , data ); /* ACKを送信 */ addsendp( rfd , seq , COMMAND_DATAACK , LEN_NOUSE , sfd , rfd , BUF_NOUSE ); } else if( cmd == COMMAND_OPEN ){ int si; /* 2重openをチェック */ for(i=0;i<rc.maxslot;i++){ if( slot[i].ip_net == ip_net && slot[i].port_net == port_net && slot[i].dslot == sfd && slot[i].use ){ break; } } if( i != rc.maxslot) continue; if( (si = findslot())<0) continue; if( addsendp( si , SEQ_NOUSE , COMMAND_OPENACK , LEN_NOUSE , sfd , si , BUF_NOUSE )<0){ /* ACKおくれん */ fprintf( stderr , "CLOSE BECAUSE OF OPENACK F**K\n"); closeslot(si); } else { slot[si].ip_net = ip_net; slot[si].port_net = port_net; slot[si].dslot = sfd; slot[si].send_i = slot[si].recv_i = 0; slot[si].open_ack = 0; slot[si].accept_wait = 1; fprintf(stderr,"NASUNASU Si:%d\n", si ); } } else if( cmd == COMMAND_CLOSE ){ if( FDINVALID( rfd ) ) continue; } else if( cmd == COMMAND_DATAACK ){ if( FDINVALID( sfd ) ) continue; fprintf( stderr , "RECEIVED DATA ACK. SEQ:%d\n" , seq ); /* 到着したパケットと同じseqをもつsendqをさがす */ for(i=0;i<SENDQSIZE;i++){ if( slot[sfd].sendq[i].seq == seq && slot[sfd].sendq[i].state == SENDP_ACKWAIT ){ /* 到着を確認! 確認の条件はseqが同じでかつ */ /* ACKWAITしていること。おなじseqをもつものはすべて消してしまう。*/ deletesendp( & slot[sfd].sendq[i] ); fprintf( stderr, "Confirmed seq %d\n", seq ); } } /* ACKまちを消せたら、閉じれる状態かもしれない。 */ if( closable( sfd ) )closeslot(sfd); } else if( cmd == COMMAND_OPENACK ){ if( FDINVALID( sfd ) )continue; slot[sfd].open_ack = 1; slot[sfd].dslot = rfd; fprintf( stderr, "BBBBBBBBBBBBBBBBB RFD:%d\n" , rfd ); deleteopensendp( sfd ); } else if( cmd == COMMAND_CLOSEACK ){ if( FDINVALID( sfd ) )continue; deleteclosesendp( sfd ); slot[sfd].close_wait = 1; } } }
/* fd, is a user file descriptor. */ PRIVILEGED_FUNCTION _off_t _lseek_r(struct _reent *ptr, int fd, _off_t offs, int dir) { int res; struct fdent *pfd; /* Valid file descriptor? */ pfd = findslot(fd); if (pfd == NULL) { ptr->_errno = EBADF; return -1; } /* Valid whence? */ if ((dir != SEEK_CUR) && (dir != SEEK_SET) && (dir != SEEK_END)) { ptr->_errno = EINVAL; return -1; } /* Convert SEEK_CUR to SEEK_SET */ if (dir == SEEK_CUR) { offs = pfd->pos + offs; /* The resulting file offset would be negative. */ if (offs < 0) { ptr->_errno = EINVAL; if ((pfd->pos > 0) && (offs > 0)) ptr->_errno = EOVERFLOW; return -1; } dir = SEEK_SET; } int block[2]; if (dir == SEEK_END) { block[0] = pfd->handle; res = checkerror(do_AngelSWI(AngelSWI_Reason_FLen, block)); if (res == -1) return -1; offs += res; } /* This code only does absolute seeks. */ block[0] = pfd->handle; block[1] = offs; res = checkerror(do_AngelSWI(AngelSWI_Reason_Seek, block)); /* At this point offs is the current file position. */ if (res >= 0) { pfd->pos = offs; return offs; } else return -1; }
int main(int argc, char **argv) { int team, s_type; char *dpyname = NULL; int usage = 0; int err = 0; char *name, *ptr, *cp; struct passwd *pwent; int passive = 0; int xpmopt = 1; int useORopt = 0; int useCookieOpt = 0; int dontUseCookieOpt = 0; /* char *defaultsFile=NULL;*/ pseudo[0] = defpasswd[0] = '\0'; name = *argv++; argc--; if ((ptr = strrchr(name, '/')) != NULL) name = ptr + 1; while (*argv) { if (**argv != '-') { serverName = *argv; /* don't abort argument processing */ argv++; argc--; } else { ++*argv; argc--; ptr = *argv++; while (*ptr) { switch (*ptr) { case 'C': /* character name */ (void) strncpy(pseudo, *argv, sizeof(pseudo)); argv++; argc--; break; case 'P': /* authorization password */ (void) strncpy(defpasswd, *argv, sizeof(defpasswd)); { int i; for (i = 0; (*argv)[i]; i++) (*argv)[i] = 0; } argv++; argc--; break; case 'u': usage++; break; case 's': if (*argv) { xtrekPort = atoi(*argv); passive = 1; argv++; argc--; } break; case 'p': if (*argv) { xtrekPort = atoi(*argv); argv++; argc--; } break; case 'd': dpyname = *argv; argc--; argv++; break; case 'm': usemeta = 1; break; case 'h': serverName = *argv; argc--; argv++; break; case 't': title = *argv; argc--; argv++; break; case 'r': defaultsFile = *argv; argv++; argc--; break; #ifdef AUTHORIZE case 'o': RSA_Client = -1; break; case 'R': RSA_Client = -2; break; #else case 'o': case 'R': printf("This client does not have binary authorization.\n"); break; #endif case 'e': #ifdef AUTHORIZE checkExpire(1); #else printf("This client does not RSA verify and will not expire.\n"); #endif exit(0); break; case 'f': /* list ftp sites */ fprintf(stderr, "\n\ The newest version of the Paradise client can be found at:\n\ ftp.netrek.org in /pub/netrek/paradise/bin/\n"); exit(0); case 'G': if (*argv) { ghoststart++; ghost_pno = atoi(*argv); printf("Emergency restart being attempted...\n"); argv++; argc--; } break; case '2': /* force paradise */ paradise = 1; break; case 'F': /* File playback */ if (*argv) { playFile = strdup(*argv); playback = 1; argv++; argc--; } break; case 'x': xpmopt = 0; break; case 'k': /* cookie mode [BDyess] */ useCookieOpt = 1; break; case 'K': /* no-cookies :( [BDyess] */ dontUseCookieOpt = 1; break; case 'v': verbose_image_loading = 1; break; case 'O': /* turn on GXor image drawing [BDyess]*/ useORopt = 1; break; case 'c': /* dump .paradiserc defaults [BDyess] */ dump_defaults = 1; break; default: fprintf(stderr, "%s: unknown option '%c'\n", name, *ptr); err++; break; } ptr++; } } } inittrigtables(); initStars(); /* moved from redraw.c at KAO\'s suggestion */ if (usage || err) { printUsage(name); #ifdef AUTHORIZE checkExpire(1); #endif exit(0); /* exit(err); Exits from checkExpire */ } defaultsFile = initDefaults(defaultsFile); if(xpmopt) xpm = 1; else xpm = booleanDefault("xpm",xpm); if(xpm) printf("XPM mode enabled.\n"); /* command line option overrides .paradiserc value [BDyess] */ if(useORopt) useOR = 1; else useOR = booleanDefault("useOR",useOR); if(useOR) printf("OR mode enabled.\n"); if(useOR || !xpm) cookie = 0; /* default no-cookies unless in XPM mode w/out OR [BDyess] */ /* note: need a milk mode :) */ if(useCookieOpt) cookie = 1; else if(dontUseCookieOpt) cookie = 0; else cookie = booleanDefault("cookie",cookie); if(cookie) printf("Cookie mode enabled.\n"); #ifdef AUTHORIZE if (RSA_Client != -1) checkExpire(0); #endif /* compatability */ if (argc > 0) serverName = argv[0]; srandom(getpid() + time((long *) 0)); if(playback || booleanDefault("playback",0)) { defNickName = "playback"; usemeta=0; serverName = "playback"; } else { if (serverName) { char temp[80], *s; sprintf(temp, "server.%s", serverName); if ((s = stringDefault(temp,NULL))) { printf("Using nickname \"%s\" for server %s\n", serverName, s); defNickName = serverName; serverName = s; defFlavor = stringDefault("flavor",NULL); } } if (!serverName) { serverName = stringDefault("server",NULL); } if (!serverName && !passive) { serverName = DEFAULT_SERVER; usemeta = 1; /* no server specified, show the menu */ } if (passive) serverName = "passive"; /* newwin gets a wrong title otherwise */ if (xtrekPort < 0) xtrekPort = intDefault("port", -1); if (xtrekPort < 0) xtrekPort = DEFAULT_PORT; } /* playback */ build_default_configuration(); metaserverAddress = stringDefault("metaserver", "metaserver.netrek.org"); if (usemeta) openmeta(); W_Initialize(dpyname); metaFork = booleanDefault("metaFork", metaFork); /* do the metawindow thang */ if (usemeta) { metawindow(); metainput(); if (metaFork) W_Initialize(dpyname); newwin(dpyname, name); } else /* this creates the necessary x windows for the game */ newwin(dpyname, name); /* open memory...? */ openmem(); if (!startPlayback()) { if (!passive) { serverName = callServer(xtrekPort, serverName); } else { connectToServer(xtrekPort); } } sendFeature("FEATURE_PACKETS", 'S', 1, 0, 0); timeStart = time(NULL); findslot(); /* sets all the settings from defaults file (.xtrekrc probably) */ resetDefaults(); #ifdef UNIX_SOUND init_sound(); play_sound(SND_PARADISE); #endif mapAll(); /* signal(SIGINT, SIG_IGN);*/ signal(SIGCHLD, reaper); /* Get login name */ if ((pwent = getpwuid(getuid())) != NULL) (void) strncpy(login, pwent->pw_name, sizeof(login)); else (void) strncpy(login, "Bozo", sizeof(login)); login[sizeof(login) - 1] = '\0'; if (pseudo[0] == '\0') { char *freeme; strncpy(pseudo, freeme = stringDefault("name",login), sizeof(pseudo)); free(freeme); } pseudo[sizeof(pseudo) - 1] = '\0'; if (defpasswd[0] == '\0') { char buf[100]; /* added password by character name -JR */ sprintf(buf,"password.%s",pseudo); if((cp = stringDefault(buf,NULL)) || (cp = stringDefault("password",NULL))) (void) strncpy(defpasswd, cp, sizeof(defpasswd)); } defpasswd[sizeof(defpasswd) - 1] = '\0'; /* sendLoginReq("Gray Lensman", "hh", "sfd", 0); loginAccept = -1; while (loginAccept == -1) { socketPause(1,0); readFromServer(); } */ getname(pseudo, defpasswd); loggedIn = 1; /* Set p_hostile to hostile, so if keeppeace is on, the guy starts off hating everyone (like a good fighter should) */ me->p_hostile = (1 << number_of_teams) - 1; redrawTstats(); me->p_planets = 0; me->p_genoplanets = 0; me->p_armsbomb = 0; me->p_genoarmsbomb = 0; /* Set up a reasonable default */ me->p_whydead = KNOREASON; me->p_teami = -1; s_type = defaultShip(CRUISER); /* from rlb7h 11/15/91 TC */ if (booleanDefault("netStats", 1)) startPing(); /* tell the server that we support pings */ /* hack to make galaxy class ships work. This could be more elegant, but the configuration code would have to be modified quite a bit, since the client doesn't know if it's on a paradise server until after it connects, and it needs the configuration info before it connects. */ init_galaxy_class(); initkeymap(-1); /* needs to have ship types initialized -JR */ setjmp(env); /* Reentry point of game */ if (ghoststart) { int i; ghoststart = 0; for (i = -1; i < 5; i++) if (teaminfo[i].letter == me->p_mapchars[0]) break; me->p_teami = i; if (me->p_damage > me->p_ship->s_maxdamage) { me->p_status = POUTFIT; } else me->p_status = PALIVE; } else me->p_status = POUTFIT; while (1) { switch (me->p_status) { case POUTFIT: case PTQUEUE: /* give the player the motd and find out which team he wants */ new_entrywindow(&team, &s_type); allowPlayerlist = 1; if (W_IsMapped(playerw)) playerlist(); if (!playback) if (team == -1) { W_DestroyWindow(w); sendByeReq(); sleep(1); printf("OK, bye!\n"); EXIT(0); } sendVersion(); myship = getship(myship->s_type); currentship = myship->s_type; /* sendOptionsPacket(); this would totally blast any flags you had on the server */ redrawall = 1; enter(); calibrate_stats(); W_ClearWindow(w); /* for (i = 0; i < NSIG; i++) { signal(i, SIG_IGN); } */ me->p_status = PALIVE; /* Put player in game */ #ifdef UNIX_SOUND kill_sound (); #endif hockeyInit(); if (showStats) /* Default showstats are on. */ W_MapWindow(statwin); if (showNewStats) /* default showNewStats are off. [BDyess] */ W_MapWindow(newstatwin); if (tryUdp && commMode != COMM_UDP) { sendUdpReq(COMM_UDP); } if (tryShort) { sendShortReq(SPK_VON); tryShort = 0; /* only try it once */ } /* Send request for a full update */ if (askforUpdate) { if(recv_short) sendShortReq(SPK_SALL); else sendUdpReq(COMM_UPDATE); } sendUpdatePacket(1000000 / updateSpeed); W_Deiconify(baseWin); break; case PALIVE: case PEXPLODE: case PDEAD: case POBSERVE: /* Get input until the player quits or dies */ input(); W_ClearWindow(mapw); break; default: printf("client has p_status=%d. how strange\n", me->p_status); me->p_status = POUTFIT; } } /* NOTREACHED */ }
PUBLIC int run_vm(VMSTATE vms) { OBJ vm_hold; /* Holding register. NOT SEEN BY GC */ int ticks_left = VM_TIMESLICE_TICKS; while (vms->c.vm_state != VM_STATE_DYING && ticks_left-- && vms->r->vm_acc != yield_thread) { if (vms->c.vm_state > 0) { vms->c.vm_state--; if (vms->c.vm_state == 0) { /* Quota expired. Warn. */ vms->c.vm_state = VM_DEFAULT_CPU_QUOTA; vm_raise(vms, (OBJ) newsym("quota-expired"), NULL); /* Make sure we don't recurse :-) */ vms->r->vm_trap_closure = NULL; } } gc_reach_safepoint(); #ifdef DEBUG debug_dump_instr( vms->r->vm_code->vec , vms->c.vm_ip ); #endif switch (CODEAT(vms->c.vm_ip)) { case OP_AT: { int index = CODEAT(vms->c.vm_ip + 1); if (index < 0 || index >= vms->r->vm_acc->length) { vm_raise(vms, (OBJ) newsym("range-check-error"), vms->r->vm_acc); break; } if (!VECTORP(vms->r->vm_acc)) { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), vms->r->vm_acc); break; } vms->r->vm_acc = AT((VECTOR) vms->r->vm_acc, index); vms->c.vm_ip += 2; break; } case OP_ATPUT: { int index = CODEAT(vms->c.vm_ip + 1); vm_hold = PEEK(); if (index < 0 || index >= vm_hold->length) { vm_raise(vms, (OBJ) newsym("range-check-error"), vm_hold); break; } if (!VECTORP(vm_hold)) { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), vm_hold); break; } ATPUT((VECTOR) vm_hold, index, vms->r->vm_acc); vms->c.vm_ip += 2; break; } case OP_MOV_A_LOCL: { int i = CODEAT(vms->c.vm_ip + 1); vm_hold = (OBJ) vms->r->vm_env; while (i-- > 0) vm_hold = AT((VECTOR) vm_hold, 0); vms->r->vm_acc = AT((VECTOR) vm_hold, CODEAT(vms->c.vm_ip + 2) + 1); vms->c.vm_ip += 3; break; } case OP_MOV_A_GLOB: vm_hold = AT(vms->r->vm_lits, CODEAT(vms->c.vm_ip + 1)); vms->r->vm_acc = AT((OVECTOR) vm_hold, SY_VALUE); vms->c.vm_ip += 2; break; case OP_MOV_A_SLOT: { OVECTOR slot, slotname; if (!OBJECTP(vms->r->vm_acc)) { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), vms->r->vm_acc); break; } slotname = (OVECTOR) AT(vms->r->vm_lits, CODEAT(vms->c.vm_ip + 1)); if (!O_CAN_X((OBJECT) vms->r->vm_acc, vms->r->vm_effuid)) { NOPERMISSION((OBJ) slotname); } slot = findslot((OBJECT) vms->r->vm_acc, slotname, NULL); if (slot == NULL) { vm_raise(vms, (OBJ) newsym("slot-not-found"), (OBJ) slotname); break; } if (!MS_CAN_R(slot, vms->r->vm_effuid)) { NOPERMISSION((OBJ) slotname); } vms->r->vm_acc = AT(slot, SL_VALUE); vms->c.vm_ip += 2; break; } case OP_MOV_A_LITL: vms->r->vm_acc = AT(vms->r->vm_lits, CODEAT(vms->c.vm_ip + 1)); vms->c.vm_ip += 2; break; case OP_MOV_A_SELF: vms->r->vm_acc = (OBJ) vms->r->vm_self; vms->c.vm_ip++; break; case OP_MOV_A_FRAM: vms->r->vm_acc = (OBJ) vms->r->vm_frame; vms->c.vm_ip++; break; case OP_MOV_LOCL_A: { int i = CODEAT(vms->c.vm_ip + 1); vm_hold = (OBJ) vms->r->vm_env; while (i-- > 0) vm_hold = AT((VECTOR) vm_hold, 0); ATPUT((VECTOR) vm_hold, CODEAT(vms->c.vm_ip + 2) + 1, vms->r->vm_acc); vms->c.vm_ip += 3; break; } case OP_MOV_GLOB_A: if (!PRIVILEGEDP(vms->r->vm_effuid)) { NOPERMISSION((OBJ) newsym("setting-global-value")); } vm_hold = AT(vms->r->vm_lits, CODEAT(vms->c.vm_ip + 1)); ATPUT((OVECTOR) vm_hold, SY_VALUE, vms->r->vm_acc); vms->c.vm_ip += 2; break; case OP_MOV_SLOT_A: { OVECTOR slot, slotname; OBJECT target = (OBJECT) POP(); OBJECT foundin; if (!OBJECTP(target)) { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), (OBJ) target); break; } slotname = (OVECTOR) AT(vms->r->vm_lits, CODEAT(vms->c.vm_ip + 1)); if (!O_CAN_X(target, vms->r->vm_effuid)) { NOPERMISSION((OBJ) slotname); } slot = findslot(target, slotname, &foundin); if (slot == NULL) { vm_raise(vms, (OBJ) newsym("slot-not-found"), (OBJ) slotname); break; } if (!MS_CAN_W(slot, vms->r->vm_effuid)) { NOPERMISSION((OBJ) slotname); } if (foundin == target) { ATPUT(slot, SL_VALUE, vms->r->vm_acc); } else { OVECTOR newslot = addslot(target, slotname, (OBJECT) AT(slot, SL_OWNER)); ATPUT(newslot, SL_FLAGS, AT(slot, SL_FLAGS)); ATPUT(newslot, SL_VALUE, vms->r->vm_acc); } vms->c.vm_ip += 2; break; } case OP_MOV_FRAM_A: if (!PRIVILEGEDP(vms->r->vm_effuid)) { NOPERMISSION((OBJ) newsym("restoring-vm-frame-pointer")); } if (!OVECTORP(vms->r->vm_acc) || ((OVECTOR) vms->r->vm_acc)->type != T_FRAME) { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), vms->r->vm_acc); break; } vms->r->vm_frame = (OVECTOR) vms->r->vm_acc; vms->c.vm_ip++; break; case OP_PUSH: PUSH(vms->r->vm_acc); vms->c.vm_ip++; break; case OP_POP: vms->r->vm_acc = POP(); vms->c.vm_ip++; break; case OP_SWAP: vm_hold = POP(); PUSH(vms->r->vm_acc); vms->r->vm_acc = vm_hold; vms->c.vm_ip++; break; case OP_VECTOR: vms->r->vm_acc = (OBJ) newvector(CODEAT(vms->c.vm_ip+1)); vms->c.vm_ip += 2; break; case OP_ENTER_SCOPE: vm_hold = (OBJ) newvector(CODEAT(vms->c.vm_ip+1) + 1); ATPUT((VECTOR) vm_hold, 0, (OBJ) vms->r->vm_env); vms->r->vm_env = (VECTOR) vm_hold; vms->c.vm_ip += 2; break; case OP_LEAVE_SCOPE: vms->r->vm_env = (VECTOR) AT(vms->r->vm_env, 0); vms->c.vm_ip++; break; case OP_MAKE_VECTOR: { int i = 0; int len = CODEAT(vms->c.vm_ip+1); VECTOR vec = newvector_noinit(len); for (i = len - 1; i >= 0; i--) ATPUT(vec, i, POP()); vms->r->vm_acc = (OBJ) vec; vms->c.vm_ip += 2; break; } case OP_CLOSURE: vms->r->vm_acc = make_closure_from((OVECTOR) vms->r->vm_acc, vms->r->vm_self, vms->r->vm_env, vms->r->vm_effuid); vms->c.vm_ip++; break; case OP_METHOD_CLOSURE: { OVECTOR methname = (OVECTOR) AT(vms->r->vm_lits, CODEAT(vms->c.vm_ip + 1)); OVECTOR method; if (!OBJECTP(vms->r->vm_acc)) { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), vms->r->vm_acc); break; } method = findmethod((OBJECT) vms->r->vm_acc, methname); if (method == NULL) { vm_raise(vms, (OBJ) newsym("method-not-found"), (OBJ) methname); break; } if (!MS_CAN_R(method, vms->r->vm_effuid)) { NOPERMISSION((OBJ) methname); } vm_hold = (OBJ) newovector(CL_MAXSLOTINDEX, T_CLOSURE); ATPUT((OVECTOR) vm_hold, CL_METHOD, (OBJ) method); ATPUT((OVECTOR) vm_hold, CL_SELF, vms->r->vm_acc); vms->r->vm_acc = vm_hold; vms->c.vm_ip += 2; break; } case OP_RET: if (vms->r->vm_frame != NULL) { restoreframe(vms, vms->r->vm_frame); if (vms->r->vm_code != NULL) break; } vms->c.vm_state = VM_STATE_DYING; return 1; /* finished, nothing more to run! */ case OP_CALL: { OVECTOR methname = (OVECTOR) AT(vms->r->vm_lits, CODEAT(vms->c.vm_ip + 1)); OVECTOR method; if (vms->r->vm_acc == NULL || TAGGEDP(vms->r->vm_acc)) { vm_raise(vms, (OBJ) newsym("null-call-error"), AT(vms->r->vm_lits, CODEAT(vms->c.vm_ip+1))); break; } if (!OBJECTP(vms->r->vm_acc)) { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), vms->r->vm_acc); break; } method = findmethod((OBJECT) vms->r->vm_acc, methname); if (method == NULL) { vm_raise(vms, (OBJ) newsym("method-not-found"), (OBJ) methname); break; } if (!MS_CAN_X(method, vms->r->vm_effuid)) { NOPERMISSION((OBJ) methname); } vm_hold = POP(); if (vm_hold->length-1 != NUM(AT(method, ME_ARGC))) { vm_raise(vms, (OBJ) newsym("wrong-argc"), (OBJ) methname); break; } vms->c.vm_ip += 2; push_frame(vms); vms->r->vm_env = (VECTOR) vm_hold; ATPUT(vms->r->vm_env, 0, AT(method, ME_ENV)); vms->r->vm_code = (BVECTOR) AT(method, ME_CODE); vms->r->vm_lits = (VECTOR) AT(method, ME_LITS); vms->r->vm_self = (OBJECT) vms->r->vm_acc; if (NUM(AT(method, ME_FLAGS)) & O_SETUID) vms->r->vm_effuid = (OBJECT) AT(method, ME_OWNER); vms->r->vm_method = method; vms->c.vm_ip = 0; break; } case OP_CALL_AS: { OVECTOR methname = (OVECTOR) AT(vms->r->vm_lits, CODEAT(vms->c.vm_ip + 1)); OVECTOR method; if (vms->r->vm_self == NULL || vms->r->vm_acc == NULL || TAGGEDP(vms->r->vm_acc)) { vm_raise(vms, (OBJ) newsym("null-call-error"), AT(vms->r->vm_lits, CODEAT(vms->c.vm_ip+1))); break; } if (!OBJECTP(vms->r->vm_acc)) { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), vms->r->vm_acc); break; } method = findmethod((OBJECT) vms->r->vm_acc, methname); if (method == NULL) { vm_raise(vms, (OBJ) newsym("method-not-found"), (OBJ) methname); break; } if (!MS_CAN_X(method, vms->r->vm_effuid)) { NOPERMISSION((OBJ) methname); } vm_hold = POP(); if (vm_hold->length-1 != NUM(AT(method, ME_ARGC))) { vm_raise(vms, (OBJ) newsym("wrong-argc"), (OBJ) methname); break; } vms->c.vm_ip += 2; push_frame(vms); vms->r->vm_env = (VECTOR) vm_hold; ATPUT(vms->r->vm_env, 0, AT(method, ME_ENV)); vms->r->vm_code = (BVECTOR) AT(method, ME_CODE); vms->r->vm_lits = (VECTOR) AT(method, ME_LITS); /* don't set vm_self, this is OP_CALL_AS. */ /* vms->r->vm_self = vms->r->vm_acc; */ if (NUM(AT(method, ME_FLAGS)) & O_SETUID) vms->r->vm_effuid = (OBJECT) AT(method, ME_OWNER); vms->r->vm_method = method; vms->c.vm_ip = 0; break; } case OP_APPLY: vms->c.vm_ip++; apply_closure(vms, (OVECTOR) vms->r->vm_acc, (VECTOR) POP()); break; case OP_JUMP: vms->c.vm_ip += 3 + ((int16_t) CODE16AT(vms->c.vm_ip+1)); break; case OP_JUMP_TRUE: vms->c.vm_ip += (vms->r->vm_acc == false) ? 3 : 3 + ((int16_t) CODE16AT(vms->c.vm_ip+1)); break; case OP_JUMP_FALSE: vms->c.vm_ip += (vms->r->vm_acc != false) ? 3 : 3 + ((int16_t) CODE16AT(vms->c.vm_ip+1)); break; case OP_NOT: vms->r->vm_acc = (vms->r->vm_acc == false) ? true : false; vms->c.vm_ip++; break; case OP_EQ: vms->r->vm_acc = (vms->r->vm_acc == POP()) ? true : false; vms->c.vm_ip++; break; case OP_NE: vms->r->vm_acc = (vms->r->vm_acc != POP()) ? true : false; vms->c.vm_ip++; break; NUMOP(OP_GT, vms->r->vm_acc = (NUM(vms->r->vm_acc) < NUM(POP())) ? true : false); NUMOP(OP_LT, vms->r->vm_acc = (NUM(vms->r->vm_acc) > NUM(POP())) ? true : false); NUMOP(OP_GE, vms->r->vm_acc = (NUM(vms->r->vm_acc) <= NUM(POP())) ? true : false); NUMOP(OP_LE, vms->r->vm_acc = (NUM(vms->r->vm_acc) >= NUM(POP())) ? true : false); NUMOP(OP_NEG, vms->r->vm_acc = MKNUM(-NUM(vms->r->vm_acc))); NUMOP(OP_BNOT, vms->r->vm_acc = MKNUM(~NUM(vms->r->vm_acc))); NUMOP(OP_BOR, vms->r->vm_acc = MKNUM(NUM(vms->r->vm_acc)|NUM(POP()))); NUMOP(OP_BAND, vms->r->vm_acc = MKNUM(NUM(vms->r->vm_acc)&NUM(POP()))); case OP_PLUS: if (vms->r->vm_acc == NULL || PEEK() == NULL) { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), vms->r->vm_acc); break; } if (NUMP(vms->r->vm_acc) && NUMP(PEEK())) vms->r->vm_acc = MKNUM(NUM(vms->r->vm_acc)+NUM(POP())); else if (TAGGEDP(vms->r->vm_acc) || TAGGEDP(PEEK())) { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), vms->r->vm_acc); break; } else if (BVECTORP(vms->r->vm_acc) && BVECTORP(PEEK())) vms->r->vm_acc = (OBJ) bvector_concat((BVECTOR) POP(), (BVECTOR) vms->r->vm_acc); else if (VECTORP(vms->r->vm_acc) && VECTORP(PEEK())) vms->r->vm_acc = (OBJ) vector_concat((VECTOR) POP(), (VECTOR) vms->r->vm_acc); else { vm_raise(vms, (OBJ) newsym("vm-runtime-type-error"), vms->r->vm_acc); break; } vms->c.vm_ip++; break; NUMOP(OP_MINUS, vms->r->vm_acc = MKNUM(NUM(POP())-NUM(vms->r->vm_acc))); NUMOP(OP_STAR, vms->r->vm_acc = MKNUM(NUM(POP())*NUM(vms->r->vm_acc))); NUMOP(OP_SLASH, if (vms->r->vm_acc == MKNUM(0)) vm_raise(vms, (OBJ) newsym("divide-by-zero"), NULL); else vms->r->vm_acc = MKNUM(NUM(POP())/NUM(vms->r->vm_acc))); NUMOP(OP_PERCENT, if (vms->r->vm_acc == MKNUM(0)) vm_raise(vms, (OBJ) newsym("divide-by-zero"), NULL); else vms->r->vm_acc = MKNUM(NUM(POP())%NUM(vms->r->vm_acc))); default: fprintf(stderr, "Unknown bytecode reached (%d == 0x%x).\n", CODEAT(vms->c.vm_ip), CODEAT(vms->c.vm_ip)); exit(MOVE_EXIT_PROGRAMMER_FUCKUP); } } return vms->c.vm_state == VM_STATE_DYING; }