static void vcc_ParseVcl(struct vcc *tl) { struct token *tok; assert(vcc_IdIs(tl->t, "vcl")); vcc_NextToken(tl); tok = tl->t; tok->src->syntax = vcc_DoubleVal(tl); ERRCHK(tl); if (tl->t->e - tok->b > 4) { VSB_printf(tl->sb, "Don't play silly buggers with VCL version numbers\n"); vcc_ErrWhere2(tl, tok, tl->t); ERRCHK(tl); } if (tl->syntax != 0.0 && tok->src->syntax > tl->syntax) { VSB_printf(tl->sb, "VCL version %.1f higher than" " the top level version %.1f\n", tok->src->syntax, tl->syntax); vcc_ErrWhere2(tl, tok, tl->t); ERRCHK(tl); } ExpectErr(tl, ';'); vcc_NextToken(tl); }
void vcc_Expr(struct vcc *tl, enum var_type fmt) { struct expr *e; struct token *t1; assert(fmt != VOID); t1 = tl->t; vcc_expr0(tl, &e, fmt); ERRCHK(tl); if (fmt == STRING || fmt == STRING_LIST) vcc_expr_tostring(&e, fmt); if (!tl->err && fmt != e->fmt) { VSB_printf(tl->sb, "Expression has type %s, expected %s\n", vcc_Type(e->fmt), vcc_Type(fmt)); tl->err = 1; } if (!tl->err) { if (e->fmt == STRING_LIST) { e = vcc_expr_edit(STRING_LIST, "\v+\n\v1,\nvrt_magic_string_end\v-", e, NULL); } vcc_expr_fmt(tl->fb, tl->indent, e); VSB_putc(tl->fb, '\n'); } else { if (t1 != tl->t) vcc_ErrWhere2(tl, t1, tl->t); } vcc_delete_expr(e); }
static void vcc_expr0(struct vcc *tl, struct expr **e, enum var_type fmt) { struct expr *e2; struct token *tk; *e = NULL; vcc_expr_cand(tl, e, fmt); ERRCHK(tl); if ((*e)->fmt != BOOL || tl->t->tok != T_COR) return; *e = vcc_expr_edit(BOOL, "(\v+\n\v1", *e, NULL); while (tl->t->tok == T_COR) { vcc_NextToken(tl); tk = tl->t; vcc_expr_cand(tl, &e2, fmt); ERRCHK(tl); if (e2->fmt != BOOL) { VSB_printf(tl->sb, "'||' must be followed by BOOL, found "); VSB_printf(tl->sb, "%s.\n", vcc_Type(e2->fmt)); vcc_ErrWhere2(tl, tk, tl->t); return; } *e = vcc_expr_edit(BOOL, "\v1\v-\n||\v+\n\v2", *e, e2); } *e = vcc_expr_edit(BOOL, "\v1\v-\n)", *e, NULL); }
static void vcc_expr_tostring(struct vcc *tl, struct expr **e, enum var_type fmt) { const char *p; uint8_t constant = EXPR_VAR; CHECK_OBJ_NOTNULL(*e, EXPR_MAGIC); AN(fmt == STRING || fmt == STRING_LIST); p = NULL; switch((*e)->fmt) { case BACKEND: p = "VRT_BACKEND_string(\v1)"; break; case BOOL: p = "VRT_BOOL_string(\v1)"; break; case DURATION: p = "VRT_REAL_string(ctx, \v1)"; break; /* XXX: should DURATION insist on "s" suffix ? */ case INT: if (vcc_isconst(*e)) { p = "\"\v1\""; constant = EXPR_CONST; } else { p = "VRT_INT_string(ctx, \v1)"; } break; case IP: p = "VRT_IP_string(ctx, \v1)"; break; case BYTES: p = "VRT_REAL_string(ctx, \v1)"; break; /* XXX */ case REAL: p = "VRT_REAL_string(ctx, \v1)"; break; case TIME: p = "VRT_TIME_string(ctx, \v1)"; break; case HEADER: p = "VRT_GetHdr(ctx, \v1)"; break; case ENUM: case STRING: case STRING_LIST: break; case BLOB: VSB_printf(tl->sb, "Wrong use of BLOB value.\n" "BLOBs can only be used as arguments to VMOD" " functions.\n"); vcc_ErrWhere2(tl, (*e)->t1, tl->t); return; default: INCOMPL(); break; } if (p != NULL) { *e = vcc_expr_edit(fmt, p, *e, NULL); (*e)->constant = constant; } }
void vcc_Eval_Func(struct vcc *tl, const char *cfunc, const char *extra, const char *name, const char *args) { struct expr *e = NULL; struct token *t1; t1 = tl->t; vcc_func(tl, &e, cfunc, extra, name, args); if (!tl->err) { vcc_expr_fmt(tl->fb, tl->indent, e); VSB_cat(tl->fb, ";\n"); } else if (t1 != tl->t) { vcc_ErrWhere2(tl, t1, tl->t); } vcc_delete_expr(e); }
void vcc_Expr_Call(struct vcc *tl, const struct symbol *sym) { struct expr *e; struct token *t1; t1 = tl->t; e = NULL; vcc_Eval_Func(tl, &e, sym); if (!tl->err) { vcc_expr_fmt(tl->fb, tl->indent, e); VSB_cat(tl->fb, ";\n"); } else if (t1 != tl->t) { vcc_ErrWhere2(tl, t1, tl->t); } vcc_delete_expr(e); }
static void vcc_expr_not(struct vcc *tl, struct expr **e, enum var_type fmt) { struct expr *e2; struct token *tk; *e = NULL; if (fmt != BOOL || tl->t->tok != '!') { vcc_expr_cmp(tl, e, fmt); return; } vcc_NextToken(tl); tk = tl->t; vcc_expr_cmp(tl, &e2, fmt); ERRCHK(tl); if (e2->fmt == BOOL) { *e = vcc_expr_edit(BOOL, "!(\v1)", e2, NULL); return; } VSB_printf(tl->sb, "'!' must be followed by BOOL, found "); VSB_printf(tl->sb, "%s.\n", vcc_Type(e2->fmt)); vcc_ErrWhere2(tl, tk, tl->t); }
static void vcc_expr_add(struct vcc *tl, struct expr **e, enum var_type fmt) { struct expr *e2; enum var_type f2; struct token *tk; *e = NULL; vcc_expr_mul(tl, e, fmt); ERRCHK(tl); f2 = (*e)->fmt; if ((f2 == STRING_LIST || f2 == STRING) && tl->t->tok == '+') { while (tl->t->tok == '+') { vcc_NextToken(tl); vcc_expr_mul(tl, &e2, STRING); ERRCHK(tl); if (e2->fmt != STRING && e2->fmt != STRING_LIST) vcc_expr_tostring(&e2, f2); ERRCHK(tl); assert(e2->fmt == STRING || e2->fmt == STRING_LIST); if ((*e)->constant && e2->constant) { assert((*e)->fmt == STRING); assert(e2->fmt == STRING); *e = vcc_expr_edit(STRING, "\v1\n\v2", *e, e2); } else { *e = vcc_expr_edit(STRING_LIST, "\v1,\n\v2", *e, e2); } } } if (fmt != STRING_LIST && (*e)->fmt == STRING_LIST) *e = vcc_expr_edit(STRING, "\v+VRT_WrkString(sp,\n\v1,\nvrt_magic_string_end)", *e, NULL); if (fmt == STRING_LIST && (*e)->fmt == STRING) (*e)->fmt = STRING_LIST; switch(f2) { case INT: break; case TIME: break; case DURATION: break; case BYTES: break; default: if (tl->t->tok != '+' && tl->t->tok != '-') return; VSB_printf(tl->sb, "Operator %.*s not possible on type %s.\n", PF(tl->t), vcc_Type(f2)); vcc_ErrWhere(tl, tl->t); return; } while (tl->t->tok == '+' || tl->t->tok == '-') { if (f2 == TIME) f2 = DURATION; tk = tl->t; vcc_NextToken(tl); vcc_expr_mul(tl, &e2, f2); ERRCHK(tl); if (tk->tok == '-' && (*e)->fmt == TIME && e2->fmt == TIME) { /* OK */ } else if (tk->tok == '-' && (*e)->fmt == BYTES && e2->fmt == BYTES) { /* OK */ } else if (e2->fmt != f2) { VSB_printf(tl->sb, "%s %.*s %s not possible.\n", vcc_Type((*e)->fmt), PF(tk), vcc_Type(e2->fmt)); vcc_ErrWhere2(tl, tk, tl->t); return; } if (tk->tok == '+') *e = vcc_expr_edit(f2, "(\v1+\v2)", *e, e2); else if (f2 == TIME && e2->fmt == TIME) *e = vcc_expr_edit(DURATION, "(\v1-\v2)", *e, e2); else *e = vcc_expr_edit(f2, "(\v1-\v2)", *e, e2); } }
void vcc_Eval_Func(struct vcc *tl, struct expr **e, const struct symbol *sym) { const char *p, *r; struct expr *e1, *e2; enum var_type fmt; char buf[32]; assert(sym->kind == SYM_FUNC || sym->kind == SYM_PROC); AN(sym->cfunc); AN(sym->args); SkipToken(tl, ID); SkipToken(tl, '('); p = sym->args; e2 = vcc_mk_expr(vcc_arg_type(&p), "%s(sp\v+", sym->cfunc); while (*p != '\0') { e1 = NULL; fmt = vcc_arg_type(&p); if (fmt == VOID && !strcmp(p, "PRIV_VCL")) { r = strchr(sym->name, '.'); AN(r); e1 = vcc_mk_expr(VOID, "&vmod_priv_%.*s", r - sym->name, sym->name); p += strlen(p) + 1; } else if (fmt == VOID && !strcmp(p, "PRIV_CALL")) { bprintf(buf, "vmod_priv_%u", tl->nvmodpriv++); Fh(tl, 0, "struct vmod_priv %s;\n", buf); e1 = vcc_mk_expr(VOID, "&%s", buf); p += strlen(p) + 1; } else if (fmt == ENUM) { ExpectErr(tl, ID); ERRCHK(tl); r = p; do { if (vcc_IdIs(tl->t, p)) break; p += strlen(p) + 1; } while (*p != '\0'); if (*p == '\0') { VSB_printf(tl->sb, "Wrong enum value."); VSB_printf(tl->sb, " Expected one of:\n"); do { VSB_printf(tl->sb, "\t%s\n", r); r += strlen(r) + 1; } while (*r != '\0'); vcc_ErrWhere(tl, tl->t); return; } e1 = vcc_mk_expr(VOID, "\"%.*s\"", PF(tl->t)); while (*p != '\0') p += strlen(p) + 1; p++; SkipToken(tl, ID); if (*p != '\0') SkipToken(tl, ','); } else if (fmt == HEADER) { const struct var *v; sym = VCC_FindSymbol(tl, tl->t, SYM_NONE); ERRCHK(tl); SkipToken(tl, ID); if (sym == NULL) { VSB_printf(tl->sb, "Symbol not found.\n"); vcc_ErrWhere(tl, tl->t); return; } vcc_AddUses(tl, tl->t, sym->r_methods, "Not available"); if (sym->kind != SYM_VAR) { VSB_printf(tl->sb, "Wrong kind of symbol.\n"); vcc_ErrWhere(tl, tl->t); return; } AN(sym->var); v = sym->var; if (v->http == NULL) { VSB_printf(tl->sb, "Variable not an HTTP header.\n"); vcc_ErrWhere(tl, tl->t); return; } e1 = vcc_mk_expr(VOID, "%s, \"%s\"", v->http, v->hdr); if (*p != '\0') SkipToken(tl, ','); } else { vcc_expr0(tl, &e1, fmt); ERRCHK(tl); if (e1->fmt != fmt) { VSB_printf(tl->sb, "Wrong argument type."); VSB_printf(tl->sb, " Expected %s.", vcc_Type(fmt)); VSB_printf(tl->sb, " Got %s.\n", vcc_Type(e1->fmt)); vcc_ErrWhere2(tl, e1->t1, tl->t); return; } assert(e1->fmt == fmt); if (e1->fmt == STRING_LIST) { e1 = vcc_expr_edit(STRING_LIST, "\v+\n\v1,\nvrt_magic_string_end\v-", e1, NULL); } if (*p != '\0') SkipToken(tl, ','); } e2 = vcc_expr_edit(e2->fmt, "\v1,\n\v2", e2, e1); } SkipToken(tl, ')'); e2 = vcc_expr_edit(e2->fmt, "\v1\n)\v-", e2, NULL); *e = e2; }
void vcc_Parse(struct vcc *tl) { struct toplev *tp; struct token *tok; AZ(tl->indent); if (tl->t->tok != ID || !vcc_IdIs(tl->t, "vcl")) { VSB_printf(tl->sb, "VCL version declaration missing\n" "Update your VCL to Version 4 syntax, and add\n" "\tvcl 4.0;\n" "on the first line of the VCL files.\n" ); vcc_ErrWhere(tl, tl->t); ERRCHK(tl); } tok = tl->t; vcc_ParseVcl(tl); if (tok->src->syntax != 4.0) { VSB_printf(tl->sb, "VCL version %.1f not supported.\n", tok->src->syntax); vcc_ErrWhere2(tl, tok, tl->t); ERRCHK(tl); } tl->syntax = tl->t->src->syntax; ERRCHK(tl); while (tl->t->tok != EOI) { ERRCHK(tl); switch (tl->t->tok) { case CSRC: if (tl->allow_inline_c) { Fc(tl, 0, "%.*s\n", (int) (tl->t->e - (tl->t->b + 4)), tl->t->b + 2); vcc_NextToken(tl); } else { VSB_printf(tl->sb, "Inline-C not allowed\n"); vcc_ErrWhere(tl, tl->t); } break; case EOI: break; case ID: for (tp = toplev; tp->name != NULL; tp++) { if (!vcc_IdIs(tl->t, tp->name)) continue; tp->func(tl); break; } if (tp->name != NULL) break; /* FALLTHROUGH */ default: /* We deliberately do not mention inline-C */ VSB_printf(tl->sb, "Expected one of\n\t"); for (tp = toplev; tp->name != NULL; tp++) { if (tp[1].name == NULL) VSB_printf(tl->sb, " or "); VSB_printf(tl->sb, "'%s'", tp->name); if (tp[1].name != NULL) VSB_printf(tl->sb, ", "); } VSB_printf(tl->sb, "\nFound: "); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at\n"); vcc_ErrWhere(tl, tl->t); return; } } AZ(tl->indent); }
void vcc_ParseImport(struct vcc *tl) { void *hdl; char fn[1024], *fnp, *fnpx; char buf[256]; struct token *mod, *t1; struct inifin *ifp; const char * const *spec; struct symbol *sym; struct symbol *msym; const struct symbol *osym; const char *p; // int *modlen; const struct vmod_data *vmd; t1 = tl->t; SkipToken(tl, ID); /* "import" */ ExpectErr(tl, ID); mod = tl->t; vcc_NextToken(tl); osym = VCC_SymbolTok(tl, NULL, mod, SYM_NONE, 0); if (osym != NULL && osym->kind != SYM_VMOD) { VSB_printf(tl->sb, "Module %.*s conflicts with other symbol.\n", PF(mod)); vcc_ErrWhere2(tl, t1, tl->t); return; } if (osym != NULL) { VSB_printf(tl->sb, "Module %.*s already imported.\n", PF(mod)); vcc_ErrWhere2(tl, t1, tl->t); VSB_printf(tl->sb, "Previous import was here:\n"); vcc_ErrWhere2(tl, osym->def_b, osym->def_e); return; } bprintf(fn, "%.*s", PF(mod)); msym = VCC_Symbol(tl, NULL, fn, NULL, SYM_VMOD, 1); ERRCHK(tl); AN(msym); msym->def_b = t1; msym->def_e = tl->t; if (tl->t->tok == ID) { if (!vcc_IdIs(tl->t, "from")) { VSB_printf(tl->sb, "Expected 'from path ...'\n"); vcc_ErrWhere(tl, tl->t); return; } vcc_NextToken(tl); if (!tl->unsafe_path && strchr(tl->t->dec, '/')) { VSB_printf(tl->sb, "'import ... from path ...' is unsafe.\nAt:"); vcc_ErrToken(tl, tl->t); vcc_ErrWhere(tl, tl->t); return; } ExpectErr(tl, CSTR); p = strrchr(tl->t->dec, '/'); if (p != NULL && p[1] == '\0') bprintf(fn, "%slibvmod_%.*s.so", tl->t->dec, PF(mod)); else bprintf(fn, "%s", tl->t->dec); vcc_NextToken(tl); } else { bprintf(fn, "libvmod_%.*s.so", PF(mod)); } SkipToken(tl, ';'); if (VFIL_searchpath(tl->vmod_path, vcc_path_dlopen, &hdl, fn, &fnpx)) { VSB_printf(tl->sb, "Could not load VMOD %.*s\n", PF(mod)); VSB_printf(tl->sb, "\tFile name: %s\n", fnpx != NULL ? fnpx : fn); VSB_printf(tl->sb, "\tdlerror: %s\n", dlerror()); vcc_ErrWhere(tl, mod); free(fnpx); return; } AN(fnpx); fnp = TlDup(tl, fnpx); free(fnpx); bprintf(buf, "Vmod_%.*s_Data", PF(mod)); vmd = dlsym(hdl, buf); if (vmd == NULL) { VSB_printf(tl->sb, "Malformed VMOD %.*s\n", PF(mod)); VSB_printf(tl->sb, "\tFile name: %s\n", fnp); VSB_printf(tl->sb, "\t(no Vmod_Data symbol)\n"); vcc_ErrWhere(tl, mod); return; } if (strcmp(VCS_Branch, "master") == 0 && strcmp(vmd->abi, VMOD_ABI_Version) != 0) { VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(mod)); VSB_printf(tl->sb, "\tFile name: %s\n", fnp); VSB_printf(tl->sb, "\tABI mismatch, expected <%s>, got <%s>\n", VMOD_ABI_Version, vmd->abi); vcc_ErrWhere(tl, mod); return; } if (vmd->vrt_major != VRT_MAJOR_VERSION || vmd->vrt_minor > VRT_MINOR_VERSION) { VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(mod)); VSB_printf(tl->sb, "\tFile name: %s\n", fnp); VSB_printf(tl->sb, "\tVMOD version %u.%u\n", vmd->vrt_major, vmd->vrt_minor); VSB_printf(tl->sb, "\tvarnishd version %u.%u\n", VRT_MAJOR_VERSION, VRT_MINOR_VERSION); vcc_ErrWhere(tl, mod); return; } if (vmd->name == NULL || vmd->func == NULL || vmd->func_len <= 0 || vmd->proto == NULL || vmd->abi == NULL) { VSB_printf(tl->sb, "Mangled VMOD %.*s\n", PF(mod)); VSB_printf(tl->sb, "\tFile name: %s\n", fnp); VSB_printf(tl->sb, "\tInconsistent metadata\n"); vcc_ErrWhere(tl, mod); return; } if (!vcc_IdIs(mod, vmd->name)) { VSB_printf(tl->sb, "Wrong VMOD file %.*s\n", PF(mod)); VSB_printf(tl->sb, "\tFile name: %s\n", fnp); VSB_printf(tl->sb, "\tContains vmod \"%s\"\n", vmd->name); vcc_ErrWhere(tl, mod); return; } ifp = New_IniFin(tl); VSB_printf(ifp->ini, "\tif (VRT_Vmod_Init(&VGC_vmod_%.*s,\n", PF(mod)); VSB_printf(ifp->ini, "\t &Vmod_%.*s_Func,\n", PF(mod)); VSB_printf(ifp->ini, "\t sizeof(Vmod_%.*s_Func),\n", PF(mod)); VSB_printf(ifp->ini, "\t \"%.*s\",\n", PF(mod)); VSB_printf(ifp->ini, "\t "); VSB_quote(ifp->ini, fnp, -1, VSB_QUOTE_CSTR); VSB_printf(ifp->ini, ",\n"); AN(vmd); AN(vmd->file_id); VSB_printf(ifp->ini, "\t \"%s\",\n", vmd->file_id); VSB_printf(ifp->ini, "\t ctx))\n"); VSB_printf(ifp->ini, "\t\treturn(1);"); /* XXX: zero the function pointer structure ?*/ VSB_printf(ifp->fin, "\t\tVRT_priv_fini(&vmod_priv_%.*s);", PF(mod)); VSB_printf(ifp->fin, "\n\t\tVRT_Vmod_Fini(&VGC_vmod_%.*s);", PF(mod)); ifp = NULL; spec = vmd->spec; for (; *spec != NULL; spec++) { p = *spec; if (!strcmp(p, "$OBJ")) { p += strlen(p) + 1; sym = VCC_Symbol(tl, NULL, p, NULL, SYM_OBJECT, 1); XXXAN(sym); sym->extra = p; sym->vmod = msym->name; } else if (!strcmp(p, "$EVENT")) { p += strlen(p) + 1; if (ifp == NULL) ifp = New_IniFin(tl); VSB_printf(ifp->ini, "\tif (%s(ctx, &vmod_priv_%.*s, VCL_EVENT_LOAD))\n" "\t\treturn(1);", p, PF(mod)); VSB_printf(ifp->fin, "\t\t(void)%s(ctx, &vmod_priv_%.*s,\n" "\t\t VCL_EVENT_DISCARD);\n", p, PF(mod)); VSB_printf(ifp->event, "\t%s(ctx, &vmod_priv_%.*s, ev)", p, PF(mod)); } else if (!strcmp(p, "$FUNC")) { p += strlen(p) + 1; sym = VCC_Symbol(tl, NULL, p, NULL, SYM_FUNC, 1); ERRCHK(tl); AN(sym); sym->vmod = msym->name; sym->eval = vcc_Eval_SymFunc; p += strlen(p) + 1; sym->eval_priv = p; sym->fmt = VCC_Type(p); AN(sym->fmt); } else { VSB_printf(tl->sb, "Internal spec error (%s)\n", p); vcc_ErrWhere(tl, mod); return; } } Fh(tl, 0, "\n/* --- BEGIN VMOD %.*s --- */\n\n", PF(mod)); Fh(tl, 0, "static struct vmod *VGC_vmod_%.*s;\n", PF(mod)); Fh(tl, 0, "static struct vmod_priv vmod_priv_%.*s;\n", PF(mod)); Fh(tl, 0, "\n%s\n", vmd->proto); Fh(tl, 0, "\n/* --- END VMOD %.*s --- */\n\n", PF(mod)); }
static void vcc_expr_add(struct vcc *tl, struct expr **e, enum var_type fmt) { struct expr *e2; enum var_type f2; struct token *tk; *e = NULL; vcc_expr_mul(tl, e, fmt); ERRCHK(tl); f2 = (*e)->fmt; /* Unless we specifically ask for a HEADER, fold them to string here */ if (fmt != HEADER && f2 == HEADER) { vcc_expr_tostring(tl, e, STRING); ERRCHK(tl); f2 = (*e)->fmt; assert(f2 == STRING); } if (tl->t->tok != '+' && tl->t->tok != '-') return; switch(f2) { case STRING: case STRING_LIST: vcc_expr_string_add(tl, e); return; case INT: break; case TIME: break; case DURATION: break; case BYTES: break; default: VSB_printf(tl->sb, "Operator %.*s not possible on type %s.\n", PF(tl->t), vcc_Type(f2)); vcc_ErrWhere(tl, tl->t); return; } while (tl->t->tok == '+' || tl->t->tok == '-') { if (f2 == TIME) f2 = DURATION; tk = tl->t; vcc_NextToken(tl); vcc_expr_mul(tl, &e2, f2); ERRCHK(tl); if (tk->tok == '-' && (*e)->fmt == TIME && e2->fmt == TIME) { /* OK */ } else if ((*e)->fmt == TIME && e2->fmt == DURATION) { f2 = TIME; /* OK */ } else if (tk->tok == '-' && (*e)->fmt == BYTES && e2->fmt == BYTES) { /* OK */ } else if (e2->fmt != f2) { VSB_printf(tl->sb, "%s %.*s %s not possible.\n", vcc_Type((*e)->fmt), PF(tk), vcc_Type(e2->fmt)); vcc_ErrWhere2(tl, tk, tl->t); return; } if (tk->tok == '+') *e = vcc_expr_edit(f2, "(\v1+\v2)", *e, e2); else if (f2 == TIME && e2->fmt == TIME) *e = vcc_expr_edit(DURATION, "(\v1-\v2)", *e, e2); else *e = vcc_expr_edit(f2, "(\v1-\v2)", *e, e2); } }
static void vcc_func(struct vcc *tl, struct expr **e, const char *cfunc, const char *extra, const char *name, const char *args) { const char *p, *r; struct expr *e1, *e2; struct inifin *ifp; enum var_type fmt; char buf[32]; AN(cfunc); AN(args); AN(name); SkipToken(tl, '('); p = args; if (extra == NULL) extra = ""; e1 = vcc_mk_expr(vcc_arg_type(&p), "%s(ctx%s\v+", cfunc, extra); while (*p != '\0') { e2 = NULL; fmt = vcc_arg_type(&p); if (fmt == VOID && !strcmp(p, "PRIV_VCL")) { r = strchr(name, '.'); AN(r); e2 = vcc_mk_expr(VOID, "&vmod_priv_%.*s", (int) (r - name), name); p += strlen(p) + 1; } else if (fmt == VOID && !strcmp(p, "PRIV_CALL")) { bprintf(buf, "vmod_priv_%u", tl->unique++); ifp = New_IniFin(tl); Fh(tl, 0, "static struct vmod_priv %s;\n", buf); VSB_printf(ifp->fin, "\tvmod_priv_fini(&%s);", buf); e2 = vcc_mk_expr(VOID, "&%s", buf); p += strlen(p) + 1; } else if (fmt == ENUM) { ExpectErr(tl, ID); ERRCHK(tl); r = p; do { if (vcc_IdIs(tl->t, p)) break; p += strlen(p) + 1; } while (*p != '\0'); if (*p == '\0') { VSB_printf(tl->sb, "Wrong enum value."); VSB_printf(tl->sb, " Expected one of:\n"); do { VSB_printf(tl->sb, "\t%s\n", r); r += strlen(r) + 1; } while (*r != '\0'); vcc_ErrWhere(tl, tl->t); return; } e2 = vcc_mk_expr(VOID, "\"%.*s\"", PF(tl->t)); while (*p != '\0') p += strlen(p) + 1; p++; SkipToken(tl, ID); if (*p != '\0') /*lint !e448 */ SkipToken(tl, ','); } else { vcc_expr0(tl, &e2, fmt); ERRCHK(tl); if (e2->fmt != fmt) { VSB_printf(tl->sb, "Wrong argument type."); VSB_printf(tl->sb, " Expected %s.", vcc_Type(fmt)); VSB_printf(tl->sb, " Got %s.\n", vcc_Type(e2->fmt)); vcc_ErrWhere2(tl, e2->t1, tl->t); return; } assert(e2->fmt == fmt); if (e2->fmt == STRING_LIST) { e2 = vcc_expr_edit(STRING_LIST, "\v+\n\v1,\nvrt_magic_string_end\v-", e2, NULL); } if (*p != '\0') SkipToken(tl, ','); } e1 = vcc_expr_edit(e1->fmt, "\v1,\n\v2", e1, e2); } SkipToken(tl, ')'); e1 = vcc_expr_edit(e1->fmt, "\v1\n)\v-", e1, NULL); *e = e1; }
static void parse_new(struct vcc *tl) { struct symbol *sy1, *sy2, *sy3; struct inifin *ifp; const char *p, *s_obj, *s_init, *s_struct, *s_fini; char buf1[128]; char buf2[128]; vcc_NextToken(tl); ExpectErr(tl, ID); if (!vcc_isCid(tl->t)) { VSB_printf(tl->sb, "Names of VCL objects cannot contain '-'\n"); vcc_ErrWhere(tl, tl->t); return; } sy1 = VCC_FindSymbol(tl, tl->t, SYM_NONE); if (sy1 != NULL) { VSB_printf(tl->sb, "Object name '%.*s' already used.\n", PF(tl->t)); VSB_printf(tl->sb, "First usage:\n"); AN(sy1->def_b); if (sy1->def_e != NULL) vcc_ErrWhere2(tl, sy1->def_b, sy1->def_e); else vcc_ErrWhere(tl, sy1->def_b); VSB_printf(tl->sb, "Redefinition:\n"); vcc_ErrWhere(tl, tl->t); return; } sy1 = VCC_AddSymbolTok(tl, tl->t, SYM_NONE); // XXX: NONE ? XXXAN(sy1); sy1->def_b = tl->t; vcc_NextToken(tl); ExpectErr(tl, '='); vcc_NextToken(tl); ExpectErr(tl, ID); sy2 = VCC_FindSymbol(tl, tl->t, SYM_OBJECT); if (sy2 == NULL) { VSB_printf(tl->sb, "Symbol not found: "); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at "); vcc_ErrWhere(tl, tl->t); return; } XXXAN(sy2); /*lint -save -e448 */ /* Split the first three args */ p = sy2->args; s_obj = p; p += strlen(p) + 1; s_init = p; while (p[0] != '\0' || p[1] != '\0') p++; p += 2; s_struct = p; p += strlen(p) + 1; s_fini = p + strlen(p) + 1; while (p[0] != '\0' || p[1] != '\0') p++; p += 2; Fh(tl, 0, "static %s *vo_%s;\n\n", s_struct, sy1->name); vcc_NextToken(tl); bprintf(buf1, ", &vo_%s, \"%s\"", sy1->name, sy1->name); vcc_Eval_Func(tl, s_init, buf1, "ASDF", s_init + strlen(s_init) + 1); ifp = New_IniFin(tl); VSB_printf(ifp->fin, "\t%s(&vo_%s);", s_fini, sy1->name); ExpectErr(tl, ';'); bprintf(buf1, ", vo_%s", sy1->name); /* Split the methods from the args */ while (*p != '\0') { p += strlen(s_obj); bprintf(buf2, "%s%s", sy1->name, p); sy3 = VCC_AddSymbolStr(tl, buf2, SYM_FUNC); AN(sy3); sy3->eval = vcc_Eval_SymFunc; p += strlen(p) + 1; sy3->cfunc = p; p += strlen(p) + 1; /* Functions which return VOID are procedures */ if (!memcmp(p, "VOID\0", 5)) sy3->kind = SYM_PROC; sy3->args = p; sy3->extra = TlDup(tl, buf1); while (p[0] != '\0' || p[1] != '\0') { if (!memcmp(p, "ENUM\0", 5)) { /* XXX: Special case for ENUM that has it's own \0\0 end marker. Not exactly elegant, we should consider alternatives here. Maybe runlength encode the entire block? */ p += strlen(p) + 1; while (p[0] != '\0' || p[1] != '\0') p++; } p++; } p += 2; } sy1->def_e = tl->t; /*lint -restore */ }
void vcc_ParseImport(struct vcc *tl) { void *hdl; char fn[1024]; char buf[256]; struct token *mod, *t1; const char *modname; const char *proto; const char *abi; const char **spec; struct symbol *sym; const struct symbol *osym; const char *p; // int *modlen; t1 = tl->t; SkipToken(tl, ID); /* "import" */ ExpectErr(tl, ID); mod = tl->t; vcc_NextToken(tl); osym = VCC_FindSymbol(tl, mod, SYM_NONE); if (osym != NULL && osym->kind != SYM_VMOD) { VSB_printf(tl->sb, "Module %.*s conflics with other symbol.\n", PF(mod)); vcc_ErrWhere2(tl, t1, tl->t); return; } if (osym != NULL) { VSB_printf(tl->sb, "Module %.*s already imported.\n", PF(mod)); vcc_ErrWhere2(tl, t1, tl->t); VSB_printf(tl->sb, "Previous import was here:\n"); vcc_ErrWhere2(tl, osym->def_b, osym->def_e); return; } bprintf(fn, "%.*s", PF(mod)); sym = VCC_AddSymbolStr(tl, fn, SYM_VMOD); ERRCHK(tl); AN(sym); sym->def_b = t1; sym->def_e = tl->t; if (tl->t->tok == ID) { if (!tl->unsafe_path) { VSB_printf(tl->sb, "'import ... from path...'" " not allowed.\nAt:"); vcc_ErrToken(tl, tl->t); vcc_ErrWhere(tl, tl->t); return; } if (!vcc_IdIs(tl->t, "from")) { VSB_printf(tl->sb, "Expected 'from path...'\n"); vcc_ErrWhere(tl, tl->t); return; } vcc_NextToken(tl); ExpectErr(tl, CSTR); bprintf(fn, "%s", tl->t->dec); vcc_NextToken(tl); } else { bprintf(fn, "%s/libvmod_%.*s.so", tl->vmod_dir, PF(mod)); } Fh(tl, 0, "static void *VGC_vmod_%.*s;\n", PF(mod)); Fi(tl, 0, "\tif (VRT_Vmod_Init(&VGC_vmod_%.*s,\n", PF(mod)); Fi(tl, 0, "\t &Vmod_%.*s_Func,\n", PF(mod)); Fi(tl, 0, "\t sizeof(Vmod_%.*s_Func),\n", PF(mod)); Fi(tl, 0, "\t \"%.*s\",\n", PF(mod)); Fi(tl, 0, "\t "); EncString(tl->fi, fn, NULL, 0); Fi(tl, 0, ",\n\t "); Fi(tl, 0, "cli))\n"); Fi(tl, 0, "\t\treturn(1);\n"); SkipToken(tl, ';'); hdl = dlopen(fn, RTLD_NOW | RTLD_LOCAL); if (hdl == NULL) { VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n", PF(mod), fn, dlerror()); vcc_ErrWhere(tl, mod); return; } bprintf(buf, "Vmod_%.*s_Name", PF(mod)); modname = dlsym(hdl, buf); if (modname == NULL) { VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n", PF(mod), fn, "Symbol Vmod_Name not found"); vcc_ErrWhere(tl, mod); return; } if (!vcc_IdIs(mod, modname)) { VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n", PF(mod), fn); VSB_printf(tl->sb, "\tModule has wrong name: <%s>\n", modname); vcc_ErrWhere(tl, mod); return; } bprintf(buf, "Vmod_%.*s_ABI", PF(mod)); abi = dlsym(hdl, buf); if (abi == NULL || strcmp(abi, VMOD_ABI_Version) != 0) { VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n", PF(mod), fn); VSB_printf(tl->sb, "\tABI mismatch, expected <%s>, got <%s>\n", VMOD_ABI_Version, abi); vcc_ErrWhere(tl, mod); return; } bprintf(buf, "Vmod_%.*s_Proto", PF(mod)); proto = dlsym(hdl, buf); if (proto == NULL) { VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n", PF(mod), fn, "Symbol Vmod_Proto not found"); vcc_ErrWhere(tl, mod); return; } bprintf(buf, "Vmod_%.*s_Spec", PF(mod)); spec = dlsym(hdl, buf); if (spec == NULL) { VSB_printf(tl->sb, "Could not load module %.*s\n\t%s\n\t%s\n", PF(mod), fn, "Symbol Vmod_Spec not found"); vcc_ErrWhere(tl, mod); return; } Fh(tl, 0, "static struct vmod_priv vmod_priv_%.*s;\n", PF(mod)); for (; *spec != NULL; spec++) { p = *spec; if (!strcmp(p, "OBJ")) { p += strlen(p) + 1; sym = VCC_AddSymbolStr(tl, p, SYM_OBJECT); XXXAN(sym); sym->args = p; } else if (!strcmp(p, "INIT")) { p += strlen(p) + 1; Fi(tl, 0, "\t%s(&vmod_priv_%.*s, &VCL_conf);\n", p, PF(mod)); } else { sym = VCC_AddSymbolStr(tl, p, SYM_FUNC); ERRCHK(tl); AN(sym); sym->eval = vcc_Eval_SymFunc; p += strlen(p) + 1; sym->cfunc = p; p += strlen(p) + 1; sym->args = p; /* Functions which return VOID are procedures */ if (!memcmp(p, "VOID\0", 5)) sym->kind = SYM_PROC; } } Fh(tl, 0, "\n%s\n", proto); /* XXX: zero the function pointer structure ?*/ Ff(tl, 0, "\tvmod_priv_fini(&vmod_priv_%.*s);\n", PF(mod)); Ff(tl, 0, "\tVRT_Vmod_Fini(&VGC_vmod_%.*s);\n", PF(mod)); }