/* - p_b_term - parse one term of a bracketed character list */ static void p_b_term(struct parse *p, cset *cs) { char c; char start, finish; int i; /* classify what we've got */ switch ((MORE()) ? PEEK() : '\0') { case '[': c = (MORE2()) ? PEEK2() : '\0'; break; case '-': SETERROR(REG_ERANGE); return; /* NOTE RETURN */ break; default: c = '\0'; break; } switch (c) { case ':': /* character class */ NEXT2(); REQUIRE(MORE(), REG_EBRACK); c = PEEK(); REQUIRE(c != '-' && c != ']', REG_ECTYPE); p_b_cclass(p, cs); REQUIRE(MORE(), REG_EBRACK); REQUIRE(EATTWO(':', ']'), REG_ECTYPE); break; case '=': /* equivalence class */ NEXT2(); REQUIRE(MORE(), REG_EBRACK); c = PEEK(); REQUIRE(c != '-' && c != ']', REG_ECOLLATE); p_b_eclass(p, cs); REQUIRE(MORE(), REG_EBRACK); REQUIRE(EATTWO('=', ']'), REG_ECOLLATE); break; default: /* symbol, ordinary character, or range */ /* xxx revision needed for multichar stuff */ start = p_b_symbol(p); if (SEE('-') && MORE2() && PEEK2() != ']') { /* range */ NEXT(); if (EAT('-')) finish = '-'; else finish = p_b_symbol(p); } else finish = start; /* xxx what about signed chars here... */ REQUIRE(start <= finish, REG_ERANGE); for (i = start; i <= finish; i++) CHadd(cs, i); break; } }
/* Output one character at the current cursor position */ void __fastcall__ cputc( char c ) { unsigned char x; unsigned char y; unsigned char i; // FIXME: Call MMU to the make sure screen is the enabled device...... // Set or unset reverse video bit, if needed. if( __conio_reverseVideo ) c += 128; // Read the current cursor position. x = PEEK( 0x301 ); y = PEEK( 0x302 ); // Set the display memory window to the line the cursor is on. POKE( 0x300, y ); // Write the character the the column the cursor is in, within the display // memory window. if ( c != '\n') POKE( 0x310+x, c ); // Advance the cursor, moving to the next line and scrolling the screen // if needed. ++x; if( x > 79 || c == '\n' ) { x = 0; if( y >= 49 ) { // Scroll... blit_shift(0,1,0,0,80,49); for (i = 0; i<80; i++) POKE( 0x310 + i, 0x20 ); } else { // no need to set if Y was 49. ++y; POKE( 0x302, y ); POKE( 0x300, y ); // set row too } } // Set the cursor to the new position. POKE( 0x301, x ); }
/* readline()s mingled with other operations: buffering tests. */ static int line_mingle(void) { ne_socket *sock; DECL(oneline, "alpha\nbeta\ndelta\ngamma\n"); CALL(begin(&sock, serve_sstring, &oneline)); READ("a"); LINE("lpha\n"); READ("beta"); LINE("\n"); PEEK("d"); PEEK("delt"); LINE("delta\n"); READ("gam"); LINE("ma\n"); return finish(sock, 1); }
/* - p_b_cclass - parse a character-class name and deal with it */ static void p_b_cclass(struct parse *p, cset *cs) { char *sp = p->next; struct cclass *cp; size_t len; const char *u; char c; while (MORE() && isalpha(PEEK())) NEXT(); len = p->next - sp; for (cp = cclasses; cp->name != NULL; cp++) if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') break; if (cp->name == NULL) { /* oops, didn't find it */ SETERROR(REG_ECTYPE); return; } u = cp->chars; while ((c = *u++) != '\0') CHadd(cs, c); for (u = cp->multis; *u != '\0'; u += strlen(u) + 1) MCadd(p, cs, u); }
static int blocking(void) { ne_socket *sock; int ret; CALL(begin(&sock, echo_server, NULL)); CALL(expect_block_timeout(sock, 1, "with non-zero timeout")); WRITEL("Hello, world.\n"); /* poll for data */ do { ret = ne_sock_block(sock, 1); } while (ret == NE_SOCK_TIMEOUT); ONV(ret != 0, ("ne_sock_block never got data: %d", ret)); PEEK("Hello,"); ret = ne_sock_block(sock, 1); ONV(ret != 0, ("ne_sock_block failed after peek: %d", ret)); LINE("Hello, world.\n"); return finish(sock, 0); }
NODE * get_argument(int i) { NODE *t; int arg_count, pcount; INSTRUCTION *pc; pc = TOP()->code_ptr; /* Op_ext_builtin instruction */ pcount = (pc + 1)->expr_count; /* max # of arguments */ arg_count = pc->expr_count; /* # of arguments supplied */ if (i < 0 || i >= pcount || i >= arg_count) return NULL; t = PEEK(arg_count - i); if (t->type == Node_param_list) t = GET_PARAM(t->param_cnt); if (t->type == Node_array_ref) { if (t->orig_array->type == Node_var) { /* already a scalar, can no longer use it as array */ t->type = Node_var; t->var_value = Nnull_string; return t; } return t->orig_array; /* Node_var_new or Node_var_array */ } if (t->type == Node_var) /* See Case Node_var in setup_frame(), eval.c */ return Nnull_string; /* Node_var_new, Node_var_array or Node_val */ return t; }
void __fastcall__ summaryScreen(void) { // display kills, items, secrets, time // like this // MAP NAME // FINISHED // KILLS % // ITEMS % // SECRET % // TIME 00:00 // PAR 00:00 char kills = p_enemy_getKillPercentage(); char items = getItemPercentage(); char secret = (100*getNumVisitedSecrets())/getNumSecrets(); int time = getMapTime(); int par = getParTime(); // clear screen clearScreen(); textcolor(1); printCentered(caLevelNames[level-1], 1); textcolor(2); printCentered("finished", 2); cputsxy(4, 5, "kills"); cputsxy(4, 7, "items"); cputsxy(4, 9, "secret"); cputsxy(4, 12, "time"); cputsxy(4, 14, "par"); setTextColor(2); POKE(198, 0); rollInPercentage(kills, 0x1000+22*5+14); waitASecond(); rollInPercentage(items, 0x1000+22*7+14); waitASecond(); rollInPercentage(secret, 0x1000+22*9+14); waitASecond(); if (time > 10*60-1) { cputsxy(13,12,"sucks"); playSound(SOUND_PISTOL); } else { rollInTime(time, 0x1000+22*12+13); } waitASecond(); rollInTime(par, 0x1000+22*14+13); waitASecond(); printCentered("press a key", 20); POKE(198, 0); while (PEEK(198) == 0) ; // clear screen clearScreen(); }
/* Return a character from the keyboard. If there is no character available, * the function waits until the user does press a key. If cursor is set to * 1 (see below), a blinking cursor is displayed while waiting. */ char cgetc( void ) { unsigned char key; unsigned char pos; while (!kbhit()) { // WAI } key = PEEK(0x306); pos = PEEK(0x304)+1; if (pos > 0x10) pos = 0; POKE(0x304,pos); return key; }
/* If onoff is 1, a cursor is displayed when waiting for keyboard input. If * onoff is 0, the cursor is hidden when waiting for keyboard input. The * function returns the old cursor setting. */ unsigned char __fastcall__ cursor( unsigned char onoff ) { // FIXME: Call MMU to the make sure screen is the enabled device...... unsigned char oldStatus = PEEK( 0x303 ); if( onoff ) POKE( 0x303, 2 ); else POKE( 0x303, 0 ); return oldStatus; }
void __fastcall__ waitASecond(void) { char i = 60; do { if (PEEK(198) == 0) { waitForRaster(1); } --i; } while (i > 0); }
/* - p_count - parse a repetition count */ static int /* the value */ p_count(struct parse *p) { int count = 0; int ndigits = 0; while (MORE() && isdigit((uch)PEEK()) && count <= DUPMAX) { count = count*10 + (GETNEXT() - '0'); ndigits++; } REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR); return(count); }
/* - p_ere - ERE parser top level, concatenation and alternation == static void p_ere(struct parse *p, int stop, size_t reclimit); */ static void p_ere( struct parse *p, int stop, /* character this ERE should end at */ size_t reclimit) { char c; sopno prevback = 0; /* pacify gcc */ sopno prevfwd = 0; /* pacify gcc */ sopno conc; int first = 1; /* is this the first alternative? */ _DIAGASSERT(p != NULL); if (reclimit++ > RECLIMIT || p->error == REG_ESPACE) { p->error = REG_ESPACE; return; } for (;;) { /* do a bunch of concatenated expressions */ conc = HERE(); while (MORE() && (c = PEEK()) != '|' && c != stop) p_ere_exp(p, reclimit); REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */ if (!EAT('|')) break; /* NOTE BREAK OUT */ if (first) { INSERT(OCH_, conc); /* offset is wrong */ prevfwd = conc; prevback = conc; first = 0; } ASTERN(OOR1, prevback); prevback = THERE(); AHEAD(prevfwd); /* fix previous offset */ prevfwd = HERE(); EMIT(OOR2, 0); /* offset is very wrong */ } if (!first) { /* tail-end fixups */ AHEAD(prevfwd); ASTERN(O_CH, prevback); } assert(!MORE() || SEE(stop)); }
/* Mark resource as initialized */ static void init_usage( ldap_debug_usage_info_t *usage, const char *msg ) { if( !options_done ) get_options(); if( !nomem ) { if( !noreinit ) { MEMERROR_IF( debug_already_initialized( usage ), msg, { /* Provoke malloc debuggers */ unsigned char *dummy = DUMMY_ADDR( usage ); PEEK( dummy ); free( dummy ); free( dummy ); } ); }
/* * create a bunch of random live cells in the requested * graphics page */ void randomize(uint16_t baseaddr[], uint16_t count) { uint16_t r; uint8_t row, col; static uint8_t resetcount = 0; // The Apple zero page has some semi-random garbage // suitable for seeding our PRNG uint16_t seed = PEEK(RSEED1) + PEEK(RSEED2) * 256; ++resetcount; srand(resetcount + seed); lo_clear(gr_page[0], TGI_COLOR_BLACK); while (count--) { r = rand(); // use the high bit to determine which nibble we turn on row = r & ROWRANDMASK; col = (r & COLRANDMASK) >> 8; row %= MAXROWCNT; col %= MAXCOLCNT; //printf("turning on %d,%d with %04x\n", row, col, r); lo_plot(baseaddr, row, col, 0xf); } }
static int line_overflow(void) { ne_socket *sock; ssize_t ret; DECL_LONG(line, 'A', OVERLEN); CALL(begin(&sock, serve_sstring, &line)); PEEK("A"); /* fill the read buffer */ ret = ne_sock_readline(sock, buffer, OVERLEN); ONV(ret != NE_SOCK_ERROR, ("readline should fail on overlong line: %" NE_FMT_SSIZE_T, ret)); ne_free(line.data); return finish(sock, 0); }
void __fastcall__ rollInPercentage(char pc, int scr) { signed char i = -4; POKE(scr + 3,'%'); do { i += 4; if (i > pc) i = pc; print3DigitNumToScreen(i, scr); playSound(SOUND_PISTOL); if (PEEK(198) == 0) { waitForRaster(2); } } while (i < pc); }
void blit_shift(unsigned char sx, unsigned char sy, unsigned char dx, unsigned char dy, unsigned char width, unsigned char height) { // FIXME: Call MMU to the make sure screen is the enabled device...... POKE( 0x30a, dx); POKE( 0x30b, dy); POKE( 0x308, sx ); POKE( 0x309, sy ); POKE( 0x30c, width ); POKE( 0x30d, height ); POKE( 0x307, 3 ); // blitter SHIFT command while ( PEEK( 0x307 ) == 3 ) { // WAI } }
//--------------------------------------------------------------------------- void OGWriteSector(int Side,int Track,int Sector,int Bytes) { FILE *f=fopen(WriteDir+SLASH+"hiscores","r+b"); if (f==NULL) return; int SavePos; for(;;){ int SavedSide=-1,SavedTrack=-1,SavedSector=-1,SavedBytes=-1; SavePos=ftell(f); fread(&SavedSide,1,sizeof(int),f); fread(&SavedTrack,1,sizeof(int),f); fread(&SavedSector,1,sizeof(int),f); fread(&SavedBytes,1,sizeof(int),f); if (SavedSide==-1 || SavedTrack==-1 || SavedSector==-1 || SavedBytes==-1) break; if (SavedSide==Side && SavedTrack==Track && SavedSector==Sector){ if (SavedBytes==Bytes){ // Can save over here break; }else{ fseek(f,SavePos+sizeof(int)*2,SEEK_SET); SavedSector=256; // Clear this one fwrite(&SavedSector,1,sizeof(int),f); fseek(f,SavePos+sizeof(int)*4+SavedBytes,SEEK_SET); } }else{ fseek(f,SavedBytes,SEEK_CUR); } } fseek(f,SavePos,SEEK_SET); fwrite(&Side,1,sizeof(int),f); fwrite(&Track,1,sizeof(int),f); fwrite(&Sector,1,sizeof(int),f); fwrite(&Bytes,1,sizeof(int),f); for (int n=0;n<Bytes;n++){ if (dma_address+n < mem_len){ BYTE b=PEEK(dma_address+n); fwrite(&b,1,1,f); } } fclose(f); }
void __fastcall__ rollInTime(int t, int scr) { int i = -5; char ih, il; POKE(scr + 2,':'); do { i += 5; if (i > t) i = t; ih = i / 60; il = i - 60 * ih; print2DigitNumToScreen(ih, scr); print2DigitNumToScreen(il, scr + 3); playSound(SOUND_PISTOL); if (PEEK(198) == 0) { waitForRaster(2); } } while (i < t); }
/* Stress out the read buffer handling a little. */ static int read_and_peek(void) { ne_socket *sock; DECL(hello, STR); CALL(begin(&sock, serve_sstring, &hello)); PEEK("Hello"); PEEK("Hell"); PEEK(STR); READ("He"); PEEK("llo, "); READ("l"); PEEK("lo, World."); READ("lo, Worl"); PEEK("d."); PEEK("d"); READ("d."); return finish(sock, 1); }
/* - p_ere - ERE parser top level, concatenation and alternation */ static void p_ere(struct parse *p, int stop) /* character this ERE should end at */ { char c; sopno prevback; sopno prevfwd; sopno conc; int first = 1; /* is this the first alternative? */ for (;;) { /* do a bunch of concatenated expressions */ conc = HERE(); while (MORE() && (c = PEEK()) != '|' && c != stop) p_ere_exp(p); REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */ if (!EAT('|')) break; /* NOTE BREAK OUT */ if (first) { INSERT(OCH_, conc); /* offset is wrong */ prevfwd = conc; prevback = conc; first = 0; } ASTERN(OOR1, prevback); prevback = THERE(); AHEAD(prevfwd); /* fix previous offset */ prevfwd = HERE(); EMIT(OOR2, 0); /* offset is very wrong */ } if (!first) { /* tail-end fixups */ AHEAD(prevfwd); ASTERN(O_CH, prevback); } assert(!MORE() || SEE(stop)); }
int parse_exp_redir(struct s_iterator *i, struct s_btree *node) { struct s_token *t; if (HAS_NEXT(i)) { t = PEEK(i); if (t->type == TT_RREDIR) return (parse_exp_rredir(i, node)); else if (t->type == TT_DRREDIR) return (parse_exp_drredir(i, node)); else if (t->type == TT_LREDIR) return (parse_exp_lredir(i, node)); else if (t->type == TT_DLREDIR) return (parse_exp_dlredir(i, node)); else if (t->type == TT_TLREDIR) return (parse_exp_tlredir(i, node)); else return (fprintf(stderr, "error: unexpected token \"%s\"\n", t->string._string), -1); } return (0); }
void blit_fill(unsigned char x, unsigned char y, unsigned char width, unsigned char height, unsigned char fillchar) { // FIXME: Call MMU to the make sure screen is the enabled device...... POKE( 0x308, fillchar); POKE( 0x30a, x); POKE( 0x30b, y); POKE( 0x30c, width ); POKE( 0x30d, height ); POKE( 0x307, 1); // blitter FILL command while ( PEEK( 0x307 ) == 1) { // WAI } // reset blit size to 0 POKE( 0x300, 0 ); // set row to 0 POKE( 0x301, 0 ); POKE( 0x302, 0 ); }
/* * determine which graphics page is active */ uint8_t find_page(void) { return (PEEK(ACTIVEPAGE) & 0x80 ? 1 : 0); }
//--------------------------------------------------------------------------- void OGIntercept() { MEM_ADDRESS OGTitleAd=0,OGPalAd=0; int OGBmpNum=0; switch (pc){ #if ONEGAME_IDX==OG_NM1_IDX case 0x21AA: // Title screen routine areg[0]=0x249E; SET_PC(0x21B0); OGTitleAd=xbios2; break; #elif ONEGAME_IDX==OG_NM2_IDX case 0x216E: // Title screen routine areg[0]=0x8AB4; SET_PC(0x2174); OGTitleAd=xbios2; OGPalAd=areg[0]; for (int i=0;i<16;i++) OGStorePal[i]=m68k_dpeek(OGPalAd + i*2); break; case 0x2178: // Restore palette m68k_lpoke(0x12E80,0x006A0098); SET_PC(0x2182); for (int i=0;i<16;i++) m68k_dpoke(0x8AB4 + i*2,OGStorePal[i]); break; case 0x387E: // Skip "Get ready.." SET_PC(0x389E); break; #elif ONEGAME_IDX==OG_SAT1_IDX case 0x153E: // Title screen routine areg[0]=0xA67E; SET_PC(0x1544); OGTitleAd=xbios2; OGPalAd=areg[0]; for (int i=0;i<16;i++) OGStorePal[i]=m68k_dpeek(OGPalAd + i*2); break; case 0x154A: // Restore palette m68k_dpoke(0x16ea,0x36B0); SET_PC(0x1552); for (int i=0;i<16;i++) m68k_dpoke(0xA67E + i*2,OGStorePal[i]); break; case 0x1984: // "Get ready for battle" case 0x1278: // "Time Over" case 0x17E8: // "Well done warrior" case 0x1802: // "The way to the magic" case 0x181C: // "Kingdom is closer" case 0x18E0: // "You got it" areg[0]=OG_TEXT_ADDRESS+m68k_dpeek(pc+2); SET_PC(pc+4); break; #elif ONEGAME_IDX==OG_SAT2_IDX case 0x11c4: // Title screen routine areg[0]=0xD8C2; SET_PC(0x11ca); OGTitleAd=0x77300; OGPalAd=areg[0]; for (int i=0;i<16;i++) OGStorePal[i]=m68k_dpeek(OGPalAd + i*2); break; case 0x11CE: // Restore palette m68k_dpoke(0x9758,0x64); SET_PC(0x11d6); for (int i=0;i<16;i++) m68k_dpoke(0xD8C2 + i*2,OGStorePal[i]); break; case 0x35BE: // Draw description of item in shop m68k_dpoke(0x93A6,0xe6); SET_PC(0x35C6); if (areg[0]==0x95DE) areg[0]=OG_TEXT_ADDRESS+m68k_dpeek(0x35BE+2); break; #elif ONEGAME_IDX==OG_AW1_IDX case 0xa0aa: // Title screen routine areg[7]-=4; m68k_lpoke(areg[7],0xA0b0); SET_PC(0xA678); OGTitleAd=0x78000; OGPalAd=0x18832; for (int i=0;i<16;i++) OGStorePal[i]=m68k_dpeek(OGPalAd + i*2); break; case 0xA0b0: // Restore palette areg[0]=0x187CE; SET_PC(0xA0b6); for (int i=0;i<16;i++) m68k_dpoke(0x18832 + i*2,OGStorePal[i]); break; case 0x8986: // Load screen fade up areg[7]-=4; m68k_lpoke(areg[7],0x8988); SET_PC(0xA670); OGTitleAd=xbios2; OGPalAd=0x18812; OGBmpNum=1; for (int i=0;i<16;i++) OGStorePal[i]=m68k_dpeek(OGPalAd + i*2); break; case 0x8988: // Load screen restore pal SET_PC(0x898a); for (int i=0;i<16;i++) m68k_dpoke(0x18812 + i*2,OGStorePal[i]); break; case 0x8CEC: // End screen fade up areg[7]-=4; m68k_lpoke(areg[7],0x8CEE); SET_PC(0xA678); OGTitleAd=xbios2; OGPalAd=0x18832; OGBmpNum=2; for (int i=0;i<16;i++) OGStorePal[i]=m68k_dpeek(OGPalAd + i*2); break; case 0x8CEE: // End screen restore pal SET_PC(0x8CF2); for (int i=0;i<16;i++) m68k_dpoke(0x18832 + i*2,OGStorePal[i]); break; case 0x8996: // Fade out before load hook areg[7]-=4; m68k_lpoke(areg[7],0x8998); // return address SET_PC(0x17976); break; case 0x8998: // Do what above instruction should hook areg[7]-=4; m68k_lpoke(areg[7],0x899a); // return address SET_PC(0x8e24); break; #elif ONEGAME_IDX==OG_AW2_IDX case 0xCFDC: // Title screen routine areg[7]-=4; m68k_lpoke(areg[7],0xCFE0); // return address SET_PC(0xfdf4); OGTitleAd=0x78000; OGPalAd=0x14312; for (int i=0;i<16;i++) OGStorePal[i]=m68k_dpeek(OGPalAd + i*2); break; case 0xCFE0: // Restore palette areg[0]=0x125B2; SET_PC(0xCFE4); for (int i=0;i<16;i++) m68k_dpoke(0x14312 + i*2,OGStorePal[i]); break; case 0x01198E: // Load enemy at end of level 2 SET_PC(m68k_lpeek(r[15])); r[15]+=4; OGDrawSprite(10,0x69a62); OGDrawSprite(11,0x69B62); OGDrawSprite(12,0x69C22); OGDrawSprite(13,0x69CA2); break; #endif } if (pOGTitle && OGTitleAd){ MEM_ADDRESS ad=OGTitleAd & 0xffffff; MEM_ADDRESS ad_end=ad+32000; WORD *p=pOGTitle; if (OGBmpNum) if (pOGExtraScreen[OGBmpNum-1]) p=pOGExtraScreen[OGBmpNum-1]; if (ad_end<=mem_len){ while (ad<ad_end){ DPEEK(ad)=*(p++); ad+=2; } if (OGBmpNum==0){ #if ONEGAME_IDX==OG_SAT2_IDX MEM_ADDRESS ad2=0x2B500; #elif ONEGAME_IDX==OG_AW1_IDX MEM_ADDRESS ad2=0x3CE00; #elif ONEGAME_IDX==OG_AW2_IDX MEM_ADDRESS ad2=0x70300; #else MEM_ADDRESS ad2=0; #endif if (ad2){ ad=OGTitleAd & 0xffffff; while (ad<ad_end) PEEK((ad2++))=PEEK((ad++)); } } if (OGPalAd){ for (int i=0;i<16;i++){ DPEEK(OGPalAd)=*(p++); OGPalAd+=2; } }else{ for (int i=0;i<16;i++) STpal[i]=*(p++); palette_convert_all(); } } } }
/* - p_bracket - parse a bracketed character list * * Note a significant property of this code: if the allocset() did SETERROR, * no set operations are done. */ static void p_bracket(struct parse *p) { cset *cs; int invert = 0; /* Dept of Truly Sickening Special-Case Kludges */ if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) { EMIT(OBOW, 0); NEXTn(6); return; } if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) { EMIT(OEOW, 0); NEXTn(6); return; } if ((cs = allocset(p)) == NULL) { /* allocset did set error status in p */ return; } if (EAT('^')) invert++; /* make note to invert set at end */ if (EAT(']')) CHadd(cs, ']'); else if (EAT('-')) CHadd(cs, '-'); while (MORE() && PEEK() != ']' && !SEETWO('-', ']')) p_b_term(p, cs); if (EAT('-')) CHadd(cs, '-'); MUSTEAT(']', REG_EBRACK); if (p->error != 0) { /* don't mess things up further */ freeset(p, cs); return; } if (p->g->cflags®_ICASE) { int i; int ci; for (i = p->g->csetsize - 1; i >= 0; i--) if (CHIN(cs, i) && isalpha(i)) { ci = othercase(i); if (ci != i) CHadd(cs, ci); } if (cs->multis != NULL) mccase(p, cs); } if (invert) { int i; for (i = p->g->csetsize - 1; i >= 0; i--) if (CHIN(cs, i)) CHsub(cs, i); else CHadd(cs, i); if (p->g->cflags®_NEWLINE) CHsub(cs, '\n'); if (cs->multis != NULL) mcinvert(p, cs); } assert(cs->multis == NULL); /* xxx */ if (nch(p, cs) == 1) { /* optimize singleton sets */ ordinary(p, firstch(p, cs)); freeset(p, cs); } else EMIT(OANYOF, freezeset(p, cs)); }
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; }
/* - p_simp_re - parse a simple RE, an atom possibly followed by a repetition */ static int /* was the simple RE an unbackslashed $? */ p_simp_re(struct parse *p, int starordinary) /* is a leading * an ordinary character? */ { int c; int count; int count2; sopno pos; int i; sopno subno; # define BACKSL (1<<CHAR_BIT) pos = HERE(); /* repetion op, if any, covers from here */ assert(MORE()); /* caller should have ensured this */ c = GETNEXT(); if (c == '\\') { REQUIRE(MORE(), REG_EESCAPE); c = BACKSL | GETNEXT(); } switch (c) { case '.': if (p->g->cflags®_NEWLINE) nonnewline(p); else EMIT(OANY, 0); break; case '[': p_bracket(p); break; case BACKSL|'{': SETERROR(REG_BADRPT); break; case BACKSL|'(': p->g->nsub++; subno = p->g->nsub; if (subno < NPAREN) p->pbegin[subno] = HERE(); EMIT(OLPAREN, subno); /* the MORE here is an error heuristic */ if (MORE() && !SEETWO('\\', ')')) p_bre(p, '\\', ')'); if (subno < NPAREN) { p->pend[subno] = HERE(); assert(p->pend[subno] != 0); } EMIT(ORPAREN, subno); REQUIRE(EATTWO('\\', ')'), REG_EPAREN); break; case BACKSL|')': /* should not get here -- must be user */ case BACKSL|'}': SETERROR(REG_EPAREN); break; case BACKSL|'1': case BACKSL|'2': case BACKSL|'3': case BACKSL|'4': case BACKSL|'5': case BACKSL|'6': case BACKSL|'7': case BACKSL|'8': case BACKSL|'9': i = (c&~BACKSL) - '0'; assert(i < NPAREN); if (p->pend[i] != 0) { assert(i <= p->g->nsub); EMIT(OBACK_, i); assert(p->pbegin[i] != 0); assert(OP(p->strip[p->pbegin[i]]) == OLPAREN); assert(OP(p->strip[p->pend[i]]) == ORPAREN); (void) dupl(p, p->pbegin[i]+1, p->pend[i]); EMIT(O_BACK, i); } else SETERROR(REG_ESUBREG); p->g->backrefs = 1; break; case '*': REQUIRE(starordinary, REG_BADRPT); /* FALLTHROUGH */ default: ordinary(p, (char)c); break; } if (EAT('*')) { /* implemented as +? */ /* this case does not require the (y|) trick, noKLUDGE */ INSERT(OPLUS_, pos); ASTERN(O_PLUS, pos); INSERT(OQUEST_, pos); ASTERN(O_QUEST, pos); } else if (EATTWO('\\', '{')) { count = p_count(p); if (EAT(',')) { if (MORE() && isdigit((uch)PEEK())) { count2 = p_count(p); REQUIRE(count <= count2, REG_BADBR); } else /* single number with comma */ count2 = INFINITY; } else /* just a single number */ count2 = count; repeat(p, pos, count, count2); if (!EATTWO('\\', '}')) { /* error heuristics */ while (MORE() && !SEETWO('\\', '}')) NEXT(); REQUIRE(MORE(), REG_EBRACE); SETERROR(REG_BADBR); } } else if (c == '$') /* $ (but not \$) ends it */ return(1); return(0); }
/* - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op */ static void p_ere_exp(struct parse *p) { char c; sopno pos; int count; int count2; sopno subno; int wascaret = 0; assert(MORE()); /* caller should have ensured this */ c = GETNEXT(); pos = HERE(); switch (c) { case '(': REQUIRE(MORE(), REG_EPAREN); p->g->nsub++; subno = p->g->nsub; if (subno < NPAREN) p->pbegin[subno] = HERE(); EMIT(OLPAREN, subno); if (!SEE(')')) p_ere(p, ')'); if (subno < NPAREN) { p->pend[subno] = HERE(); assert(p->pend[subno] != 0); } EMIT(ORPAREN, subno); MUSTEAT(')', REG_EPAREN); break; #ifndef POSIX_MISTAKE case ')': /* happens only if no current unmatched ( */ /* * You may ask, why the ifndef? Because I didn't notice * this until slightly too late for 1003.2, and none of the * other 1003.2 regular-expression reviewers noticed it at * all. So an unmatched ) is legal POSIX, at least until * we can get it fixed. */ SETERROR(REG_EPAREN); break; #endif case '^': EMIT(OBOL, 0); p->g->iflags |= USEBOL; p->g->nbol++; wascaret = 1; break; case '$': EMIT(OEOL, 0); p->g->iflags |= USEEOL; p->g->neol++; break; case '|': SETERROR(REG_EMPTY); break; case '*': case '+': case '?': SETERROR(REG_BADRPT); break; case '.': if (p->g->cflags®_NEWLINE) nonnewline(p); else EMIT(OANY, 0); break; case '[': p_bracket(p); break; case '\\': REQUIRE(MORE(), REG_EESCAPE); c = GETNEXT(); ordinary(p, c); break; case '{': /* okay as ordinary except if digit follows */ REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT); /* FALLTHROUGH */ default: ordinary(p, c); break; } if (!MORE()) return; c = PEEK(); /* we call { a repetition if followed by a digit */ if (!( c == '*' || c == '+' || c == '?' || (c == '{' && MORE2() && isdigit((uch)PEEK2())) )) return; /* no repetition, we're done */ NEXT(); REQUIRE(!wascaret, REG_BADRPT); switch (c) { case '*': /* implemented as +? */ /* this case does not require the (y|) trick, noKLUDGE */ INSERT(OPLUS_, pos); ASTERN(O_PLUS, pos); INSERT(OQUEST_, pos); ASTERN(O_QUEST, pos); break; case '+': INSERT(OPLUS_, pos); ASTERN(O_PLUS, pos); break; case '?': /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ INSERT(OCH_, pos); /* offset slightly wrong */ ASTERN(OOR1, pos); /* this one's right */ AHEAD(pos); /* fix the OCH_ */ EMIT(OOR2, 0); /* offset very wrong... */ AHEAD(THERE()); /* ...so fix it */ ASTERN(O_CH, THERETHERE()); break; case '{': count = p_count(p); if (EAT(',')) { if (isdigit((uch)PEEK())) { count2 = p_count(p); REQUIRE(count <= count2, REG_BADBR); } else /* single number with comma */ count2 = INFINITY; } else /* just a single number */ count2 = count; repeat(p, pos, count, count2); if (!EAT('}')) { /* error heuristics */ while (MORE() && PEEK() != '}') NEXT(); REQUIRE(MORE(), REG_EBRACE); SETERROR(REG_BADBR); } break; } if (!MORE()) return; c = PEEK(); if (!( c == '*' || c == '+' || c == '?' || (c == '{' && MORE2() && isdigit((uch)PEEK2())) ) ) return; SETERROR(REG_BADRPT); }
void ppbuiltin(void) { register int c; register char* p; register char* a; int n; int op; char* token; char* t; long number; long onumber; struct ppinstk* in; struct pplist* list; struct ppsymbol* sym; Sfio_t* sp; number = pp.state; pp.state |= DISABLE|FILEPOP|NOSPACE; token = pp.token; p = pp.token = pp.tmpbuf; *(a = pp.args) = 0; if ((c = pplex()) != T_ID) { error(2, "%s: #(<identifier>...) expected", p); *p = 0; } switch (op = (int)hashget(pp.strtab, p)) { case V_DEFAULT: n = 0; p = pp.token = pp.valbuf; if ((c = pplex()) == ',') { op = -1; c = pplex(); } pp.state &= ~NOSPACE; for (;;) { if (!c) { error(2, "%s in #(...) argument", pptokchr(c)); break; } if (c == '(') n++; else if (c == ')' && !n--) break; else if (c == ',' && !n && op > 0) op = 0; if (op) pp.token = pp.toknxt; c = pplex(); } *pp.token = 0; pp.token = token; pp.state = number; break; case V_EMPTY: p = pp.valbuf; if ((c = pplex()) == ')') *p = '1'; else { *p = '0'; n = 0; for (;;) { if (!c) { error(2, "%s in #(...) argument", pptokchr(c)); break; } if (c == '(') n++; else if (c == ')' && !n--) break; c = pplex(); } } *(p + 1) = 0; pp.token = token; pp.state = number; break; case V_ITERATE: n = 0; pp.token = pp.valbuf; if ((c = pplex()) != T_ID || !(sym = ppsymref(pp.symtab, pp.token)) || !sym->macro || sym->macro->arity != 1 || (c = pplex()) != ',') { error(2, "#(%s <macro(x)>, ...) expected", p); for (;;) { if (!c) { error(2, "%s in #(...) argument", pptokchr(c)); break; } if (c == '(') n++; else if (c == ')' && !n--) break; c = pplex(); } *pp.valbuf = 0; } else while (c != ')') { p = pp.token; if (pp.token > pp.valbuf) *pp.token++ = ' '; STRCOPY(pp.token, sym->name, a); *pp.token++ = '('; if (!c || !(c = pplex())) { pp.token = p; error(2, "%s in #(...) argument", pptokchr(c)); break; } pp.state &= ~NOSPACE; while (c) { if (c == '(') n++; else if (c == ')' && !n--) break; else if (c == ',' && !n) break; pp.token = pp.toknxt; c = pplex(); } *pp.token++ = ')'; pp.state |= NOSPACE; } p = pp.valbuf; pp.token = token; pp.state = number; break; default: pp.token = token; while (c != ')') { if (!c) { error(2, "%s in #(...) argument", pptokchr(c)); break; } if ((c = pplex()) == T_ID && !*a) strcpy(a, pp.token); } pp.state = number; switch (op) { case V_ARGC: c = -1; for (in = pp.in; in; in = in->prev) if ((in->type == IN_MACRO || in->type == IN_MULTILINE) && (in->symbol->flags & SYM_FUNCTION)) { c = *((unsigned char*)(pp.macp->arg[0] - 2)); break; } sfsprintf(p = pp.valbuf, MAXTOKEN, "%d", c); break; case V_BASE: p = (a = strrchr(error_info.file, '/')) ? a + 1 : error_info.file; break; case V_DATE: if (!(p = pp.date)) { time_t tm; time(&tm); a = p = ctime(&tm) + 4; *(p + 20) = 0; for (p += 7; *p = *(p + 9); p++); pp.date = p = strdup(a); } break; case V_FILE: p = error_info.file; break; case V_LINE: sfsprintf(p = pp.valbuf, MAXTOKEN, "%d", error_info.line); break; case V_PATH: p = pp.path; break; case V_SOURCE: p = error_info.file; for (in = pp.in; in->prev; in = in->prev) if (in->prev->type == IN_FILE && in->file) p = in->file; break; case V_STDC: p = pp.valbuf; p[0] = ((pp.state & (COMPATIBILITY|TRANSITION)) || (pp.mode & (HOSTED|HOSTEDTRANSITION)) == (HOSTED|HOSTEDTRANSITION)) ? '0' : '1'; p[1] = 0; break; case V_TIME: if (!(p = pp.time)) { time_t tm; time(&tm); p = ctime(&tm) + 11; *(p + 8) = 0; pp.time = p = strdup(p); } break; case V_VERSION: p = (char*)pp.version; break; case V_DIRECTIVE: pp.state |= NEWLINE; pp.mode |= RELAX; strcpy(p = pp.valbuf, "#"); break; case V_GETENV: if (!(p = getenv(a))) p = ""; break; case V_GETMAC: p = (sym = pprefmac(a, REF_NORMAL)) ? sym->macro->value : ""; break; case V_GETOPT: sfsprintf(p = pp.valbuf, MAXTOKEN, "%ld", ppoption(a)); break; case V_GETPRD: p = (list = (struct pplist*)hashget(pp.prdtab, a)) ? list->value : ""; break; case V__PRAGMA: if ((c = pplex()) == '(') { number = pp.state; pp.state |= NOSPACE|STRIP; c = pplex(); pp.state = number; if (c == T_STRING || c == T_WSTRING) { if (!(sp = sfstropen())) error(3, "temporary buffer allocation error"); sfprintf(sp, "#%s %s\n", dirname(PRAGMA), pp.token); a = sfstruse(sp); if ((c = pplex()) == ')') { pp.state |= NEWLINE; PUSH_BUFFER(p, a, 1); } sfstrclose(sp); } } if (c != ')') error(2, "%s: (\"...\") expected", p); return; case V_FUNCTION: #define BACK(a,p) ((a>p)?*--a:(number++?0:((p=pp.outbuf+PPBUFSIZ),(a=pp.outbuf+2*PPBUFSIZ),*--a))) #define PEEK(a,p) ((a>p)?*(a-1):(number?0:*(pp.outbuf+2*PPBUFSIZ-1))) number = pp.outbuf != pp.outb; a = pp.outp; p = pp.outb; op = 0; while (c = BACK(a, p)) { if (c == '"' || c == '\'') { op = 0; while ((n = BACK(a, p)) && n != c || PEEK(a, p) == '\\'); } else if (c == '\n') { token = a; while (c = BACK(a, p)) if (c == '\n') { a = token; break; } else if (c == '#' && PEEK(a, p) == '\n') break; } else if (c == ' ') /*ignore*/; else if (c == '{') /* '}' */ op = 1; else if (op == 1) { if (c == ')') { op = 2; n = 1; } else op = 0; } else if (op == 2) { if (c == ')') n++; else if (c == '(' && !--n) op = 3; } else if (op == 3) { if (ppisidig(c)) { for (t = p, token = a, onumber = number; ppisidig(PEEK(a, p)) && a >= p; BACK(a, p)); p = pp.valbuf + 1; if (a > token) { for (; a < pp.outbuf+2*PPBUFSIZ; *p++ = *a++); a = pp.outbuf; } for (; a <= token; *p++ = *a++); *p = 0; p = pp.valbuf + 1; if (streq(p, "for") || streq(p, "if") || streq(p, "switch") || streq(p, "while")) { op = 0; p = t; number = onumber; continue; } } else op = 0; break; } } if (op == 3) p = strncpy(pp.funbuf, p, sizeof(pp.funbuf) - 1); else if (*pp.funbuf) p = pp.funbuf; else p = "__FUNCTION__"; break; default: if (pp.builtin && (a = (*pp.builtin)(pp.valbuf, p, a))) p = a; break; } break; } if (strchr(p, MARK)) { a = pp.tmpbuf; strcpy(a, p); c = p != pp.valbuf; p = pp.valbuf + c; for (;;) { if (p < pp.valbuf + MAXTOKEN - 2) switch (*p++ = *a++) { case 0: break; case MARK: *p++ = MARK; /*FALLTHROUGH*/ default: continue; } break; } p = pp.valbuf + c; } if (p == pp.valbuf) PUSH_STRING(p); else { if (p == pp.valbuf + 1) *pp.valbuf = '"'; else { if (strlen(p) > MAXTOKEN - 2) error(1, "%-.16s: builtin value truncated", p); sfsprintf(pp.valbuf, MAXTOKEN, "\"%-.*s", MAXTOKEN - 2, p); } PUSH_QUOTE(pp.valbuf, 1); } }