double rnum(double range) { double r; double rmax = ( (1<<31) - 1); r=random(); errlog1(5,"random returns: %g",r); r=r * (BSIZE/rmax) + 1; errlog1(5,"rnum returns: %g",r); return(r); }
int parseaf(char *buf) { double baro, dewpt_in, dewpt_out; if (!sumcheck(buf, SIZEAF)) { errlog(8, "Checksum failure for AF block."); return (-1); } baro = DDtoint(buf[3]) + (DDtoint(buf[4]) * 100.0) + (xDtoint(buf[5]) * 10000.0); baro /= 10; dewpt_in = DDtoint(buf[7]); dewpt_out = DDtoint(buf[18]); correct(dewpt_in, current_cal.dp_in_mul, current_cal.dp_in_offs); correct(dewpt_out, current_cal.dp_out_mul, current_cal.dp_out_offs); correct(baro, current_cal.barometer_mul, current_cal.barometer_offs); update(current_obs.dp_in, dewpt_in, DEWIN); update(current_obs.dp_out, dewpt_out, DEWOUT); update(current_obs.barometer, baro, BARO); errlog1(9, "Barometer: %g mb", baro); errlog2(9, "Indoor dewpoint: %gC, Outdoor dewpoint: %gC", dewpt_in, dewpt_out); }
int parsecf(char *buf) { double gust, avg, chill, hum_out; double avg_dir, gust_dir; if (!sumcheck(buf, SIZECF)) { errlog(9, "Checksum failure for CF block."); return (-1); } gust = ((xDtoint(buf[2]) * 100) + DDtoint(buf[1])) / 10; gust_dir = (Dxtoint(buf[2])) + (DDtoint(buf[3]) * 10); avg = ((xDtoint(buf[5]) * 100) + DDtoint(buf[4])) / 10; avg_dir = (Dxtoint(buf[5])) + (DDtoint(buf[6]) * 10); chill = DDtoint(buf[16]); if (buf[21] & 0x20) { chill = -1.0 * chill; } #if 0 pthread_mutex_lock(¤t_obs_lock); if (((chill - current_obs.temp_out) > 0.5) && (avg > 0 || gust > 0)) { chill = -1.0 * chill; } pthread_mutex_unlock(¤t_obs_lock); #endif correct(chill, current_cal.chill_mul, current_cal.chill_offs); correct(gust, current_cal.gust_spd_mul, current_cal.gust_spd_offs); correct(gust_dir, current_cal.gust_dir_mul, current_cal.gust_dir_offs); correct(avg_dir, current_cal.wavg_dir_mul, current_cal.wavg_dir_offs); gust_dir = (gust_dir < 0) ? 360 + ((int) gust_dir % 360) : (int) gust_dir % 360; correct(avg, current_cal.wavg_spd_mul, current_cal.wavg_spd_offs); avg_dir = (avg_dir < 0) ? 360 + ((int) avg_dir % 360) : (int) avg_dir % 360; update(current_obs.gust, gust, GUST); update(current_obs.wavg, avg, WAVG); update(current_obs.gust_dir, gust_dir, GUSTDIR); update(current_obs.wavg_dir, avg_dir, WAVGDIR); update(current_obs.chill, chill, WCHILL); errlog2(9, "Wind gust %g m/s, direction: %g", gust, gust_dir); errlog2(9, "Wind avg %g m/s, direction: %g", avg, avg_dir); errlog1(9, "Wind chill %g C", chill); }
main(int argc, char **argv) { pthread_attr_t sched_attr; int maxprio, minprio; int go = 1; struct sched_param fifo_param; struct sigaction ignoreChildDeath = {NULL, 0, (SA_NOCLDSTOP | SA_RESTART), NULL}; struct sigaction hupAction = {hupcatch, 0, SA_RESTART, NULL}; struct sigaction termAction = {termcatch, 0, SA_RESTART, NULL}; myName=argv[0]; ch_flag = 0; terminate = 0; fprintf(stderr,"%s daemon start.\n", myName); pthread_attr_init(&sched_attr); pthread_attr_setinheritsched(&sched_attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedpolicy(&sched_attr, /*SCHED_RR */ SCHED_FIFO); maxprio = sched_get_priority_max(SCHED_FIFO); minprio = sched_get_priority_min(SCHED_FIFO); sigaction(SIGCHLD, &ignoreChildDeath, NULL); /*zombie protection */ sigaction(SIGHUP, &hupAction, NULL); sigaction(SIGTERM, &termAction, NULL); if (terminate == TERM_TERM) { go = 0; } else { go = 1; } while (go) { /*The main restart loop */ terminate = 0; /*read config file here */ cfg_read(CONFIG_FILE, "", ""); /* do command line option processing, they override config file opts */ do_opts(argc, argv); if (!foreground) { daemon(); } wxin = serial_open(opts.ttydev); last_write_time = time(NULL); if (wxin > 0) { sane_defaults(); init_db(); if (setupio(wxin) < 0) { errlog(9, "setupio bailed."); } iobuf = make_cbuf(BSIZE); pthread_mutex_init(¤t_obs_lock, pthread_mutexattr_default); pthread_mutex_init(¤t_cal_lock, pthread_mutexattr_default); pthread_mutex_init(&terminate_lock, pthread_mutexattr_default); pthread_mutex_init(&cond_update_lock, pthread_mutexattr_default); pthread_cond_init(&cond_update, pthread_condattr_default); #if USE_CBUF /* fifo_param.sched_priority = (minprio + maxprio) / 2; pthread_attr_setschedparam(&sched_attr, &fifo_param);*/ pthread_create(&reader, /*pthread_attr_default */ NULL, (pthread_startroutine_t) serial_reader, (pthread_addr_t) iobuf); pthread_create(&parser, NULL /*&sched_attr*/, (pthread_startroutine_t) parse_input, (pthread_addr_t) iobuf); #if SCREENOUT pthread_create(&writer, NULL /*&sched_attr*/, (pthread_startroutine_t) screen_writer, (pthread_addr_t) NULL); #else /* Make a db writer thread */ pthread_create(&writer, NULL /*&sched_attr*/, (pthread_startroutine_t) db_writer, (pthread_addr_t) NULL); #endif pthread_join(reader, NULL); pthread_join(parser, NULL); pthread_join(writer, NULL); #else parse_input(iobuf); #endif release_cbuf(iobuf); serial_close(opts.ttydev); if (terminate == TERM_TERM) { errlog1(1, "%s: TERMINATE.", argv[0]); go = 0; } if (terminate == TERM_RESTART) { errlog1(1, "%s: RESTART.", argv[0]); go = 1; } #if SCREENOUT #else db_getout(dbconn); #endif } else { go = 0; errlog2(1, "%s: cannot open serial port: %s", argv[0], opts.ttydev); } } errlog1(1,"%s daemon shutdown.", myName); exit(0); }
void screen_writer(void) { double rain; int write_screen = 1; pthread_mutex_lock(&terminate_lock); if (terminate) write_screen = 0;; pthread_mutex_unlock(&terminate_lock); while (write_screen) { pthread_mutex_lock(&cond_update_lock); pthread_cond_wait(&cond_update, &cond_update_lock); pthread_mutex_unlock(&cond_update_lock); pthread_mutex_lock(¤t_obs_lock); if (ch_flag != 0) { if (test_bit(ch_flag, RAINTOT)) { rain = current_obs.rain_tot + current_obs.rtot_offset; errlog1(8, "Rain total: %d mm", rain); clear_bit(ch_flag, RAINTOT); } if (test_bit(ch_flag, RAINRATE)) { errlog1(8, "Rain rate: %d mm/hr", current_obs.rain_rate); clear_bit(ch_flag, RAINRATE); } if (test_bit(ch_flag, TEMPIN)) { errlog1(8, "Indoor temp: %gC", current_obs.temp_in); clear_bit(ch_flag, TEMPIN); } if (test_bit(ch_flag, TEMPOUT)) { errlog1(8, "Outdoor temp: %gC", current_obs.temp_out); clear_bit(ch_flag, TEMPOUT); } if (test_bit(ch_flag, WCHILL)) { errlog1(8, "Wind chill: %gC", current_obs.chill); clear_bit(ch_flag, WCHILL); } if (test_bit(ch_flag, DEWIN)) { errlog1(8, "Indoor dewpoint: %gC", current_obs.dp_in); clear_bit(ch_flag, DEWIN); } if (test_bit(ch_flag, DEWOUT)) { errlog1(8, "Outdoor dewpoint: %gC", current_obs.dp_out); clear_bit(ch_flag, DEWOUT); } if (test_bit(ch_flag, HUMIN)) { errlog1(8, "Indoor humidity: %d%%", current_obs.rh_in); clear_bit(ch_flag, HUMIN); } if (test_bit(ch_flag, HUMOUT)) { errlog1(8, "Outdoor humidity: %d%%", current_obs.rh_out); clear_bit(ch_flag, HUMOUT); } if (test_bit(ch_flag, BARO)) { errlog1(8, "Barometer %g mb", current_obs.barometer); clear_bit(ch_flag, BARO); } if (test_bit(ch_flag, GUSTDIR) && test_bit(ch_flag, GUST)) { errlog1(8, "Wind gust direction: %d deg", current_obs.gust_dir); clear_bit(ch_flag, GUSTDIR); } if (test_bit(ch_flag, GUST)) { errlog1(8, "Wind gust: %g m/s", current_obs.gust); clear_bit(ch_flag, GUST); } if (test_bit(ch_flag, WAVGDIR) && test_bit(ch_flag, WAVG)) { errlog1(8, "Wind avg direction: %d deg", current_obs.wavg_dir); clear_bit(ch_flag, WAVGDIR); } if (test_bit(ch_flag, WAVG)) { errlog1(8, "Wind avg: %g m/s", current_obs.wavg); clear_bit(ch_flag, WAVG); } } pthread_mutex_unlock(¤t_obs_lock); pthread_mutex_lock(&terminate_lock); if (terminate) write_screen = 0;; pthread_mutex_unlock(&terminate_lock); /*sleep(1);*/ } errlog(8, "Screenwriter exits."); pthread_exit(0); }
/* get the next token, removing it from the input stream */ int toknext(tokcxdef *ctx) { char *p; tokdef *tok = &ctx->tokcxcur; int len; /* * Check for the special case that we pushed an open paren prior to * a string containing an embedded expression. If this is the case, * immediately return the string we previously parsed. */ if ((ctx->tokcxflg & TOKCXF_EMBED_PAREN_PRE) != 0) { /* * convert the token to a string - note that the offset * information for the string is already in the current token * structure, since we set everything up for it on the previous * call where we actually parsed the beginning of the string */ tok->toktyp = TOKTDSTRING; /* clear the special flag - we've now consumed the pushed string */ ctx->tokcxflg &= ~TOKCXF_EMBED_PAREN_PRE; /* immediately return the string */ return tok->toktyp; } /* set up at the current scanning position */ p = ctx->tokcxptr; len = ctx->tokcxlen; /* scan off whitespace and comments until we find something */ do { skipblanks: /* if there's nothing on this line, get the next one */ if (len == 0) { /* if we're in a macro expansion, continue after it */ if (ctx->tokcxmlvl) { ctx->tokcxmlvl--; p = ctx->tokcxmsav[ctx->tokcxmlvl]; len = ctx->tokcxmsvl[ctx->tokcxmlvl]; } else { if (tokgetlin(ctx, TRUE)) { tok->toktyp = TOKTEOF; goto done; } p = ctx->tokcxptr; len = ctx->tokcxlen; } } while (len && t_isspace(*p)) ++p, --len; /* scan off whitespace */ /* check for comments, and remove if present */ if (len >= 2 && *p == '/' && *(p+1) == '/') len = 0; else if (len >= 2 && *p == '/' && *(p+1) == '*') { while (len < 2 || *p != '*' || *(p+1) != '/') { if (len != 0) ++p, --len; if (len == 0) { if (ctx->tokcxmlvl != 0) { ctx->tokcxmlvl--; p = ctx->tokcxmsav[ctx->tokcxmlvl]; len = ctx->tokcxmsvl[ctx->tokcxmlvl]; } else { if (tokgetlin(ctx, FALSE)) { ctx->tokcxptr = p; tok->toktyp = TOKTEOF; goto done; } p = ctx->tokcxptr; len = ctx->tokcxlen; } } } p += 2; len -= 2; goto skipblanks; } } while (len == 0); nexttoken: if (isalpha((uchar)*p) || *p == '_' || *p == '$') { int l; int hash; char *q; toktdef *tab; int found = FALSE; uchar thischar; tokdfdef *df; for (hash = 0, l = 0, q = tok->toknam ; len != 0 && TOKISSYM(*p) && l < TOKNAMMAX ; (thischar = ((isupper((uchar)*p) && (ctx->tokcxflg & TOKCXCASEFOLD)) ? tolower((uchar)*p) : *p)), (hash = ((hash + thischar) & (TOKHASHSIZE - 1))), (*q++ = thischar), ++p, --len, ++l) ; *q = '\0'; if (len != 0 && TOKISSYM(*p)) { while (len != 0 && TOKISSYM(*p)) ++p, --len; errlog1(ctx->tokcxerr, ERR_TRUNC, ERRTSTR, errstr(ctx->tokcxerr, tok->toknam, tok->toklen)); } tok->toklen = l; tok->tokhash = hash; /* * check for the special defined() preprocessor operator */ if (l == 9 && !memcmp(tok->toknam, ((ctx->tokcxflg & TOKCXCASEFOLD) ? "__defined" : "__DEFINED"), (size_t)9) && len > 2 && *p == '(' && TOKISSYM(*(p+1)) && !isdigit((uchar)*(p+1))) { int symlen; char mysym[TOKNAMMAX]; /* find the matching ')', allowing only symbolic characters */ ++p, --len; for (symlen = 0, q = p ; len && *p != ')' && TOKISSYM(*p) ; ++p, --len, ++symlen) ; /* make sure we found the closing paren */ if (!len || *p != ')') errsig(ctx->tokcxerr, ERR_BADISDEF); ++p, --len; /* if we're folding case, convert the symbol to lower case */ q = tok_casefold_defsym(ctx, mysym, q, symlen); /* check to see if it's defined */ tok->toktyp = TOKTNUMBER; tok->tokval = (tok_find_define(ctx, q, symlen) != 0); goto done; } /* substitute the preprocessor #define, if any */ if ((df = tok_find_define(ctx, tok->toknam, l)) != 0) { /* save the current parsing position */ if (ctx->tokcxmlvl >= TOKMACNEST) errsig(ctx->tokcxerr, ERR_MACNEST); ctx->tokcxmsav[ctx->tokcxmlvl] = p; ctx->tokcxmsvl[ctx->tokcxmlvl] = len; ctx->tokcxmlvl++; /* point to the token's expansion and keep going */ p = df->expan; len = df->explen; goto nexttoken; } /* look up in symbol table(s), if any */ for (tab = ctx->tokcxstab ; tab ; tab = tab->toktnxt) { if ((found = (*tab->toktfsea)(tab, tok->toknam, l, hash, &tok->toksym)) != 0) break; } if (found && tok->toksym.tokstyp == TOKSTKW) tok->toktyp = tok->toksym.toksval; else { tok->toktyp = TOKTSYMBOL; if (!found) tok->toksym.tokstyp = TOKSTUNK; } goto done; } else if (isdigit((uchar)*p)) { long acc = 0; /* check for octal/hex */ if (*p == '0') { ++p, --len; if (len && (*p == 'x' || *p == 'X')) { /* hex */ ++p, --len; while (len && TOKISHEX(*p)) { acc = (acc << 4) + TOKHEX2INT(*p); ++p, --len; } } else { /* octal */ while (len && TOKISOCT(*p)) { acc = (acc << 3) + TOKOCT2INT(*p); ++p, --len; } } } else { /* decimal */ while (len && isdigit((uchar)*p)) { acc = (acc << 1) + (acc << 3) + TOKDEC2INT(*p); ++p, --len; } } tok->tokval = acc; tok->toktyp = TOKTNUMBER; goto done; } else if (*p == '"' || *p == '\'') { char delim; /* closing delimiter we're looking for */ char *strstart; /* pointer to start of string */ int warned; delim = *p; --len; strstart = ++p; if (delim == '"' && len >= 2 && *p == '<' && *(p+1) == '<') { /* save the current parsing position */ if (ctx->tokcxmlvl >= TOKMACNEST) errsig(ctx->tokcxerr, ERR_MACNEST); ctx->tokcxmsav[ctx->tokcxmlvl] = p + 2; ctx->tokcxmsvl[ctx->tokcxmlvl] = len - 2; ctx->tokcxmlvl++; /* * read from the special "<<" expansion string - use the * version for a "<<" at the very beginning of the string */ p = tokmac1s; len = strlen(p); ctx->tokcxflg |= TOKCXFINMAC; goto nexttoken; } tok->toktyp = (delim == '"' ? TOKTDSTRING : TOKTSSTRING); tok->tokofs = (*ctx->tokcxsst)(ctx->tokcxscx); /* start the string */ for (warned = FALSE ;; ) { if (len >= 2 && *p == '\\') { if (*(p+1) == '"' || *(p+1) == '\'') { (*ctx->tokcxsad)(ctx->tokcxscx, strstart, (ushort)(p - strstart)); strstart = p + 1; } p += 2; len -= 2; } else if (len == 0 || *p == delim || (delim == '"' && len >= 2 && *p == '<' && *(p+1) == '<' && !(ctx->tokcxflg & TOKCXFINMAC))) { (*ctx->tokcxsad)(ctx->tokcxscx, strstart, (ushort)(p - strstart)); if (len == 0) { if (ctx->tokcxmlvl) { ctx->tokcxmlvl--; p = ctx->tokcxmsav[ctx->tokcxmlvl]; len = ctx->tokcxmsvl[ctx->tokcxmlvl]; } else (*ctx->tokcxsad)(ctx->tokcxscx, " ", (ushort)1); while (len == 0) { if (tokgetlin(ctx, FALSE)) errsig(ctx->tokcxerr, ERR_STREOF); p = ctx->tokcxptr; len = ctx->tokcxlen; /* warn if it looks like the end of an object */ if (!warned && len && (*p == ';' || *p == '}')) { errlog(ctx->tokcxerr, ERR_STREND); warned = TRUE; /* warn only once per string */ } /* scan past whitespace at start of line */ while (len && t_isspace(*p)) ++p, --len; } strstart = p; } else break; } else ++p, --len; } /* end the string */ (*ctx->tokcxsend)(ctx->tokcxscx); /* check to see how it ended */ if (len != 0 && *p == delim) { /* * We ended with the matching delimiter. Move past the * closing delimiter. */ ++p; --len; /* * If we have a pending close paren we need to put in * because of an embedded expression that occurred earlier * in the string, parse the macro to provide the paren. */ if ((ctx->tokcxflg & TOKCXF_EMBED_PAREN_AFT) != 0 && !(ctx->tokcxflg & TOKCXFINMAC)) { /* clear the flag */ ctx->tokcxflg &= ~TOKCXF_EMBED_PAREN_AFT; /* push the current parsing position */ if (ctx->tokcxmlvl >= TOKMACNEST) errsig(ctx->tokcxerr, ERR_MACNEST); ctx->tokcxmsav[ctx->tokcxmlvl] = p; ctx->tokcxmsvl[ctx->tokcxmlvl] = len; ctx->tokcxmlvl++; /* parse the macro */ p = tokmac4; len = strlen(p); } } else if (len != 0 && *p == '<') { /* save the current parsing position */ if (ctx->tokcxmlvl >= TOKMACNEST) errsig(ctx->tokcxerr, ERR_MACNEST); ctx->tokcxmsav[ctx->tokcxmlvl] = p + 2; ctx->tokcxmsvl[ctx->tokcxmlvl] = len - 2; ctx->tokcxmlvl++; /* read from the "<<" expansion */ p = tokmac1; len = strlen(p); ctx->tokcxflg |= TOKCXFINMAC; /* * Set the special push-a-paren flag: we'll return an open * paren now, so that we have an open paren before the * string, and then on the next call to toknext() we'll * immediately return the string we've already parsed here. * This will ensure that everything in the string is * properly grouped together as a single indivisible * expression. * * Note that we only need to do this for the first embedded * expression in a string. Once we have a close paren * pending, we don't need more open parens. */ if (!(ctx->tokcxflg & TOKCXF_EMBED_PAREN_AFT)) { ctx->tokcxflg |= TOKCXF_EMBED_PAREN_PRE; tok->toktyp = TOKTLPAR; } } goto done; } else if (len >= 2 && *p == '>' && *(p+1) == '>' && (ctx->tokcxflg & TOKCXFINMAC) != 0) { /* skip the ">>" */ ctx->tokcxflg &= ~TOKCXFINMAC; p += 2; len -= 2; /* save the current parsing position */ if (ctx->tokcxmlvl >= TOKMACNEST) errsig(ctx->tokcxerr, ERR_MACNEST); ctx->tokcxmsav[ctx->tokcxmlvl] = p; ctx->tokcxmsvl[ctx->tokcxmlvl] = len; ctx->tokcxmlvl++; if (*p == '"') { ++(ctx->tokcxmsav[ctx->tokcxmlvl - 1]); --(ctx->tokcxmsvl[ctx->tokcxmlvl - 1]); p = tokmac3; /* * we won't need an extra closing paren now, since tokmac3 * provides it */ ctx->tokcxflg &= ~TOKCXF_EMBED_PAREN_AFT; } else { /* * The string is continuing. Set a flag to note that we * need to provide a close paren after the end of the * string, and parse the glue (tokmac2) that goes between * the expression and the resumption of the string. */ ctx->tokcxflg |= TOKCXF_EMBED_PAREN_AFT; p = tokmac2; } len = strlen(p); goto nexttoken; } else { tokscdef *sc; for (sc = ctx->tokcxsc[ctx->tokcxinx[(uchar)*p]] ; sc ; sc = sc->tokscnxt) { if (toksceq(sc->tokscstr, p, sc->toksclen, len)) { tok->toktyp = sc->toksctyp; p += sc->toksclen; len -= sc->toksclen; goto done; } } errsig(ctx->tokcxerr, ERR_INVTOK); } done: ctx->tokcxptr = p; ctx->tokcxlen = len; return(tok->toktyp); }
/* process a #include directive */ static void tokinclude(tokcxdef *ctx, char *p, int len) { linfdef *child; tokpdef *path; char *fname; int match; int flen; linfdef *lin; char *q; size_t flen2; /* find the filename portion */ fname = p + 1; /* remember start of filename */ path = ctx->tokcxinc; /* start with first path entry */ if (!len) { errlog(ctx->tokcxerr, ERR_INCNOFN); return; } switch(*p) { case '<': match = '>'; if (path && path->tokpnxt) path = path->tokpnxt; /* skip 1st path */ goto find_matching_delim; case '"': match = '"'; find_matching_delim: for (++p, --len ; len && *p != match ; --len, ++p) ; if (len == 0 || *p != match) errlog(ctx->tokcxerr, ERR_INCMTCH); break; default: errlog(ctx->tokcxerr, ERR_INCSYN); return; } flen = p - fname; /* compute length of filename */ for (q = p, flen2 = 0 ; q > fname && *(q-1) != OSPATHCHAR && !strchr(OSPATHALT, *(q-1)) ; --q, ++flen2) ; /* check to see if this file has already been included */ for (lin = ctx->tokcxhdr ; lin ; lin = (linfdef *)lin->linflin.linnxt) { char *p = lin->linfnam; p += strlen(p); while (p > lin->linfnam && *(p-1) != OSPATHCHAR && !strchr(OSPATHALT, *(p-1))) --p; if (strlen(p) == flen2 && !memicmp(p, q, flen2)) { errlog1(ctx->tokcxerr, ERR_INCRPT, ERRTSTR, errstr(ctx->tokcxerr, fname, flen)); return; } } /* initialize the line source */ child = linfini(ctx->tokcxmem, ctx->tokcxerr, fname, flen, path, TRUE, (ctx->tokcxflg & TOKCXFLIN2) != 0); /* if not found, signal an error */ if (!child) errsig1(ctx->tokcxerr, ERR_INCSEAR, ERRTSTR, errstr(ctx->tokcxerr, fname, flen)); /* link into tokenizer list of line records */ child->linflin.linnxt = (lindef *)ctx->tokcxhdr; ctx->tokcxhdr = child; /* if we're tracking sources for debugging, add into the chain */ if (ctx->tokcxdbg) { ctx->tokcxdbg->dbgcxlin = &child->linflin; child->linflin.linid = ctx->tokcxdbg->dbgcxfid++; } /* remember my C-mode setting */ if (ctx->tokcxflg & TOKCXFCMODE) ctx->tokcxlin->linflg |= LINFCMODE; else ctx->tokcxlin->linflg &= ~LINFCMODE; child->linflin.linpar = ctx->tokcxlin; /* remember parent line source */ ctx->tokcxlin = &child->linflin; /* make the child the current source */ }
/* process a #error */ static void tok_p_error(tokcxdef *ctx, char *p, int len) { errlog1(ctx->tokcxerr, ERR_P_ERROR, ERRTSTR, errstr(ctx->tokcxerr, p, len)); }