/* cmetar.c by TOYODA Eizi, 2014 - licensed GPLv3 */ #include #include #include #include #include "cdetac.h" long inhg_to_hpa(long val) { if (val == LONG_MIN) { return val; } return (val * 2 + 1) * 6170 / 3644; } int ms_metar(struct message_t *ms, enum TokenType tt, const char *token, enum TokenType tt2, const char *token2) { ms_default(ms, tt, token, tt2, token2); switch (tt) { case TTEQ: if (ms->ms_state == MSS_EQ) { fprintf(stdout, "# duplicated TTEQ\n"); } else { /* unit conversion if necessary */; } ms->ms_state = MSS_EQ; goto endfunc; } /* state by position */ switch (ms->ms_state) { case MSS_MetarMain: if (tt == TTMetarWW) { goto MetarWW; } else if (tt == TTMetarNH) { /* (FEW|SCT|BKN|OVC|\/\/\/)([0-9]{3}|\/\/\/)(CB|TCU|SC|CU|\/\/\/)? */ char buf[3 + 1]; long n; strncpy(buf, token + 3, 3); buf[3] = '\0'; n = *token == '/' ? LONG_MIN : *token == 'F' ? 2 : *token == 'S' ? 4 : *token == 'B' ? 6 : 8; ms_set(ms, "3Ns", buf, n); if (token[6] && (token[6] != '/')) { ms_set(ms, token + 6, buf, 1); } } else if (tt == TTMetarZ) { /* [0-9]{6}Z */ ms_set(ms, "2Y", NULL, tac_atoi(token, 0, 2)); ms_set(ms, "2G", NULL, tac_atoi(token, 2, 2)); ms_set(ms, "2g", NULL, tac_atoi(token, 4, 2)); } else if (tt == TTMetarSM) { /* M?(([12]\040)?[1-5]\/)?[1-9][0-9]*SM */ const char *fr = token; char *sp = strchr(token, ' '); char *sl = strchr(token, '/'); long base, frac, fact, val; if (*fr == 'M') { fr++; } base = sp ? atoi(fr) : 0; frac = sp ? atoi(sp + 1) : atoi(fr); fact = sl ? atoi(sl + 1) : 1; val = (base * fact) + frac; val = val * 4828 / (fact * 3); ms_set(ms, "4V", NULL, val); } else if (tt == TTMetarTTd) { /* M?[0-9\/][0-9\/]\/M?[0-9\/][0-9\/] */ const char *tt, *td; int mtt, mtd; tt = token; if (*token == 'M') { tt++; } mtt = (*token == 'M') ? '1' : '0'; td = strchr(token, '/'); if (td) { td++; if (*td == 'M') { td++; } } mtd = (td && (td[-1] == 'M')) ? '1' : '0'; ms_set(ms, "2T_", NULL, tac_atosi(tt, mtt, 0, 2)); ms_set(ms, "2Td_", NULL, tac_atosi(td, mtd, 0, 2)); } else if (tt == TTMetarR) { /* R[0123][0-9][LCR]?\/[PM]?[0-9\/]{4}[UDN]? */ const char *v; char rwy[7 + 1]; long vr; v = strchr(token, '/'); StringCopy(rwy, token, v - token); v++; if ((*v == 'P') || (*v == 'M')) { ms_set(ms, "tVR", rwy, tac_atoi(v, 0, 4)); v++; } ms_set(ms, "4VR", rwy, tac_atoi(v, 0, 4)); ms_set(ms, "i", rwy, v[4]); } else if (tt == TTMetarKT) { /* [0123][0-9][0]P?[0-9]{2,3}(GP?[0-9]{2,3})?(KTS?|MPS) */ const char *c = token; long ff, fm; int w; /* direction takes always 3 digits */ ms_set(ms, "3d", NULL, tac_atoi(c, 0, 3)); c += 3; /* ff may take 2 or 3 digits */ if (*c == 'P') { c++; } w = isdigit(c[2]) ? 3 : 2; ff = tac_atoi(c, 0, w); c += w; /* if c points to 'G' that is follwed by fm that may take 2 or 3 */ if (*c == 'G') { if (*c == 'P') { c++; } w = isdigit(c[3]) ? 3 : 2; fm = tac_atoi(c, 0, w); c += w; } else { fm = LONG_MIN; } if (*c == 'M') { if (ff != LONG_MIN) { ff = ff * 10; } if (fm != LONG_MIN) { fm = fm * 10; } } else { if (c[1] == 'M') { /* KMH */ if (ff != LONG_MIN) { ff = ff * 1000 / 360; } if (fm != LONG_MIN) { fm = fm * 1000 / 360; } } else { /* KT or KTS */ ff = knot_to_mps(ff); fm = knot_to_mps(fm); } } ms_set(ms, "2f", NULL, ff); ms_set(ms, "2m", NULL, fm); } else if (tt == TTMetarDVD) { /* [0123][0-9][0-9]V[0123][0-9][0-9] */ ms_set(ms, "3dn", NULL, tac_atoi(token, 0, 3)); ms_set(ms, "3dx", NULL, tac_atoi(token, 4, 3)); } else if (tt == TTMetarQNH) { /* [QA][0-9]{4} */ if (token[0] == 'Q') { long ph = tac_atoi(token, 1, 4); if (ph != LONG_MIN) { ph *= 10; } ms_set(ms, "4PH", NULL, ph); } else if (token[0] == 'A') { ms_set(ms, "4PH", NULL, inhg_to_hpa(tac_atoi(token, 1, 4))); } else { goto BadTokenMetarMain; } } else if (tt == TTMetarFix) { if (StringEq(token, "CAVOK")) { ms_set(ms, "CAVOK", NULL, 1); ms_set(ms, "4V", NULL, 9999L); } else if (StringEq(token, "RMK")) { ms->ms_state = MSS_MetarRmk; } else if (StringEq(token, "BECMG") || StringEq(token, "TEMPO")) { ms->ms_state = MSS_MetarTrend; } else if (StringEq(token, "COR")) { ms_set(ms, "/COR", NULL, 1); } else if (StringEq(token, "NSC")) { ms_set(ms, "NSC", NULL, 1); } else if (StringEq(token, "NCD")) { ms_set(ms, "NCD", NULL, 1); } else if (StringEq(token, "CLR")) { ms_set(ms, "CLR", NULL, 1); } else if (StringEq(token, "SKC")) { ms_set(ms, "SKC", NULL, 1); } else if (StringEq(token, "NOSIG")) { ms_set(ms, "NOSIG", NULL, 1); } else { goto BadTokenMetarMain; } } else if (tt == TTNIL) { /* bad to omit YYGGggZ */ if (ms_get(ms, "2Y", "") == LONG_MIN) { ms_set(ms, "2Y", NULL, tac_atoi(ms->ms_cccc, 5, 2)); ms_set(ms, "2G", NULL, tac_atoi(ms->ms_cccc, 7, 2)); ms_set(ms, "2g", NULL, tac_atoi(ms->ms_cccc, 9, 2)); } ms->ms_state = MSS_MetarRmk; } else if (tt == TTMetarVV) { /* VV[0-9\/]{3} */ ms_set(ms, "3hs", NULL, tac_atoi(token, 2, 3)); } else if (tt == TTMetarRVR) { ms_set(ms, "4V", token + 4, tac_atoi(token, 0, 4)); } else if (StringEq(token, "AUTO")) { ms_set(ms, "AUTO", NULL, 1); } else if (string_match(token, "[A-Z][-A-Z0-9][A-Z0-9][A-Z0-9]")) { if (ms->ms_id[0] == '\0') { StringCopy(ms->ms_id, token, 4); } else { goto MetarWW; } } else if ((token[2] == '/') && string_match(token, "[0-9/][0-9/]/[0-9/][0-9/]")) { ms_set(ms, "2T_", NULL, tac_atoi(token, 0, 2)); ms_set(ms, "2Td_", NULL, tac_atoi(token, 3, 2)); } else if (string_match(token, "[A-Z][A-Z][A-Z][A-Z]")) { MetarWW: if (string_match(token, "RE%")) { ms_set(ms, "2w_/RE", token + 2, 1); } else { ms_set(ms, "2w_", token, 1); } } else { BadTokenMetarMain: if (ms->ms_state == MSS_MetarMain) { fprintf(stdout, "# unrecognised (%s) in MetarMain\n", token); } } break; case MSS_MetarRmk: if (tt == TTMetarRI) { /* RI([0-9]{3}|\+\+) */ if (token[2] == '+') { ms_set(ms, "RI", NULL, 30L); } else { ms_set(ms, "RI", NULL, tac_atoi(token, 2, 3)); } } else if ((tt == TTMetarQNH) && (token[0] == 'A')) { ms_set(ms, "4PH", NULL, inhg_to_hpa(tac_atoi(token, 1, 4))); } else if (tt == TTMetarSLP) { /* SLP[0-9]{3} */ long p = tac_atoi(token, 3, 3); if (p >= 500) { p += 9000; } else if (p >= 0) { p += 10000; } ms_set(ms, "4P", NULL, p); } else if (tt == TTMetarTT) { /* T[01][0-9]{3}[01][0-9]{3} */ ms_set(ms, "3T", NULL, tac_atosi(token, token[1], 2, 3)); ms_set(ms, "3Td", NULL, tac_atosi(token, token[5], 6, 3)); } else if (tt == TTMetarCld) { /* [0-9](CU|SC|AS|AC|CI|CS|CB|TCU)[0-9]{3} */ const char *p; char cld[4]; p = token + 3; if (p[0] == 'U') { p++; } StringCopy(cld, token + 1, (p - token - 1)); ms_set(ms, cld, p, 1); ms_set(ms, "N", p, tac_atoi(token, 0, 1)); } else if (tt == TTMetarA) { ms_set(ms, token, NULL, 1); } else if (tt == TTMetarSD) { ms_set(ms, "SD", NULL, tac_atoi(token, 2, 3)); ms_set(ms, "SDCHG", NULL, tac_atoi(token, 6, 3)); } break; } endfunc: return 0; }