static void report_missing_export(prefix *pfx, int depth) { const char *filename_store = file.filename; unsigned int line_store = file.line; prefix *survey = pfx; char *s; int i; for (i = depth + 1; i; i--) { survey = survey->up; SVX_ASSERT(survey); } s = osstrdup(sprint_prefix(survey)); if (survey->filename) { file.filename = survey->filename; file.line = survey->line; } compile_error(/*Station “%s” not exported from survey “%s”*/26, sprint_prefix(pfx), s); if (survey->filename) { file.filename = filename_store; file.line = line_store; } osfree(s); }
static void check_node(prefix *p) { if (!p->pos) { if (!TSTBIT(p->sflags, SFLAGS_SURVEY)) { /* Could do away with the SFLAGS_SURVEY check and check * p->min_export instead of p->max_export I think ... */ if (TSTBIT(p->sflags, SFLAGS_ENTRANCE) || p->max_export) { /* p is a station which was referred to in "*entrance" and/or * "*export" but not elsewhere (otherwise it'd have a position). * p could also be a survey (SFLAGS_SURVEY) or be mentioned as * a station, but only in a line of data which was rejected * because of an error. */ warning_in_file(p->filename, p->line, /*Station “%s” referred to by *entrance or *export but never used*/190, sprint_prefix(p)); } } } else { /* Do we need to worry about export violations in hanging surveys? */ if (fExportUsed) { #if 0 printf("L min %d max %d pfx %s\n", p->min_export, p->max_export, sprint_prefix(p)); #endif if ((p->min_export > 1 && p->min_export != USHRT_MAX) || (p->min_export == 0 && p->max_export)) { char *s; prefix *where = p->up; int msgno; SVX_ASSERT(where); s = osstrdup(sprint_prefix(where)); /* Report better when station called 2.1 for example */ while (!where->filename && where->up) where = where->up; if (TSTBIT(where->sflags, SFLAGS_PREFIX_ENTERED)) { msgno = /*Station “%s” not exported from survey “%s”*/26; } else { /* TRANSLATORS: This error occurs if there's an attempt to * export a station from a survey which doesn't actually exist. */ msgno = /*Reference to station “%s” from non-existent survey “%s”*/286; } compile_error_pfx(where, msgno, sprint_prefix(p), s); osfree(s); } } if (TSTBIT(p->sflags, SFLAGS_SUSPECTTYPO)) { /* TRANSLATORS: Here "station" is a survey station, not a train station. */ warning_in_file(p->filename, p->line, /*Station “%s” referred to just once, with an explicit survey name - typo?*/70, sprint_prefix(p)); } } }
static void do_range(int d, int msgno) { /* sprint_prefix uses a single buffer, so to report two stations in one * message we need to make a temporary copy of the string for one of them. */ char * pfx_hi = osstrdup(sprint_prefix(pfxHi[d])); char * pfx_lo = sprint_prefix(pfxLo[d]); printf(msg(msgno), max[d] - min[d], pfx_hi, max[d], pfx_lo, min[d]); osfree(pfx_hi); putnl(); }
static void do_range(int d, int msgno, real length_factor, const char * units) { /* sprint_prefix uses a single buffer, so to report two stations in one * message we need to make a temporary copy of the string for one of them. */ char * pfx_hi = osstrdup(sprint_prefix(pfxHi[d])); char * pfx_lo = sprint_prefix(pfxLo[d]); real hi = max[d] * length_factor; real lo = min[d] * length_factor; printf(msg(msgno), hi - lo, units, pfx_hi, hi, units, pfx_lo, lo, units); osfree(pfx_hi); putnl(); }
void ircd_send(struct irc_session *session, struct irc_prefix *prefix, uv_write_cb on_written, const char *format, ...) { char buffer[MESHCHAT_MESSAGE_LEN]; // 512 va_list ap; size_t prefixlen; size_t suffixlen = 2; int len = 0; prefixlen = prefix ? sprint_prefix(buffer, prefix) : 0; va_start(ap, format); len = vsnprintf(buffer + prefixlen, MESHCHAT_MESSAGE_LEN - prefixlen - suffixlen, format, ap); va_end(ap); len += prefixlen; if (len > MESHCHAT_MESSAGE_LEN - suffixlen) { len = MESHCHAT_MESSAGE_LEN; } strcpy(buffer + len, "\r\n"); len += suffixlen; uv_write_t* writer = NEW(uv_write_t); writer->data = session->ircd; uv_buf_t buf; buf.base = buffer; buf.len = len; uv_write(writer, (uv_stream_t*) &session->handle, &buf, 1, on_written); }
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); }
/* if prefix is omitted: if PFX_OPT set return NULL, otherwise use longjmp */ extern prefix * read_prefix(unsigned pfx_flags) { bool f_optional = !!(pfx_flags & PFX_OPT); bool fSurvey = !!(pfx_flags & PFX_SURVEY); bool fSuspectTypo = !!(pfx_flags & PFX_SUSPECT_TYPO); prefix *back_ptr, *ptr; char *name; size_t name_len = 32; size_t i; bool fNew; bool fImplicitPrefix = fTrue; int depth = -1; filepos fp_firstsep; skipblanks(); #ifndef NO_DEPRECATED if (isRoot(ch)) { if (!(pfx_flags & PFX_ALLOW_ROOT)) { compile_diagnostic(DIAG_ERR|DIAG_COL, /*ROOT is deprecated*/25); LONGJMP(file.jbSkipLine); } if (root_depr_count < 5) { compile_diagnostic(DIAG_WARN|DIAG_COL, /*ROOT is deprecated*/25); if (++root_depr_count == 5) compile_diagnostic(DIAG_WARN, /*Further uses of this deprecated feature will not be reported*/95); } nextch(); ptr = root; if (!isNames(ch)) { if (!isSep(ch)) return ptr; /* Allow optional SEPARATOR after ROOT */ get_pos(&fp_firstsep); nextch(); } fImplicitPrefix = fFalse; #else if (0) { #endif } else { if ((pfx_flags & PFX_ANON) && (isSep(ch) || (pcs->dash_for_anon_wall_station && ch == '-'))) { int first_ch = ch; filepos here; get_pos(&here); nextch(); if (isBlank(ch) || isEol(ch)) { if (!isSep(first_ch)) goto anon_wall_station; /* A single separator alone ('.' by default) is an anonymous * station which is on a point inside the passage and implies * the leg to it is a splay. */ if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) { set_pos(&here); compile_diagnostic(DIAG_ERR|DIAG_TOKEN, /*Can't have a leg between two anonymous stations*/3); LONGJMP(file.jbSkipLine); } pcs->flags |= BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY); return new_anon_station(); } if (isSep(first_ch) && ch == first_ch) { nextch(); if (isBlank(ch) || isEol(ch)) { /* A double separator ('..' by default) is an anonymous station * which is on the wall and implies the leg to it is a splay. */ prefix * pfx; anon_wall_station: if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) { set_pos(&here); compile_diagnostic(DIAG_ERR|DIAG_TOKEN, /*Can't have a leg between two anonymous stations*/3); LONGJMP(file.jbSkipLine); } pcs->flags |= BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY); pfx = new_anon_station(); pfx->sflags |= BIT(SFLAGS_WALL); return pfx; } if (ch == first_ch) { nextch(); if (isBlank(ch) || isEol(ch)) { /* A triple separator ('...' by default) is an anonymous * station, but otherwise not handled specially (e.g. for * a single leg down an unexplored side passage to a station * which isn't refindable). */ if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) { set_pos(&here); compile_diagnostic(DIAG_ERR|DIAG_TOKEN, /*Can't have a leg between two anonymous stations*/3); LONGJMP(file.jbSkipLine); } pcs->flags |= BIT(FLAGS_ANON_ONE_END); return new_anon_station(); } } } set_pos(&here); } ptr = pcs->Prefix; } i = 0; name = NULL; do { fNew = fFalse; if (name == NULL) { /* Need a new name buffer */ name = osmalloc(name_len); } /* i==0 iff this is the first pass */ if (i) { i = 0; nextch(); } while (isNames(ch)) { if (i < pcs->Truncate) { /* truncate name */ name[i++] = (pcs->Case == LOWER ? tolower(ch) : (pcs->Case == OFF ? ch : toupper(ch))); if (i >= name_len) { name_len = name_len + name_len; name = osrealloc(name, name_len); } } nextch(); } if (isSep(ch)) { fImplicitPrefix = fFalse; get_pos(&fp_firstsep); } if (i == 0) { osfree(name); if (!f_optional) { if (isEol(ch)) { if (fSurvey) { compile_diagnostic(DIAG_ERR|DIAG_COL, /*Expecting survey name*/89); } else { compile_diagnostic(DIAG_ERR|DIAG_COL, /*Expecting station name*/28); } } else { /* TRANSLATORS: Here "station" is a survey station, not a train station. */ compile_diagnostic(DIAG_ERR|DIAG_COL, /*Character “%c” not allowed in station name (use *SET NAMES to set allowed characters)*/7, ch); } LONGJMP(file.jbSkipLine); } return (prefix *)NULL; } name[i++] = '\0'; back_ptr = ptr; ptr = ptr->down; if (ptr == NULL) { /* Special case first time around at each level */ name = osrealloc(name, i); ptr = osnew(prefix); ptr->ident = name; name = NULL; ptr->right = ptr->down = NULL; ptr->pos = NULL; ptr->shape = 0; ptr->stn = NULL; ptr->up = back_ptr; ptr->filename = file.filename; ptr->line = file.line; ptr->min_export = ptr->max_export = 0; ptr->sflags = BIT(SFLAGS_SURVEY); if (fSuspectTypo && !fImplicitPrefix) ptr->sflags |= BIT(SFLAGS_SUSPECTTYPO); back_ptr->down = ptr; fNew = fTrue; } else { /* Use caching to speed up adding an increasing sequence to a * large survey */ static prefix *cached_survey = NULL, *cached_station = NULL; prefix *ptrPrev = NULL; int cmp = 1; /* result of strcmp ( -ve for <, 0 for =, +ve for > ) */ if (cached_survey == back_ptr) { cmp = strcmp(cached_station->ident, name); if (cmp <= 0) ptr = cached_station; } while (ptr && (cmp = strcmp(ptr->ident, name))<0) { ptrPrev = ptr; ptr = ptr->right; } if (cmp) { /* ie we got to one that was higher, or the end */ prefix *newptr; name = osrealloc(name, i); newptr = osnew(prefix); newptr->ident = name; name = NULL; if (ptrPrev == NULL) back_ptr->down = newptr; else ptrPrev->right = newptr; newptr->right = ptr; newptr->down = NULL; newptr->pos = NULL; newptr->shape = 0; newptr->stn = NULL; newptr->up = back_ptr; newptr->filename = file.filename; newptr->line = file.line; newptr->min_export = newptr->max_export = 0; newptr->sflags = BIT(SFLAGS_SURVEY); if (fSuspectTypo && !fImplicitPrefix) newptr->sflags |= BIT(SFLAGS_SUSPECTTYPO); ptr = newptr; fNew = fTrue; } cached_survey = back_ptr; cached_station = ptr; } depth++; f_optional = fFalse; /* disallow after first level */ if (isSep(ch)) get_pos(&fp_firstsep); } while (isSep(ch)); if (name) osfree(name); /* don't warn about a station that is referred to twice */ if (!fNew) ptr->sflags &= ~BIT(SFLAGS_SUSPECTTYPO); if (fNew) { /* fNew means SFLAGS_SURVEY is currently set */ SVX_ASSERT(TSTBIT(ptr->sflags, SFLAGS_SURVEY)); if (!fSurvey) { ptr->sflags &= ~BIT(SFLAGS_SURVEY); if (TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX; } } else { /* check that the same name isn't being used for a survey and station */ if (fSurvey ^ TSTBIT(ptr->sflags, SFLAGS_SURVEY)) { /* TRANSLATORS: Here "station" is a survey station, not a train station. * * Here "survey" is a "cave map" rather than list of questions - it should be * translated to the terminology that cavers using the language would use. */ compile_diagnostic(DIAG_ERR, /*“%s” can’t be both a station and a survey*/27, sprint_prefix(ptr)); } if (!fSurvey && TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX; } /* check the export level */ #if 0 printf("R min %d max %d depth %d pfx %s\n", ptr->min_export, ptr->max_export, depth, sprint_prefix(ptr)); #endif if (ptr->min_export == 0 || ptr->min_export == USHRT_MAX) { if (depth > ptr->max_export) ptr->max_export = depth; } else if (ptr->max_export < depth) { prefix *survey = ptr; char *s; const char *p; int level; for (level = ptr->max_export + 1; level; level--) { survey = survey->up; SVX_ASSERT(survey); } s = osstrdup(sprint_prefix(survey)); p = sprint_prefix(ptr); if (survey->filename) { compile_diagnostic_pfx(DIAG_ERR, survey, /*Station “%s” not exported from survey “%s”*/26, p, s); } else { compile_diagnostic(DIAG_ERR, /*Station “%s” not exported from survey “%s”*/26, p, s); } osfree(s); #if 0 printf(" *** pfx %s warning not exported enough depth %d " "ptr->max_export %d\n", sprint_prefix(ptr), depth, ptr->max_export); #endif } if (!fImplicitPrefix && (pfx_flags & PFX_WARN_SEPARATOR)) { filepos fp_tmp; get_pos(&fp_tmp); set_pos(&fp_firstsep); compile_diagnostic(DIAG_WARN|DIAG_COL, /*Separator in survey name*/392); set_pos(&fp_tmp); } return ptr; } /* if numeric expr is omitted: if f_optional return HUGE_REAL, else longjmp */ static real read_number(bool f_optional) { bool fPositive, fDigits = fFalse; real n = (real)0.0; filepos fp; int ch_old; get_pos(&fp); ch_old = ch; fPositive = !isMinus(ch); if (isSign(ch)) nextch(); while (isdigit(ch)) { n = n * (real)10.0 + (char)(ch - '0'); nextch(); fDigits = fTrue; } if (isDecimal(ch)) { real mult = (real)1.0; nextch(); while (isdigit(ch)) { mult *= (real).1; n += (char)(ch - '0') * mult; fDigits = fTrue; nextch(); } } /* !'fRead' => !fDigits so fDigits => 'fRead' */ if (fDigits) return (fPositive ? n : -n); /* didn't read a valid number. If it's optional, reset filepos & return */ set_pos(&fp); if (f_optional) { return HUGE_REAL; } if (isOmit(ch_old)) { compile_diagnostic(DIAG_ERR|DIAG_COL, /*Field may not be omitted*/8); } else { compile_diagnostic_token_show(DIAG_ERR, /*Expecting numeric field, found “%s”*/9); } LONGJMP(file.jbSkipLine); return 0.0; /* for brain-fried compilers */ }
extern void articulate(void) { node *stn, *stnStart; int i; long cFixed; component_list = NULL; articulation_list = NULL; artlist = NULL; fixedlist = NULL; /* find articulation points and components */ colour = 0; stnStart = NULL; cMaxVisits = 0; FOR_EACH_STN(stn, stnlist) { if (fixed(stn)) { remove_stn_from_list(&stnlist, stn); add_stn_to_list(&fixedlist, stn); colour++; stn->colour = -colour; #ifdef DEBUG_ARTIC printf("Putting stn "); print_prefix(stn->name); printf(" on fixedlist\n"); #endif } else { cMaxVisits++; stn->colour = 0; } } dirn_stack = osmalloc(cMaxVisits); min_stack = osmalloc(cMaxVisits * sizeof(long)); /* fixedlist can be NULL here if we've had a *solve followed by survey * which is all hanging. */ cFixed = colour; while (fixedlist) { int c; stnStart = fixedlist; stn = stnStart; /* see if this is a fresh component - it may not be, we may be * processing the other way from a fixed point cut-line */ if (stn->colour < 0) { #ifdef DEBUG_ARTIC printf("new component\n"); #endif stn->colour = -stn->colour; /* fixed points are negative until we colour from them */ cComponents++; /* FIXME: logic to count components isn't the same as the logic * to start a new one - we should start a new one for a fixed point * cut-line (see below) */ if (artlist) { component *comp; articulation *art; art = osnew(articulation); art->stnlist = artlist; art->next = articulation_list; articulation_list = art; artlist = NULL; comp = osnew(component); comp->next = component_list; comp->artic = articulation_list; component_list = comp; articulation_list = NULL; } #ifdef DEBUG_ARTIC print_prefix(stn->name); printf(" [%p] is root of component %ld\n", stn, cComponents); printf(" and colour = %d/%d\n", stn->colour, cFixed); #endif } c = 0; for (i = 0; i <= 2 && stn->leg[i]; i++) { node *stn2 = stn->leg[i]->l.to; if (stn2->colour < 0) { stn2->colour = -stn2->colour; } else if (stn2->colour == 0) { /* Special case to check if start station is an articulation point * which it is iff we have to colour from it in more than one dirn * * We're looking for articulation legs - these are those where * colouring from here doesn't reach a fixed point (including * stn - the fixed point we've started from) * * FIXME: this is a "fixed point cut-line" case where we could * start a new component. */ long col = visit(stn2, reverse_leg_dirn(stn->leg[i])); #ifdef DEBUG_ARTIC print_prefix(stn->name); printf(" -> "); print_prefix(stn2->name); printf(" col %d cFixed %d\n", col, cFixed); #endif if (col > cFixed) { /* start new articulation - FIXME - overeager */ articulation *art = osnew(articulation); art->stnlist = artlist; art->next = articulation_list; articulation_list = art; artlist = NULL; c |= 1 << i; } } } switch (c) { /* had to colour in 2 or 3 directions from start point */ case 3: case 5: case 6: case 7: #ifdef DEBUG_ARTIC print_prefix(stn->name); printf(" is a special case start articulation point [%d]\n", c); #endif for (i = 0; i <= 2 && stn->leg[i]; i++) { if (TSTBIT(c, i)) { /* flag leg as an articulation for loop error reporting */ stn->leg[i]->l.reverse |= FLAG_ARTICULATION; #ifdef DEBUG_ARTIC print_prefix(stn->leg[i]->l.to->name); putnl(); #endif reverse_leg(stn->leg[i])->l.reverse |= FLAG_ARTICULATION; } } } #ifdef DEBUG_ARTIC printf("Putting FIXED stn "); print_prefix(stn->name); printf(" on artlist\n"); #endif remove_stn_from_list(&fixedlist, stn); add_stn_to_list(&artlist, stn); if (stnStart->colour == 1) { #ifdef DEBUG_ARTIC printf("%ld components\n",cComponents); #endif break; } } osfree(dirn_stack); dirn_stack = NULL; osfree(min_stack); min_stack = NULL; if (artlist) { articulation *art = osnew(articulation); art->stnlist = artlist; art->next = articulation_list; articulation_list = art; artlist = NULL; } if (articulation_list) { component *comp = osnew(component); comp->next = component_list; comp->artic = articulation_list; component_list = comp; articulation_list = NULL; } if (stnlist) { /* Any stations still in stnlist are unfixed, which is means we have * one or more hanging surveys. * * The cause of the problem is pretty likely to be a typo, so run the * checks which report errors and warnings about issues which such a * typo is likely to result in. */ check_node_stats(); /* Actually this error is fatal, but we want to list the survey * stations which aren't connected, so we report it as an error * and die after listing them... */ bool fNotAttached = fFalse; error(/*Survey not all connected to fixed stations*/45); FOR_EACH_STN(stn, stnlist) { /* Anonymous stations must be at the end of a trailing traverse (since * the same anonymous station can't be referred to more than once), * and trailing traverses have been removed at this point. */ SVX_ASSERT(!TSTBIT(stn->name->sflags, SFLAGS_ANON)); if (stn->name->ident) { if (!fNotAttached) { fNotAttached = fTrue; puts(msg(/*The following survey stations are not attached to a fixed point:*/71)); } puts(sprint_prefix(stn->name)); } } exit(EXIT_FAILURE); }