/* @(#)tz3.c 17.1.1.1 (ES0-DMD) 01/25/02 17:36:45 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .TYPE Module .NAME tz3.c .LANGUAGE C .AUTHOR J.D.Ponz, F. Ochsenbein IPG-ESO Garching .CATEGORY table interface (Design 3.0). .KEYWORDS tables, file name .PURPOSE Code / Decode Routines .VERSION 3.0 01-Jul-1990 Extracted from tz2 .VERSION 3.1 19-Dec-1990: Added NULL setup .VERSION 3.2 22-Sep-1992: treats properly NULL values (for the Convex) .COMMENTS An extended set of formats for i/o was implemented. \begin{TeX} These are described below, with an example on the integer number 86401 or the Floating number 83.5 \begin{tabular}{| l | l | l r |} \hline & Meaning & \multicolumn{2}{l |}{Example}\\ \hline \multicolumn{4}{| c | } { Integer Numbers} \\ \hline I$n$ & Decimal edition & I8 & {\tt 86401} \\ i$n$ & Decimal with sign & i8 & {\tt +86401} \\ X$n$ & Hexadecimal & X8 & {\tt 15181} \\ o$n$ & Octal & o8 & {\tt 250601} \\ T$n.d$ & Time, numeric & T19.6 & {\tt 1970-01-02:00:00:01} \\ t$n.d$ & Time, litteral & t20.6 & {\tt 02-Jan-1970:00:00:01} \\ Z$n$ & Zero-filled number& Z12 & {\tt 000000086401} \\ z$n$ & zero-filled with sign & z12 & {\tt +00000086401} \\ \hline \multicolumn{4}{| c | } { Floating-point Numbers} \\ \hline F$n.d$ & F format & F12.2 & {\tt 83.50} \\ f$n.d$ & F format with sign & f12.2 & {\tt +83.50} \\ E$n.d$ & E format & E12.2 & {\tt 8.3e+01 } \\ f$n.d$ & E format with sign & f12.2 & {\tt +8.3e+01} \\ R$n.d$ & RA (angle of 24h) & R11.6 & {\tt 05 34 00.00} \\ r$n.d$ & RA (angle of 24h) & R12.6 & {\tt +05 34 00.00} \\ S$n.d$ & Sexagesimal & S9.4 & {\tt 83 00 00} \\ s$n.d$ & Signed Sexagesimal & S9.4 & {\tt +83 00 00} \\ T$n.d$ & Julian Date & & \\ t$n.d$ & Litteral Julian Date & & \\ Z$n.d$ & Zero-filled number& Z12.2 & {\tt 000000083.50} \\ Z$n.d$ & Zero-filled number& Z12.2 & {\tt 000000083.50} \\ z$n.d$ & zero-filled with sign & z12.2 & {\tt +00000083.50} \\ \hline \end{tabular} \end{TeX} For Integers ------------------------------------------------------------*/ #include /* General MIDAS Symbols */ #include #include /* Table System parameters */ #include /* List of Table Errors */ #include /* Classical Macros */ #include /* Character classification */ double modf(); /* Modulo function in DP (math) */ #define LEN 80 #define issign(c) ((c == '+') || (c == '-')) #define GobbleSpaces(s,l) s += oscspan((unsigned char *)s, l, _SPACE_, main_ascii) static char *errmsg = (char *)0; static char *stopped; /* To communicate the stopping char */ static int accu; static int base = 10; static char sign; static char has_decimals; /* Limits related to integer size */ static int llim[] = { -127, -32767, -2147483647, -2147483647}; static int ulim[] = { 255, 65535, 2147483647, 2147483647}; /*==========================================================================* * NULL definitions for floating-point *==========================================================================*/ /*==========================================================================* * Internal for Time Manipulation *==========================================================================*/ #include /* System */ #define JD1970 2440587.5e0 /* JD of 00:00:00 Jan. 1, 1970 */ #if 0 /*===========================TAKEN FROM SYSTEM ===================*/ struct tm { /* Gregorian! */ int tm_year, /* Complete year */ tm_mon, /* 0-11 */ tm_mday, /* 1-31 */ tm_hour, /* 0-23 */ tm_min, /* 0-59 */ tm_sec, /* 0-59 */ tm_wday, /* 0(Sunday)-6 */ tm_yday, /* 0-365 */ tm_isdst; /* unused */ }; #endif static char month_list[] = "\0Jan\01Feb\02Mar\03Apr\04May\05Jun\06Jul\07Aug\ \010Sep\011Oct\012Nov\013Dec\01Fev\03Avr\04Mai\05Jui\07Aou\011Okt\013Dez"; static char wday_list[] = "SunMonTueWedThuFriSat"; static unsigned char month[12]={31,28,31,30,31,30,31,31,30,31,30,31}; /*========================================================================*/ #ifdef __STDC__ static int tr_tm(struct tm *T) #else static int tr_tm(T) /*+++ .PURPOSE Compute missing info in T structure .RETURNS 0 (good date) / -1 (bad data: invalid month or day number ...) .REMARKS ---*/ struct tm *T; /* MOD: Time as a structure */ #endif { int y, j, t; month[1] = 29; if (T->tm_mday) { /* Compute Day of 400 yr cycle */ if ( (T->tm_mon > 11) || (T->tm_mon < 0) ) errmsg = "bad month"; if ( (T->tm_mday <= 0) || (T->tm_mday > (int)month[T->tm_mon])) errmsg = "bad day_in_month"; if (errmsg) return (-1); } /* Convert time */ j = 0; t = ((T->tm_hour*60) + (T->tm_min))*60 + T->tm_sec; while (t < 0) { j--; t += 86400L; } while (t >= 86400L) { j++; t -= 86400L; } T->tm_sec = t%60; t /= 60; T->tm_min = t%60; T->tm_hour= t/60; t = j; /* Days */ y = T->tm_year % 400; T->tm_year /= 400; if (y < 0) { y += 400; T->tm_year -= 1;} T->tm_year *= 400; if (T->tm_mday){ /* Compute Day of 400 yr cycle */ y += 400; /* Positive interval */ j = y - (11 - T->tm_mon)/10; t += ((1461L*j)/4 + (306L * ((T->tm_mon+10)%12) + 5)/10 - (3* ((j + 100L)/100L))/4 + T->tm_mday + 59L) % 146097L; y -= 400; } else t += 365*y + (y+3)/4 - (y-1)/100 + T->tm_yday; while (t < 0) { T->tm_year -= 400; t += 146097L;} /* Compute Week day */ T->tm_wday = (t+6L)%7L; /* Compute Year */ T->tm_year += 400L*(t/146097L); t %= 146097L; y = 4 *(t + (t-60)/36524L) / 1461L; T->tm_year += y; T->tm_yday = t - y*365L - (y+3)/4 + (y-1)/100; /* Compute mday + mon from yday */ if (y&3) month[1] = 28; if ( ((y%100) == 0) && (y)) month[1] = 28; for (y=T->tm_yday, j=0; y>=(int)month[j]; y -= month[j], j++) ; T->tm_mon = j; T->tm_mday = y+1; return(0); } /*========================================================================*/ #ifdef __STDC__ static int tr_itm(int t, struct tm *T) #else static int tr_itm(t, T) /*+++ .PURPOSE Transform integer time to structure .RETURNS 0 .REMARKS ---*/ int t; /* IN: Time in seconds since Jan 1, 1970 */ struct tm *T; /* OUT: Time in the structure */ #endif { int days, year; days = t/86400L; if (t < 0) days--; t -= (days*86400L); T->tm_hour = t/3600; T->tm_min = 0; T->tm_sec = (t%3600); days += (70L*365L + 18L); /* Offset 1900 */ year = (4L*days)/1461L; T->tm_year = year; T->tm_mon = 0; T->tm_mday = 0; T->tm_yday = days - 365L*year - (year+3)/4; T->tm_year+= 1900; tr_tm(T); return(0); } /*========================================================================*/ #ifdef __STDC__ static int tr_tmi(struct tm *T, int *t) #else static int tr_tmi(T, t) /*+++ .PURPOSE Transform structure time to time in seconds from Jan 1, 1970 .RETURNS 0 / -1 (time not in limits 1902-2037). Error message logged, .REMARKS ---*/ struct tm *T; /* IN: Time as a structure */ int *t; /* OUT: Time in seconds */ #endif { register int n, y; *t = 0x80000000; /* Default returned time... */ if (tr_tm(T)) /* Compute missing information... */ return(-1); if ((T->tm_year < 1902) || (T->tm_year >=2038)) { errmsg = "Year outside limits [1902, 2038]"; return(-1); } n = T->tm_year - 1970; y = (n >= 0 ? n+1 : n-2); /* Leap year counter */ n = 365*n + y/4; *t = (n + T->tm_yday) * 86400L + T->tm_hour * 3600L + T->tm_min * 60L + T->tm_sec; return(0); } /*========================================================================*/ #ifdef __STDC__ static double tmtojd(struct tm *T) #else static double tmtojd(T) /*+++ .PURPOSE Transform structure time to Julian Day .RETURNS JD equivalence .REMARKS ---*/ struct tm *T; /* IN: Time as a structure */ #endif { int jm, j; double JD; tr_tm(T); /* Can be wrong... */ if (T->tm_year <= -4712) { j = 1 + (T->tm_year + 4712)/400; /* Number of 400-yr cycles */ jm = -j * 146097L; j = T->tm_year + 400*j; } else jm = 0, j = T->tm_year; j -= (11 - T->tm_mon)/10; jm += (1461L* ( j + 4712L))/4 + (306L * ((T->tm_mon+10)%12) + 5)/10 - (3* ((j + 4900L)/100))/4 + T->tm_mday + 96; JD = jm; jm = ((12+T->tm_hour))*3600L + T->tm_min*60 + T->tm_sec; JD += (jm/86400.e0); return(JD); } /*========================================================================*/ #ifdef __STDC__ static int tr_jdtm(double JD, struct tm *T) #else static int tr_jdtm(JD, T) /*+++ .PURPOSE Transform Julian Date to time structure .RETURNS 0 .REMARKS ---*/ double JD; /* IN: Julian date */ struct tm *T; /* OUT: Date in structure */ #endif { register int j, n4, nd10; double x; x = JD + 0.5e0 + 0.5e0/86400.e0; /* Round day */ j = x; if (x < 0) --j; x = x - j; /* Fraction of day */ T->tm_year = -4712; while (j <= 4480) { j += 146097L; T->tm_year -= 400;} n4 = 4*(j+((2*((4*j-17918L)/146097L)*3)/4+1)/2-37); nd10=10*( ((n4-237)%1461)/4)+5; T->tm_year += n4/1461; T->tm_mon = (nd10/306+2)%12; T->tm_mday = (nd10%306)/10+1; x *= 86400.e0; /* Seconds */ j = x; T->tm_hour = j/3600; T->tm_min = 0; T->tm_sec = j%3600; tr_tm(T); /* Add missing info... */ return(0); } /*==========================================================================* * Internal Routines for Edition *==========================================================================*/ #ifdef __STDC__ static char *ed60 (char *buf,int n,char sep) #else static char *ed60 (buf, n, sep) /*++++++++++++++++++++ .PURPOSE Edit a sexagesimal element, starting from the right .RETURNS Position ---------------------*/ char *buf; /* IN: Rightmost+1 position */ int n; /* IN: Number 0-50 to edit */ char sep; /* IN: Separator */ #endif { char *a; a = buf; *--a = '0' + n%10; n /= 10; *--a = '0' + n; *--a = sep; return(a); } #ifdef __STDC__ int ed_sexa(char *buf,char *pic,double value) #else int ed_sexa(buf, pic, value) /*++++++++++++++++++++ .PURPOSE Edit a value in sexagesimal .RETURNS Status .REMARKS pic is L.d with d = 0 : No fraction 1 : .1 degree 2 : arcmin 3 : .1 arcmin 4 : arcsec 5... fractions of arcseconds ---------------------*/ char *buf; /* OUT: edited value */ char *pic; /* IN: Edition elements */ double value; /* IN: Value to edit */ #endif { static double factor[10] = {1., 10., 60., 600., 3600., 3.6e4, 3.6e5, 3.6e6, 3.6e7, 3.6e8 }; double x, f; char *p ,*a; int len, dec; int n; x = ABSOLUTE(value); for (len = 0, p = pic; isdigit(*p); p++) len = len*10 + (*p - '0'); for (dec = 0, ++p; isdigit(*p); p++) dec = dec*10 + (*p - '0'); if (dec > 9) dec = 9; x += .5 / factor[dec]; f = modf (x, &x) * factor[dec]; n = f; a = buf + len; *a = EOS; while (dec > 5) { *--a = '0' + n%10; n /= 10; dec--; } switch(dec) { case 5: *--a = '0' + n%10; n /= 10; *--a = '.'; case 4: *--a = '0' + n%10; n /= 10; *--a = '0' + n%6; n /= 6; *--a = *p; goto case_2; case 3: *--a = '0' + n%10; n /= 10; *--a = '.'; case 2: case_2: *--a = '0' + n%10; n /= 10; *--a = '0' + n%6 ; n /= 6; *--a = *p; break; case 1: *--a = '0' + n; *--a = '.'; break; } n = x; /* Degrees */ while (a > buf) { *--a = '0' + n%10; n /= 10; } if (value < 0) *buf = '-'; return(0); } /*=============================================================== * The following Conversion Routines are extracted from * tc3lib / tral.c *================================================================*/ /*===========================================================================*/ #ifdef __STDC__ static int Number(char *str, int len) #else static int Number(str, len) /*++++++ .PURPOSE Just scan a string until non-valid characters are found. The number is stored in accu. .RETURNS Number of valid characters .REMARKS Not traced. --------*/ char *str; /* IN: The string to scan */ int len; /* IN: Length of the string */ #endif { char *p, *pe; int i; accu = 0; if (len <= 0) return(0); for (p = str, pe = p + len; (p < pe) && (isxdigit(*p)); p++) { if (isdigit(*p)) i = '0'; else if (isupper(*p)) i = 'A' - 10; else i = 'a' - 10; i = *p - i; if (i >= base) break; accu = accu * base + i; } i = p - str; /* Number of Digits */ return(i); } /*===========================================================================*/ #ifdef __STDC__ static int Sign(char *str, int len) #else static int Sign(str, len) /*++++++ .PURPOSE Just scan the beginning of a string: skip leading blanks, and get the sign. .RETURNS Number of valid characters .REMARKS Not traced. --------*/ char *str; /* IN: The string to scan */ int len; /* IN: Length of the string */ #endif { char *p, *pe; sign = 0; if (len <= 0) return(0); p = str, pe = p + len; GobbleSpaces(p, len); if (p < pe) { switch(*p) { case '-': sign = 1; case '+': p++; break; } GobbleSpaces(p, pe-p); /* Skip blanks */ } return(p-str); } /*===========================================================================*/ #ifdef __STDC__ static int tral(char *str, int len, int *value) #else static int tral(str, len, value) /*++++++ .PURPOSE Converts a string to a int number. Input is assumed to be in decimal, unless the string starts with 'X' (hexadecimal) or 'O' (octal). The digits may be followed by K (implies a 1024 factor) .RETURNS Number of digits (excluding spaces) scanned, -1 for error (message logged) .REMARKS Return 0 if string contains only spaces or a sign. Value is then set to NULL4. --------*/ char *str; /* IN: String to scan */ int len; /* IN: Length of str */ int *value; /* OUT: result */ #endif { char *p, *pe; int nd; nd = 1; accu = 0; errmsg = (char *)0; p = str + Sign(str, len); /* Skip trailer + sign */ pe = str + len; if (*p == '\'') /* Get a Character */ { p++; if (*p != '\'') accu = *(p++); if (*p == '\'') p++; goto check_remaining_bytes; } if (*p == '^') /* Get a Control Character */ { p++; accu = tocntrl(*p), p++; goto check_remaining_bytes; } nd = Number(p, pe-p); /* Get number */ p += nd; /* End of number */ /* If the string is not completely understood, look if it can be due to O(octal), X(hexadecimal), k (k-factor) Note that X and O can only be at the beginning, i.e. when accu == 0; k can only be a suffix. */ if (p < pe) switch(toupper(*p)) { case 'O': base = 8; if (accu == 0) goto special_base; break; case 'X': base = 16; if (accu == 0) goto special_base; break; special_base: p++; nd = Number(p, pe-p); p += nd; break; case 'K': accu *= 1024; p++; break; } /* Take Sign into account, and check remaining bytes are only white spaces */ check_remaining_bytes: if (nd > 0) *value = (sign ? -accu : accu); else toNULL4(value); stopped = p; return(nd); } /*=============================================================== * The following Conversion Routines are extracted from * tc3lib / traf.c *================================================================*/ /*===========================================================================*/ #ifdef __STDC__ static int traf(char *str, int len, double *value) #else static int traf(str, len, value) /*++++++ .PURPOSE Converts a string to a floating point. Input is assumed to be in decimal. .RETURNS Number of significant digits / -1 for error .REMARKS Return 0 if string contains only spaces. Stopped index returned in static `stopped'. The static has_decimals is not-zero if decimals found. --------*/ char *str; /* IN: String to scan */ int len; /* IN: Length of str */ double *value; /* OUT: result */ #endif { char *p, *pe, *ps, x, something; int i, nd; double atof(); errmsg = (char *)0; has_decimals = 0; nd = 0, something = 0; p = str, pe = p + len; GobbleSpaces(p,len); if (p == pe) { errmsg = "Wrong Input"; goto error; } ps = p; /* Starting point of string */ if (issign(*p)) p++; if (p == pe) goto error; /* Zero */ if (something == 0) something = *p; if (*p != '0') p += oscskip(p, pe-p, '0'); /* Skip leading zeroes */ /* MP 060391 */ if (p == pe) goto error; /* Zero */ nd = oscspan((unsigned char *)p, pe-p, _DIGIT_, main_ascii), p += nd; if (p == pe) goto get_value; if (*p == '.') has_decimals = 1, p++; if (nd == 0) { /* Skip leading zeroes */ if (something == 0) something = *p; p += oscskip(p, pe-p, '0'); } i = oscspan((unsigned char *)p, pe-p, _DIGIT_, main_ascii); /* Decimals */ p += i, nd += i; /* Look for Exponent */ if ((p < pe) && (isalpha(*p))) { x = toupper(*p); if ((x == 'E') || (x == 'D')) /* Exponent */ { if (p == ps) errmsg = "Missing exponent"; p++; if (issign(*p)) p++; p += oscspan((unsigned char *)p, pe-p, _DIGIT_, main_ascii); } } get_value: if (p == ps) errmsg = "No data"; x = *p, *p = '\0', *value = atof(str), *p = x; error: if ((nd == 0) && (has_decimals)) nd = 1; if (nd == 0) toNULLD(value); stopped = p; return(nd); } /*=============================================================== * The following Conversion Routines are extracted from * as3lib / traq.c (Sexagesimal) *================================================================*/ /*===========================================================================*/ #ifdef __STDC__ static int trasex(char *str, int l, double *value) #else static int trasex(str, l, value) /*++++++ .PURPOSE Converts a string to a double value; input may be in sexagesimal. .RETURNS The precision, from 0 (degree) to 9 (.00001"), or -1 (error or no data) .REMARKS No error logging. --------*/ char *str; /* IN: String to scan */ int l; /* IN: Length of str */ double *value; /* OUT: result */ #endif { char *p, *pe; int i, nd, ndec; int hms[3], fraction; static double factor[3] = {1., 60., 3600.}; p = str, pe = p + l; errmsg = (char *)0; base = 10; ndec = 0; hms[0] = hms[1] = hms[2] = fraction = 0; /* Extract the Sign, if any */ p += Sign (p, pe-p); /* Get the 3 numbers */ for (i=0; (p < pe) && isdigit(*p) && (i<3); i++) { p += Number (p, pe-p); hms[i] = accu; GobbleSpaces(p, pe-p); if (p >= pe) continue; if (*p == ':') p++, GobbleSpaces (p, pe-p); } if (i == 0) { errmsg = "No data"; goto error; } if ((p < pe) && (*p == '.')) { p++; ndec = Number (p, pe-p); fraction = accu; p += ndec; } /* Convert */ nd = 2*i + ndec; for (*value = fraction; --ndec >= 0; *value /= 1.e1) ; *value /= factor[--i]; while (i >= 0) *value += hms[i] / factor[i], i--; error: if (sign) *value = -(*value); if (nd == 0) toNULLD(value); stopped = p; return(nd); } /*=============================================================== * The following Conversion Routines are extracted from * tc3lib / tratime.c *================================================================*/ /*===========================================================================*/ #ifdef __STDC__ static int tratm(char *str, int len, struct tm *T) #else static int tratm(str, len, T) /*++++++ .PURPOSE Converts a string to a date/time; input can be YYYY MM DD hh mm ss, or MMM DD YYYY hh mm ss, with month alphabetic or numeric. .RETURNS -1 if error (error logged) / Number of Items present, from 1 (only year) to 6 (year + month + day + hours + min + sec) .REMARKS An empty string gives the current date/time --------*/ char *str; /* IN: String to scan */ int len; /* IN: Length of string to scan */ struct tm *T; /* OUT: the date structure */ #endif { char *p, *pe; int k, i; int l; p = str, pe = p + len; errmsg = (char *)0; base = 10; p += oscspan((unsigned char *)p, pe-p, _SPACE_|_PUNCT_, main_ascii); /* Skip blanks */ if (p == pe) /* Empty String: Get Current Date / Time */ { tr_itm((int)oshtime(), T); k = 0; goto error; } /* Initialize the structure to zero */ oscfill((char *)T, sizeof(struct tm), 0); T->tm_mon = -1; /* ... but with a bad month */ for (k=0; p < pe; p += l + oscspan((unsigned char *)(p+l), pe-p, _SPACE_|_PUNCT_, main_ascii)){ if (k >= 6) break; /* We have all items! */ if (isdigit(*p)) { /* A number comes now ... */ l = Number(p, pe-p); i = accu; /* ... get it ... */ switch(k) { case 1: /* Month number or day number */ if (T->tm_mon < 0) T->tm_mon = i-1; else T->tm_mday = i; break; case 0: /* Year or Day */ if (i <= 31) T->tm_mday = i; else T->tm_year = i; break; case 2: /* Year or Day */ if (T->tm_mday == 0) T->tm_mday = i; else T->tm_year = i; break; case 3: /* Hours */ T->tm_hour = i; break; case 4: /* Hours */ T->tm_min = i; break; case 5: /* Hours */ T->tm_sec = i; break; } k++; continue; } if (isalpha(*p)) { /* A text comes now ... */ l = oscspan((unsigned char *)p, pe-p, _ALPHA_, main_ascii); if (k >= 2) continue; /* Useless... */ for (i=1; i < sizeof(month_list); i += 4) if (osccomp(&month_list[i], p, 3) == 0) break; if (i >= sizeof(month_list)) { /* Not Found... */ if (k > 0) k++; continue; } T->tm_mon = month_list[i-1]; k++; continue; } break; /* Control character ?? */ } p += oscspan((unsigned char *)p, pe-p, _SPACE_, main_ascii); /* Strip trailing */ tr_tm(T); /* Add missing info */ error: stopped = p; return(errmsg ? -1 : k); } #ifdef __STDC__ static int trat(char *str, int len, int *t) #else static int trat(str, len, t) /*++++++ .PURPOSE Converts a string to a date/time; input can be YYYY MM DD hh mm ss, or MMM DD YYYY hh mm ss, with month alphabetic or numeric. .RETURNS Length of the scanned text / -1 if error (error logged) .REMARKS An empty string (value 0 returned) gives the current date/time --------*/ char *str; /* IN: String to scan */ int len; /* IN: Length of string to scan */ int *t; /* OUT: the date (seconds since 1970) */ #endif { struct tm T; int status; *t = 0x80000000; if (len > 0) status = tratm(str, len, &T); else status = 0; if(status == 0) *t = oshtime(); else if (status > 0) { if (T.tm_year < 100) { /*T.tm_year += 1900; Two digits for year are not enough!*/ printf("Ambiguous entry for year! Please use always 4 digits.\n"); printf("However, for these two digits, 1900 will be added now.\n"); T.tm_year += 1900; } if (tr_tmi(&T, t) < 0) status = -1; } return(status); } #ifdef __STDC__ static int fmtdec(char *str) #else static int fmtdec(str) /*++++++++++++++++++++ .PURPOSE Extract the number of decimals in a Format .RETURNS Number of decimals ---------------------*/ char *str; /* IN: String to scan */ #endif { char *p; for (p = str; *p && (*p != '.'); p++) ; return (*p ? atoi(p+1) : 0); } /*========================================================================== * Conversion according to Format *==========================================================================*/ #ifdef __STDC__ static int toLong(char *str, int len, char *f, int *value) #else static int toLong(str, len, f, value) /*++++++++++++++++++++ .PURPOSE Convert a string to a Long according to Format .RETURNS Number of significant digits / 0 for Error .REMARKS Sexagesimal values are given in marcsec. ---------------------*/ char *str; /* IN: String to scan */ int len; /* IN: Length of str */ char *f; /* IN: Format */ int *value; /* OUT: result */ #endif { double aDouble; int status, round, E; base = 10; toNULL4(value); switch(*f) { case 'R': case 'r': status = trasex (str, len, &aDouble); if (status > 0) *value = aDouble * 15.e0 * 3.6e6; break; case 'S': case 's': status = trasex (str, len, &aDouble); if (status > 0) *value = aDouble * 3.6e6; break; case 'T': case 't': status = trat(str, len, value); if (status == 0) { /* Adjust to e.g. integer days */ switch(fmtdec(f)/2) { case 0: round = 86400; break; case 1: round = 3600; break; case 2: round = 60; break; default: round = 1; break; } E = *value/round; /* Adjust for Negative times */ if (*value < round*E) E--; *value = E*round; } break; case 'O': case 'o': base = 8; convert_int: status = tral (str, len, value); break; case 'X': case 'x': base = 16; goto convert_int; default: base = 10; goto convert_int; } return(status); } #ifdef __STDC__ static int toDouble(char *str, int len, char *f, double *value) #else static int toDouble(str, len, f, value) /*++++++++++++++++++++ .PURPOSE Convert a string to a Long according to Format .RETURNS Number of significant digits / 0 for Error .REMARKS ---------------------*/ char *str; /* IN: String to scan */ int len; /* IN: Length of str */ char *f; /* IN: Format */ double *value; /* OUT: result */ #endif { int aLong; double aDouble; struct tm T; int status; toNULLD(value); switch(*f) { case 'R': case 'r': status = trasex (str, len, value); if (status > 0) *value *= 15.e0; break; case 'S': case 's': status = trasex(str, len, value); break; case 'T': case 't': status = tratm (str, len, &T); if (status == 0) { /* Current value. Remove useless items */ switch(fmtdec(f)) { case 0: T.tm_hour = 0; case 1: T.tm_min = 0; case 2: T.tm_sec = 0; break; } } if (status >= 0) *value = tmtojd (&T); break; case 'O': case 'o': base = 8; convert_int: status = tral (str, len, &aLong); if (status > 0) *value = aLong; break; case 'X': case 'x': base = 16; goto convert_int; default: status = traf (str, len, value); } return(status); } /*========================================================================== * Public Routines *==========================================================================*/ int TBL_cv(buf, form, dtype, addr) /*++++++++++++++++++++ .PURPOSE Convert a string according to F77 format .RETURNS Status .REMARKS The array is NOT filled with NULL values, which means that ONLY the values which are present are converted. Elements in an array column may be separated by , or ; ---------------------*/ char *buf; /* IN: Edited string */ char *form; /* IN: F77 Format */ int dtype; /* IN: Data type in Table Format */ char *addr; /* OUT: Converted Value(s) */ { char *p, *pe; int len, items, status, etype, elen; double aDouble; int aLong; etype = TBL_ElementType(dtype); elen = (1<< ( etype & 3)); items = TBL_Items(dtype); status = 0; errmsg = (char *)0; len = strlen(buf); if (etype == TBL_D_A1) { /* Character String */ if (++len > items) len = items; oscopy(addr, buf, len); return (ERR_NORMAL); } for (p = buf, pe = p + len; (!errmsg) && (p < pe) && (--items >= 0); addr += elen) { if (etype & 020) status = toDouble(p, pe-p, form, &aDouble); else { status = toLong (p, pe-p, form, &aLong); if ( (aLong < llim[etype&3]) || (aLong > ulim[etype&3]) ) errmsg = "integer outside range"; if ((status == 0) && ((etype & 010) == 0)) /* A1 A2 A4 */ aLong = 0; } /* if (status == 0) TBL_errf(-1, toupper(*form) == 'T' ? "Missing date, assumed to be NOW" : "Missing number, assumed to be NULL." ); */ switch (etype) { case TBL_D_I1: if (aLong == NULL4) aLong = NULL1; *addr = aLong; break; case TBL_D_I2: if (aLong == NULL4) aLong = NULL2; case TBL_D_A2: *(short *)addr = aLong; break; case TBL_D_A4: case TBL_D_I4: *(int *)addr = aLong; break; case TBL_D_R4: if (status > 0) *(float *)addr = aDouble; else toNULLF(addr); break; case TBL_D_R8: *(double *)addr = aDouble; break; } p = stopped; GobbleSpaces(p, pe-p); /* Skip blanks */ if ( (*p == ',') || (*p == ';')) p++; } /* Fill remaining items with 0 */ if (items > 0) oscfill (addr, items*elen, 0); /* Was something not understood?*/ if ((!errmsg) && (p != pe)) errmsg = "non-numeric character "; status = (errmsg ? ERR_TBLFMT : ERR_NORMAL); /* if (status) TBL_errf(status, "%s in '%s'", errmsg, buf); */ return (status); } /*========================================================================== * edT *==========================================================================*/ #ifdef __STDC__ static int edT(char *buf,char *pic, struct tm *T) #else static int edT(buf, pic, T) /*+++ .PURPOSE Edit the structure describing time & date (localtime) .RETURNS Length of edited date / time ---------*/ char *buf; /* OUT: Output buffer */ char *pic; /* IN: Used picture */ struct tm *T; /* IN: Decomposed time */ #endif { char *p ,*a; int len, dec, ny, n; len = atoi(pic); dec = fmtdec(pic); if (dec > 6) dec = 6; dec &= ~1; /* Even number of decimals */ a = buf + len; *a = EOS; if (dec >= 6) a = ed60(a, T->tm_sec, ':'); if (dec >= 4) a = ed60(a, T->tm_min, ':'); if (dec >= 2) a = ed60(a, T->tm_hour, ':'); ny = len - dec - dec/2 - 6; /* Digits for Year edition */ /* The last byte indices litteral month */ for (p = pic; ischar(*p, _PUNCT_|_DIGIT_); p++) ; if (isalpha(*p)) ny--; if ((T->tm_year < 10000) && (ny > 4)) ny = 4; if (isalpha(*p)) { /* Alphabetic Edition DD-MMM-YYYY */ if (T->tm_year >= 0) for (n = T->tm_year; --ny >= 0; n /= 10) *--a = '0' + n%10; else while (--ny >= 0) *--a = '*'; if (a > buf) *--a = '-'; if ((a-buf) >= 6) { a -= 3; oscopy (a, &month_list[4*T->tm_mon+1], 3); *--a = '-'; } if ((a-buf) >= 2) { *--a = '0' + T->tm_mday%10; *--a = '0' + T->tm_mday/10; } if ((a-buf) >= 4) { /* Add Weekday ... */ *--a = ':'; a -= 3; oscopy (a, &wday_list[3*T->tm_wday], 3); } } else { /* Numeric Edition */ if ((a-buf) >= 3) a = ed60 (a, T->tm_mday, '-'); if ((a-buf) >= 3) a = ed60 (a, T->tm_mon+1, '-'); n = T->tm_year; ny = 0; if (n < 0) n = -n, ny = 1; for ( ; (a > buf) && (n); n /= 10) *--a = '0' + n%10; if (ny) { if (a > buf) *--a = '-'; else *buf = '*'; /* Error */ } } /* Fill leading blanks */ while (a > buf) *--a = ' '; return(len); } int TBL_ed(buf, form, dtype, addr) /*++++++++++++++++++++ .PURPOSE Edit a value according to F77 format .RETURNS Status .REMARKS NULL values are edited as NOTHING (two consecutive commas). A comma is inserted between items in an array. ---------------------*/ char *buf; /* OUT: Edited string */ char *form; /* IN: F77 Format */ int dtype; /* IN: Data type */ char *addr; /* IN: Value to edit */ { char *Cform, isnull, sep_items, *p, *f; int len, items, etype, elen; double aDouble; int aLong; struct tm T; items = TBL_Items(dtype); etype = TBL_ElementType(dtype); elen = (1<< ( etype & 3)); len = atoi(form+1); if (etype == TBL_D_A1) { /* Character String */ if (len > items) len = items; oscopy(buf, addr, len); buf[len] = '\0'; return (ERR_NORMAL); } Cform = TBL_Cfmt(form, dtype); sep_items = ','; for (; --items >= 0; addr += elen) { switch (etype) { case TBL_D_I1: aLong = *addr; isnull = (aLong == NULL1); break; case TBL_D_I2: aLong = *(short *)addr; isnull = (aLong == NULL2); break; case TBL_D_A2: aLong = *(unsigned short *)addr; isnull = (aLong == 0); break; case TBL_D_A4: aLong = *(int *)addr; isnull = (aLong == 0); break; case TBL_D_I4: aLong = *(int *)addr; isnull = (aLong == NULL4); break; case TBL_D_R4: isnull = isNULLF(addr); if (!isnull) aDouble = *(float *)addr; break; case TBL_D_R8: aDouble = *(double *)addr; isnull = isNULLD(addr); break; } /* if (isnull) *buf = '\0'; */ if (isnull) { oscfill(buf,len,' '); buf[len-1] = '*'; } else for (f = Cform; *f; f++) { switch(*f) { case 'H': aDouble /= 15.; continue; case '%': if (etype & 020) sprintf(buf, f, aDouble); else sprintf(buf, f, aLong); f += strlen(f); continue; case 'Z': for (p = buf; *p == ' '; p++) *p = '0'; if (*p == '-') *p = '0', *buf = '-'; continue; case '+': for (p = buf; *p == ' '; p++) ; if (*p == '-') continue; if (p > buf) p--; if ((*p == '0') || (*p == ' ')) *p = '+'; continue; case 'S': /* Sexagesimal */ if (etype & 020) ; else aDouble = aLong / 3.6e6; ed_sexa (buf, f+1, aDouble); f += strlen(f); continue; case 'T': /* Time */ if (etype & 020) tr_jdtm (aDouble, &T); else tr_itm (aLong, &T); edT (buf, f+1, &T); f += strlen(f); continue; } } if (items > 0) { buf += strlen(buf); *(buf++) = sep_items; } } return(ERR_NORMAL); }