#include #include #include "vars.h" #include "pline.h" #include "structs.h" #include "format.h" typedef struct ifstack IFSTACK; struct ifstack { IFSTACK *link; unsigned int true; unsigned int evertrue; } ; static void format(FILE *f, const char *s, INVOBJ *io) { IFSTACK *ifstack; OBJTYPE *ot; const char *s0; static void fmtstring(const char *str) { if (! str) panic("invalid %%%c in format %.*s | %s",*s,(int)(s-s0),s0,s); fprintf(f,"%s",str); } static int parse_cond(void) { switch (*s++) { case 'C': return(!!ot->called); break; case '2': return(!!ot->name2); break; case '3': return(!!ot->name3); break; case 'K': return(!!(ot->flags&OTF_KNOWN)); break; case 'P': return(io->dispn>1); break; case '!': return(!parse_cond()); break; case '+': return((*ot->ops->fmt_cond)(*s++,io)); break; case '(': { int v; v = parse_cond(); while (1) { switch (*s++) { case ')': return(v); break; case '|': v = parse_cond() || v; break; case '&': v = parse_cond() && v; break; case '^': if (parse_cond()) v = ! v; break; case '\0': panic("end of format within conditional: %s",s0); break; default: panic("bad conditional connective %c in format %.*s | %s",s[-1],(int)(s-s0),s0,s); break; } } } break; case '\0': panic("end of format within conditional: %s",s0); break; default: panic("bad conditional %c in format %.*s | %s",s[-1],(int)(s-s0),s0,s); break; } } s0 = s; ot = &objtypes[io->v[0]->type]; #define IFTRUE() (!ifstack||ifstack->true) ifstack = 0; while (*s) { if (*s != '%') { if (IFTRUE()) putc(*s,f); s ++; continue; } s ++; switch (*s++) { case '\0': panic("end of format after %%: %s",s0); break; default: panic("invalid spec `%%%c' in format %.*s | %s",s[-1],(int)(s-s0),s0,s); break; case 'n': if (IFTRUE()) fprintf(f,"%d",io->dispn); break; case '1': if (IFTRUE()) fmtstring(ot->name); break; case '2': if (IFTRUE()) fmtstring(ot->name2); break; case '3': if (IFTRUE()) fmtstring(ot->name3); break; case 'c': if (IFTRUE()) fmtstring(ot->called); break; case '@': if (IFTRUE()) panic("%%@ in format: %s",s0); break; case '+': if (IFTRUE()) (*ot->ops->fmt_spec)(f,*s++,io); break; case '?': { int eif; int cond; eif = 0; if (*s == '|') { eif = 1; s ++; } cond = parse_cond(); if (eif) { if (! ifstack) panic("%%?| not within %%?...%%. in format %.*s | %s",(int)(s-s0),s0,s); ifstack->true = cond && !ifstack->evertrue; ifstack->evertrue |= ifstack->true; } else { IFSTACK *i; i = malloc(sizeof(IFSTACK)); if (IFTRUE()) { i->true = cond; i->evertrue = cond; } else { i->true = 0; i->evertrue = 1; } i->link = ifstack; ifstack = i; } } break; case '|': if (! ifstack) panic("%%| not within %%?...%%. in format %.*s | %s",(int)(s-s0),s0,s); if (ifstack->evertrue) { ifstack->true = 0; } else { ifstack->evertrue = 1; ifstack->true = 1; } break; case '.': { IFSTACK *i; if (! ifstack) panic("%%. not closing a %%? in format %.*s | %s",(int)(s-s0),s0,s); i = ifstack; ifstack = i->link; free(i); } break; } } if (ifstack) panic("unclosed conditional in format %s",s0); #undef IFTRUE } void std_format(FILE *f, INVOBJ *io) { format(f,objtypes[io->v[0]->type].format,io); }