/* * Return operator type for operand types @lft, @rgt. */ static int nstr_optype(enum nsc_type lft, enum nsc_type rgt) { lft = nstr_promote(lft); rgt = nstr_promote(rgt); if (lft == rgt) return lft; if (lft == NSC_DOUBLE && rgt == NSC_LONG) return NSC_DOUBLE; if (rgt == NSC_DOUBLE && lft == NSC_LONG) return NSC_DOUBLE; return NSC_NOTYPE; }
/* * Change @val to resolve identifier to value @selval for selector @ca. * Return @val. * @val must be an identifier, and @selval must have been obtained from * nstr_match_val(@val, CA0, @idx), where @ca = &CA0[@IDX]. */ static struct valstr * nstr_resolve_val(struct valstr *val, int selval, struct castr *ca) { enum nsc_type type = nstr_promote(ca->ca_type); if (CANT_HAPPEN(val->val_cat != NSC_ID)) { val->val_cat = NSC_NOCAT; return val; } if (type == NSC_STRING) { val->val_type = NSC_STRING; val->val_cat = NSC_VAL; /* map identifier ~ to empty string, like some commands do */ if (val->val_as.str.maxsz == 1 && val->val_as.str.base[0] == '~') val->val_as.str.maxsz = 0; return val; } if (CANT_HAPPEN(type != NSC_LONG || ca->ca_table == EF_BAD)) { val->val_type = NSC_NOTYPE; val->val_cat = NSC_NOCAT; return val; } val->val_type = type; val->val_cat = NSC_VAL; val->val_as.lng = selval; return val; }
/* * Match @val in a selector's values, return its (non-negative) value. * Match values of selector descriptor @ca[@idx], provided @idx is not * negative. @ca may be null when @idx is negative. * Return M_NOTFOUND if there are no matches, M_NOTUNIQUE if there are * several. */ static int nstr_match_val(struct valstr *val, struct castr *ca, int idx) { char id[32]; enum nsc_type type; if (val->val_cat != NSC_ID || idx < 0) return M_NOTFOUND; type = nstr_promote(ca[idx].ca_type); if (type == NSC_STRING) return 0; if (ca[idx].ca_table == EF_BAD || CANT_HAPPEN(type != NSC_LONG)) return M_NOTFOUND; if (val->val_as.str.maxsz >= sizeof(id)) return M_NOTFOUND; memcpy(id, val->val_as.str.base, val->val_as.str.maxsz); id[val->val_as.str.maxsz] = 0; return ef_elt_byname(ca[idx].ca_table, id); }
/* * survey type <sarg> ?cond * */ int surv(void) { int nsect; struct nstr_sect nstr; int y; struct valstr val; struct natstr *np; struct sctstr sect; struct range range; char *ptr; struct nscstr cond[NS_NCOND]; int ncond; int i; char buf[1024]; /* Note this is not re-entrant anyway, so we keep the buffers around */ static char *mapbuf = NULL; static char **map = NULL; nsect = 0; ptr = getstarg(player->argp[1], "commodity or variable? ", buf); if (!ptr || !*ptr) return RET_SYN; ptr = nstr_comp_val(ptr, &val, EF_SECTOR); if (!ptr) return RET_SYN; if (val.val_cat != NSC_OFF || nstr_promote(val.val_type) != NSC_LONG) { pr("Can't survey this\n"); return RET_SYN; } for (; isspace(*ptr); ++ptr) ; if (*ptr) return RET_SYN; if (!snxtsct(&nstr, player->argp[2])) return RET_SYN; if (!mapbuf) mapbuf = malloc(WORLD_Y * MAPWIDTH(1)); if (!map) { map = malloc(WORLD_Y * sizeof(char *)); if (map && mapbuf) { for (i = 0; i < WORLD_Y; i++) map[i] = &mapbuf[MAPWIDTH(1) * i]; } else if (map) { free(map); map = NULL; } } if (!mapbuf || !map) { pr("Memory error, tell the deity.\n"); logerror("malloc failed in sect\n"); return RET_FAIL; } ncond = nstr.ncond; memcpy(cond, nstr.cond, sizeof(struct nscstr) * ncond); nstr.ncond = 0; np = getnatp(player->cnum); xyrelrange(np, &nstr.range, &range); border(&range, " ", ""); blankfill(mapbuf, &nstr.range, 1); while (nxtsct(&nstr, §)) { if (!player->owner) continue; ptr = &map[nstr.dy][nstr.dx]; if (nstr_exec(cond, ncond, §)) { ++nsect; *ptr = 0x80 | code_char(val, §); } else { *ptr = dchr[sect.sct_type].d_mnem; } } for (y = nstr.range.ly, i = 0; i < nstr.range.height; y++, i++) { int yval; yval = yrel(np, y); pr("%4d %s %4d\n", yval, map[i], yval); if (y >= WORLD_Y) y -= WORLD_Y; } border(&range, " ", ""); if (nsect > 0) pr("\n%d sector%s.\n", nsect, splur(nsect)); return RET_OK; }