static void cmd_export(void) { prefix *pfx; fExportUsed = fTrue; pfx = read_prefix(PFX_STATION); do { int depth = 0; { prefix *p = pfx; while (p != NULL && p != pcs->Prefix) { depth++; p = p->up; } /* Something like: *export \foo, but we've excluded use of root */ SVX_ASSERT(p); } /* *export \ or similar bogus stuff */ SVX_ASSERT(depth); #if 0 printf("C min %d max %d depth %d pfx %s\n", pfx->min_export, pfx->max_export, depth, sprint_prefix(pfx)); #endif if (pfx->min_export == 0) { /* not encountered *export for this name before */ if (pfx->max_export > depth) report_missing_export(pfx, depth); pfx->min_export = pfx->max_export = depth; } else if (pfx->min_export != USHRT_MAX) { /* FIXME: what to do if a station is marked for inferred exports * but is then explicitly exported? Currently we just ignore the * explicit export... */ if (pfx->min_export - 1 > depth) { report_missing_export(pfx, depth); } else if (pfx->min_export - 1 < depth) { compile_error(/*Station “%s” already exported*/66, sprint_prefix(pfx)); } pfx->min_export = depth; } pfx = read_prefix(PFX_STATION|PFX_OPT); } while (pfx); }
static void cmd_equate(void) { prefix *name1, *name2; bool fOnlyOneStn = fTrue; /* to trap eg *equate entrance.6 */ name1 = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_SUSPECT_TYPO); while (fTrue) { name2 = name1; name1 = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_SUSPECT_TYPO|PFX_OPT); if (name1 == NULL) { if (fOnlyOneStn) { compile_error_skip(-/*Only one station in EQUATE command*/33); } return; } process_equate(name1, name2); fOnlyOneStn = fFalse; } }
static int prefix_opts(JFT_Stem *prefix, JFT_Symbol **stop, int argc, char **argv) { extern char *optarg; extern int optind, optopt; int opt, ptr, err = 0, omit = 1; static struct option options[] = { {"null", no_argument, NULL, 'n'}, {"stop", no_argument, NULL, 's'}, {"primary", no_argument, NULL, 'p'}, {"indices", no_argument, NULL, 'i'}, {} }; // default prefix->pre = JFT_SYMBOL_PRIMARY; prefix->size = 1; while ((opt = getopt_long(argc, argv, "hnspi", options, &ptr)) != -1) { switch(opt) { case 'h': return usage(0); case 'n': omit = 0; break; case 's': *stop = &null; break; case 'p': prefix->pre = JFT_SYMBOL_PRIMARY; prefix->size = 1; break; case 'i': prefix->pre = JFT_SYMBOL_INDICES; prefix->size = 1; break; case ':': pwarn("%s: option requires an argument -- %c", argv[0], optopt); err++; break; case '?': pwarn("%s: illegal option -- %c", argv[0], optopt); err++; break; } } read_prefix(prefix, omit, argc - optind, argv + optind); return err; }
static void cmd_prefix(void) { static int prefix_depr_count = 0; prefix *tag; /* Issue warning first, so "*prefix \" warns first that *prefix is * deprecated and then that ROOT is... */ if (prefix_depr_count < 5) { compile_warning(-/**prefix is deprecated - use *begin and *end instead*/6); if (++prefix_depr_count == 5) compile_warning(/*Further uses of this deprecated feature will not be reported*/95); } tag = read_prefix(PFX_SURVEY|PFX_ALLOW_ROOT); pcs->Prefix = tag; check_reentry(tag); }
static void cmd_begin(void) { prefix *tag; settings *pcsNew; pcsNew = osnew(settings); *pcsNew = *pcs; /* copy contents */ pcsNew->begin_lineno = file.line; pcsNew->next = pcs; pcs = pcsNew; tag = read_prefix(PFX_SURVEY|PFX_OPT|PFX_ALLOW_ROOT|PFX_WARN_SEPARATOR); pcs->tag = tag; if (tag) { pcs->Prefix = tag; check_reentry(tag); f_export_ok = fTrue; } }
static void cmd_end(void) { settings *pcsParent; prefix *tag, *tagBegin; pcsParent = pcs->next; if (pcs->begin_lineno == 0) { if (pcsParent == NULL) { /* more ENDs than BEGINs */ compile_error_skip(/*No matching BEGIN*/192); } else { compile_error_skip(/*END with no matching BEGIN in this file*/22); } return; } tagBegin = pcs->tag; SVX_ASSERT(pcsParent); free_settings(pcs); pcs = pcsParent; /* note need to read using root *before* BEGIN */ tag = read_prefix(PFX_SURVEY|PFX_OPT|PFX_ALLOW_ROOT); if (tag != tagBegin) { if (tag) { if (!tagBegin) { /* "*begin" / "*end foo" */ compile_error_skip(-/*Matching BEGIN tag has no prefix*/36); } else { /* tag mismatch */ compile_error_skip(-/*Prefix tag doesn’t match BEGIN*/193); } } else { /* close tag omitted; open tag given */ compile_warning(-/*Closing prefix omitted from END*/194); } } }
void Glulxe::unparse_glk_args(dispatch_splot_t *splot, const char **proto, int depth, int *argnumptr, uint subaddress, int subpassout) { const char *cx; int ix, argx; int gargnum, numwanted; void *opref; gluniversal_t *garglist; uint *varglist; garglist = splot->garglist; varglist = splot->varglist; gargnum = *argnumptr; cx = *proto; numwanted = 0; while (*cx >= '0' && *cx <= '9') { numwanted = 10 * numwanted + (*cx - '0'); cx++; } for (argx = 0, ix = 0; argx < numwanted; argx++, ix++) { char typeclass; int skipval; int isref, passin, passout, nullok, isarray, isretained, isreturn; cx = read_prefix(cx, &isref, &isarray, &passin, &passout, &nullok, &isretained, &isreturn); typeclass = *cx; cx++; skipval = false; if (isref) { if (!isreturn && varglist[ix] == 0) { if (!nullok) error("Zero passed invalidly to Glk function."); garglist[gargnum]._ptrflag = false; gargnum++; skipval = true; } else { garglist[gargnum]._ptrflag = true; gargnum++; } } if (!skipval) { uint thisval = 0; if (typeclass == '[') { unparse_glk_args(splot, &cx, depth + 1, &gargnum, varglist[ix], passout); } else if (isarray) { /* definitely isref */ switch (typeclass) { case 'C': ReleaseCArray((char *)garglist[gargnum]._array, varglist[ix], varglist[ix + 1], passout); gargnum++; ix++; gargnum++; cx++; break; case 'I': ReleaseIArray((uint *)garglist[gargnum]._array, varglist[ix], varglist[ix + 1], passout); gargnum++; ix++; gargnum++; cx++; break; case 'Q': ReleasePtrArray((void **)garglist[gargnum]._array, varglist[ix], varglist[ix + 1], (*cx - 'a'), passout); gargnum++; ix++; gargnum++; cx++; break; default: error("Illegal format string."); break; } } else { /* a plain value or a reference to one. */ if (isreturn || (depth > 0 && subpassout) || (isref && passout)) { skipval = false; } else { skipval = true; } switch (typeclass) { case 'I': if (!skipval) { if (*cx == 'u') thisval = (uint)garglist[gargnum]._uint; else if (*cx == 's') thisval = (uint)garglist[gargnum]._sint; else error("Illegal format string."); } gargnum++; cx++; break; case 'Q': if (!skipval) { opref = garglist[gargnum]._opaqueref; if (opref) { gidispatch_rock_t objrock = gidispatch_get_objrock(opref, *cx - 'a'); assert(objrock.ptr); thisval = ((classref_t *)objrock.ptr)->id; } else { thisval = 0; } } gargnum++; cx++; break; case 'C': if (!skipval) { if (*cx == 'u') thisval = (uint)garglist[gargnum]._uch; else if (*cx == 's') thisval = (uint)garglist[gargnum]._sch; else if (*cx == 'n') thisval = (uint)garglist[gargnum]._ch; else error("Illegal format string."); } gargnum++; cx++; break; case 'S': if (garglist[gargnum]._charstr) ReleaseVMString(garglist[gargnum]._charstr); gargnum++; break; #ifdef GLK_MODULE_UNICODE case 'U': if (garglist[gargnum]._unicharstr) ReleaseVMUstring(garglist[gargnum]._unicharstr); gargnum++; break; #endif /* GLK_MODULE_UNICODE */ default: error("Illegal format string."); break; } if (isreturn) { *(splot->retval) = thisval; } else if (depth > 0) { /* Definitely not isref or isarray. */ if (subpassout) WriteStructField(subaddress, ix, thisval); } else if (isref) { if (passout) WriteMemory(varglist[ix], thisval); } } } else { /* We got a null reference, so we have to skip the format element. */ if (typeclass == '[') { int numsubwanted, refdepth; numsubwanted = 0; while (*cx >= '0' && *cx <= '9') { numsubwanted = 10 * numsubwanted + (*cx - '0'); cx++; } refdepth = 1; while (refdepth > 0) { if (*cx == '[') refdepth++; else if (*cx == ']') refdepth--; cx++; } } else if (typeclass == 'S' || typeclass == 'U') { /* leave it */ } else { cx++; if (isarray) ix++; } } } if (depth > 0) { if (*cx != ']') error("Illegal format string."); cx++; } else { if (*cx != ':' && *cx != '\0') error("Illegal format string."); } *proto = cx; *argnumptr = gargnum; }
void Glulxe::parse_glk_args(dispatch_splot_t *splot, const char **proto, int depth, int *argnumptr, uint subaddress, int subpassin) { const char *cx; int ix, argx; int gargnum, numwanted; void *opref; gluniversal_t *garglist; uint *varglist; garglist = splot->garglist; varglist = splot->varglist; gargnum = *argnumptr; cx = *proto; numwanted = 0; while (*cx >= '0' && *cx <= '9') { numwanted = 10 * numwanted + (*cx - '0'); cx++; } for (argx = 0, ix = 0; argx < numwanted; argx++, ix++) { char typeclass; int skipval; int isref, passin, passout, nullok, isarray, isretained, isreturn; cx = read_prefix(cx, &isref, &isarray, &passin, &passout, &nullok, &isretained, &isreturn); typeclass = *cx; cx++; skipval = false; if (isref) { if (!isreturn && varglist[ix] == 0) { if (!nullok) error("Zero passed invalidly to Glk function."); garglist[gargnum]._ptrflag = false; gargnum++; skipval = true; } else { garglist[gargnum]._ptrflag = true; gargnum++; } } if (!skipval) { uint thisval; if (typeclass == '[') { parse_glk_args(splot, &cx, depth + 1, &gargnum, varglist[ix], passin); } else if (isarray) { /* definitely isref */ switch (typeclass) { case 'C': /* This test checks for a giant array length, which is deprecated. It displays a warning and cuts it down to something reasonable. Future releases of this interpreter may remove this test and go on to verify_array_addresses(), which treats this case as a fatal error. */ if (varglist[ix + 1] > endmem || varglist[ix] + varglist[ix + 1] > endmem) { nonfatal_warning_i("Memory access was much too long -- perhaps a print_to_array call with only one argument", varglist[ix + 1]); varglist[ix + 1] = endmem - varglist[ix]; } verify_array_addresses(varglist[ix], varglist[ix + 1], 1); garglist[gargnum]._array = CaptureCArray(varglist[ix], varglist[ix + 1], passin); gargnum++; ix++; garglist[gargnum]._uint = varglist[ix]; gargnum++; cx++; break; case 'I': /* See comment above. */ if (varglist[ix + 1] > endmem / 4 || varglist[ix + 1] > (endmem - varglist[ix]) / 4) { nonfatal_warning_i("Memory access was much too long -- perhaps a print_to_array call with only one argument", varglist[ix + 1]); varglist[ix + 1] = (endmem - varglist[ix]) / 4; } verify_array_addresses(varglist[ix], varglist[ix + 1], 4); garglist[gargnum]._array = CaptureIArray(varglist[ix], varglist[ix + 1], passin); gargnum++; ix++; garglist[gargnum]._uint = varglist[ix]; gargnum++; cx++; break; case 'Q': /* This case was added after the giant arrays were deprecated, so we don't bother to allow for that case. We just verify the length. */ verify_array_addresses(varglist[ix], varglist[ix + 1], 4); garglist[gargnum]._array = CapturePtrArray(varglist[ix], varglist[ix + 1], (*cx - 'a'), passin); gargnum++; ix++; garglist[gargnum]._uint = varglist[ix]; gargnum++; cx++; break; default: error("Illegal format string."); break; } } else { /* a plain value or a reference to one. */ if (isreturn) { thisval = 0; } else if (depth > 0) { /* Definitely not isref or isarray. */ if (subpassin) thisval = ReadStructField(subaddress, ix); else thisval = 0; } else if (isref) { if (passin) thisval = ReadMemory(varglist[ix]); else thisval = 0; } else { thisval = varglist[ix]; } switch (typeclass) { case 'I': if (*cx == 'u') garglist[gargnum]._uint = (uint)(thisval); else if (*cx == 's') garglist[gargnum]._sint = (int)(thisval); else error("Illegal format string."); gargnum++; cx++; break; case 'Q': if (thisval) { opref = classes_get(*cx - 'a', thisval); if (!opref) { error("Reference to nonexistent Glk object."); } } else { opref = nullptr; } garglist[gargnum]._opaqueref = opref; gargnum++; cx++; break; case 'C': if (*cx == 'u') garglist[gargnum]._uch = (unsigned char)(thisval); else if (*cx == 's') garglist[gargnum]._sch = (signed char)(thisval); else if (*cx == 'n') garglist[gargnum]._ch = (char)(thisval); else error("Illegal format string."); gargnum++; cx++; break; case 'S': garglist[gargnum]._charstr = DecodeVMString(thisval); gargnum++; break; #ifdef GLK_MODULE_UNICODE case 'U': garglist[gargnum]._unicharstr = DecodeVMUstring(thisval); gargnum++; break; #endif /* GLK_MODULE_UNICODE */ default: error("Illegal format string."); break; } } } else { /* We got a null reference, so we have to skip the format element. */ if (typeclass == '[') { int numsubwanted, refdepth; numsubwanted = 0; while (*cx >= '0' && *cx <= '9') { numsubwanted = 10 * numsubwanted + (*cx - '0'); cx++; } refdepth = 1; while (refdepth > 0) { if (*cx == '[') refdepth++; else if (*cx == ']') refdepth--; cx++; } } else if (typeclass == 'S' || typeclass == 'U') { /* leave it */ } else { cx++; if (isarray) ix++; } } } if (depth > 0) { if (*cx != ']') error("Illegal format string."); cx++; } else { if (*cx != ':' && *cx != '\0') error("Illegal format string."); } *proto = cx; *argnumptr = gargnum; }
void Glulxe::prepare_glk_args(const char *proto, dispatch_splot_t *splot) { static gluniversal_t *garglist = nullptr; static int garglist_size = 0; int ix; int numwanted, numvargswanted, maxargs; const char *cx; cx = proto; numwanted = 0; while (*cx >= '0' && *cx <= '9') { numwanted = 10 * numwanted + (*cx - '0'); cx++; } splot->numwanted = numwanted; maxargs = 0; numvargswanted = 0; for (ix = 0; ix < numwanted; ix++) { int isref, passin, passout, nullok, isarray, isretained, isreturn; cx = read_prefix(cx, &isref, &isarray, &passin, &passout, &nullok, &isretained, &isreturn); if (isref) { maxargs += 2; } else { maxargs += 1; } if (!isreturn) { if (isarray) { numvargswanted += 2; } else { numvargswanted += 1; } } if (*cx == 'I' || *cx == 'C') { cx += 2; } else if (*cx == 'Q') { cx += 2; } else if (*cx == 'S' || *cx == 'U') { cx += 1; } else if (*cx == '[') { int refdepth, nwx; cx++; nwx = 0; while (*cx >= '0' && *cx <= '9') { nwx = 10 * nwx + (*cx - '0'); cx++; } maxargs += nwx; /* This is *only* correct because all structs contain plain values. */ refdepth = 1; while (refdepth > 0) { if (*cx == '[') refdepth++; else if (*cx == ']') refdepth--; cx++; } } else { error("Illegal format string."); } } if (*cx != ':' && *cx != '\0') error("Illegal format string."); splot->maxargs = maxargs; if (splot->numvargs != numvargswanted) error("Wrong number of arguments to Glk function."); if (garglist && garglist_size < maxargs) { glulx_free(garglist); garglist = nullptr; garglist_size = 0; } if (!garglist) { garglist_size = maxargs + 16; garglist = (gluniversal_t *)glulx_malloc(garglist_size * sizeof(gluniversal_t)); } if (!garglist) error("Unable to allocate storage for Glk arguments."); splot->garglist = garglist; }
static void cmd_fix(void) { prefix *fix_name; node *stn = NULL; static node *stnOmitAlready = NULL; real x, y, z; int nx, ny, nz; filepos fp; fix_name = read_prefix(PFX_STATION|PFX_ALLOW_ROOT); fix_name->sflags |= BIT(SFLAGS_FIXED); get_pos(&fp); get_token(); if (strcmp(ucbuffer, "REFERENCE") == 0) { /* suppress "unused fixed point" warnings for this station */ fix_name->sflags |= BIT(SFLAGS_USED); } else { if (*ucbuffer) set_pos(&fp); } x = read_numeric(fTrue, &nx); if (x == HUGE_REAL) { /* If the end of the line isn't blank, read a number after all to * get a more helpful error message */ if (!isEol(ch) && !isComm(ch)) x = read_numeric(fFalse, &nx); } if (x == HUGE_REAL) { if (stnOmitAlready) { if (fix_name != stnOmitAlready->name) { compile_error_skip(/*More than one FIX command with no coordinates*/56); } else { compile_warning(/*Same station fixed twice with no coordinates*/61); } return; } stn = StnFromPfx(fix_name); compile_warning(/*FIX command with no coordinates - fixing at (0,0,0)*/54); x = y = z = (real)0.0; stnOmitAlready = stn; } else { real sdx; y = read_numeric(fFalse, &ny); z = read_numeric(fFalse, &nz); sdx = read_numeric(fTrue, NULL); if (sdx != HUGE_REAL) { real sdy, sdz; real cxy = 0, cyz = 0, czx = 0; sdy = read_numeric(fTrue, NULL); if (sdy == HUGE_REAL) { /* only one variance given */ sdy = sdz = sdx; } else { sdz = read_numeric(fTrue, NULL); if (sdz == HUGE_REAL) { /* two variances given - horizontal & vertical */ sdz = sdy; sdy = sdx; } else { cxy = read_numeric(fTrue, NULL); if (cxy != HUGE_REAL) { /* covariances given */ cyz = read_numeric(fFalse, NULL); czx = read_numeric(fFalse, NULL); } else { cxy = 0; } } } stn = StnFromPfx(fix_name); if (!fixed(stn)) { node *fixpt = osnew(node); prefix *name; name = osnew(prefix); name->pos = osnew(pos); name->ident = NULL; name->shape = 0; fixpt->name = name; name->stn = fixpt; name->up = NULL; if (TSTBIT(pcs->infer, INFER_EXPORTS)) { name->min_export = USHRT_MAX; } else { name->min_export = 0; } name->max_export = 0; name->sflags = 0; add_stn_to_list(&stnlist, fixpt); POS(fixpt, 0) = x; POS(fixpt, 1) = y; POS(fixpt, 2) = z; fix(fixpt); fixpt->leg[0] = fixpt->leg[1] = fixpt->leg[2] = NULL; addfakeleg(fixpt, stn, 0, 0, 0, sdx * sdx, sdy * sdy, sdz * sdz #ifndef NO_COVARIANCES , cxy, cyz, czx #endif ); } return; } stn = StnFromPfx(fix_name); } if (!fixed(stn)) { POS(stn, 0) = x; POS(stn, 1) = y; POS(stn, 2) = z; fix(stn); return; } if (x != POS(stn, 0) || y != POS(stn, 1) || z != POS(stn, 2)) { compile_error(/*Station already fixed or equated to a fixed point*/46); return; } compile_warning(/*Station already fixed at the same coordinates*/55); }
static void cmd_entrance(void) { prefix *pfx = read_prefix(PFX_STATION); pfx->sflags |= BIT(SFLAGS_ENTRANCE); }
ll read_range(int l, int r) { // get sum v[l..r] return read_prefix(r) - read_prefix(l - 1); }
/* parse_glk_args(): This long and unpleasant function translates a set of Floo objects into a gluniversal_t array. It's recursive, too, to deal with structures. */ static void parse_glk_args(dispatch_splot_t *splot, char **proto, int depth, int *argnumptr, glui32 subaddress, int subpassin) { char *cx; int ix, argx; int gargnum, numwanted; void *opref; gluniversal_t *garglist; glui32 *varglist; garglist = splot->garglist; varglist = splot->varglist; gargnum = *argnumptr; cx = *proto; numwanted = 0; while (*cx >= '0' && *cx <= '9') { numwanted = 10 * numwanted + (*cx - '0'); cx++; } for (argx = 0, ix = 0; argx < numwanted; argx++, ix++) { char typeclass; int skipval; int isref, passin, passout, nullok, isarray, isretained, isreturn; cx = read_prefix(cx, &isref, &isarray, &passin, &passout, &nullok, &isretained, &isreturn); typeclass = *cx; cx++; skipval = FALSE; if (isref) { if (!isreturn && varglist[ix] == 0) { if (!nullok) fatalError("Zero passed invalidly to Glk function."); garglist[gargnum].ptrflag = FALSE; gargnum++; skipval = TRUE; } else { garglist[gargnum].ptrflag = TRUE; gargnum++; } } if (!skipval) { glui32 thisval; if (typeclass == '[') { parse_glk_args(splot, &cx, depth+1, &gargnum, varglist[ix], passin); } else if (isarray) { /* definitely isref */ switch (typeclass) { case 'C': /* This test checks for a giant array length, and cuts it down to something reasonable. Future releases of this interpreter may treat this case as a fatal error. */ if (varglist[ix+1] > gEndMem || varglist[ix]+varglist[ix+1] > gEndMem) varglist[ix+1] = gEndMem - varglist[ix]; garglist[gargnum].array = (void*) CaptureCArray(varglist[ix], varglist[ix+1], passin); gargnum++; ix++; garglist[gargnum].uint = varglist[ix]; gargnum++; cx++; break; case 'I': /* See comment above. */ if (varglist[ix+1] > gEndMem/4 || varglist[ix+1] > (gEndMem-varglist[ix])/4) varglist[ix+1] = (gEndMem - varglist[ix]) / 4; garglist[gargnum].array = CaptureIArray(varglist[ix], varglist[ix+1], passin); gargnum++; ix++; garglist[gargnum].uint = varglist[ix]; gargnum++; cx++; break; case 'Q': garglist[gargnum].array = CapturePtrArray(varglist[ix], varglist[ix+1], (*cx-'a'), passin); gargnum++; ix++; garglist[gargnum].uint = varglist[ix]; gargnum++; cx++; break; default: fatalError("Illegal format string."); break; } } else { /* a plain value or a reference to one. */ if (isreturn) { thisval = 0; } else if (depth > 0) { /* Definitely not isref or isarray. */ if (subpassin) thisval = ReadStructField(subaddress, ix); else thisval = 0; } else if (isref) { if (passin) thisval = ReadMemory(varglist[ix]); else thisval = 0; } else { thisval = varglist[ix]; } switch (typeclass) { case 'I': if (*cx == 'u') garglist[gargnum].uint = (glui32)(thisval); else if (*cx == 's') garglist[gargnum].sint = (glsi32)(thisval); else fatalError("Illegal format string."); gargnum++; cx++; break; case 'Q': if (thisval) { opref = classes_get(*cx-'a', thisval); if (!opref) { fatalError("Reference to nonexistent Glk object."); } } else { opref = NULL; } garglist[gargnum].opaqueref = opref; gargnum++; cx++; break; case 'C': if (*cx == 'u') garglist[gargnum].uch = (unsigned char)(thisval); else if (*cx == 's') garglist[gargnum].sch = (signed char)(thisval); else if (*cx == 'n') garglist[gargnum].ch = (char)(thisval); else fatalError("Illegal format string."); gargnum++; cx++; break; case 'S': garglist[gargnum].charstr = DecodeVMString(thisval); gargnum++; break; #ifdef GLK_MODULE_UNICODE case 'U': garglist[gargnum].unicharstr = DecodeVMUstring(thisval); gargnum++; break; #endif /* GLK_MODULE_UNICODE */ default: fatalError("Illegal format string."); break; } } } else { /* We got a null reference, so we have to skip the format element. */ if (typeclass == '[') { int numsubwanted, refdepth; numsubwanted = 0; while (*cx >= '0' && *cx <= '9') { numsubwanted = 10 * numsubwanted + (*cx - '0'); cx++; } refdepth = 1; while (refdepth > 0) { if (*cx == '[') refdepth++; else if (*cx == ']') refdepth--; cx++; } } else if (typeclass == 'S' || typeclass == 'U') { /* leave it */ } else { cx++; if (isarray) ix++; } } } if (depth > 0) { if (*cx != ']') fatalError("Illegal format string."); cx++; } else { if (*cx != ':' && *cx != '\0') fatalError("Illegal format string."); } *proto = cx; *argnumptr = gargnum; }