OpenCPN Partial API docs
All Classes Namespaces Functions Variables Pages
tcmgr.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: Tide and Current Manager
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2010 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 **************************************************************************/
25
26#include <wx/wxprec.h>
27#ifndef WX_PRECOMP
28#include <wx/wx.h>
29#endif // precompiled headers
30#include <wx/datetime.h>
31#include <wx/hashmap.h>
32
33#include <stdlib.h>
34#include <math.h>
35#include <time.h>
36
37#include "gui_lib.h"
38#include "dychart.h"
39#include "tcmgr.h"
40#include "georef.h"
41#include "logger.h"
42
43//-----------------------------------------------------------------------------------
44// TIDELIB
45//-----------------------------------------------------------------------------------
46
47// Static variables for the TIDELIB
48
49time_t s_next_epoch = TIDE_BAD_TIME; /* next years newyears */
50time_t s_this_epoch = TIDE_BAD_TIME; /* this years newyears */
51int s_this_year = -1;
52
53double time2dt_tide(time_t t, int deriv, IDX_entry *pIDX);
54int yearoftimet(time_t t);
55void happy_new_year(IDX_entry *pIDX, int new_year);
56void set_epoch(IDX_entry *pIDX, int year);
57
58double time2tide(time_t t, IDX_entry *pIDX) { return time2dt_tide(t, 0, pIDX); }
59
64double BOGUS_amplitude(double mpy, IDX_entry *pIDX) {
65 Station_Data *pmsd = pIDX->pref_sta_data;
66
67 if (!pmsd->have_BOGUS) // || !convert_BOGUS) // Added mgh
68 return (mpy * pIDX->max_amplitude);
69 else {
70 if (mpy >= 0.0)
71 return (sqrt(mpy * pIDX->max_amplitude));
72 else
73 return (-sqrt(-mpy * pIDX->max_amplitude));
74 }
75}
76
77/* Calculate the denormalized tide. */
78double time2atide(time_t t, IDX_entry *pIDX) {
79 return BOGUS_amplitude(time2tide(t, pIDX), pIDX) + pIDX->pref_sta_data->DATUM;
80}
81
82/* Next high tide, low tide, transition of the mark level, or some
83 * combination.
84 * Bit Meaning
85 * 0 low tide
86 * 1 high tide
87 * 2 falling transition
88 * 3 rising transition
89 */
90int next_big_event(time_t *tm, IDX_entry *pIDX) {
91 double p, q;
92 int flags = 0, slope = 0;
93 p = time2atide(*tm, pIDX);
94 *tm += 60;
95 q = time2atide(*tm, pIDX);
96 *tm += 60;
97 if (p < q) slope = 1;
98 while (1) {
99 if ((slope == 1 && q < p) || (slope == 0 && p < q)) {
100 /* Tide event */
101 flags |= (1 << slope);
102 }
103 /* Modes in which to return mark transitions: */
104 /* -text (no -graph) */
105 /* -graph (no -text) */
106 /* -ppm */
107 /* -gif */
108 /* -ps */
109
110 // if (mark && ((text && !graphmode) || (!text && graphmode)
111 // || ppm || gif || ps))
112 // int marklev = 0;
113#if (0)
114 if (0)
115 if ((p > marklev && q <= marklev) || (p < marklev && q >= marklev)) {
116 /* Transition event */
117 if (p < q)
118 flags |= 8;
119 else
120 flags |= 4;
121 if (!(flags & 3)) {
122 /* If we're incredibly unlucky, we could miss a tide event if we
123 * don't check for it here:
124 *
125 * . <---- Value that would be
126 * returned
127 * ----------- Mark level
128 * . .
129 */
130 p = q;
131 q = time2atide(*tm, pIDX);
132 if ((slope == 1 && q < p) || (slope == 0 && p < q)) {
133 /* Tide event */
134 flags |= (1 << slope);
135 }
136 }
137 }
138#endif
139
140 if (flags) {
141 *tm -= 60;
142 /* Don't back up over a transition event, but do back up to where the
143 * tide changed if possible. If they happen at the same
144 * time, then we're off by a minute on the tide, but if we back it up it
145 * will get snagged on the transition event over and over. */
146 if (flags < 4) *tm -= 60;
147 return flags;
148 }
149 p = q;
150 q = time2atide(*tm, pIDX);
151 *tm += 60;
152 }
153}
154
155/* Estimate the normalized mean tide level around a particular time by
156 * summing only the long-term constituents. */
157/* Does not do any blending around year's end. */
158/* This is used only by time2asecondary for finding the mean tide level */
159double time2mean(time_t t, IDX_entry *pIDX) {
160 double tide = 0.0;
161 int a;
162 int new_year = yearoftimet(t);
163 if (pIDX->epoch_year != new_year) happy_new_year(pIDX, new_year);
164
165 for (a = 0; a < pIDX->num_csts; a++) {
166 if (pIDX->m_cst_speeds[a] < 6e-6) {
167 tide += pIDX->m_work_buffer[a] *
168 cos(pIDX->m_cst_speeds[a] * ((long)(t - pIDX->epoch) +
169 pIDX->pref_sta_data->meridian) +
170 pIDX->m_cst_epochs[a][pIDX->epoch_year - pIDX->first_year] -
171 pIDX->pref_sta_data->epoch[a]);
172 }
173 }
174
175 return tide;
176}
177
178/* If offsets are in effect, interpolate the 'corrected' denormalized
179 * tide. The normalized is derived from this, instead of the other way
180 * around, because the application of height offsets requires the
181 * denormalized tide. */
182double time2asecondary(time_t t, IDX_entry *pIDX) {
183 time_t tadj = t + pIDX->station_tz_offset;
184
185 /* Get rid of the normals. */
186 if (!(pIDX->have_offsets)) return time2atide(tadj, pIDX);
187
188 {
189 /* Intervalwidth of 14 (was originally 13) failed on this input:
190 * -location Dublon -hloff +0.0001 -gstart 1997:09:10:00:00 -raw
191 * 1997:09:15:00:00
192 */
193#define intervalwidth 15
194#define stretchfactor 3
195
196 static time_t lowtime = 0, hightime = 0;
197 static double lowlvl, highlvl; /* Normalized tide levels for MIN, MAX */
198 time_t T; /* Adjusted t */
199 double S, Z, HI, HS, magicnum;
200 time_t interval = 3600 * intervalwidth;
201 long difflow, diffhigh;
202 int badlowflag = 0, badhighflag = 0;
203
204 /* Algorithm by Jean-Pierre Lapointe (scipur@collegenotre-dame.qc.ca) */
205 /* as interpreted, munged, and implemented by DWF */
206
207 /* This is the initial guess (average of time offsets) */
208 // T = t - (httimeoff + lttimeoff) / 2;
209 T = tadj - (pIDX->IDX_ht_time_off * 60 + pIDX->IDX_lt_time_off * 60) / 2;
210 /* The usage of an estimate of mean tide level here is to correct
211 * for seasonal changes in tide level. Previously I had simply
212 * used the zero of the tide function as the mean, but this gave bad results
213 * around summer and winter for locations with large seasonal variations. */
214 // printf("-----time2asecondary %ld %ld %d %d\n", t, T,
215 // pIDX->IDX_ht_time_off ,pIDX->IDX_lt_time_off);
216
217 Z = time2mean(T, pIDX);
218 S = time2tide(T, pIDX) - Z;
219
220 /* Find MAX and MIN. I use the highest high tide and the lowest
221 * low tide over a 26 hour period, but I allow the interval to
222 * stretch a lot if necessary to avoid creating discontinuities. The
223 * heuristic used is not perfect but will hopefully be good
224 * enough.
225 *
226 * It is an assumption in the algorithm that the tide level will
227 * be above the mean tide level for MAX and below it for MIN. A
228 * changeover occurs at mean tide level. It would be nice to
229 * always use the two tides that immediately bracket T and to put
230 * the changeover at mid tide instead of always at mean tide
231 * level, since this would eliminate much of the inaccuracy.
232 * Unfortunately if you change the location of the changeover it
233 * causes the tide function to become discontinuous.
234 *
235 * Now that I'm using time2mean, the changeover does move, but so
236 * slowly that it makes no difference.
237 */
238
239 if (lowtime < T)
240 difflow = T - lowtime;
241 else
242 difflow = lowtime - T;
243 if (hightime < T)
244 diffhigh = T - hightime;
245 else
246 diffhigh = hightime - T;
247
248 /* Update MIN? */
249 if (difflow > interval * stretchfactor) badlowflag = 1;
250 if (badlowflag || (difflow > interval && S > 0)) {
251 time_t tt;
252 double tl;
253 tt = T - interval;
254 next_big_event(&tt, pIDX);
255 lowlvl = time2tide(tt, pIDX);
256 lowtime = tt;
257 while (tt < T + interval) {
258 next_big_event(&tt, pIDX);
259 tl = time2tide(tt, pIDX);
260 if (tl < lowlvl && tt < T + interval) {
261 lowlvl = tl;
262 lowtime = tt;
263 }
264 }
265 }
266 /* Update MAX? */
267 if (diffhigh > interval * stretchfactor) badhighflag = 1;
268 if (badhighflag || (diffhigh > interval && S < 0)) {
269 time_t tt;
270 double tl;
271 tt = T - interval;
272 next_big_event(&tt, pIDX);
273 highlvl = time2tide(tt, pIDX);
274 hightime = tt;
275 while (tt < T + interval) {
276 next_big_event(&tt, pIDX);
277 tl = time2tide(tt, pIDX);
278 if (tl > highlvl && tt < T + interval) {
279 highlvl = tl;
280 hightime = tt;
281 }
282 }
283 }
284
285#if 0
286 /* UNFORTUNATELY there are times when the tide level NEVER CROSSES
287 * THE MEAN for extended periods of time. ARRRGH! */
288 if (lowlvl >= 0.0)
289 lowlvl = -1.0;
290 if (highlvl <= 0.0)
291 highlvl = 1.0;
292#endif
293 /* Now that I'm using time2mean, I should be guaranteed to get
294 * an appropriate low and high. */
295
296 /* Improve the initial guess. */
297 if (S > 0)
298 magicnum = 0.5 * S / fabs(highlvl - Z);
299 else
300 magicnum = 0.5 * S / fabs(lowlvl - Z);
301 // T = T - magicnum * (httimeoff - lttimeoff);
302 T = T - (time_t)(magicnum * ((pIDX->IDX_ht_time_off * 60) -
303 (pIDX->IDX_lt_time_off * 60)));
304 HI = time2tide(T, pIDX);
305
306 // Correct the amplitude offsets for BOGUS knot^2 units
307 double ht_off, lt_off;
308 if (pIDX->pref_sta_data->have_BOGUS) {
309 ht_off = pIDX->IDX_ht_off *
310 pIDX->IDX_ht_off; // Square offset in kts to adjust for kts^2
311 lt_off = pIDX->IDX_lt_off * pIDX->IDX_lt_off;
312 } else {
313 ht_off = pIDX->IDX_ht_off;
314 lt_off = pIDX->IDX_lt_off;
315 }
316
317 /* Denormalize and apply the height offsets. */
318 HI = BOGUS_amplitude(HI, pIDX) + pIDX->pref_sta_data->DATUM;
319 {
320 double RH = 1.0, RL = 1.0, HH = 0.0, HL = 0.0;
321 RH = pIDX->IDX_ht_mpy;
322 HH = ht_off;
323 RL = pIDX->IDX_lt_mpy;
324 HL = lt_off;
325
326 /* I patched the usage of RH and RL to avoid big ugly
327 * discontinuities when they are not equal. -- DWF */
328
329 HS = HI * ((RH + RL) / 2 + (RH - RL) * magicnum) + (HH + HL) / 2 +
330 (HH - HL) * magicnum;
331 }
332
333 return HS;
334 }
335}
336
337/*
338 * We will need a function for tidal height as a function of time
339 * which is continuous (and has continuous first and second derivatives)
340 * for all times.
341 *
342 * Since the epochs & multipliers for the tidal constituents change
343 * with the year, the regular time2tide(t) function has small
344 * discontinuities at new years. These discontinuities really
345 * fry the fast root-finders.
346 *
347 * We will eliminate the new-years discontinuities by smoothly
348 * interpolating (or "blending") between the tides calculated with one
349 * year's coefficients, and the tides calculated with the next year's
350 * coefficients.
351 *
352 * i.e. for times near a new years, we will "blend" a tide
353 * as follows:
354 *
355 * tide(t) = tide(year-1, t)
356 * + w((t - t0) / Tblend) * (tide(year,t) - tide(year-1,t))
357 *
358 * Here: t0 is the time of the nearest new-year.
359 * tide(year-1, t) is the tide calculated using the coefficients
360 * for the year just preceding t0.
361 * tide(year, t) is the tide calculated using the coefficients
362 * for the year which starts at t0.
363 * Tblend is the "blending" time scale. This is set by
364 * the macro TIDE_BLEND_TIME, currently one hour.
365 * w(x) is the "blending function", whice varies smoothly
366 * from 0, for x < -1 to 1 for x > 1.
367 *
368 * Derivatives of the blended tide can be evaluated in terms of derivatives
369 * of w(x), tide(year-1, t), and tide(year, t). The blended tide is
370 * guaranteed to have as many continuous derivatives as w(x). */
371
372/* time2dt_tide(time_t t, int n)
373 *
374 * Calculate nth time derivative the normalized tide.
375 *
376 * Notes: This function does not check for changes in year.
377 * This is important to our algorithm, since for times near
378 * new years, we interpolate between the tides calculated
379 * using one years coefficients, and the next years coefficients.
380 *
381 * Except for this detail, time2dt_tide(t,0) should return a value
382 * identical to time2tide(t).
383 */
384double _time2dt_tide(time_t t, int deriv, IDX_entry *pIDX) {
385 double dt_tide = 0.0;
386 int a, b;
387 double term, tempd;
388
389 tempd = M_PI / 2.0 * deriv;
390 for (a = 0; a < pIDX->num_csts; a++) {
391 term = pIDX->m_work_buffer[a] *
392 cos(tempd +
393 pIDX->m_cst_speeds[a] *
394 ((long)(t - pIDX->epoch) + pIDX->pref_sta_data->meridian) +
395 pIDX->m_cst_epochs[a][pIDX->epoch_year - pIDX->first_year] -
396 pIDX->pref_sta_data->epoch[a]);
397 for (b = deriv; b > 0; b--) term *= pIDX->m_cst_speeds[a];
398 dt_tide += term;
399 }
400 return dt_tide;
401}
402
403/* blend_weight (double x, int deriv)
404 *
405 * Returns the value nth derivative of the "blending function" w(x):
406 *
407 * w(x) = 0, for x <= -1
408 *
409 * w(x) = 1/2 + (15/16) x - (5/8) x^3 + (3/16) x^5,
410 * for -1 < x < 1
411 *
412 * w(x) = 1, for x >= 1
413 *
414 * This function has the following desirable properties:
415 *
416 * w(x) is exactly either 0 or 1 for |x| > 1
417 *
418 * w(x), as well as its first two derivatives are continuous for all x.
419 */
420static double blend_weight(double x, int deriv) {
421 double x2 = x * x;
422
423 if (x2 >= 1.0) return deriv == 0 && x > 0.0 ? 1.0 : 0.0;
424
425 switch (deriv) {
426 case 0:
427 return ((3.0 * x2 - 10.0) * x2 + 15.0) * x / 16.0 + 0.5;
428 case 1:
429 return ((x2 - 2.0) * x2 + 1.0) * (15.0 / 16.0);
430 case 2:
431 return (x2 - 1.0) * x * (15.0 / 4.0);
432 }
433 return (0); // mgh+ to get rid of compiler warning
434}
435
436/*
437 * This function does the actual "blending" of the tide
438 * and its derivatives.
439 */
440double blend_tide(time_t t, unsigned int deriv, int first_year, double blend,
441 IDX_entry *pIDX) {
442 double fl[TIDE_MAX_DERIV + 1];
443 double fr[TIDE_MAX_DERIV + 1];
444 double *fp = fl;
445 double w[TIDE_MAX_DERIV + 1];
446 double fact = 1.0;
447 double f;
448 unsigned int n;
449
450 /*
451 * If we are already happy_new_year()ed into one of the two years
452 * of interest, compute that years tide values first.
453 */
454 int year = yearoftimet(t);
455 if (year == first_year + 1)
456 fp = fr;
457 else if (year != first_year)
458 happy_new_year(pIDX, first_year);
459 for (n = 0; n <= deriv; n++) fp[n] = _time2dt_tide(t, n, pIDX);
460
461 /*
462 * Compute tide values for the other year of interest,
463 * and the needed values of w(x) and its derivatives.
464 */
465 if (fp == fl) {
466 happy_new_year(pIDX, first_year + 1);
467 fp = fr;
468 } else {
469 happy_new_year(pIDX, first_year);
470 fp = fl;
471 }
472 for (n = 0; n <= deriv; n++) {
473 fp[n] = _time2dt_tide(t, n, pIDX);
474 w[n] = blend_weight(blend, n);
475 }
476
477 /*
478 * Do the blending.
479 */
480
481 f = fl[deriv];
482 for (n = 0; n <= deriv; n++) {
483 f += fact * w[n] * (fr[deriv - n] - fl[deriv - n]);
484 fact *= (double)(deriv - n) / (n + 1) * (1.0 / TIDE_BLEND_TIME);
485 }
486 printf(" %ld %g %g %g %g\n", (long)t, blend, fr[0], fl[0], f);
487 return f;
488}
489
490double time2dt_tide(time_t t, int deriv, IDX_entry *pIDX) {
491 int new_year;
492 int yott = yearoftimet(t);
493 new_year = yott;
494
495 /* Make sure our values of next_epoch and epoch are up to date. */
496 if (new_year != s_this_year) {
497 if (new_year + 1 < pIDX->first_year + pIDX->num_epochs) {
498 set_epoch(pIDX, new_year + 1);
499 s_next_epoch = pIDX->epoch;
500 } else
501 s_next_epoch = TIDE_BAD_TIME;
502
503 happy_new_year(pIDX, s_this_year = new_year);
504 s_this_epoch = pIDX->epoch;
505 }
506
507 /*
508 * If we're close to either the previous or the next
509 * new years we must blend the two years tides.
510 */
511 if (t - s_this_epoch <= TIDE_BLEND_TIME && s_this_year > pIDX->first_year)
512 return blend_tide(t, deriv, s_this_year - 1,
513 (double)(t - s_this_epoch) / TIDE_BLEND_TIME, pIDX);
514 else if (s_next_epoch - t <= TIDE_BLEND_TIME &&
515 s_this_year + 1 < pIDX->first_year + pIDX->num_epochs)
516 return blend_tide(t, deriv, s_this_year,
517 -(double)(s_next_epoch - t) / TIDE_BLEND_TIME, pIDX);
518
519 /*
520 * Else, we're far enough from newyears to ignore the blending.
521 */
522 if (pIDX->epoch_year != new_year) happy_new_year(pIDX, new_year);
523
524 return _time2dt_tide(t, deriv, pIDX);
525}
526
527/* Figure out max amplitude over all the years in the node factors table. */
528/* This function by Geoffrey T. Dairiki */
529void figure_max_amplitude(IDX_entry *pIDX) {
530 int i, a;
531
532 if (pIDX->max_amplitude == 0.0) {
533 for (i = 0; i < pIDX->num_nodes; i++) {
534 double year_amp = 0.0;
535
536 for (a = 0; a < pIDX->num_csts; a++)
537 year_amp += pIDX->pref_sta_data->amplitude[a] * pIDX->m_cst_nodes[a][i];
538 if (year_amp > pIDX->max_amplitude) pIDX->max_amplitude = year_amp;
539 }
540 }
541}
542
543/* Figure out normalized multipliers for constituents for a particular year. */
544void figure_multipliers(IDX_entry *pIDX, int year) {
545 int a;
546
547 figure_max_amplitude(pIDX);
548 for (a = 0; a < pIDX->num_csts; a++) {
549 pIDX->m_work_buffer[a] = pIDX->pref_sta_data->amplitude[a] *
550 pIDX->m_cst_nodes[a][year - pIDX->first_year] /
551 pIDX->max_amplitude; // BOGUS_amplitude?
552 }
553}
554
555/* This idiotic function is needed by the new tm2gmt. */
556#define compare_int(a, b) (((int)(a)) - ((int)(b)))
557int compare_tm(struct tm *a, struct tm *b) {
558 int temp;
559 /* printf ("A is %d:%d:%d:%d:%d:%d B is %d:%d:%d:%d:%d:%d\n",
560 * a->tm_year+1900, a->tm_mon+1, a->tm_mday, a->tm_hour,
561 * a->tm_min, a->tm_sec,
562 * b->tm_year+1900, b->tm_mon+1, b->tm_mday, b->tm_hour,
563 * b->tm_min, b->tm_sec); */
564
565 temp = compare_int(a->tm_year, b->tm_year);
566 if (temp) return temp;
567 temp = compare_int(a->tm_mon, b->tm_mon);
568 if (temp) return temp;
569 temp = compare_int(a->tm_mday, b->tm_mday);
570 if (temp) return temp;
571 temp = compare_int(a->tm_hour, b->tm_hour);
572 if (temp) return temp;
573 temp = compare_int(a->tm_min, b->tm_min);
574 if (temp) return temp;
575 return compare_int(a->tm_sec, b->tm_sec);
576}
577
578/* Convert a struct tm in GMT back to a time_t. isdst is ignored, since
579 * it never should have been needed by mktime in the first place.
580 */
581time_t tm2gmt(struct tm *ht) {
582 time_t guess, newguess, thebit;
583 int loopcounter, compare;
584 struct tm *gt;
585
586 guess = 0;
587 loopcounter = (sizeof(time_t) * 8) - 1;
588 thebit = ((time_t)1) << (loopcounter - 1);
589
590 /* For simplicity, I'm going to insist that the time_t we want is
591 * positive. If time_t is signed, skip the sign bit.
592 */
593 if ((signed long)thebit < (time_t)(0)) {
594 /* You can't just shift thebit right because it propagates the sign bit. */
595 loopcounter--;
596 thebit = ((time_t)1) << (loopcounter - 1);
597 }
598
599 for (; loopcounter; loopcounter--) {
600 newguess = guess | thebit;
601 gt = gmtime(&newguess);
602 if (NULL != gt) {
603 compare = compare_tm(gt, ht);
604 if (compare <= 0) guess = newguess;
605 }
606 thebit >>= 1;
607 }
608
609 return guess;
610}
611
612int yearoftimet(time_t t) { return ((gmtime(&t))->tm_year) + 1900; }
613
614/* Calculate time_t of the epoch. */
615void set_epoch(IDX_entry *pIDX, int year) {
616 struct tm ht;
617
618 ht.tm_year = year - 1900;
619 ht.tm_sec = ht.tm_min = ht.tm_hour = ht.tm_mon = 0;
620 ht.tm_mday = 1;
621 pIDX->epoch = tm2gmt(&ht);
622}
623
624/* Re-initialize for a different year */
625void happy_new_year(IDX_entry *pIDX, int new_year) {
626 pIDX->epoch_year = new_year;
627 figure_multipliers(pIDX, new_year);
628 set_epoch(pIDX, new_year);
629}
630
631// TCMgr Implementation
632TCMgr::TCMgr() {}
633
634TCMgr::~TCMgr() { PurgeData(); }
635
636void TCMgr::PurgeData() {
637 // Index entries are owned by the data sources
638 // so we need to clear them from the combined list without
639 // deleting them
640 while (m_Combined_IDX_array.GetCount()) {
641 m_Combined_IDX_array.Detach(0);
642 }
643
644 // Delete all the data sources
645 m_source_array.Clear();
646}
647
648TC_Error_Code TCMgr::LoadDataSources(wxArrayString &sources) {
649 PurgeData();
650
651 // Take a copy of dataset file name array
652 m_sourcefile_array.Clear();
653 m_sourcefile_array = sources;
654
655 // Arrange for the index array to begin counting at "one"
656 m_Combined_IDX_array.Add((IDX_entry *)(NULL));
657 int num_IDX = 1;
658
659 for (unsigned int i = 0; i < sources.GetCount(); i++) {
660 TCDataSource *s = new TCDataSource;
661 TC_Error_Code r = s->LoadData(sources[i]);
662 if (r != TC_NO_ERROR) {
663 wxString msg;
664 msg.Printf(_T(" Error loading Tide/Currect data source %s "),
665 sources[i].c_str());
666 if (r == TC_FILE_NOT_FOUND)
667 msg += _T("Error Code: TC_FILE_NOT_FOUND");
668 else {
669 wxString msg1;
670 msg1.Printf(_T("Error code: %d"), r);
671 msg += msg1;
672 }
673 wxLogMessage(msg);
674 delete s;
675 } else {
676 m_source_array.Add(s);
677
678 for (int k = 0; k < s->GetMaxIndex(); k++) {
679 IDX_entry *pIDX = s->GetIndexEntry(k);
680 pIDX->IDX_rec_num = num_IDX;
681 num_IDX++;
682 m_Combined_IDX_array.Add(pIDX);
683 }
684 }
685 }
686
687 bTCMReady = true;
688
689 if (m_Combined_IDX_array.Count() <= 1)
690 OCPNMessageBox(
691 NULL, _("It seems you have no tide/current harmonic data installed."),
692 _("OpenCPN Info"), wxOK | wxCENTER);
693
694 ScrubCurrentDepths();
695 return TC_NO_ERROR;
696}
697
698void TCMgr::ScrubCurrentDepths() {
699 // Process Current stations reporting values at multiple depths
700 // Identify and mark the shallowest record, as being most usable to OCPN
701 // users
702
703 WX_DECLARE_STRING_HASH_MAP(int, currentDepth_index_hash);
704
705 currentDepth_index_hash hash1;
706
707 for (unsigned int i = 1; i < m_Combined_IDX_array.Count(); i++) {
708 IDX_entry *a = (IDX_entry *)GetIDX_entry(i);
709
710 if (a->IDX_type == 'C') {
711 if (a->current_depth > 0) {
712 int depth_a = a->current_depth;
713
714 // We formulate the hash map with geo-location as the keys
715 // Using "doubles" as hashmap key values is dangerous, especially
716 // cross-platform So, we a printf-ed string of lat/lon for hash key,
717 // This is relatively inefficient. but tolerable in this little used
718 // method.
719
720 wxString key1;
721 key1.Printf("%10.6f %10.6f", a->IDX_lat, a->IDX_lon);
722
723 currentDepth_index_hash::iterator it = hash1.find(key1);
724 if (it == hash1.end()) {
725 // Key not found, needs to be added
726 hash1[key1] = i;
727 } else {
728 // Check the depth value at the referenced index
729 // if less than the current depth, replace the hashmap value
730 IDX_entry *b = (IDX_entry *)GetIDX_entry(it->second);
731 std::string bName(b->IDX_station_name);
732 int depth_b = b->current_depth;
733 if (depth_a < depth_b) {
734 hash1[key1] = i;
735 b->b_skipTooDeep = 1; // mark deeper index to skip display
736 } else {
737 a->b_skipTooDeep = 1; // mark deeper index to skip display
738 }
739 }
740 }
741 }
742 }
743}
744
745const IDX_entry *TCMgr::GetIDX_entry(int index) const {
746 if ((unsigned int)index < m_Combined_IDX_array.GetCount())
747 return &m_Combined_IDX_array[index];
748 else
749 return NULL;
750}
751
752bool TCMgr::GetTideOrCurrent(time_t t, int idx, float &tcvalue, float &dir) {
753 // Return a sensible value of 0,0 by default
754 dir = 0;
755 tcvalue = 0;
756
757 // Load up this location data
758 IDX_entry *pIDX = &m_Combined_IDX_array[idx]; // point to the index entry
759
760 if (!pIDX) {
761 dir = 0;
762 tcvalue = 0;
763 return false;
764 }
765
766 if (!pIDX->IDX_Useable) {
767 dir = 0;
768 tcvalue = 0;
769 return (false); // no error, but unuseable
770 }
771
772 if (pIDX->pDataSource) {
773 if (pIDX->pDataSource->LoadHarmonicData(pIDX) != TC_NO_ERROR) return false;
774 }
775
776 pIDX->max_amplitude = 0.0; // Force multiplier re-compute
777 int yott = yearoftimet(t);
778
779 happy_new_year(pIDX, yott); // Calculate new multipliers
780
781 // Finally, calculate the tide/current
782
783 double level = time2asecondary(t + (00 * 60), pIDX); // 300. 240
784 if (level >= 0)
785 dir = pIDX->IDX_flood_dir;
786 else
787 dir = pIDX->IDX_ebb_dir;
788
789 tcvalue = level;
790
791 return (true); // Got it!
792}
793
794extern wxDateTime gTimeSource;
795
796bool TCMgr::GetTideOrCurrent15(time_t t_d, int idx, float &tcvalue, float &dir,
797 bool &bnew_val) {
798 int ret;
799 IDX_entry *pIDX = &m_Combined_IDX_array[idx]; // point to the index entry
800
801 if (!pIDX) {
802 dir = 0;
803 tcvalue = 0;
804 return false;
805 }
806
807 // Figure out this computer timezone minute offset
808 wxDateTime this_now = gTimeSource; // wxDateTime::Now();
809 if (this_now.IsValid() == false) this_now = wxDateTime::Now();
810 wxDateTime this_gmt = this_now.ToGMT();
811 wxTimeSpan diff = this_gmt.Subtract(this_now);
812 int diff_mins = diff.GetMinutes();
813
814 int station_offset = pIDX->IDX_time_zone;
815 if (this_now.IsDST()) station_offset += 60;
816 int corr_mins = station_offset - diff_mins;
817
818 wxDateTime today_00 = this_now;
819 today_00.ResetTime();
820 int t_today_00 = today_00.GetTicks();
821 int t_today_00_at_station = t_today_00 - (corr_mins * 60);
822
823 int t_at_station =
824 this_gmt.GetTicks() - (station_offset * 60) + (corr_mins * 60);
825
826 int t_mins = (t_at_station - t_today_00_at_station) / 60;
827 int t_15s = t_mins / 15;
828
829 if (pIDX->Valid15) // valid data available
830 {
831 int tref1 = t_today_00_at_station + t_15s * 15 * 60;
832 if (tref1 == pIDX->Valid15) {
833 tcvalue = pIDX->Value15;
834 dir = pIDX->Dir15;
835 bnew_val = false;
836 return pIDX->Ret15;
837 } else {
838 int tref = t_today_00_at_station + t_15s * 15 * 60;
839 ret = GetTideOrCurrent(tref, idx, tcvalue, dir);
840
841 pIDX->Valid15 = tref;
842 pIDX->Value15 = tcvalue;
843 pIDX->Dir15 = dir;
844 pIDX->Ret15 = !(ret == 0);
845 bnew_val = true;
846
847 return !(ret == 0);
848 }
849 }
850
851 else {
852 int tref = t_today_00_at_station + t_15s * 15 * 60;
853 ret = GetTideOrCurrent(tref, idx, tcvalue, dir);
854
855 pIDX->Valid15 = tref;
856 pIDX->Value15 = tcvalue;
857 pIDX->Dir15 = dir;
858 pIDX->Ret15 = !(ret == 0);
859 bnew_val = true;
860 }
861
862 return !(ret == 0);
863}
864
865bool TCMgr::GetTideFlowSens(time_t t, int sch_step, int idx, float &tcvalue_now,
866 float &tcvalue_prev, bool &w_t) {
867 // Return a sensible value of 0 by default
868 tcvalue_now = 0;
869 tcvalue_prev = 0;
870 w_t = false;
871
872 // Load up this location data
873 IDX_entry *pIDX = &m_Combined_IDX_array[idx]; // point to the index entry
874
875 if (!pIDX) return false;
876
877 if (!pIDX->IDX_Useable) return false; // no error, but unuseable
878
879 if (pIDX->pDataSource) {
880 if (pIDX->pDataSource->LoadHarmonicData(pIDX) != TC_NO_ERROR) return false;
881 }
882
883 pIDX->max_amplitude = 0.0; // Force multiplier re-compute
884 int yott = yearoftimet(t);
885 happy_new_year(pIDX, yott); // Force new multipliers
886
887 // Finally, process the tide flow sens
888
889 tcvalue_now = time2asecondary(t, pIDX);
890 tcvalue_prev = time2asecondary(t + sch_step, pIDX);
891
892 w_t =
893 tcvalue_now > tcvalue_prev; // w_t = true --> flood , w_t = false --> ebb
894
895 return true;
896}
897
898void TCMgr::GetHightOrLowTide(time_t t, int sch_step_1, int sch_step_2,
899 float tide_val, bool w_t, int idx, float &tcvalue,
900 time_t &tctime) {
901 // Return a sensible value of 0,0 by default
902 tcvalue = 0;
903 tctime = t;
904
905 // Load up this location data
906 IDX_entry *pIDX = &m_Combined_IDX_array[idx]; // point to the index entry
907
908 if (!pIDX) return;
909
910 if (!pIDX->IDX_Useable) return; // no error, but unuseable
911
912 if (pIDX->pDataSource) {
913 if (pIDX->pDataSource->LoadHarmonicData(pIDX) != TC_NO_ERROR) return;
914 }
915
916 // Is the cache data reasonably fresh?
917 if (abs(t - pIDX->recent_highlow_calc_time) < 60) {
918 if (w_t) {
919 tcvalue = pIDX->recent_high_level;
920 tctime = pIDX->recent_high_time;
921 } else {
922 tcvalue = pIDX->recent_low_level;
923 tctime = pIDX->recent_low_time;
924 }
925 return;
926 }
927
928 pIDX->max_amplitude = 0.0; // Force multiplier re-compute
929 int yott = yearoftimet(t);
930 happy_new_year(pIDX, yott);
931
932 // Finally, calculate the Hight and low tides
933 double newval = tide_val;
934 double oldval = (w_t) ? newval - 1 : newval + 1;
935 int j = 0;
936 int k = 0;
937 int ttt = 0;
938 while ((newval > oldval) == w_t) // searching each ten minute
939 {
940 j++;
941 oldval = newval;
942 ttt = t + (sch_step_1 * j);
943 newval = time2asecondary(ttt, pIDX);
944 }
945 oldval = (w_t) ? newval - 1 : newval + 1;
946 while ((newval > oldval) == w_t) // searching back each minute
947 {
948 oldval = newval;
949 k++;
950 ttt = t + (sch_step_1 * j) - (sch_step_2 * k);
951 newval = time2asecondary(ttt, pIDX);
952 }
953 tcvalue = newval;
954 tctime = ttt + sch_step_2;
955
956 // Cache the data
957 pIDX->recent_highlow_calc_time = t;
958 if (w_t) {
959 pIDX->recent_high_level = newval;
960 pIDX->recent_high_time = tctime;
961 } else {
962 pIDX->recent_low_level = newval;
963 pIDX->recent_low_time = tctime;
964 }
965}
966
967int TCMgr::GetStationTimeOffset(IDX_entry *pIDX) { return pIDX->IDX_time_zone; }
968
969double TCMgr::GetStationLat(IDX_entry *pIDX) { return pIDX->IDX_lat; }
970
971double TCMgr::GetStationLon(IDX_entry *pIDX) { return pIDX->IDX_lon; }
972
973int TCMgr::GetNextBigEvent(time_t *tm, int idx) {
974 float tcvalue[1];
975 float dir;
976 bool ret;
977 double p, q;
978 int flags = 0, slope = 0;
979 ret = GetTideOrCurrent(*tm, idx, tcvalue[0], dir);
980 p = tcvalue[0];
981 *tm += 60;
982 ret = GetTideOrCurrent(*tm, idx, tcvalue[0], dir);
983 q = tcvalue[0];
984 *tm += 60;
985 if (p < q) slope = 1;
986 while (1) {
987 if ((slope == 1 && q < p) || (slope == 0 && p < q)) {
988 /* Tide event */
989 flags |= (1 << slope);
990 }
991 if (flags) {
992 *tm -= 60;
993 if (flags < 4) *tm -= 60;
994 return flags;
995 }
996 p = q;
997 ret = GetTideOrCurrent(*tm, idx, tcvalue[0], dir);
998 if (!ret) return 0; // Harmonics file error, data not available
999 q = tcvalue[0];
1000 *tm += 60;
1001 }
1002 return 0;
1003}
1004
1005std::map<double, const IDX_entry *> TCMgr::GetStationsForLL(double xlat,
1006 double xlon) const {
1007 std::map<double, const IDX_entry *> x;
1008 const IDX_entry *lpIDX;
1009
1010 for (int j = 1; j < Get_max_IDX() + 1; j++) {
1011 lpIDX = GetIDX_entry(j);
1012 char type = lpIDX->IDX_type;
1013 wxString locnx(lpIDX->IDX_station_name, wxConvUTF8);
1014
1015 if (type == 't' || type == 'T') {
1016 double brg, dist;
1017 DistanceBearingMercator(xlat, xlon, lpIDX->IDX_lat, lpIDX->IDX_lon, &brg,
1018 &dist);
1019 x.emplace(std::make_pair(dist, lpIDX));
1020 }
1021 }
1022
1023 return x;
1024}
1025
1026int TCMgr::GetStationIDXbyName(const wxString &prefix, double xlat,
1027 double xlon) const {
1028 const IDX_entry *lpIDX;
1029 int jx = 0;
1030 wxString locn;
1031 double distx = 100000.;
1032
1033 int jmax = Get_max_IDX();
1034
1035 for (int j = 1; j < Get_max_IDX() + 1; j++) {
1036 lpIDX = GetIDX_entry(j);
1037 char type = lpIDX->IDX_type; // Entry "TCtcIUu" identifier
1038 wxString locnx(lpIDX->IDX_station_name, wxConvUTF8);
1039
1040 if (((type == 't') || (type == 'T')) // only Tides
1041 && (locnx.StartsWith(prefix))) {
1042 double brg, dist;
1043 DistanceBearingMercator(xlat, xlon, lpIDX->IDX_lat, lpIDX->IDX_lon, &brg,
1044 &dist);
1045 if (dist < distx) {
1046 distx = dist;
1047 jx = j;
1048 }
1049 }
1050 } // end for loop
1051 //} // end if @~~ found in WP
1052 return (jx);
1053}
1054
1055int TCMgr::GetStationIDXbyNameType(const wxString &prefix, double xlat,
1056 double xlon, char type) const {
1057 const IDX_entry *lpIDX;
1058 int jx = 0;
1059 wxString locn;
1060 double distx = 100000.;
1061
1062 // if (prp->m_MarkName.Find(_T("@~~")) != wxNOT_FOUND) {
1063 // tide_form = prp->m_MarkName.Mid(prp->m_MarkName.Find(_T("@~~"))+3);
1064 int jmax = Get_max_IDX();
1065
1066 for (int j = 1; j < Get_max_IDX() + 1; j++) {
1067 lpIDX = GetIDX_entry(j);
1068 char typep = lpIDX->IDX_type; // Entry "TCtcIUu" identifier
1069 wxString locnx(lpIDX->IDX_station_name, wxConvUTF8);
1070
1071 if ((type == typep) && (locnx.StartsWith(prefix))) {
1072 double brg, dist;
1073 DistanceBearingMercator(xlat, xlon, lpIDX->IDX_lat, lpIDX->IDX_lon, &brg,
1074 &dist);
1075 if (dist < distx) {
1076 distx = dist;
1077 jx = j;
1078 }
1079 }
1080 } // end for loop
1081 return (jx);
1082}
1083
1084/* $Id: tide_db_default.h 1092 2006-11-16 03:02:42Z flaterco $ */
1085
1086//#include "tcd.h"
1087
1088/*****************************************************************************
1089 *
1090 * DISTRIBUTION STATEMENT
1091 *
1092 * This source file is unclassified, distribution unlimited, public
1093 * domain. It is distributed in the hope that it will be useful, but
1094 * WITHOUT ANY WARRANTY; without even the implied warranty of
1095 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1096 *
1097 ******************************************************************************/
1098
1099#define DEFAULT_HEADER_SIZE 4096
1100#define DEFAULT_NUMBER_OF_RECORDS 0
1101#define DEFAULT_LEVEL_UNIT_TYPES 5
1102#define DEFAULT_DIR_UNIT_TYPES 3
1103#define DEFAULT_RESTRICTION_TYPES 2
1104#define DEFAULT_RESTRICTION_BITS 4
1105#define DEFAULT_TZFILES 406
1106#define DEFAULT_TZFILE_BITS 10
1107#define DEFAULT_COUNTRIES 240
1108#define DEFAULT_COUNTRY_BITS 9
1109#define DEFAULT_DATUM_TYPES 61
1110#define DEFAULT_DATUM_BITS 7
1111#define DEFAULT_LEGALESES 1
1112#define DEFAULT_LEGALESE_BITS 4
1113#define DEFAULT_SPEED_SCALE 10000000
1114#define DEFAULT_EQUILIBRIUM_SCALE 100
1115#define DEFAULT_NODE_SCALE 10000
1116#define DEFAULT_AMPLITUDE_BITS 19
1117#define DEFAULT_AMPLITUDE_SCALE 10000
1118#define DEFAULT_EPOCH_BITS 16
1119#define DEFAULT_EPOCH_SCALE 100
1120#define DEFAULT_RECORD_TYPE_BITS 4
1121#define DEFAULT_LATITUDE_BITS 25
1122#define DEFAULT_LATITUDE_SCALE 100000
1123#define DEFAULT_LONGITUDE_BITS 26
1124#define DEFAULT_LONGITUDE_SCALE 100000
1125#define DEFAULT_RECORD_SIZE_BITS 16
1126#define DEFAULT_STATION_BITS 18
1127#define DEFAULT_DATUM_OFFSET_BITS 28
1128#define DEFAULT_DATUM_OFFSET_SCALE 10000
1129#define DEFAULT_DATE_BITS 27
1130#define DEFAULT_MONTHS_ON_STATION_BITS 10
1131#define DEFAULT_CONFIDENCE_VALUE_BITS 4
1132#define DEFAULT_NUMBER_OF_CONSTITUENTS_BITS 8
1133#define DEFAULT_TIME_BITS 13
1134#define DEFAULT_LEVEL_ADD_BITS 17
1135#define DEFAULT_LEVEL_ADD_SCALE 1000
1136#define DEFAULT_LEVEL_MULTIPLY_BITS 16
1137#define DEFAULT_LEVEL_MULTIPLY_SCALE 1000
1138#define DEFAULT_DIRECTION_BITS 9
1139#define DEFAULT_CONSTITUENT_SIZE 10
1140#define DEFAULT_LEVEL_UNIT_SIZE 15
1141#define DEFAULT_DIR_UNIT_SIZE 15
1142#define DEFAULT_RESTRICTION_SIZE 30
1143#define DEFAULT_DATUM_SIZE 70
1144#define DEFAULT_LEGALESE_SIZE 70
1145#define DEFAULT_TZFILE_SIZE 30
1146#define DEFAULT_COUNTRY_SIZE 50
1147
1148/* Stuff for inferring constituents (NAVO short duration tide stations). */
1149
1150#define INFERRED_SEMI_DIURNAL_COUNT 10
1151#define INFERRED_DIURNAL_COUNT 10
1152
1153#ifdef __MSVC__
1154#pragma warning(disable : 4305) // conversion loss, double to float
1155#endif
1156
1157const NV_CHAR *inferred_semi_diurnal[INFERRED_SEMI_DIURNAL_COUNT] = {
1158 "N2", "NU2", "MU2", "2N2", "LDA2", "T2", "R2", "L2", "K2", "KJ2"};
1159const NV_CHAR *inferred_diurnal[INFERRED_DIURNAL_COUNT] = {
1160 "OO1", "M1", "J1", "RHO1", "Q1", "2Q1", "P1", "PI1", "PHI1", "PSI1"};
1161NV_FLOAT32 semi_diurnal_coeff[INFERRED_SEMI_DIURNAL_COUNT] = {
1162 .1759, .0341, .0219, .0235, .0066, .0248, .0035, .0251, .1151, .0064};
1163NV_FLOAT32 diurnal_coeff[INFERRED_DIURNAL_COUNT] = {
1164 .0163, .0209, .0297, .0142, .0730, .0097, .1755, .0103, .0076, .0042};
1165
1166/* These represent M2 and O1. */
1167
1168NV_FLOAT32 coeff[2] = {.9085, .3771};
1169
1170/* The following lookup tables are only used for initialization
1171 * purposes and in the pull-down menus in TideEditor. It should be
1172 * possible to change them without breaking existing TCD files. TCD
1173 * files embed their own lookup tables.
1174 */
1175
1176/* Level unit names */
1177
1178NV_CHAR level_unit[DEFAULT_LEVEL_UNIT_TYPES][DEFAULT_LEVEL_UNIT_SIZE] = {
1179 "Unknown", "feet", "meters", "knots", "knots^2"};
1180
1181/* Direction unit names */
1182
1183NV_CHAR dir_unit[DEFAULT_DIR_UNIT_TYPES][DEFAULT_DIR_UNIT_SIZE] = {
1184 "Unknown", "degrees true", "degrees"};
1185
1186/* Restriction types */
1187
1188NV_CHAR restriction[DEFAULT_RESTRICTION_TYPES][DEFAULT_RESTRICTION_SIZE] = {
1189 "Public Domain", "DoD/DoD Contractors Only"};
1190
1191/* Legaleses */
1192
1193NV_CHAR legalese[DEFAULT_LEGALESES][DEFAULT_LEGALESE_SIZE] = {"NULL"};
1194
1195/* # Datum names */
1196
1197NV_CHAR datum[DEFAULT_DATUM_TYPES][DEFAULT_DATUM_SIZE] = {
1198 "Unknown",
1199 "Mean Sea Level",
1200 "Mean Low Water",
1201 "Mean Lower Low Water",
1202 "Mean High Water",
1203 "Mean Higher High Water",
1204 "Mean Lower High Water",
1205 "Mean Higher Low Water",
1206 "Mean Low Water Springs",
1207 "Mean Lower Low Water Springs",
1208 "Mean Low Water Neaps",
1209 "Mean High Water Neaps",
1210 "Mean High Water Springs",
1211 "Mean Higher High Water Springs",
1212 "Indian Spring Low Water",
1213 "Equatorial Spring Low Water",
1214 "Lowest Normal Low Water",
1215 "Lowest Low Water",
1216 "Lowest Possible Low Water",
1217 "Lowest Astronomical Tide",
1218 "International Great Lakes Datum(1955)",
1219 "Lower Low Water, Large Tide",
1220 "Lowest Normal Tide",
1221 "Higher High Water, Large Tide",
1222 "Mean Water Level",
1223 "Higher High Water, Mean Tide",
1224 "Lower Low Water, Mean Tide",
1225 "Mean Tide Level",
1226 "World Geodetic System (1984)",
1227 "National Geodetic Vertical Datum",
1228 "Gulf Coast Low Water Datum",
1229 "Approximate Level of Mean Sea Level",
1230 "Approximate Level of Mean Low Water",
1231 "Approximate Level of Mean Lower Low Water",
1232 "Approximate Level of Mean High Water",
1233 "Approximate Level of Mean Higher High Water",
1234 "Approximate Level of Mean Lower High Water",
1235 "Approximate Level of Mean Higher Low Water",
1236 "Approximate Level of Mean Low Water Springs",
1237 "Approximate Level of Mean Lower Low Water Springs",
1238 "Approximate Level of Mean Low Water Neaps",
1239 "Approximate Level of Mean High Water Neaps",
1240 "Approximate Level of Mean High Water Springs",
1241 "Approximate Level of Mean Higher High Water Springs",
1242 "Approximate Level of Indian Spring Low Water",
1243 "Approximate Level of Equatorial Spring Low Water",
1244 "Approximate Level of Lowest Normal Low Water",
1245 "Approximate Level of Lowest Low Water",
1246 "Approximate Level of Lowest Possible Low Water",
1247 "Approximate Level of Lowest Astronomical Tide",
1248 "Approximate Level of International Great Lakes Datum (1955)",
1249 "Approximate Level of Lower Low Water, Large Tide",
1250 "Approximate Level of Lowest Normal Tide",
1251 "Approximate Level of Higher High Water, Large Tide",
1252 "Approximate Level of Mean Water Level",
1253 "Approximate Level of Higher High Water, Mean Tide",
1254 "Approximate Level of Lower Low Water, Mean Tide",
1255 "Approximate Level of Mean Tide Level",
1256 "Approximate Level of World Geodetic System (1984)",
1257 "Approximate Level of National Geodetic Vertical Datum",
1258 "Approximate Level of Gulf Coast Low Water Datum"};
1259
1260/* # Country names from ISO 3166-1:1999 2-character country code list */
1261
1262NV_CHAR country[DEFAULT_COUNTRIES][DEFAULT_COUNTRY_SIZE] = {
1263 "Unknown",
1264 "Afghanistan",
1265 "Albania",
1266 "Algeria",
1267 "Andorra",
1268 "Angola",
1269 "Anguilla",
1270 "Antarctica",
1271 "Antigua & Barbuda",
1272 "Argentina",
1273 "Armenia",
1274 "Aruba",
1275 "Australia",
1276 "Austria",
1277 "Azerbaijan",
1278 "Bahamas",
1279 "Bahrain",
1280 "Bangladesh",
1281 "Barbados",
1282 "Belarus",
1283 "Belgium",
1284 "Belize",
1285 "Benin",
1286 "Bermuda",
1287 "Bhutan",
1288 "Bolivia",
1289 "Bosnia & Herzegovina",
1290 "Botswana",
1291 "Bouvet Island",
1292 "Brazil",
1293 "Britain (UK)",
1294 "British Indian Ocean Territory",
1295 "Brunei",
1296 "Bulgaria",
1297 "Burkina Faso",
1298 "Burundi",
1299 "Cambodia",
1300 "Cameroon",
1301 "Canada",
1302 "Cape Verde",
1303 "Cayman Islands",
1304 "Central African Rep.",
1305 "Chad",
1306 "Chile",
1307 "China",
1308 "Christmas Island",
1309 "Cocos (Keeling) Islands",
1310 "Colombia",
1311 "Comoros",
1312 "Congo (Dem. Rep.)",
1313 "Congo (Rep.)",
1314 "Cook Islands",
1315 "Costa Rica",
1316 "Cote d'Ivoire",
1317 "Croatia",
1318 "Cuba",
1319 "Cyprus",
1320 "Czech Republic",
1321 "Denmark",
1322 "Djibouti",
1323 "Dominica",
1324 "Dominican Republic",
1325 "East Timor",
1326 "Ecuador",
1327 "Egypt",
1328 "El Salvador",
1329 "Equatorial Guinea",
1330 "Eritrea",
1331 "Estonia",
1332 "Ethiopia",
1333 "Faeroe Islands",
1334 "Falkland Islands",
1335 "Fiji",
1336 "Finland",
1337 "France",
1338 "French Guiana",
1339 "French Polynesia",
1340 "French Southern & Antarctic Lands",
1341 "Gabon",
1342 "Gambia",
1343 "Georgia",
1344 "Germany",
1345 "Ghana",
1346 "Gibraltar",
1347 "Greece",
1348 "Greenland",
1349 "Grenada",
1350 "Guadeloupe",
1351 "Guam",
1352 "Guatemala",
1353 "Guinea",
1354 "Guinea-Bissau",
1355 "Guyana",
1356 "Haiti",
1357 "Heard Island & McDonald Islands",
1358 "Honduras",
1359 "Hong Kong",
1360 "Hungary",
1361 "Iceland",
1362 "India",
1363 "Indonesia",
1364 "Iran",
1365 "Iraq",
1366 "Ireland",
1367 "Israel",
1368 "Italy",
1369 "Jamaica",
1370 "Japan",
1371 "Jordan",
1372 "Kazakhstan",
1373 "Kenya",
1374 "Kiribati",
1375 "Korea (North)",
1376 "Korea (South)",
1377 "Kuwait",
1378 "Kyrgyzstan",
1379 "Laos",
1380 "Latvia",
1381 "Lebanon",
1382 "Lesotho",
1383 "Liberia",
1384 "Libya",
1385 "Liechtenstein",
1386 "Lithuania",
1387 "Luxembourg",
1388 "Macau",
1389 "Macedonia",
1390 "Madagascar",
1391 "Malawi",
1392 "Malaysia",
1393 "Maldives",
1394 "Mali",
1395 "Malta",
1396 "Marshall Islands",
1397 "Martinique",
1398 "Mauritania",
1399 "Mauritius",
1400 "Mayotte",
1401 "Mexico",
1402 "Micronesia",
1403 "Moldova",
1404 "Monaco",
1405 "Mongolia",
1406 "Montserrat",
1407 "Morocco",
1408 "Mozambique",
1409 "Myanmar (Burma)",
1410 "Namibia",
1411 "Nauru",
1412 "Nepal",
1413 "Netherlands",
1414 "Netherlands Antilles",
1415 "New Caledonia",
1416 "New Zealand",
1417 "Nicaragua",
1418 "Niger",
1419 "Nigeria",
1420 "Niue",
1421 "Norfolk Island",
1422 "Northern Mariana Islands",
1423 "Norway",
1424 "Oman",
1425 "Pakistan",
1426 "Palau",
1427 "Palestine",
1428 "Panama",
1429 "Papua New Guinea",
1430 "Paraguay",
1431 "Peru",
1432 "Philippines",
1433 "Pitcairn",
1434 "Poland",
1435 "Portugal",
1436 "Puerto Rico",
1437 "Qatar",
1438 "Reunion",
1439 "Romania",
1440 "Russia",
1441 "Rwanda",
1442 "Samoa (American)",
1443 "Samoa (Western)",
1444 "San Marino",
1445 "Sao Tome & Principe",
1446 "Saudi Arabia",
1447 "Senegal",
1448 "Seychelles",
1449 "Sierra Leone",
1450 "Singapore",
1451 "Slovakia",
1452 "Slovenia",
1453 "Solomon Islands",
1454 "Somalia",
1455 "South Africa",
1456 "South Georgia & the South Sandwich Islands",
1457 "Spain",
1458 "Sri Lanka",
1459 "St Helena",
1460 "St Kitts & Nevis",
1461 "St Lucia",
1462 "St Pierre & Miquelon",
1463 "St Vincent",
1464 "Sudan",
1465 "Suriname",
1466 "Svalbard & Jan Mayen",
1467 "Swaziland",
1468 "Sweden",
1469 "Switzerland",
1470 "Syria",
1471 "Taiwan",
1472 "Tajikistan",
1473 "Tanzania",
1474 "Thailand",
1475 "Togo",
1476 "Tokelau",
1477 "Tonga",
1478 "Trinidad & Tobago",
1479 "Tunisia",
1480 "Turkey",
1481 "Turkmenistan",
1482 "Turks & Caicos Is",
1483 "Tuvalu",
1484 "Uganda",
1485 "Ukraine",
1486 "United Arab Emirates",
1487 "United States",
1488 "Uruguay",
1489 "US minor outlying islands",
1490 "Uzbekistan",
1491 "Vanuatu",
1492 "Vatican City",
1493 "Venezuela",
1494 "Vietnam",
1495 "Virgin Islands (UK)",
1496 "Virgin Islands (US)",
1497 "Wallis & Futuna",
1498 "Western Sahara",
1499 "Yemen",
1500 "Yugoslavia",
1501 "Zambia",
1502 "Zimbabwe"};
1503
1504/* # Time zones extracted from tzdata2002? . */
1505
1506NV_CHAR tzfile[DEFAULT_TZFILES][DEFAULT_TZFILE_SIZE] = {
1507 "Unknown",
1508 ":Africa/Abidjan",
1509 ":Africa/Accra",
1510 ":Africa/Addis_Ababa",
1511 ":Africa/Algiers",
1512 ":Africa/Asmera",
1513 ":Africa/Bamako",
1514 ":Africa/Bangui",
1515 ":Africa/Banjul",
1516 ":Africa/Bissau",
1517 ":Africa/Blantyre",
1518 ":Africa/Brazzaville",
1519 ":Africa/Bujumbura",
1520 ":Africa/Cairo",
1521 ":Africa/Casablanca",
1522 ":Africa/Ceuta",
1523 ":Africa/Conakry",
1524 ":Africa/Dakar",
1525 ":Africa/Dar_es_Salaam",
1526 ":Africa/Djibouti",
1527 ":Africa/Douala",
1528 ":Africa/El_Aaiun",
1529 ":Africa/Freetown",
1530 ":Africa/Gaborone",
1531 ":Africa/Harare",
1532 ":Africa/Johannesburg",
1533 ":Africa/Kampala",
1534 ":Africa/Khartoum",
1535 ":Africa/Kigali",
1536 ":Africa/Kinshasa",
1537 ":Africa/Lagos",
1538 ":Africa/Libreville",
1539 ":Africa/Lome",
1540 ":Africa/Luanda",
1541 ":Africa/Lubumbashi",
1542 ":Africa/Lusaka",
1543 ":Africa/Malabo",
1544 ":Africa/Maputo",
1545 ":Africa/Maseru",
1546 ":Africa/Mbabane",
1547 ":Africa/Mogadishu",
1548 ":Africa/Monrovia",
1549 ":Africa/Nairobi",
1550 ":Africa/Ndjamena",
1551 ":Africa/Niamey",
1552 ":Africa/Nouakchott",
1553 ":Africa/Ouagadougou",
1554 ":Africa/Porto-Novo",
1555 ":Africa/Sao_Tome",
1556 ":Africa/Timbuktu",
1557 ":Africa/Tripoli",
1558 ":Africa/Tunis",
1559 ":Africa/Windhoek",
1560 ":America/Adak",
1561 ":America/Anchorage",
1562 ":America/Anguilla",
1563 ":America/Antigua",
1564 ":America/Araguaina",
1565 ":America/Aruba",
1566 ":America/Asuncion",
1567 ":America/Atka",
1568 ":America/Barbados",
1569 ":America/Belem",
1570 ":America/Belize",
1571 ":America/Boa_Vista",
1572 ":America/Bogota",
1573 ":America/Boise",
1574 ":America/Buenos_Aires",
1575 ":America/Cambridge_Bay",
1576 ":America/Cancun",
1577 ":America/Caracas",
1578 ":America/Catamarca",
1579 ":America/Cayenne",
1580 ":America/Cayman",
1581 ":America/Chicago",
1582 ":America/Chihuahua",
1583 ":America/Cordoba",
1584 ":America/Costa_Rica",
1585 ":America/Cuiaba",
1586 ":America/Curacao",
1587 ":America/Danmarkshavn",
1588 ":America/Dawson",
1589 ":America/Dawson_Creek",
1590 ":America/Denver",
1591 ":America/Detroit",
1592 ":America/Dominica",
1593 ":America/Edmonton",
1594 ":America/Eirunepe",
1595 ":America/El_Salvador",
1596 ":America/Ensenada",
1597 ":America/Fortaleza",
1598 ":America/Glace_Bay",
1599 ":America/Godthab",
1600 ":America/Goose_Bay",
1601 ":America/Grand_Turk",
1602 ":America/Grenada",
1603 ":America/Guadeloupe",
1604 ":America/Guatemala",
1605 ":America/Guayaquil",
1606 ":America/Guyana",
1607 ":America/Halifax",
1608 ":America/Havana",
1609 ":America/Hermosillo",
1610 ":America/Indiana/Knox",
1611 ":America/Indiana/Marengo",
1612 ":America/Indianapolis",
1613 ":America/Indiana/Vevay",
1614 ":America/Inuvik",
1615 ":America/Iqaluit",
1616 ":America/Jamaica",
1617 ":America/Jujuy",
1618 ":America/Juneau",
1619 ":America/Kentucky/Monticello",
1620 ":America/La_Paz",
1621 ":America/Lima",
1622 ":America/Los_Angeles",
1623 ":America/Louisville",
1624 ":America/Maceio",
1625 ":America/Managua",
1626 ":America/Manaus",
1627 ":America/Martinique",
1628 ":America/Mazatlan",
1629 ":America/Mendoza",
1630 ":America/Menominee",
1631 ":America/Merida",
1632 ":America/Mexico_City",
1633 ":America/Miquelon",
1634 ":America/Monterrey",
1635 ":America/Montevideo",
1636 ":America/Montreal",
1637 ":America/Montserrat",
1638 ":America/Nassau",
1639 ":America/New_York",
1640 ":America/Nipigon",
1641 ":America/Nome",
1642 ":America/Noronha",
1643 ":America/North_Dakota/Center",
1644 ":America/Panama",
1645 ":America/Pangnirtung",
1646 ":America/Paramaribo",
1647 ":America/Phoenix",
1648 ":America/Port-au-Prince",
1649 ":America/Port_of_Spain",
1650 ":America/Porto_Velho",
1651 ":America/Puerto_Rico",
1652 ":America/Rainy_River",
1653 ":America/Rankin_Inlet",
1654 ":America/Recife",
1655 ":America/Regina",
1656 ":America/Rio_Branco",
1657 ":America/Santiago",
1658 ":America/Santo_Domingo",
1659 ":America/Sao_Paulo",
1660 ":America/Scoresbysund",
1661 ":America/Shiprock",
1662 ":America/St_Johns",
1663 ":America/St_Kitts",
1664 ":America/St_Lucia",
1665 ":America/St_Thomas",
1666 ":America/St_Vincent",
1667 ":America/Swift_Current",
1668 ":America/Tegucigalpa",
1669 ":America/Thule",
1670 ":America/Thunder_Bay",
1671 ":America/Tijuana",
1672 ":America/Tortola",
1673 ":America/Vancouver",
1674 ":America/Whitehorse",
1675 ":America/Winnipeg",
1676 ":America/Yakutat",
1677 ":America/Yellowknife",
1678 ":Antarctica/Casey",
1679 ":Antarctica/Davis",
1680 ":Antarctica/DumontDUrville",
1681 ":Antarctica/Mawson",
1682 ":Antarctica/McMurdo",
1683 ":Antarctica/Palmer",
1684 ":Antarctica/South_Pole",
1685 ":Antarctica/Syowa",
1686 ":Antarctica/Vostok",
1687 ":Arctic/Longyearbyen",
1688 ":Asia/Aden",
1689 ":Asia/Almaty",
1690 ":Asia/Amman",
1691 ":Asia/Anadyr",
1692 ":Asia/Aqtau",
1693 ":Asia/Aqtobe",
1694 ":Asia/Ashgabat",
1695 ":Asia/Baghdad",
1696 ":Asia/Bahrain",
1697 ":Asia/Baku",
1698 ":Asia/Bangkok",
1699 ":Asia/Beirut",
1700 ":Asia/Bishkek",
1701 ":Asia/Brunei",
1702 ":Asia/Calcutta",
1703 ":Asia/Choibalsan",
1704 ":Asia/Chongqing",
1705 ":Asia/Colombo",
1706 ":Asia/Damascus",
1707 ":Asia/Dhaka",
1708 ":Asia/Dili",
1709 ":Asia/Dubai",
1710 ":Asia/Dushanbe",
1711 ":Asia/Gaza",
1712 ":Asia/Harbin",
1713 ":Asia/Hong_Kong",
1714 ":Asia/Hovd",
1715 ":Asia/Irkutsk",
1716 ":Asia/Jakarta",
1717 ":Asia/Jayapura",
1718 ":Asia/Jerusalem",
1719 ":Asia/Kabul",
1720 ":Asia/Kamchatka",
1721 ":Asia/Karachi",
1722 ":Asia/Kashgar",
1723 ":Asia/Katmandu",
1724 ":Asia/Krasnoyarsk",
1725 ":Asia/Kuala_Lumpur",
1726 ":Asia/Kuching",
1727 ":Asia/Kuwait",
1728 ":Asia/Macau",
1729 ":Asia/Magadan",
1730 ":Asia/Makassar",
1731 ":Asia/Manila",
1732 ":Asia/Muscat",
1733 ":Asia/Nicosia",
1734 ":Asia/Novosibirsk",
1735 ":Asia/Omsk",
1736 ":Asia/Oral",
1737 ":Asia/Phnom_Penh",
1738 ":Asia/Pontianak",
1739 ":Asia/Pyongyang",
1740 ":Asia/Qatar",
1741 ":Asia/Qyzylorda",
1742 ":Asia/Rangoon",
1743 ":Asia/Riyadh",
1744 ":Asia/Saigon",
1745 ":Asia/Sakhalin",
1746 ":Asia/Samarkand",
1747 ":Asia/Seoul",
1748 ":Asia/Shanghai",
1749 ":Asia/Singapore",
1750 ":Asia/Taipei",
1751 ":Asia/Tashkent",
1752 ":Asia/Tbilisi",
1753 ":Asia/Tehran",
1754 ":Asia/Thimphu",
1755 ":Asia/Tokyo",
1756 ":Asia/Ulaanbaatar",
1757 ":Asia/Urumqi",
1758 ":Asia/Vientiane",
1759 ":Asia/Vladivostok",
1760 ":Asia/Yakutsk",
1761 ":Asia/Yekaterinburg",
1762 ":Asia/Yerevan",
1763 ":Atlantic/Azores",
1764 ":Atlantic/Bermuda",
1765 ":Atlantic/Canary",
1766 ":Atlantic/Cape_Verde",
1767 ":Atlantic/Faeroe",
1768 ":Atlantic/Jan_Mayen",
1769 ":Atlantic/Madeira",
1770 ":Atlantic/Reykjavik",
1771 ":Atlantic/South_Georgia",
1772 ":Atlantic/Stanley",
1773 ":Atlantic/St_Helena",
1774 ":Australia/Adelaide",
1775 ":Australia/Brisbane",
1776 ":Australia/Broken_Hill",
1777 ":Australia/Darwin",
1778 ":Australia/Hobart",
1779 ":Australia/Lindeman",
1780 ":Australia/Lord_Howe",
1781 ":Australia/Melbourne",
1782 ":Australia/Perth",
1783 ":Australia/Sydney",
1784 ":Etc/GMT",
1785 ":Etc/GMT-1",
1786 ":Etc/GMT+1",
1787 ":Etc/GMT-10",
1788 ":Etc/GMT+10",
1789 ":Etc/GMT-11",
1790 ":Etc/GMT+11",
1791 ":Etc/GMT-12",
1792 ":Etc/GMT+12",
1793 ":Etc/GMT-13",
1794 ":Etc/GMT-14",
1795 ":Etc/GMT-2",
1796 ":Etc/GMT+2",
1797 ":Etc/GMT-3",
1798 ":Etc/GMT+3",
1799 ":Etc/GMT-4",
1800 ":Etc/GMT+4",
1801 ":Etc/GMT-5",
1802 ":Etc/GMT+5",
1803 ":Etc/GMT-6",
1804 ":Etc/GMT+6",
1805 ":Etc/GMT-7",
1806 ":Etc/GMT+7",
1807 ":Etc/GMT-8",
1808 ":Etc/GMT+8",
1809 ":Etc/GMT-9",
1810 ":Etc/GMT+9",
1811 ":Etc/UCT",
1812 ":Etc/UTC",
1813 ":Europe/Amsterdam",
1814 ":Europe/Andorra",
1815 ":Europe/Athens",
1816 ":Europe/Belfast",
1817 ":Europe/Belgrade",
1818 ":Europe/Berlin",
1819 ":Europe/Bratislava",
1820 ":Europe/Brussels",
1821 ":Europe/Bucharest",
1822 ":Europe/Budapest",
1823 ":Europe/Chisinau",
1824 ":Europe/Copenhagen",
1825 ":Europe/Dublin",
1826 ":Europe/Gibraltar",
1827 ":Europe/Helsinki",
1828 ":Europe/Istanbul",
1829 ":Europe/Kaliningrad",
1830 ":Europe/Kiev",
1831 ":Europe/Lisbon",
1832 ":Europe/Ljubljana",
1833 ":Europe/London",
1834 ":Europe/Luxembourg",
1835 ":Europe/Madrid",
1836 ":Europe/Malta",
1837 ":Europe/Minsk",
1838 ":Europe/Monaco",
1839 ":Europe/Moscow",
1840 ":Europe/Oslo",
1841 ":Europe/Paris",
1842 ":Europe/Prague",
1843 ":Europe/Riga",
1844 ":Europe/Rome",
1845 ":Europe/Samara",
1846 ":Europe/San_Marino",
1847 ":Europe/Sarajevo",
1848 ":Europe/Simferopol",
1849 ":Europe/Skopje",
1850 ":Europe/Sofia",
1851 ":Europe/Stockholm",
1852 ":Europe/Tallinn",
1853 ":Europe/Tirane",
1854 ":Europe/Uzhgorod",
1855 ":Europe/Vaduz",
1856 ":Europe/Vatican",
1857 ":Europe/Vienna",
1858 ":Europe/Vilnius",
1859 ":Europe/Warsaw",
1860 ":Europe/Zagreb",
1861 ":Europe/Zaporozhye",
1862 ":Europe/Zurich",
1863 ":Indian/Antananarivo",
1864 ":Indian/Chagos",
1865 ":Indian/Christmas",
1866 ":Indian/Cocos",
1867 ":Indian/Comoro",
1868 ":Indian/Kerguelen",
1869 ":Indian/Mahe",
1870 ":Indian/Maldives",
1871 ":Indian/Mauritius",
1872 ":Indian/Mayotte",
1873 ":Indian/Reunion",
1874 ":Pacific/Apia",
1875 ":Pacific/Auckland",
1876 ":Pacific/Chatham",
1877 ":Pacific/Easter",
1878 ":Pacific/Efate",
1879 ":Pacific/Enderbury",
1880 ":Pacific/Fakaofo",
1881 ":Pacific/Fiji",
1882 ":Pacific/Funafuti",
1883 ":Pacific/Galapagos",
1884 ":Pacific/Gambier",
1885 ":Pacific/Guadalcanal",
1886 ":Pacific/Guam",
1887 ":Pacific/Honolulu",
1888 ":Pacific/Johnston",
1889 ":Pacific/Kiritimati",
1890 ":Pacific/Kosrae",
1891 ":Pacific/Kwajalein",
1892 ":Pacific/Majuro",
1893 ":Pacific/Marquesas",
1894 ":Pacific/Midway",
1895 ":Pacific/Nauru",
1896 ":Pacific/Niue",
1897 ":Pacific/Norfolk",
1898 ":Pacific/Noumea",
1899 ":Pacific/Pago_Pago",
1900 ":Pacific/Palau",
1901 ":Pacific/Pitcairn",
1902 ":Pacific/Ponape",
1903 ":Pacific/Port_Moresby",
1904 ":Pacific/Rarotonga",
1905 ":Pacific/Saipan",
1906 ":Pacific/Tahiti",
1907 ":Pacific/Tarawa",
1908 ":Pacific/Tongatapu",
1909 ":Pacific/Truk",
1910 ":Pacific/Wake",
1911 ":Pacific/Wallis",
1912 ":Pacific/Yap"};
1913
1914/* $Id: tide_db.c 3744 2010-08-17 22:34:46Z flaterco $ */
1915
1916//#include "tcd.h"
1917//#include "tide_db_header.h"
1918//#include "tide_db_default.h"
1919
1920/* This should be done with stdbool.h, but VC doesn't have it. */
1921/* Using crappy old int, must be careful not to 'require' a 64-bit value. */
1922#ifndef require
1923#define require(expr) \
1924 { \
1925 int require_expr; \
1926 require_expr = (int)(expr); \
1927 assert(require_expr); \
1928 }
1929#endif
1930
1931#include <stdio.h>
1932#include <stdlib.h>
1933#include <string.h>
1934#include <errno.h>
1935#include <time.h>
1936#include <math.h>
1937#include <ctype.h>
1938#include <assert.h>
1939
1940#ifdef HAVE_UNISTD_H
1941#include <unistd.h>
1942#endif
1943
1944#ifdef HAVE_IO_H
1945#include <io.h>
1946#endif
1947
1948/****************************************************************************
1949
1950 DISTRIBUTION STATEMENT
1951
1952 This source file is unclassified, distribution unlimited, public
1953 domain. It is distributed in the hope that it will be useful, but
1954 WITHOUT ANY WARRANTY; without even the implied warranty of
1955 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1956
1957*****************************************************************************/
1958
1959/* Some of the following commentary is out of date. See the new
1960 documentation in libtcd.html. */
1961
1962/****************************************************************************
1963
1964 Tide Constituent Database API
1965
1966
1967 Author : Jan C. Depner (depnerj@navo.navy.mil)
1968
1969 Date : 08/01/02
1970 (First day of Micro$oft's "Licensing 6" policy - P.T. Barnum was
1971 right!!!)
1972
1973 Purpose : To replace the ASCII/XML formatted harmonic constituent data
1974 files, used in Dave Flater's (http://www.flaterco.com/xtide/)
1975 exceptionally fine open-source XTide program, with a fast,
1976 efficient binary format. In addition, we wanted to replace the
1977 Naval Oceanographic Office's (http://www.navo.navy.mil)
1978 antiquated ASCII format harmonic constituent data file due to
1979 problems with configuration management of the file. The
1980 resulting database will become a Navy OAML (Oceanographic and
1981 Atmospheric Master Library) standard harmonic tide constituent
1982 database.
1983
1984 Design : The following describes the database file and some of the
1985 rationale behind the design.
1986
1987 First question - Why didn't I use PostgreSQL or MySQL? Mostly
1988 portability. What? PostgreSQL runs on everything! Yes, but it doesn't
1989 come installed on everything. This would have meant that the poor,
1990 benighted Micro$oft borgs would have had to actually load a software
1991 package. In addition, the present harmonics/offset files only contain
1992 a total of 6,409 stations. It hardly seemed worth the effort (or overhead)
1993 of a fullblown RDBMS to handle this. Second question - Why binary and not
1994 ASCII or XML? This actually gets into philosophy. At NAVO we have used an
1995 ASCII harmonic constituent file for years (we were founded in 1830 and I
1996 think that that's when they designed the file). We have about fifty
1997 million copies floating around and each one is slightly different. Why?
1998 Because they're ASCII and everyone thinks they know what they're doing so
1999 they tend to modify the file. Same problem with XML, it's still ASCII.
2000 We wanted a file that people weren't going to mess with and that we could
2001 version control. We also wanted a file that was small and fast. This is
2002 very difficult to do with ASCII. The big slowdown with the old format
2003 was I/O and parsing. Third question - will it run on any OS? Hopefully,
2004 yes. After twenty-five years of working with low bidder systems I've
2005 worked on almost every OS known to man. Once you've been bitten by big
2006 endian vs little endian or IEEE floating point format vs VAX floating
2007 point format or byte addressable memory vs word addressable memory or 32
2008 bit word vs 36 bit word vs 48 bit word vs 64 bit word sizes you get the
2009 message. All of the data in the file is stored either as ASCII text or
2010 scaled integers (32 bits or smaller), bit-packed and stuffed into an
2011 unsigned character buffer for I/O. No endian issues, no floating point
2012 issues, no word size issues, no memory mapping issues. I will be testing
2013 this on x86 Linux, HP-UX, and Micro$oft Windoze. By the time you read
2014 this it will be portable to those systems at least.
2015
2016 Now, on to the file layout. As much as I dislike ASCII it is occasionally
2017 handy to be able to see some information about a file without having to
2018 resort to a special purpose program. With that in mind I made the first
2019 part of the header of the file ASCII. The following is an example of the
2020 ASCII portion of the header:
2021
2022 [VERSION] = PFM Software - tide_db V1.00 - 08/01/02
2023 [LAST MODIFIED] = Thu Aug 1 02:46:29 2002
2024 [HEADER SIZE] = 4096
2025 [NUMBER OF RECORDS] = 10652
2026 [START YEAR] = 1970
2027 [NUMBER OF YEARS] = 68
2028 [SPEED BITS] = 31
2029 [SPEED SCALE] = 10000000
2030 [SPEED OFFSET] = -410667
2031 [EQUILIBRIUM BITS] = 16
2032 [EQUILIBRIUM SCALE] = 100
2033 [EQUILIBRIUM OFFSET] = 0
2034 [NODE BITS] = 15
2035 [NODE SCALE] = 10000
2036 [NODE OFFSET] = -3949
2037 [AMPLITUDE BITS] = 19
2038 [AMPLITUDE SCALE] = 10000
2039 [EPOCH BITS] = 16
2040 [EPOCH SCALE] = 100
2041 [RECORD TYPE BITS] = 4
2042 [LATITUDE BITS] = 25
2043 [LATITUDE SCALE] = 100000
2044 [LONGITUDE BITS] = 26
2045 [LONGITUDE SCALE] = 100000
2046 [RECORD SIZE BITS] = 12
2047 [STATION BITS] = 18
2048 [DATUM OFFSET BITS] = 32
2049 [DATUM OFFSET SCALE] = 10000
2050 [DATE BITS] = 27
2051 [MONTHS ON STATION BITS] = 10
2052 [CONFIDENCE VALUE BITS] = 4
2053 [TIME BITS] = 13
2054 [LEVEL ADD BITS] = 16
2055 [LEVEL ADD SCALE] = 100
2056 [LEVEL MULTIPLY BITS] = 16
2057 [LEVEL MULTIPLY SCALE] = 1000
2058 [DIRECTION BITS] = 9
2059 [LEVEL UNIT BITS] = 3
2060 [LEVEL UNIT TYPES] = 6
2061 [LEVEL UNIT SIZE] = 15
2062 [DIRECTION UNIT BITS] = 2
2063 [DIRECTION UNIT TYPES] = 3
2064 [DIRECTION UNIT SIZE] = 15
2065 [RESTRICTION BITS] = 4
2066 [RESTRICTION TYPES] = 2
2067 [RESTRICTION SIZE] = 30
2068 [PEDIGREE BITS] = 6
2069 [PEDIGREE TYPES] = 13
2070 [PEDIGREE SIZE] = 60
2071 [DATUM BITS] = 7
2072 [DATUM TYPES] = 61
2073 [DATUM SIZE] = 70
2074 [CONSTITUENT BITS] = 8
2075 [CONSTITUENTS] = 173
2076 [CONSTITUENT SIZE] = 10
2077 [COUNTRY BITS] = 9
2078 [COUNTRIES] = 240
2079 [COUNTRY SIZE] = 50
2080 [TZFILE BITS] = 10
2081 [TZFILES] = 449
2082 [TZFILE SIZE] = 30
2083 [END OF FILE] = 2585170
2084 [END OF ASCII HEADER DATA]
2085
2086 Most of these values will make sense in the context of the following
2087 description of the rest of the file. Some caveats on the data storage -
2088 if no SCALE is listed for a field, the scale is 1. If no BITS field is
2089 listed, this is a variable length character field and is stored as 8 bit
2090 ASCII characters. If no OFFSET is listed, the offset is 0. Offsets are
2091 scaled. All SIZE fields refer to the maximum length, in characters, of a
2092 variable length character field. Some of the BITS fields are calculated
2093 while others are hardwired (see code). For instance, [DIRECTION BITS] is
2094 hardwired because it is an integer field whose value can only be from 0 to
2095 361 (361 = no direction flag). [NODE BITS], on the other hand, is
2096 calculated on creation by checking the min, max, and range of all of the
2097 node factor values. The number of bits needed is easily calculated by
2098 taking the log of the adjusted, scaled range, dividing by the log of 2 and
2099 adding 1. Immediately following the ASCII portion of the header is a 32
2100 bit checksum of the ASCII portion of the header. Why? Because some
2101 genius always gets the idea that he/she can modify the header with a text
2102 or hex editor. Go figure.
2103
2104 The rest of the header is as follows :
2105
2106 [LEVEL UNIT TYPES] fields of [LEVEL UNIT SIZE] characters, each field
2107 is internally 0 terminated (anything after the zero is garbage)
2108
2109 [DIRECTION UNIT TYPES] fields of [DIRECTION UNIT SIZE] characters, 0
2110 terminated
2111
2112 [RESTRICTION TYPES] fields of [RESTRICTION SIZE] characters, 0
2113 terminated
2114
2115 [PEDIGREE TYPES] fields of [PEDIGREE SIZE] characters, 0 terminated
2116
2117 [TZFILES] fields of [TZFILE SIZE] characters, 0 terminated
2118
2119 [COUNTRIES] fields of [COUNTRY SIZE] characters, 0 terminated
2120
2121 [DATUM TYPES] fields of [DATUM SIZE] characters, 0 terminated
2122
2123 [CONSTITUENTS] fields of [CONSTITUENT SIZE] characters, 0 terminated
2124 Yes, I know, I wasted some space with these fields but I wasn't
2125 worried about a couple of hundred bytes.
2126
2127 [CONSTITUENTS] fields of [SPEED BITS], speed values (scaled and offset)
2128
2129 [CONSTITUENTS] groups of [NUMBER OF YEARS] fields of
2130 [EQUILIBRIUM BITS], equilibrium arguments (scaled and offset)
2131
2132 [CONSTITUENTS] groups of [NUMBER OF YEARS] fields of [NODE BITS], node
2133 factors (scaled and offset)
2134
2135
2136 Finally, the data. At present there are two types of records in the file.
2137 These are reference stations (record type 1) and subordinate stations
2138 (record type 2). Reference stations contain a set of constituents while
2139 subordinate stations contain a number of offsets to be applied to the
2140 reference station that they are associated with. Note that reference
2141 stations (record type 1) may, in actuality, be subordinate stations, albeit
2142 with a set of constituents. All of the records have the following subset
2143 of information stored as the first part of the record:
2144
2145 [RECORD SIZE BITS] - record size in bytes
2146 [RECORD TYPE BITS] - record type (1 or 2)
2147 [LATITUDE BITS] - latitude (degrees, south negative, scaled & offset)
2148 [LONGITUDE BITS] - longitude (degrees, west negative, scaled & offset)
2149 [TZFILE BITS] - index into timezone array (retrieved from header)
2150 variable size - station name, 0 terminated
2151 [STATION BITS] - record number of reference station or -1
2152 [COUNTRY_BITS] index into country array (retrieved from header)
2153 [PEDIGREE BITS] - index into pedigree array (retrieved from header)
2154 variable size - source, 0 terminated
2155 [RESTRICTION BITS] - index into restriction array
2156 variable size - comments, may contain LFs to indicate newline (no CRs)
2157
2158
2159 These are the rest of the fields for record type 1:
2160
2161 [LEVEL UNIT BITS] - index into level units array
2162 [DATUM OFFSET BITS] - datum offset (scaled)
2163 [DATUM BITS] - index into datum name array
2164 [TIME BITS] - time zone offset from GMT0 (meridian, integer +/-HHMM)
2165 [DATE BITS] - expiration date, (integer YYYYMMDD, default is 0)
2166 [MONTHS ON STATION BITS] - months on station
2167 [DATE BITS] - last date on station, default is 0
2168 [CONFIDENCE BITS] - confidence value (TBD)
2169 [CONSTITUENT BITS] - "N", number of constituents for this station
2170
2171 N groups of:
2172 [CONSTITUENT BITS] - constituent number
2173 [AMPLITUDE BITS] - amplitude (scaled & offset)
2174 [EPOCH BITS] - epoch (scaled & offset)
2175
2176
2177 These are the rest of the fields for record type 2:
2178
2179 [LEVEL UNIT BITS] - leveladd units, index into level_units array
2180 [DIRECTION UNIT BITS] - direction units, index into dir_units array
2181 [LEVEL UNIT BITS] - avglevel units, index into level_units array
2182 [TIME BITS] - min timeadd (integer +/-HHMM) or 0
2183 [LEVEL ADD BITS] - min leveladd (scaled) or 0
2184 [LEVEL MULTIPLY BITS] - min levelmultiply (scaled) or 0
2185 [LEVEL ADD BITS] - min avglevel (scaled) or 0
2186 [DIRECTION BITS] - min direction (0-360 or 361 for no direction)
2187 [TIME BITS] - max timeadd (integer +/-HHMM) or 0
2188 [LEVEL ADD BITS] - max leveladd (scaled) or 0
2189 [LEVEL MULTIPLY BITS] - max levelmultiply (scaled) or 0
2190 [LEVEL ADD BITS] - max avglevel (scaled) or 0
2191 [DIRECTION BITS] - max direction (0-360 or 361 for no direction)
2192 [TIME BITS] - floodbegins (integer +/-HHMM) or NULLSLACKOFFSET
2193 [TIME BITS] - ebbbegins (integer +/-HHMM) or NULLSLACKOFFSET
2194
2195
2196 Back to philosophy! When you design a database of any kind the first
2197 thing you should ask yourself is "Self, how am I going to access this
2198 data most of the time?". If you answer yourself out loud you should
2199 consider seeing a shrink. 99 and 44/100ths percent of the time this
2200 database is going to be read to get station data. The other 66/100ths
2201 percent of the time it will be created/modified. Variable length records
2202 are no problem on retrieval. They are no problem to create. They can be
2203 a major pain in the backside if you have to modify/delete them. Since we
2204 shouldn't be doing too much editing of the data (usually just adding
2205 records) this is a pretty fair design. At some point though we are going
2206 to want to modify or delete a record. There are two possibilities here.
2207 We can dump the database to an ASCII file or files using restore_tide_db,
2208 use a text editor to modify them, and then rebuild the database. The
2209 other possibility is to modify the record in place. This is OK if you
2210 don't change a variable length field but what if you want to change the
2211 station name or add a couple of constituents? With the design as is we
2212 have to read the remainder of the file from the end of the record to be
2213 modified, write the modified record, rewrite the remainder of the file,
2214 and then change the end_of_file pointer in the header. So, which fields
2215 are going to be a problem? Changes to station name, source, comments, or
2216 the number of constituents for a station will require a resizing of the
2217 database. Changes to any of the other fields can be done in place. The
2218 worst thing that you can do though is to delete a record. Not just
2219 because the file has to be resized but because it might be a reference
2220 record with subordinate stations. These would have to be deleted as well.
2221 The delete_tide_record function will do just that so make sure you check
2222 before you call it. You might not want to do that.
2223
2224 Another point to note is that when you open the database the records are
2225 indexed at that point. This takes about half a second on a dual 450.
2226 Most applications use the header part of the record very often and
2227 the rest of the record only if they are going to actually produce
2228 predicted tides. For instance, XTide plots all of the stations on a
2229 world map or globe and lists all of the station names. It also needs the
2230 timezone up front. To save re-indexing to get these values I save them
2231 in memory. The only time an application needs to actually read an entire
2232 record is when you want to do the prediction. Otherwise just use
2233 get_partial_tide_record or get_next_partial_tide_record to yank the good
2234 stuff out of memory.
2235
2236 'Nuff said?
2237
2238
2239 See libtcd.html for changelog.
2240
2241*****************************************************************************/
2242
2243/* Maintenance by DWF */
2244
2245/* Function prototypes. */
2246
2247NV_U_INT32 calculate_bits(NV_U_INT32 value);
2248void bit_pack(NV_U_BYTE *, NV_U_INT32, NV_U_INT32, NV_INT32);
2249NV_U_INT32 bit_unpack(NV_U_BYTE *, NV_U_INT32, NV_U_INT32);
2250NV_INT32 signed_bit_unpack(NV_U_BYTE buffer[], NV_U_INT32 start,
2251 NV_U_INT32 numbits);
2252
2253/* Global variables. */
2254
2255typedef struct {
2256 NV_INT32 address;
2257 NV_U_INT32 record_size;
2258 NV_U_INT16 tzfile;
2259 NV_INT32 reference_station;
2260 NV_INT32 lat;
2261 NV_INT32 lon;
2262 NV_U_BYTE record_type;
2263 NV_CHAR *name;
2264} TIDE_INDEX;
2265
2266static FILE *fp = NULL;
2267static TIDE_INDEX *tindex = NULL;
2268static NV_BOOL modified = NVFalse;
2269static NV_INT32 current_record, current_index;
2270static NV_CHAR filename[MONOLOGUE_LENGTH];
2271
2272/*****************************************************************************\
2273 Checked fread and fwrite wrappers
2274 DWF 2007-12-02
2275
2276 Fedora package compiles generate warnings for invoking these
2277 functions without checking the return.
2278\*****************************************************************************/
2279
2280static void chk_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
2281 size_t ret;
2282 ret = fread(ptr, size, nmemb, stream);
2283 if (ret != nmemb) {
2284 // LOG_ERROR ("libtcd unexpected error: fread failed\n");
2285 // LOG_ERROR ("nmemb = %lu, got %lu\n", nmemb, ret);
2286 abort();
2287 }
2288}
2289
2290static void chk_fwrite(const void *ptr, size_t size, size_t nmemb,
2291 FILE *stream) {
2292 size_t ret;
2293 ret = fwrite(ptr, size, nmemb, stream);
2294 if (ret != nmemb) {
2295 // LOG_ERROR ("libtcd unexpected error: fwrite failed\n");
2296 // LOG_ERROR ("nmemb = %lu, got %lu\n", nmemb, ret);
2297 // LOG_ERROR ("The database is probably corrupt now.\n");
2298 abort();
2299 }
2300}
2301
2302/*****************************************************************************\
2303
2304 Function dump_tide_record - prints out all of the fields in the
2305 input tide record
2306
2307 Synopsis dump_tide_record (rec);
2308
2309 TIDE_RECORD *rec pointer to the tide record
2310
2311 Returns void
2312
2313 Author Jan C. Depner
2314 Date 08/01/02
2315
2316 See libtcd.html for changelog.
2317
2318\*****************************************************************************/
2319
2320void dump_tide_record(const TIDE_RECORD *rec) {
2321 NV_U_INT32 i;
2322
2323 assert(rec);
2324
2325 LOG_ERROR("\n\nRecord number = %d\n", rec->header.record_number);
2326 LOG_ERROR("Record size = %u\n", rec->header.record_size);
2327 LOG_ERROR("Record type = %u\n", rec->header.record_type);
2328 LOG_ERROR("Latitude = %f\n", rec->header.latitude);
2329 LOG_ERROR("Longitude = %f\n", rec->header.longitude);
2330 LOG_ERROR("Reference station = %d\n", rec->header.reference_station);
2331 LOG_ERROR("Tzfile = %s\n", get_tzfile(rec->header.tzfile));
2332 LOG_ERROR("Name = %s\n", rec->header.name);
2333
2334 LOG_ERROR("Country = %s\n", get_country(rec->country));
2335 LOG_ERROR("Source = %s\n", rec->source);
2336 LOG_ERROR("Restriction = %s\n", get_restriction(rec->restriction));
2337 LOG_ERROR("Comments = %s\n", rec->comments);
2338 LOG_ERROR("Notes = %s\n", rec->notes);
2339 LOG_ERROR("Legalese = %s\n", get_legalese(rec->legalese));
2340 LOG_ERROR("Station ID context = %s\n", rec->station_id_context);
2341 LOG_ERROR("Station ID = %s\n", rec->station_id);
2342 LOG_ERROR("Date imported = %d\n", rec->date_imported);
2343 LOG_ERROR("Xfields = %s\n", rec->xfields);
2344
2345 LOG_ERROR("Direction units = %s\n", get_dir_units(rec->direction_units));
2346 LOG_ERROR("Min direction = %d\n", rec->min_direction);
2347 LOG_ERROR("Max direction = %d\n", rec->max_direction);
2348 LOG_ERROR("Level units = %s\n", get_level_units(rec->level_units));
2349
2350 if (rec->header.record_type == REFERENCE_STATION) {
2351 LOG_ERROR("Datum offset = %f\n", rec->datum_offset);
2352 LOG_ERROR("Datum = %s\n", get_datum(rec->datum));
2353 LOG_ERROR("Zone offset = %d\n", rec->zone_offset);
2354 LOG_ERROR("Expiration date = %d\n", rec->expiration_date);
2355 LOG_ERROR("Months on station = %d\n", rec->months_on_station);
2356 LOG_ERROR("Last date on station = %d\n", rec->last_date_on_station);
2357 LOG_ERROR("Confidence = %d\n", rec->confidence);
2358 for (i = 0; i < hd.pub.constituents; ++i) {
2359 if (rec->amplitude[i] != 0.0 || rec->epoch[i] != 0.0) {
2360 LOG_ERROR("Amplitude[%d] = %f\n", i, rec->amplitude[i]);
2361 LOG_ERROR("Epoch[%d] = %f\n", i, rec->epoch[i]);
2362 }
2363 }
2364 }
2365
2366 else if (rec->header.record_type == SUBORDINATE_STATION) {
2367 LOG_ERROR("Min time add = %d\n", rec->min_time_add);
2368 LOG_ERROR("Min level add = %f\n", rec->min_level_add);
2369 LOG_ERROR("Min level multiply = %f\n", rec->min_level_multiply);
2370 LOG_ERROR("Max time add = %d\n", rec->max_time_add);
2371 LOG_ERROR("Max level add = %f\n", rec->max_level_add);
2372 LOG_ERROR("Max level multiply = %f\n", rec->max_level_multiply);
2373 LOG_ERROR("Flood begins = %d\n", rec->flood_begins);
2374 LOG_ERROR("Ebb begins = %d\n", rec->ebb_begins);
2375 }
2376}
2377
2378/*****************************************************************************\
2379
2380 Function write_protect - prevent trying to modify TCD files of
2381 an earlier version. Nothing to do with file locking.
2382
2383 David Flater, 2004-10-14.
2384
2385\*****************************************************************************/
2386
2387static void write_protect() {
2388 if (hd.pub.major_rev < LIBTCD_MAJOR_REV) {
2389 LOG_ERROR(
2390 "libtcd error: can't modify TCD files created by earlier version. "
2391 "Use\nrewrite_tide_db to upgrade the TCD file.\n");
2392 exit(-1);
2393 }
2394}
2395
2396/*****************************************************************************\
2397
2398 Function get_country - gets the country field for record "num"
2399
2400 Synopsis get_country (num);
2401
2402 NV_INT32 num tide record number
2403
2404 Returns NV_CHAR * country name (associated with
2405 ISO 3166-1:1999 2-character
2406 country code
2407
2408 Author Jan C. Depner
2409 Date 08/01/02
2410
2411 See libtcd.html for changelog.
2412
2413\*****************************************************************************/
2414
2415const NV_CHAR *get_country(NV_INT32 num) {
2416 if (!fp) {
2417 LOG_ERROR(
2418 "libtcd error: attempt to access database when database not open\n");
2419 exit(-1);
2420 }
2421 if (num >= 0 && num < (NV_INT32)hd.pub.countries) return (hd.country[num]);
2422 return ("Unknown");
2423}
2424
2425/*****************************************************************************\
2426
2427 Function get_tzfile - gets the time zone name for record "num"
2428
2429 Synopsis get_tzfile (num);
2430
2431 NV_INT32 num tide record number
2432
2433 Returns NV_CHAR * time zone name used in TZ variable
2434
2435 Author Jan C. Depner
2436 Date 08/01/02
2437
2438 See libtcd.html for changelog.
2439
2440\*****************************************************************************/
2441
2442const NV_CHAR *get_tzfile(NV_INT32 num) {
2443 if (!fp) {
2444 LOG_ERROR(
2445 "libtcd error: attempt to access database when database not open\n");
2446 exit(-1);
2447 }
2448 if (num >= 0 && num < (NV_INT32)hd.pub.tzfiles) return (hd.tzfile[num]);
2449 return ("Unknown");
2450}
2451
2452/*****************************************************************************\
2453
2454 Function get_station - get the name of the station for record "num"
2455
2456 Synopsis get_station (num);
2457
2458 NV_INT32 num tide record number
2459
2460 Returns NV_CHAR * station name
2461
2462 Author Jan C. Depner
2463 Date 08/01/02
2464
2465 See libtcd.html for changelog.
2466
2467\*****************************************************************************/
2468
2469const NV_CHAR *get_station(NV_INT32 num) {
2470 if (!fp) {
2471 LOG_ERROR(
2472 "libtcd error: attempt to access database when database not open\n");
2473 exit(-1);
2474 }
2475 if (num >= 0 && num < (NV_INT32)hd.pub.number_of_records)
2476 return (tindex[num].name);
2477 return ("Unknown");
2478}
2479
2480/*****************************************************************************\
2481
2482 Function get_constituent - get the constituent name for constituent
2483 number "num"
2484
2485 Synopsis get_constituent (num);
2486
2487 NV_INT32 num constituent number
2488
2489 Returns NV_CHAR * constituent name
2490
2491 Author Jan C. Depner
2492 Date 08/01/02
2493
2494 See libtcd.html for changelog.
2495
2496\*****************************************************************************/
2497
2498const NV_CHAR *get_constituent(NV_INT32 num) {
2499 if (!fp) {
2500 LOG_ERROR(
2501 "libtcd error: attempt to access database when database not open\n");
2502 exit(-1);
2503 }
2504 if (num >= 0 && num < (NV_INT32)hd.pub.constituents)
2505 return (hd.constituent[num]);
2506 return ("Unknown");
2507}
2508
2509/*****************************************************************************\
2510
2511 Function get_level_units - get the level units for level units
2512 number "num"
2513
2514 Synopsis get_level_units (num);
2515
2516 NV_INT32 num level units number
2517
2518 Returns NV_CHAR * units (ex. "meters");
2519
2520 Author Jan C. Depner
2521 Date 08/01/02
2522
2523 See libtcd.html for changelog.
2524
2525\*****************************************************************************/
2526
2527const NV_CHAR *get_level_units(NV_INT32 num) {
2528 if (!fp) {
2529 LOG_ERROR(
2530 "libtcd error: attempt to access database when database not open\n");
2531 exit(-1);
2532 }
2533 if (num >= 0 && num < (NV_INT32)hd.pub.level_unit_types)
2534 return (hd.level_unit[num]);
2535 return ("Unknown");
2536}
2537
2538/*****************************************************************************\
2539
2540 Function get_dir_units - get the direction units for direction
2541 units number "num"
2542
2543 Synopsis get_dir_units (num);
2544
2545 NV_INT32 num direction units number
2546
2547 Returns NV_CHAR * units (ex. "degrees true");
2548
2549 Author Jan C. Depner
2550 Date 08/01/02
2551
2552 See libtcd.html for changelog.
2553
2554\*****************************************************************************/
2555
2556const NV_CHAR *get_dir_units(NV_INT32 num) {
2557 if (!fp) {
2558 LOG_ERROR(
2559 "libtcd error: attempt to access database when database not open\n");
2560 exit(-1);
2561 }
2562 if (num >= 0 && num < (NV_INT32)hd.pub.dir_unit_types)
2563 return (hd.dir_unit[num]);
2564 return ("Unknown");
2565}
2566
2567/*****************************************************************************\
2568
2569 Function get_restriction - gets the restriction description for
2570 restriction number "num"
2571
2572 Synopsis get_restriction (num);
2573
2574 NV_INT32 num restriction number
2575
2576 Returns NV_CHAR * restriction (ex. "PUBLIC DOMAIN");
2577
2578 Author Jan C. Depner
2579 Date 08/01/02
2580
2581 See libtcd.html for changelog.
2582
2583\*****************************************************************************/
2584
2585const NV_CHAR *get_restriction(NV_INT32 num) {
2586 if (!fp) {
2587 LOG_ERROR(
2588 "libtcd error: attempt to access database when database not open\n");
2589 exit(-1);
2590 }
2591 if (num >= 0 && num < (NV_INT32)hd.pub.restriction_types)
2592 return (hd.restriction[num]);
2593 return ("Unknown");
2594}
2595
2596/*****************************************************************************\
2597
2598 Function get_pedigree - gets the pedigree description for pedigree
2599 number "num"
2600
2601 Synopsis get_pedigree (num);
2602
2603 NV_INT32 num pedigree number
2604
2605 Returns NV_CHAR * pedigree description
2606
2607 Author Jan C. Depner
2608 Date 08/01/02
2609
2610 See libtcd.html for changelog.
2611
2612\*****************************************************************************/
2613
2614#ifdef COMPAT114
2615NV_CHAR *get_pedigree(NV_INT32 num) { return "Unknown"; }
2616#endif
2617
2618/*****************************************************************************\
2619
2620 Function get_datum - gets the datum name for datum number "num"
2621
2622 Synopsis get_datum (num);
2623
2624 NV_INT32 num datum number
2625
2626 Returns NV_CHAR * datum name
2627
2628 Author Jan C. Depner
2629 Date 08/01/02
2630
2631 See libtcd.html for changelog.
2632
2633\*****************************************************************************/
2634
2635const NV_CHAR *get_datum(NV_INT32 num) {
2636 if (!fp) {
2637 LOG_ERROR(
2638 "libtcd error: attempt to access database when database not open\n");
2639 exit(-1);
2640 }
2641 if (num >= 0 && num < (NV_INT32)hd.pub.datum_types) return (hd.datum[num]);
2642 return ("Unknown");
2643}
2644
2645/*****************************************************************************\
2646DWF 2004-10-14
2647\*****************************************************************************/
2648const NV_CHAR *get_legalese(NV_INT32 num) {
2649 if (!fp) {
2650 LOG_ERROR(
2651 "libtcd error: attempt to access database when database not open\n");
2652 exit(-1);
2653 }
2654 if (num >= 0 && num < (NV_INT32)hd.pub.legaleses) return (hd.legalese[num]);
2655 return ("Unknown");
2656}
2657
2658/*****************************************************************************\
2659
2660 Function get_speed - gets the speed value for constituent number
2661 "num"
2662
2663 Synopsis get_speed (num);
2664
2665 NV_INT32 num constituent number
2666
2667 Returns NV_FLOAT64 speed
2668
2669 Author Jan C. Depner
2670 Date 08/01/02
2671
2672 See libtcd.html for changelog.
2673
2674\*****************************************************************************/
2675
2676NV_FLOAT64 get_speed(NV_INT32 num) {
2677 if (!fp) {
2678 LOG_ERROR(
2679 "libtcd error: attempt to access database when database not open\n");
2680 exit(-1);
2681 }
2682 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents);
2683 return hd.speed[num];
2684}
2685
2686/*****************************************************************************\
2687
2688 Function get_equilibrium - gets the equilibrium value for
2689 constituent number "num" and year "year"
2690
2691 Synopsis get_equilibrium (num, year);
2692
2693 NV_INT32 num constituent number
2694 NV_INT32 year year
2695
2696 Returns NV_FLOAT32 equilibrium argument
2697
2698 Author Jan C. Depner
2699 Date 08/01/02
2700
2701 See libtcd.html for changelog.
2702
2703\*****************************************************************************/
2704
2705NV_FLOAT32 get_equilibrium(NV_INT32 num, NV_INT32 year) {
2706 if (!fp) {
2707 LOG_ERROR(
2708 "libtcd error: attempt to access database when database not open\n");
2709 exit(-1);
2710 }
2711 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents && year >= 0 &&
2712 year < (NV_INT32)hd.pub.number_of_years);
2713 return hd.equilibrium[num][year];
2714}
2715
2716/*****************************************************************************\
2717 DWF 2004-10-04
2718\*****************************************************************************/
2719NV_FLOAT32 *get_equilibriums(NV_INT32 num) {
2720 if (!fp) {
2721 LOG_ERROR(
2722 "libtcd error: attempt to access database when database not open\n");
2723 exit(-1);
2724 }
2725 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents);
2726 return hd.equilibrium[num];
2727}
2728
2729/*****************************************************************************\
2730
2731 Function get_node_factor - gets the node factor value for
2732 constituent number "num" and year "year"
2733
2734 Synopsis get_node_factor (num, year);
2735
2736 NV_INT32 num constituent number
2737 NV_INT32 year year
2738
2739 Returns NV_FLOAT32 node factor
2740
2741 Author Jan C. Depner
2742 Date 08/01/02
2743
2744 See libtcd.html for changelog.
2745
2746\*****************************************************************************/
2747
2748NV_FLOAT32 get_node_factor(NV_INT32 num, NV_INT32 year) {
2749 if (!fp) {
2750 LOG_ERROR(
2751 "libtcd error: attempt to access database when database not open\n");
2752 exit(-1);
2753 }
2754 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents && year >= 0 &&
2755 year < (NV_INT32)hd.pub.number_of_years);
2756 return hd.node_factor[num][year];
2757}
2758
2759/*****************************************************************************\
2760 DWF 2004-10-04
2761\*****************************************************************************/
2762NV_FLOAT32 *get_node_factors(NV_INT32 num) {
2763 if (!fp) {
2764 LOG_ERROR(
2765 "libtcd error: attempt to access database when database not open\n");
2766 exit(-1);
2767 }
2768 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents);
2769 return hd.node_factor[num];
2770}
2771
2772/*****************************************************************************\
2773
2774 Function get_partial_tide_record - gets "header" portion of record
2775 "num" from the index that is stored in memory. This is
2776 way faster than reading it again and we have to read it
2777 to set up the index. This costs a bit in terms of
2778 memory but most applications use this data far more than
2779 the rest of the record.
2780
2781 Synopsis get_partial_tide_record (num, rec);
2782
2783 NV_INT32 num record number
2784 TIDE_STATION_HEADER *rec header portion of the record
2785
2786 Returns NV_BOOL NVTrue if successful
2787
2788 Author Jan C. Depner
2789 Date 08/01/02
2790
2791 See libtcd.html for changelog.
2792
2793\*****************************************************************************/
2794
2795NV_BOOL get_partial_tide_record(NV_INT32 num, TIDE_STATION_HEADER *rec) {
2796 if (!fp) {
2797 LOG_ERROR(
2798 "libtcd error: attempt to access database when database not open\n");
2799 return NVFalse;
2800 }
2801
2802 if (num < 0 || num >= (NV_INT32)hd.pub.number_of_records) return (NVFalse);
2803
2804 assert(rec);
2805
2806 rec->record_number = num;
2807 rec->record_size = tindex[num].record_size;
2808 rec->record_type = tindex[num].record_type;
2809 rec->latitude = (NV_FLOAT64)tindex[num].lat / hd.latitude_scale;
2810 rec->longitude = (NV_FLOAT64)tindex[num].lon / hd.longitude_scale;
2811 rec->reference_station = tindex[num].reference_station;
2812 rec->tzfile = tindex[num].tzfile;
2813 strcpy(rec->name, tindex[num].name);
2814
2815 current_index = num;
2816
2817 return (NVTrue);
2818}
2819
2820/*****************************************************************************\
2821
2822 Function get_next_partial_tide_record - gets "header" portion of
2823 the next record from the index that is stored in memory.
2824
2825 Synopsis get_next_partial_tide_record (rec);
2826
2827 TIDE_STATION_HEADER *rec header portion of the record
2828
2829 Returns NV_INT32 record number or -1 on failure
2830
2831 Author Jan C. Depner
2832 Date 08/01/02
2833
2834 See libtcd.html for changelog.
2835
2836\*****************************************************************************/
2837
2838NV_INT32 get_next_partial_tide_record(TIDE_STATION_HEADER *rec) {
2839 if (!get_partial_tide_record(current_index + 1, rec)) return (-1);
2840
2841 return (current_index);
2842}
2843
2844/*****************************************************************************\
2845
2846 Function get_nearest_partial_tide_record - gets "header" portion of
2847 the record closest geographically to the input position.
2848
2849 Synopsis get_nearest_partial_tide_record (lat, lon, rec);
2850
2851 NV_FLOAT64 lat latitude
2852 NV_FLOAT64 lon longitude
2853 TIDE_STATION_HEADER *rec header portion of the record
2854
2855 Returns NV_INT32 record number or -1 on failure
2856
2857 Author Jan C. Depner
2858 Date 08/01/02
2859
2860 See libtcd.html for changelog.
2861
2862\*****************************************************************************/
2863
2864NV_INT32 get_nearest_partial_tide_record(NV_FLOAT64 lat, NV_FLOAT64 lon,
2865 TIDE_STATION_HEADER *rec) {
2866 NV_FLOAT64 diff, min_diff, lt, ln;
2867 NV_U_INT32 i, shortest = 0;
2868
2869 min_diff = 999999999.9;
2870 for (i = 0; i < hd.pub.number_of_records; ++i) {
2871 lt = (NV_FLOAT64)tindex[i].lat / hd.latitude_scale;
2872 ln = (NV_FLOAT64)tindex[i].lon / hd.longitude_scale;
2873
2874 diff = sqrt((lat - lt) * (lat - lt) + (lon - ln) * (lon - ln));
2875
2876 if (diff < min_diff) {
2877 min_diff = diff;
2878 shortest = i;
2879 }
2880 }
2881
2882 if (!get_partial_tide_record(shortest, rec)) return (-1);
2883 return (shortest);
2884}
2885
2886/*****************************************************************************\
2887
2888 Function get_time - converts a time string in +/-HH:MM form to an
2889 integer in +/-HHMM form
2890
2891 Synopsis get_time (string);
2892
2893 NV_CHAR *string time string
2894
2895 Returns NV_INT32 time
2896
2897 Author Jan C. Depner
2898 Date 08/01/02
2899
2900 See libtcd.html for changelog.
2901
2902\*****************************************************************************/
2903
2904NV_INT32 get_time(const NV_CHAR *string) {
2905 NV_INT32 hour, minute, hhmm;
2906
2907 assert(string);
2908 sscanf(string, "%d:%d", &hour, &minute);
2909
2910 /* Trying to deal with negative 0 (-00:45). */
2911
2912 if (string[0] == '-') {
2913 if (hour < 0) hour = -hour;
2914
2915 hhmm = -(hour * 100 + minute);
2916 } else {
2917 hhmm = hour * 100 + minute;
2918 }
2919
2920 return (hhmm);
2921}
2922
2923/*****************************************************************************\
2924
2925 Function ret_time - converts a time value in +/-HHMM form to a
2926 time string in +/-HH:MM form
2927
2928 Synopsis ret_time (time);
2929
2930 NV_INT32 time
2931
2932 Returns NV_CHAR * time string
2933
2934 Author Jan C. Depner
2935 Date 08/01/02
2936
2937 See libtcd.html for changelog.
2938
2939\*****************************************************************************/
2940
2941NV_CHAR *ret_time(NV_INT32 time) {
2942 NV_INT32 hour, minute;
2943 static NV_CHAR tname[16];
2944
2945 hour = abs(time) / 100;
2946 assert(hour <= 99999 && hour >= -99999); /* 9 chars: +99999:99 */
2947 minute = abs(time) % 100;
2948
2949 if (time < 0) {
2950 sprintf(tname, "-%02d:%02d", hour, minute);
2951 } else {
2952 sprintf(tname, "+%02d:%02d", hour, minute);
2953 }
2954
2955 return tname;
2956}
2957
2958/*****************************************************************************\
2959 DWF 2004-10-04
2960\*****************************************************************************/
2961NV_CHAR *ret_time_neat(NV_INT32 time) {
2962 NV_INT32 hour, minute;
2963 static NV_CHAR tname[16];
2964
2965 hour = abs(time) / 100;
2966 assert(hour <= 99999 && hour >= -99999); /* 9 chars: +99999:99 */
2967 minute = abs(time) % 100;
2968
2969 if (time < 0)
2970 sprintf(tname, "-%d:%02d", hour, minute);
2971 else if (time > 0)
2972 sprintf(tname, "+%d:%02d", hour, minute);
2973 else
2974 strcpy(tname, "0:00");
2975
2976 return tname;
2977}
2978
2979/*****************************************************************************\
2980 DWF 2004-10-04
2981\*****************************************************************************/
2982NV_CHAR *ret_date(NV_U_INT32 date) {
2983 static NV_CHAR tname[30];
2984 if (!date)
2985 strcpy(tname, "NULL");
2986 else {
2987 unsigned y, m, d;
2988 y = date / 10000;
2989 date %= 10000;
2990 m = date / 100;
2991 d = date % 100;
2992 sprintf(tname, "%4u-%02u-%02u", y, m, d);
2993 }
2994 return tname;
2995}
2996
2997/*****************************************************************************\
2998
2999 Function get_tide_db_header - gets the public portion of the tide
3000 database header
3001
3002 Synopsis get_tide_db_header ();
3003
3004 Returns DB_HEADER_PUBLIC public tide header
3005
3006 Author Jan C. Depner
3007 Date 08/01/02
3008
3009 See libtcd.html for changelog.
3010
3011\*****************************************************************************/
3012
3013DB_HEADER_PUBLIC get_tide_db_header() {
3014 if (!fp) {
3015 LOG_ERROR(
3016 "libtcd error: attempt to access database when database not open\n");
3017 exit(-1);
3018 }
3019 return (hd.pub);
3020}
3021
3022/*****************************************************************************\
3023 DWF 2004-09-30
3024 Prevent buffer overflows for MONOLOGUE_LENGTH strings.
3025\*****************************************************************************/
3026static void boundscheck_monologue(const NV_CHAR *string) {
3027 assert(string);
3028 if (strlen(string) >= MONOLOGUE_LENGTH) {
3029 // LOG_ERROR ("libtcd fatal error: static buffer size exceeded\n");
3030 // LOG_ERROR ("Buffer is size MONOLOGUE_LENGTH (%u)\n",
3031 // MONOLOGUE_LENGTH);
3032 // LOG_ERROR ("String is length %lu\n", strlen(string));
3033 // LOG_ERROR ("The offending string is:\n%s\n", string);
3034 exit(-1);
3035 }
3036}
3037
3038/*****************************************************************************\
3039 DWF 2004-09-30
3040 Prevent buffer overflows for ONELINER_LENGTH strings.
3041\*****************************************************************************/
3042static void boundscheck_oneliner(const NV_CHAR *string) {
3043 assert(string);
3044 if (strlen(string) >= ONELINER_LENGTH) {
3045 // LOG_ERROR ("libtcd fatal error: static buffer size exceeded\n");
3046 // LOG_ERROR ("Buffer is size ONELINER_LENGTH (%u)\n",
3047 // ONELINER_LENGTH);
3048 // LOG_ERROR ("String is length %lu\n", strlen(string));
3049 // LOG_ERROR ("The offending string is:\n%s\n", string);
3050 exit(-1);
3051 }
3052}
3053
3054/*****************************************************************************\
3055
3056 Function clip_string - removes leading and trailing spaces from
3057 search strings.
3058
3059 Synopsis clip_string (string);
3060
3061 NV_CHAR *string search string
3062
3063 Returns NV_CHAR * clipped string
3064
3065 Author Jan C. Depner
3066 Date 09/16/02
3067
3068 See libtcd.html for changelog.
3069
3070\*****************************************************************************/
3071
3072static NV_CHAR *clip_string(const NV_CHAR *string) {
3073 static NV_CHAR new_string[MONOLOGUE_LENGTH];
3074 NV_INT32 i, l, start = -1, end = -1;
3075
3076 boundscheck_monologue(string);
3077 new_string[0] = '\0';
3078
3079 l = (int)strlen(string);
3080 if (l) {
3081 for (i = 0; i < l; ++i) {
3082 if (string[i] != ' ') {
3083 start = i;
3084 break;
3085 }
3086 }
3087 for (i = l - 1; i >= start; --i) {
3088 if (string[i] != ' ' && string[i] != 10 && string[i] != 13) {
3089 end = i;
3090 break;
3091 }
3092 }
3093 if (start > -1 && end > -1 && end >= start) {
3094 strncpy(new_string, string + start, end - start + 1);
3095 new_string[end - start + 1] = '\0';
3096 }
3097 }
3098 return new_string;
3099}
3100
3101/*****************************************************************************\
3102
3103 Function search_station - returns record numbers of all stations
3104 that have the string "string" anywhere in the station
3105 name. This search is case insensitive. When no more
3106 records are found it returns -1;
3107
3108 Synopsis search_station (string);
3109
3110 NV_CHAR *string search string
3111
3112 Returns NV_INT32 record number or -1 when no more
3113 matches
3114
3115 Author Jan C. Depner
3116 Date 08/01/02
3117
3118 See libtcd.html for changelog.
3119
3120\*****************************************************************************/
3121
3122NV_INT32 search_station(const NV_CHAR *string) {
3123 static NV_CHAR last_search[ONELINER_LENGTH];
3124 static NV_U_INT32 j = 0;
3125 NV_U_INT32 i;
3126 NV_CHAR name[ONELINER_LENGTH], search[ONELINER_LENGTH];
3127
3128 if (!fp) {
3129 LOG_ERROR(
3130 "libtcd error: attempt to access database when database not open\n");
3131 return -1;
3132 }
3133
3134 boundscheck_oneliner(string);
3135
3136 for (i = 0; i < strlen(string) + 1; ++i) search[i] = tolower(string[i]);
3137
3138 if (strcmp(search, last_search)) j = 0;
3139
3140 strcpy(last_search, search);
3141
3142 while (j < hd.pub.number_of_records) {
3143 for (i = 0; i < strlen(tindex[j].name) + 1; ++i)
3144 name[i] = tolower(tindex[j].name[i]);
3145
3146 ++j;
3147 if (strstr(name, search)) return (j - 1);
3148 }
3149
3150 j = 0;
3151 return -1;
3152}
3153
3154/*****************************************************************************\
3155
3156 Function find_station - finds the record number of the station
3157 that has name "name"
3158
3159 Synopsis find_station (name);
3160
3161 NV_CHAR *name station name
3162
3163 Returns NV_INT32 record number
3164
3165 Author Jan C. Depner
3166 Date 08/01/02
3167
3168 See libtcd.html for changelog.
3169
3170\*****************************************************************************/
3171
3172NV_INT32 find_station(const NV_CHAR *name) {
3173 NV_U_INT32 i;
3174
3175 if (!fp) {
3176 LOG_ERROR(
3177 "libtcd error: attempt to access database when database not open\n");
3178 return -1;
3179 }
3180
3181 assert(name);
3182 for (i = 0; i < hd.pub.number_of_records; ++i) {
3183 if (!strcmp(name, tindex[i].name)) return (i);
3184 }
3185
3186 return (-1);
3187}
3188
3189/*****************************************************************************\
3190
3191 Function find_tzfile - gets the timezone number (index into
3192 tzfile array) given the tzfile name
3193
3194 Synopsis find_tzfile (name);
3195
3196 NV_CHAR *name tzfile name
3197
3198 Returns NV_INT32 tzfile number
3199
3200 Author Jan C. Depner
3201 Date 08/01/02
3202
3203 See libtcd.html for changelog.
3204
3205\*****************************************************************************/
3206
3207NV_INT32 find_tzfile(const NV_CHAR *name) {
3208 NV_INT32 j;
3209 NV_U_INT32 i;
3210 NV_CHAR *temp;
3211
3212 if (!fp) {
3213 LOG_ERROR(
3214 "libtcd error: attempt to access database when database not open\n");
3215 return -1;
3216 }
3217
3218 temp = clip_string(name);
3219
3220 j = -1;
3221 for (i = 0; i < hd.pub.tzfiles; ++i) {
3222 if (!strcmp(temp, get_tzfile(i))) {
3223 j = i;
3224 break;
3225 }
3226 }
3227
3228 return (j);
3229}
3230
3231/*****************************************************************************\
3232
3233 Function find_country - gets the timezone number (index into
3234 country array) given the country name
3235
3236 Synopsis find_country (name);
3237
3238 NV_CHAR *name country name
3239
3240 Returns NV_INT32 country number
3241
3242 Author Jan C. Depner
3243 Date 08/01/02
3244
3245 See libtcd.html for changelog.
3246
3247\*****************************************************************************/
3248
3249NV_INT32 find_country(const NV_CHAR *name) {
3250 NV_INT32 j;
3251 NV_U_INT32 i;
3252 NV_CHAR *temp;
3253
3254 if (!fp) {
3255 LOG_ERROR(
3256 "libtcd error: attempt to access database when database not open\n");
3257 return -1;
3258 }
3259
3260 temp = clip_string(name);
3261
3262 j = -1;
3263 for (i = 0; i < hd.pub.countries; ++i) {
3264 if (!strcmp(temp, get_country(i))) {
3265 j = i;
3266 break;
3267 }
3268 }
3269
3270 return (j);
3271}
3272
3273/*****************************************************************************\
3274
3275 Function find_level_units - gets the index into the level_units
3276 array given the level units name
3277
3278 Synopsis find_level_units (name);
3279
3280 NV_CHAR *name units name (ex. "meters")
3281
3282 Returns NV_INT32 units number
3283
3284 Author Jan C. Depner
3285 Date 08/01/02
3286
3287 See libtcd.html for changelog.
3288
3289\*****************************************************************************/
3290
3291NV_INT32 find_level_units(const NV_CHAR *name) {
3292 NV_INT32 j;
3293 NV_U_INT32 i;
3294 NV_CHAR *temp;
3295
3296 if (!fp) {
3297 LOG_ERROR(
3298 "libtcd error: attempt to access database when database not open\n");
3299 return -1;
3300 }
3301
3302 temp = clip_string(name);
3303
3304 j = -1;
3305 for (i = 0; i < hd.pub.level_unit_types; ++i) {
3306 if (!strcmp(get_level_units(i), temp)) {
3307 j = i;
3308 break;
3309 }
3310 }
3311
3312 return (j);
3313}
3314
3315/*****************************************************************************\
3316
3317 Function find_dir_units - gets the index into the dir_units
3318 array given the direction units name
3319
3320 Synopsis find_dir_units (name);
3321
3322 NV_CHAR *name units name (ex. "degrees true")
3323
3324 Returns NV_INT32 units number
3325
3326 Author Jan C. Depner
3327 Date 08/01/02
3328
3329 See libtcd.html for changelog.
3330
3331\*****************************************************************************/
3332
3333NV_INT32 find_dir_units(const NV_CHAR *name) {
3334 NV_INT32 j;
3335 NV_U_INT32 i;
3336 NV_CHAR *temp;
3337
3338 if (!fp) {
3339 LOG_ERROR(
3340 "libtcd error: attempt to access database when database not open\n");
3341 return -1;
3342 }
3343
3344 temp = clip_string(name);
3345
3346 j = -1;
3347 for (i = 0; i < hd.pub.dir_unit_types; ++i) {
3348 if (!strcmp(get_dir_units(i), temp)) {
3349 j = i;
3350 break;
3351 }
3352 }
3353
3354 return (j);
3355}
3356
3357/*****************************************************************************\
3358
3359 Function find_pedigree - gets the index into the pedigree array
3360 given the pedigree name
3361
3362 Synopsis find_pedigree (name);
3363
3364 NV_CHAR *name pedigree name
3365
3366 Returns NV_INT32 pedigree number
3367
3368 Author Jan C. Depner
3369 Date 08/01/02
3370
3371 See libtcd.html for changelog.
3372
3373\*****************************************************************************/
3374
3375#ifdef COMPAT114
3376NV_INT32 find_pedigree(const NV_CHAR *name) { return 0; }
3377#endif
3378
3379/*****************************************************************************\
3380
3381 Function find_datum - gets the index into the datum array given the
3382 datum name
3383
3384 Synopsis find_datum (name);
3385
3386 NV_CHAR *name datum name
3387
3388 Returns NV_INT32 datum number
3389
3390 Author Jan C. Depner
3391 Date 08/01/02
3392
3393 See libtcd.html for changelog.
3394
3395\*****************************************************************************/
3396
3397NV_INT32 find_datum(const NV_CHAR *name) {
3398 NV_INT32 j;
3399 NV_U_INT32 i;
3400 NV_CHAR *temp;
3401
3402 if (!fp) {
3403 LOG_ERROR(
3404 "libtcd error: attempt to access database when database not open\n");
3405 return -1;
3406 }
3407
3408 temp = clip_string(name);
3409
3410 j = -1;
3411 for (i = 0; i < hd.pub.datum_types; ++i) {
3412 if (!strcmp(get_datum(i), temp)) {
3413 j = i;
3414 break;
3415 }
3416 }
3417
3418 return (j);
3419}
3420
3421/*****************************************************************************\
3422 DWF 2004-10-14
3423\*****************************************************************************/
3424NV_INT32 find_legalese(const NV_CHAR *name) {
3425 NV_INT32 j;
3426 NV_U_INT32 i;
3427 NV_CHAR *temp;
3428
3429 if (!fp) {
3430 LOG_ERROR(
3431 "libtcd error: attempt to access database when database not open\n");
3432 return -1;
3433 }
3434
3435 temp = clip_string(name);
3436
3437 j = -1;
3438 for (i = 0; i < hd.pub.legaleses; ++i) {
3439 if (!strcmp(get_legalese(i), temp)) {
3440 j = i;
3441 break;
3442 }
3443 }
3444
3445 return (j);
3446}
3447
3448/*****************************************************************************\
3449
3450 Function find_constituent - gets the index into the constituent
3451 arrays for the named constituent.
3452
3453 Synopsis find_constituent (name);
3454
3455 NV_CHAR *name constituent name (ex. M2)
3456
3457 Returns NV_INT32 index into constituent arrays or -1
3458 on failure
3459
3460 Author Jan C. Depner
3461 Date 08/01/02
3462
3463 See libtcd.html for changelog.
3464
3465\*****************************************************************************/
3466
3467NV_INT32 find_constituent(const NV_CHAR *name) {
3468 NV_U_INT32 i;
3469 NV_CHAR *temp;
3470
3471 if (!fp) {
3472 LOG_ERROR(
3473 "libtcd error: attempt to access database when database not open\n");
3474 return -1;
3475 }
3476
3477 temp = clip_string(name);
3478
3479 for (i = 0; i < hd.pub.constituents; ++i) {
3480 if (!strcmp(get_constituent(i), temp)) return (i);
3481 }
3482
3483 return (-1);
3484}
3485
3486/*****************************************************************************\
3487
3488 Function find_restriction - gets the index into the restriction
3489 array given the restriction name
3490
3491 Synopsis find_restriction (name);
3492
3493 NV_CHAR *name restriction name
3494
3495 Returns NV_INT32 restriction number
3496
3497 Author Jan C. Depner
3498 Date 08/01/02
3499
3500 See libtcd.html for changelog.
3501
3502\*****************************************************************************/
3503
3504NV_INT32 find_restriction(const NV_CHAR *name) {
3505 NV_INT32 j;
3506 NV_U_INT32 i;
3507 NV_CHAR *temp;
3508
3509 if (!fp) {
3510 LOG_ERROR(
3511 "libtcd error: attempt to access database when database not open\n");
3512 return -1;
3513 }
3514
3515 temp = clip_string(name);
3516
3517 j = -1;
3518 for (i = 0; i < hd.pub.restriction_types; ++i) {
3519 if (!strcmp(get_restriction(i), temp)) {
3520 j = i;
3521 break;
3522 }
3523 }
3524 return (j);
3525}
3526
3527/*****************************************************************************\
3528
3529 Function set_speed - sets the speed value for constituent "num"
3530
3531 Synopsis set_speed (num, value);
3532
3533 NV_INT32 num constituent number
3534 NV_FLOAT64 value speed value
3535
3536 Returns void
3537
3538 Author Jan C. Depner
3539 Date 08/01/02
3540
3541 See libtcd.html for changelog.
3542
3543\*****************************************************************************/
3544
3545void set_speed(NV_INT32 num, NV_FLOAT64 value) {
3546 if (!fp) {
3547 LOG_ERROR(
3548 "libtcd error: attempt to access database when database not open\n");
3549 exit(-1);
3550 }
3551 write_protect();
3552 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents);
3553 if (value < 0.0) {
3554 LOG_ERROR("libtcd set_speed: somebody tried to set a negative speed (%f)\n",
3555 value);
3556 exit(-1);
3557 }
3558 hd.speed[num] = value;
3559 modified = NVTrue;
3560}
3561
3562/*****************************************************************************\
3563
3564 Function set_equilibrium - sets the equilibrium argument for
3565 constituent "num" and year "year"
3566
3567 Synopsis set_equilibrium (num, year, value);
3568
3569 NV_INT32 num constituent number
3570 NV_INT32 year year
3571 NV_FLOAT64 value equilibrium argument
3572
3573 Returns void
3574
3575 Author Jan C. Depner
3576 Date 08/01/02
3577
3578 See libtcd.html for changelog.
3579
3580\*****************************************************************************/
3581
3582void set_equilibrium(NV_INT32 num, NV_INT32 year, NV_FLOAT32 value) {
3583 if (!fp) {
3584 LOG_ERROR(
3585 "libtcd error: attempt to access database when database not open\n");
3586 exit(-1);
3587 }
3588 write_protect();
3589 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents && year >= 0 &&
3590 year < (NV_INT32)hd.pub.number_of_years);
3591 hd.equilibrium[num][year] = value;
3592 modified = NVTrue;
3593}
3594
3595/*****************************************************************************\
3596
3597 Function set_node_factor - sets the node factor for constituent
3598 "num" and year "year"
3599
3600 Synopsis set_node_factor (num, year, value);
3601
3602 NV_INT32 num constituent number
3603 NV_INT32 year year
3604 NV_FLOAT64 value node factor
3605
3606 Returns void
3607
3608 Author Jan C. Depner
3609 Date 08/01/02
3610
3611 See libtcd.html for changelog.
3612
3613\*****************************************************************************/
3614
3615void set_node_factor(NV_INT32 num, NV_INT32 year, NV_FLOAT32 value) {
3616 if (!fp) {
3617 LOG_ERROR(
3618 "libtcd error: attempt to access database when database not open\n");
3619 exit(-1);
3620 }
3621 write_protect();
3622 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents && year >= 0 &&
3623 year < (NV_INT32)hd.pub.number_of_years);
3624 if (value <= 0.0) {
3625 LOG_ERROR(
3626 "libtcd set_node_factor: somebody tried to set a negative or zero node "
3627 "factor (%f)\n",
3628 value);
3629 exit(-1);
3630 }
3631 hd.node_factor[num][year] = value;
3632 modified = NVTrue;
3633}
3634
3635/*****************************************************************************\
3636
3637 Function add_pedigree - adds a new pedigree to the database
3638
3639 Synopsis add_pedigree (name, db);
3640
3641 NV_CHAR *name new pedigree string
3642 DB_HEADER_PUBLIC *db modified header
3643
3644 Returns NV_INT32 new pedigree index
3645
3646 Author Jan C. Depner
3647 Date 09/20/02
3648
3649 See libtcd.html for changelog.
3650
3651\*****************************************************************************/
3652
3653#ifdef COMPAT114
3654NV_INT32 add_pedigree(const NV_CHAR *name, const DB_HEADER_PUBLIC *db) {
3655 return 0;
3656}
3657#endif
3658
3659/*****************************************************************************\
3660
3661 Function add_tzfile - adds a new tzfile to the database
3662
3663 Synopsis add_tzfile (name, db);
3664
3665 NV_CHAR *name new tzfile string
3666 DB_HEADER_PUBLIC *db modified header
3667
3668 Returns NV_INT32 new tzfile index
3669
3670 Author Jan C. Depner
3671 Date 09/20/02
3672
3673 See libtcd.html for changelog.
3674
3675\*****************************************************************************/
3676
3677NV_INT32 add_tzfile(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3678 NV_CHAR *c_name;
3679
3680 if (!fp) {
3681 LOG_ERROR(
3682 "libtcd error: attempt to access database when database not open\n");
3683 exit(-1);
3684 }
3685 write_protect();
3686
3687 assert(name);
3688 if (strlen(name) + 1 > hd.tzfile_size) {
3689 LOG_ERROR("libtcd error: tzfile exceeds size limit (%u).\n",
3690 hd.tzfile_size);
3691 LOG_ERROR("The offending input is: %s\n", name);
3692 exit(-1);
3693 }
3694
3695 if (hd.pub.tzfiles == hd.max_tzfiles) {
3696 LOG_ERROR("You have exceeded the maximum number of tzfile types!\n");
3697 LOG_ERROR("You cannot add any new tzfile types.\n");
3698 LOG_ERROR("Modify the DEFAULT_TZFILE_BITS and rebuild the database.\n");
3699 exit(-1);
3700 }
3701
3702 c_name = clip_string(name);
3703
3704 hd.tzfile[hd.pub.tzfiles] =
3705 (NV_CHAR *)calloc(strlen(c_name) + 1, sizeof(NV_CHAR));
3706
3707 if (hd.tzfile[hd.pub.tzfiles] == NULL) {
3708 perror("Allocating new tzfile string");
3709 exit(-1);
3710 }
3711
3712 strcpy(hd.tzfile[hd.pub.tzfiles++], c_name);
3713 if (db) *db = hd.pub;
3714 modified = NVTrue;
3715 return (hd.pub.tzfiles - 1);
3716}
3717
3718/*****************************************************************************\
3719
3720 Function add_country - adds a new country to the database
3721
3722 Synopsis add_country (name, db);
3723
3724 NV_CHAR *name new country string
3725 DB_HEADER_PUBLIC *db modified header
3726
3727 Returns NV_INT32 new country index
3728
3729 Author Jan C. Depner
3730 Date 09/20/02
3731
3732 See libtcd.html for changelog.
3733
3734\*****************************************************************************/
3735
3736NV_INT32 add_country(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3737 NV_CHAR *c_name;
3738
3739 if (!fp) {
3740 LOG_ERROR(
3741 "libtcd error: attempt to access database when database not open\n");
3742 exit(-1);
3743 }
3744 write_protect();
3745
3746 assert(name);
3747 if (strlen(name) + 1 > hd.country_size) {
3748 LOG_ERROR("libtcd error: country exceeds size limit (%u).\n",
3749 hd.country_size);
3750 LOG_ERROR("The offending input is: %s\n", name);
3751 exit(-1);
3752 }
3753
3754 if (hd.pub.countries == hd.max_countries) {
3755 LOG_ERROR("You have exceeded the maximum number of country names!\n");
3756 LOG_ERROR("You cannot add any new country names.\n");
3757 LOG_ERROR("Modify the DEFAULT_COUNTRY_BITS and rebuild the database.\n");
3758 exit(-1);
3759 }
3760
3761 c_name = clip_string(name);
3762
3763 hd.country[hd.pub.countries] =
3764 (NV_CHAR *)calloc(strlen(c_name) + 1, sizeof(NV_CHAR));
3765
3766 if (hd.country[hd.pub.countries] == NULL) {
3767 perror("Allocating new country string");
3768 exit(-1);
3769 }
3770
3771 strcpy(hd.country[hd.pub.countries++], c_name);
3772 if (db) *db = hd.pub;
3773 modified = NVTrue;
3774 return (hd.pub.countries - 1);
3775}
3776
3777/*****************************************************************************\
3778
3779 Function add_datum - adds a new datum to the database
3780
3781 Synopsis add_datum (name, db);
3782
3783 NV_CHAR *name new datum string
3784 DB_HEADER_PUBLIC *db modified header
3785
3786 Returns NV_INT32 new datum index
3787
3788 Author Jan C. Depner
3789 Date 09/20/02
3790
3791 See libtcd.html for changelog.
3792
3793\*****************************************************************************/
3794
3795NV_INT32 add_datum(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3796 NV_CHAR *c_name;
3797
3798 if (!fp) {
3799 LOG_ERROR(
3800 "libtcd error: attempt to access database when database not open\n");
3801 exit(-1);
3802 }
3803 write_protect();
3804
3805 assert(name);
3806 if (strlen(name) + 1 > hd.datum_size) {
3807 LOG_ERROR("libtcd error: datum exceeds size limit (%u).\n", hd.datum_size);
3808 LOG_ERROR("The offending input is: %s\n", name);
3809 exit(-1);
3810 }
3811
3812 if (hd.pub.datum_types == hd.max_datum_types) {
3813 LOG_ERROR("You have exceeded the maximum number of datum types!\n");
3814 LOG_ERROR("You cannot add any new datum types.\n");
3815 LOG_ERROR("Modify the DEFAULT_DATUM_BITS and rebuild the database.\n");
3816 exit(-1);
3817 }
3818
3819 c_name = clip_string(name);
3820
3821 hd.datum[hd.pub.datum_types] =
3822 (NV_CHAR *)calloc(strlen(c_name) + 1, sizeof(NV_CHAR));
3823
3824 if (hd.datum[hd.pub.datum_types] == NULL) {
3825 perror("Allocating new datum string");
3826 exit(-1);
3827 }
3828
3829 strcpy(hd.datum[hd.pub.datum_types++], c_name);
3830 if (db) *db = hd.pub;
3831 modified = NVTrue;
3832 return (hd.pub.datum_types - 1);
3833}
3834
3835/*****************************************************************************\
3836 DWF 2004-10-14
3837\*****************************************************************************/
3838NV_INT32 add_legalese(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3839 NV_CHAR *c_name;
3840
3841 if (!fp) {
3842 LOG_ERROR(
3843 "libtcd error: attempt to access database when database not open\n");
3844 exit(-1);
3845 }
3846 write_protect();
3847
3848 assert(name);
3849 if (strlen(name) + 1 > hd.legalese_size) {
3850 LOG_ERROR("libtcd error: legalese exceeds size limit (%u).\n",
3851 hd.legalese_size);
3852 LOG_ERROR("The offending input is: %s\n", name);
3853 exit(-1);
3854 }
3855
3856 if (hd.pub.legaleses == hd.max_legaleses) {
3857 LOG_ERROR("You have exceeded the maximum number of legaleses!\n");
3858 LOG_ERROR("You cannot add any new legaleses.\n");
3859 LOG_ERROR("Modify the DEFAULT_LEGALESE_BITS and rebuild the database.\n");
3860 exit(-1);
3861 }
3862
3863 c_name = clip_string(name);
3864
3865 hd.legalese[hd.pub.legaleses] =
3866 (NV_CHAR *)calloc(strlen(c_name) + 1, sizeof(NV_CHAR));
3867
3868 if (hd.legalese[hd.pub.legaleses] == NULL) {
3869 perror("Allocating new legalese string");
3870 exit(-1);
3871 }
3872
3873 strcpy(hd.legalese[hd.pub.legaleses++], c_name);
3874 if (db) *db = hd.pub;
3875 modified = NVTrue;
3876 return (hd.pub.legaleses - 1);
3877}
3878
3879/*****************************************************************************\
3880
3881 Function add_restriction - adds a new restriction to the database
3882
3883 Synopsis add_restriction (name, db);
3884
3885 NV_CHAR *name new restriction string
3886 DB_HEADER_PUBLIC *db modified header
3887
3888 Returns NV_INT32 new restriction index
3889
3890 Author Jan C. Depner
3891 Date 09/20/02
3892
3893 See libtcd.html for changelog.
3894
3895\*****************************************************************************/
3896
3897NV_INT32 add_restriction(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3898 NV_CHAR *c_name;
3899
3900 if (!fp) {
3901 LOG_ERROR(
3902 "libtcd error: attempt to access database when database not open\n");
3903 exit(-1);
3904 }
3905 write_protect();
3906
3907 assert(name);
3908 if (strlen(name) + 1 > hd.restriction_size) {
3909 LOG_ERROR("libtcd error: restriction exceeds size limit (%u).\n",
3910 hd.restriction_size);
3911 LOG_ERROR("The offending input is: %s\n", name);
3912 exit(-1);
3913 }
3914
3915 if (hd.pub.restriction_types == hd.max_restriction_types) {
3916 LOG_ERROR("You have exceeded the maximum number of restriction types!\n");
3917 LOG_ERROR("You cannot add any new restriction types.\n");
3918 LOG_ERROR(
3919 "Modify the DEFAULT_RESTRICTION_BITS and rebuild the database.\n");
3920 exit(-1);
3921 }
3922
3923 c_name = clip_string(name);
3924
3925 hd.restriction[hd.pub.restriction_types] =
3926 (NV_CHAR *)calloc(strlen(c_name) + 1, sizeof(NV_CHAR));
3927
3928 if (hd.restriction[hd.pub.restriction_types] == NULL) {
3929 perror("Allocating new restriction string");
3930 exit(-1);
3931 }
3932
3933 strcpy(hd.restriction[hd.pub.restriction_types++], c_name);
3934 if (db) *db = hd.pub;
3935 modified = NVTrue;
3936 return (hd.pub.restriction_types - 1);
3937}
3938
3939/*****************************************************************************\
3940 DWF 2004-10-04
3941\*****************************************************************************/
3942NV_INT32 find_or_add_restriction(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3943 NV_INT32 ret;
3944 ret = find_restriction(name);
3945 if (ret < 0) ret = add_restriction(name, db);
3946 assert(ret >= 0);
3947 return ret;
3948}
3949
3950/*****************************************************************************\
3951 DWF 2004-10-04
3952\*****************************************************************************/
3953NV_INT32 find_or_add_tzfile(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3954 NV_INT32 ret;
3955 ret = find_tzfile(name);
3956 if (ret < 0) ret = add_tzfile(name, db);
3957 assert(ret >= 0);
3958 return ret;
3959}
3960
3961/*****************************************************************************\
3962 DWF 2004-10-04
3963\*****************************************************************************/
3964NV_INT32 find_or_add_country(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3965 NV_INT32 ret;
3966 ret = find_country(name);
3967 if (ret < 0) ret = add_country(name, db);
3968 assert(ret >= 0);
3969 return ret;
3970}
3971
3972/*****************************************************************************\
3973 DWF 2004-10-04
3974\*****************************************************************************/
3975NV_INT32 find_or_add_datum(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3976 NV_INT32 ret;
3977 ret = find_datum(name);
3978 if (ret < 0) ret = add_datum(name, db);
3979 assert(ret >= 0);
3980 return ret;
3981}
3982
3983/*****************************************************************************\
3984 DWF 2004-10-14
3985\*****************************************************************************/
3986NV_INT32 find_or_add_legalese(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3987 NV_INT32 ret;
3988 ret = find_legalese(name);
3989 if (ret < 0) ret = add_legalese(name, db);
3990 assert(ret >= 0);
3991 return ret;
3992}
3993
3994/*****************************************************************************\
3995
3996 Function check_simple - checks tide record to see if it is a
3997 "simple" subordinate station.
3998
3999 Synopsis check_simple (rec);
4000
4001 TIDE_RECORD rec tide record
4002
4003 Returns NV_BOOL NVTrue if "simple"
4004
4005 Author Jan C. Depner
4006 Date 08/01/02
4007
4008 See libtcd.html for changelog.
4009
4010 "Simplified" type 2 records were done away with 2003-03-27 per the
4011 discussion in http://www.flaterco.com/xtide/tcd_notes.html. This
4012 function is now of interest only in restore_tide_db, which uses it
4013 to determine which XML format to output. Deprecated here, moved
4014 to restore_tide_db.
4015
4016\*****************************************************************************/
4017
4018#ifdef COMPAT114
4019NV_BOOL check_simple(TIDE_RECORD rec) {
4020 if (rec.max_time_add == rec.min_time_add &&
4021 rec.max_level_add == rec.min_level_add &&
4022 rec.max_level_multiply == rec.min_level_multiply &&
4023 rec.max_avg_level == 0 && rec.min_avg_level == 0 &&
4024 rec.max_direction == 361 && rec.min_direction == 361 &&
4025 rec.flood_begins == NULLSLACKOFFSET && rec.ebb_begins == NULLSLACKOFFSET)
4026 return (NVTrue);
4027
4028 return (NVFalse);
4029}
4030#endif
4031
4032/*****************************************************************************\
4033
4034 Function header_checksum - compute the checksum for the ASCII
4035 portion of the database header
4036
4037 Synopsis header_checksum ();
4038
4039 Returns NV_U_INT32 checksum value
4040
4041 Author Jan C. Depner
4042 Date 08/01/02
4043
4044 See libtcd.html for changelog.
4045
4046\*****************************************************************************/
4047
4048static NV_U_INT32 header_checksum() {
4049 NV_U_INT32 checksum, i, save_pos;
4050 NV_U_BYTE *buf;
4051 NV_U_INT32 crc_table[256] = {
4052 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
4053 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
4054 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
4055 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
4056 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
4057 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
4058 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
4059 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
4060 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
4061 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
4062 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
4063 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
4064 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
4065 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
4066 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
4067 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
4068 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
4069 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
4070 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
4071 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
4072 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
4073 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
4074 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
4075 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
4076 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
4077 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
4078 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
4079 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
4080 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
4081 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
4082 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
4083 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
4084 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
4085 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
4086 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
4087 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
4088 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
4089 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
4090 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
4091 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
4092 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
4093 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
4094 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
4095
4096 if (!fp) {
4097 LOG_ERROR(
4098 "libtcd error: attempt to access database when database not open\n");
4099 exit(-1);
4100 }
4101
4102 save_pos = ftell(fp);
4103
4104 fseek(fp, 0, SEEK_SET);
4105
4106 if ((buf = (NV_U_BYTE *)calloc(hd.header_size, sizeof(NV_U_BYTE))) == NULL) {
4107 perror("Allocating checksum buffer");
4108 exit(-1);
4109 }
4110
4111 checksum = ~0;
4112
4113 assert(hd.header_size > 0);
4114 chk_fread(buf, hd.header_size, 1, fp);
4115 for (i = 0; i < (NV_U_INT32)hd.header_size; ++i) {
4116 checksum = crc_table[(checksum ^ buf[i]) & 0xff] ^ (checksum >> 8);
4117 }
4118 checksum ^= ~0;
4119
4120 free(buf);
4121
4122 fseek(fp, save_pos, SEEK_SET);
4123
4124 return (checksum);
4125}
4126
4127/*****************************************************************************\
4128
4129 Function old_header_checksum - compute the old-style checksum for
4130 the ASCII portion of the database header just in case this
4131 is a pre 1.02 file.
4132
4133 Synopsis old_header_checksum ();
4134
4135 Returns NV_U_INT32 checksum value
4136
4137 Author Jan C. Depner
4138 Date 11/15/02
4139
4140\*****************************************************************************/
4141
4142#ifdef COMPAT114
4143static NV_U_INT32 old_header_checksum() {
4144 NV_U_INT32 checksum, i, save_pos;
4145 NV_U_BYTE *buf;
4146
4147 if (!fp) {
4148 LOG_ERROR(
4149 "libtcd error: attempt to access database when database not open\n");
4150 exit(-1);
4151 }
4152
4153 save_pos = ftell(fp);
4154
4155 checksum = 0;
4156
4157 fseek(fp, 0, SEEK_SET);
4158
4159 if ((buf = (NV_U_BYTE *)calloc(hd.header_size, sizeof(NV_U_BYTE))) == NULL) {
4160 perror("Allocating checksum buffer");
4161 exit(-1);
4162 }
4163
4164 chk_fread(buf, hd.header_size, 1, fp);
4165
4166 for (i = 0; i < hd.header_size; ++i) checksum += buf[i];
4167
4168 free(buf);
4169
4170 fseek(fp, save_pos, SEEK_SET);
4171
4172 return (checksum);
4173}
4174#endif
4175
4176/*****************************************************************************\
4177 DWF 2004-10-01
4178 Get current time in preferred format.
4179\*****************************************************************************/
4180static NV_CHAR *curtime() {
4181 static NV_CHAR buf[ONELINER_LENGTH];
4182 time_t t = time(NULL);
4183 require(strftime(buf, ONELINER_LENGTH, "%Y-%m-%d %H:%M %Z", localtime(&t)) >
4184 0);
4185 return buf;
4186}
4187
4188/*****************************************************************************\
4189 DWF 2004-10-15
4190 Calculate bytes for number of bits.
4191\*****************************************************************************/
4192static NV_U_INT32 bits2bytes(NV_U_INT32 nbits) {
4193 if (nbits % 8) return nbits / 8 + 1;
4194 return nbits / 8;
4195}
4196
4197/*****************************************************************************\
4198
4199 Function write_tide_db_header - writes the database header to the
4200 file
4201
4202 Synopsis write_tide_db_header ();
4203
4204 Returns void
4205
4206 Author Jan C. Depner
4207 Date 08/01/02
4208
4209 See libtcd.html for changelog.
4210
4211\*****************************************************************************/
4212
4213static void write_tide_db_header() {
4214 NV_U_INT32 i, size, pos;
4215 NV_INT32 start, temp_int;
4216 static NV_CHAR zero = 0;
4217 NV_U_BYTE *buf, checksum_c[4];
4218
4219 if (!fp) {
4220 LOG_ERROR(
4221 "libtcd error: attempt to access database when database not open\n");
4222 exit(-1);
4223 }
4224 write_protect();
4225
4226 fseek(fp, 0, SEEK_SET);
4227
4228 fprintf(fp, "[VERSION] = %s\n", LIBTCD_VERSION);
4229 fprintf(fp, "[MAJOR REV] = %u\n", LIBTCD_MAJOR_REV);
4230 fprintf(fp, "[MINOR REV] = %u\n", LIBTCD_MINOR_REV);
4231
4232 fprintf(fp, "[LAST MODIFIED] = %s\n", curtime());
4233
4234 fprintf(fp, "[HEADER SIZE] = %u\n", hd.header_size);
4235 fprintf(fp, "[NUMBER OF RECORDS] = %u\n", hd.pub.number_of_records);
4236
4237 fprintf(fp, "[START YEAR] = %d\n", hd.pub.start_year);
4238 fprintf(fp, "[NUMBER OF YEARS] = %u\n", hd.pub.number_of_years);
4239
4240 fprintf(fp, "[SPEED BITS] = %u\n", hd.speed_bits);
4241 fprintf(fp, "[SPEED SCALE] = %u\n", hd.speed_scale);
4242 fprintf(fp, "[SPEED OFFSET] = %d\n", hd.speed_offset);
4243 fprintf(fp, "[EQUILIBRIUM BITS] = %u\n", hd.equilibrium_bits);
4244 fprintf(fp, "[EQUILIBRIUM SCALE] = %u\n", hd.equilibrium_scale);
4245 fprintf(fp, "[EQUILIBRIUM OFFSET] = %d\n", hd.equilibrium_offset);
4246 fprintf(fp, "[NODE BITS] = %u\n", hd.node_bits);
4247 fprintf(fp, "[NODE SCALE] = %u\n", hd.node_scale);
4248 fprintf(fp, "[NODE OFFSET] = %d\n", hd.node_offset);
4249 fprintf(fp, "[AMPLITUDE BITS] = %u\n", hd.amplitude_bits);
4250 fprintf(fp, "[AMPLITUDE SCALE] = %u\n", hd.amplitude_scale);
4251 fprintf(fp, "[EPOCH BITS] = %u\n", hd.epoch_bits);
4252 fprintf(fp, "[EPOCH SCALE] = %u\n", hd.epoch_scale);
4253
4254 fprintf(fp, "[RECORD TYPE BITS] = %u\n", hd.record_type_bits);
4255 fprintf(fp, "[LATITUDE BITS] = %u\n", hd.latitude_bits);
4256 fprintf(fp, "[LATITUDE SCALE] = %u\n", hd.latitude_scale);
4257 fprintf(fp, "[LONGITUDE BITS] = %u\n", hd.longitude_bits);
4258 fprintf(fp, "[LONGITUDE SCALE] = %u\n", hd.longitude_scale);
4259 fprintf(fp, "[RECORD SIZE BITS] = %u\n", hd.record_size_bits);
4260
4261 fprintf(fp, "[STATION BITS] = %u\n", hd.station_bits);
4262
4263 fprintf(fp, "[DATUM OFFSET BITS] = %u\n", hd.datum_offset_bits);
4264 fprintf(fp, "[DATUM OFFSET SCALE] = %u\n", hd.datum_offset_scale);
4265 fprintf(fp, "[DATE BITS] = %u\n", hd.date_bits);
4266 fprintf(fp, "[MONTHS ON STATION BITS] = %u\n", hd.months_on_station_bits);
4267 fprintf(fp, "[CONFIDENCE VALUE BITS] = %u\n", hd.confidence_value_bits);
4268
4269 fprintf(fp, "[TIME BITS] = %u\n", hd.time_bits);
4270 fprintf(fp, "[LEVEL ADD BITS] = %u\n", hd.level_add_bits);
4271 fprintf(fp, "[LEVEL ADD SCALE] = %u\n", hd.level_add_scale);
4272 fprintf(fp, "[LEVEL MULTIPLY BITS] = %u\n", hd.level_multiply_bits);
4273 fprintf(fp, "[LEVEL MULTIPLY SCALE] = %u\n", hd.level_multiply_scale);
4274 fprintf(fp, "[DIRECTION BITS] = %u\n", hd.direction_bits);
4275
4276 fprintf(fp, "[LEVEL UNIT BITS] = %u\n", hd.level_unit_bits);
4277 fprintf(fp, "[LEVEL UNIT TYPES] = %u\n", hd.pub.level_unit_types);
4278 fprintf(fp, "[LEVEL UNIT SIZE] = %u\n", hd.level_unit_size);
4279
4280 fprintf(fp, "[DIRECTION UNIT BITS] = %u\n", hd.dir_unit_bits);
4281 fprintf(fp, "[DIRECTION UNIT TYPES] = %u\n", hd.pub.dir_unit_types);
4282 fprintf(fp, "[DIRECTION UNIT SIZE] = %u\n", hd.dir_unit_size);
4283
4284 fprintf(fp, "[RESTRICTION BITS] = %u\n", hd.restriction_bits);
4285 fprintf(fp, "[RESTRICTION TYPES] = %u\n", hd.pub.restriction_types);
4286 fprintf(fp, "[RESTRICTION SIZE] = %u\n", hd.restriction_size);
4287
4288 fprintf(fp, "[DATUM BITS] = %u\n", hd.datum_bits);
4289 fprintf(fp, "[DATUM TYPES] = %u\n", hd.pub.datum_types);
4290 fprintf(fp, "[DATUM SIZE] = %u\n", hd.datum_size);
4291
4292 fprintf(fp, "[LEGALESE BITS] = %u\n", hd.legalese_bits);
4293 fprintf(fp, "[LEGALESE TYPES] = %u\n", hd.pub.legaleses);
4294 fprintf(fp, "[LEGALESE SIZE] = %u\n", hd.legalese_size);
4295
4296 fprintf(fp, "[CONSTITUENT BITS] = %u\n", hd.constituent_bits);
4297 fprintf(fp, "[CONSTITUENTS] = %u\n", hd.pub.constituents);
4298 fprintf(fp, "[CONSTITUENT SIZE] = %u\n", hd.constituent_size);
4299
4300 fprintf(fp, "[TZFILE BITS] = %u\n", hd.tzfile_bits);
4301 fprintf(fp, "[TZFILES] = %u\n", hd.pub.tzfiles);
4302 fprintf(fp, "[TZFILE SIZE] = %u\n", hd.tzfile_size);
4303
4304 fprintf(fp, "[COUNTRY BITS] = %u\n", hd.country_bits);
4305 fprintf(fp, "[COUNTRIES] = %u\n", hd.pub.countries);
4306 fprintf(fp, "[COUNTRY SIZE] = %u\n", hd.country_size);
4307
4308 fprintf(fp, "[END OF FILE] = %u\n", hd.end_of_file);
4309 fprintf(fp, "[END OF ASCII HEADER DATA]\n");
4310
4311 /* Fill the remainder of the [HEADER SIZE] ASCII header with zeroes. */
4312
4313 start = ftell(fp);
4314 assert(start >= 0);
4315 for (i = start; i < hd.header_size; ++i) chk_fwrite(&zero, 1, 1, fp);
4316 fflush(fp);
4317
4318 /* Compute and save the checksum. */
4319
4320 bit_pack(checksum_c, 0, 32, header_checksum());
4321 chk_fwrite(checksum_c, 4, 1, fp);
4322
4323 /* NOTE : Using strcpy for character strings (no endian issue). */
4324
4325 /* Write level units. */
4326
4327 pos = 0;
4328 size = hd.pub.level_unit_types * hd.level_unit_size;
4329
4330 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4331 perror("Allocating unit write buffer");
4332 exit(-1);
4333 }
4334 memset(buf, 0, size);
4335
4336 for (i = 0; i < hd.pub.level_unit_types; ++i) {
4337 assert(strlen(hd.level_unit[i]) + 1 <= hd.level_unit_size);
4338 strcpy((NV_CHAR *)&buf[pos], hd.level_unit[i]);
4339 pos += hd.level_unit_size;
4340 }
4341
4342 chk_fwrite(buf, pos, 1, fp);
4343 free(buf);
4344
4345 /* Write direction units. */
4346
4347 pos = 0;
4348 size = hd.pub.dir_unit_types * hd.dir_unit_size;
4349
4350 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4351 perror("Allocating unit write buffer");
4352 exit(-1);
4353 }
4354 memset(buf, 0, size);
4355
4356 for (i = 0; i < hd.pub.dir_unit_types; ++i) {
4357 assert(strlen(hd.dir_unit[i]) + 1 <= hd.dir_unit_size);
4358 strcpy((NV_CHAR *)&buf[pos], hd.dir_unit[i]);
4359 pos += hd.dir_unit_size;
4360 }
4361
4362 chk_fwrite(buf, pos, 1, fp);
4363 free(buf);
4364
4365 /* Write restrictions. */
4366
4367 pos = 0;
4368 size = hd.max_restriction_types * hd.restriction_size;
4369
4370 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4371 perror("Allocating restriction write buffer");
4372 exit(-1);
4373 }
4374 memset(buf, 0, size);
4375
4376 for (i = 0; i < hd.max_restriction_types; ++i) {
4377 if (i == hd.pub.restriction_types) break;
4378 assert(strlen(hd.restriction[i]) + 1 <= hd.restriction_size);
4379 strcpy((NV_CHAR *)&buf[pos], hd.restriction[i]);
4380 pos += hd.restriction_size;
4381 }
4382 memcpy(&buf[pos], "__END__", 7);
4383
4384 chk_fwrite(buf, size, 1, fp);
4385 free(buf);
4386
4387 /* Write tzfiles. */
4388
4389 pos = 0;
4390 size = hd.max_tzfiles * hd.tzfile_size;
4391
4392 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4393 perror("Allocating tzfile write buffer");
4394 exit(-1);
4395 }
4396 memset(buf, 0, size);
4397
4398 for (i = 0; i < hd.max_tzfiles; ++i) {
4399 if (i == hd.pub.tzfiles) break;
4400 assert(strlen(hd.tzfile[i]) + 1 <= hd.tzfile_size);
4401 strcpy((NV_CHAR *)&buf[pos], hd.tzfile[i]);
4402 pos += hd.tzfile_size;
4403 }
4404 memcpy(&buf[pos], "__END__", 7);
4405
4406 chk_fwrite(buf, size, 1, fp);
4407 free(buf);
4408
4409 /* Write countries. */
4410
4411 pos = 0;
4412 size = hd.max_countries * hd.country_size;
4413
4414 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4415 perror("Allocating country write buffer");
4416 exit(-1);
4417 }
4418 memset(buf, 0, size);
4419
4420 for (i = 0; i < hd.max_countries; ++i) {
4421 if (i == hd.pub.countries) break;
4422 assert(strlen(hd.country[i]) + 1 <= hd.country_size);
4423 strcpy((NV_CHAR *)&buf[pos], hd.country[i]);
4424 pos += hd.country_size;
4425 }
4426 memcpy(&buf[pos], "__END__", 7);
4427
4428 chk_fwrite(buf, size, 1, fp);
4429 free(buf);
4430
4431 /* Write datums. */
4432
4433 pos = 0;
4434 size = hd.max_datum_types * hd.datum_size;
4435
4436 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4437 perror("Allocating datum write buffer");
4438 exit(-1);
4439 }
4440 memset(buf, 0, size);
4441
4442 for (i = 0; i < hd.max_datum_types; ++i) {
4443 if (i == hd.pub.datum_types) break;
4444 assert(strlen(hd.datum[i]) + 1 <= hd.datum_size);
4445 strcpy((NV_CHAR *)&buf[pos], hd.datum[i]);
4446 pos += hd.datum_size;
4447 }
4448 memcpy(&buf[pos], "__END__", 7);
4449
4450 chk_fwrite(buf, size, 1, fp);
4451 free(buf);
4452
4453 /* Write legaleses. */
4454
4455 pos = 0;
4456 size = hd.max_legaleses * hd.legalese_size;
4457
4458 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4459 perror("Allocating legalese write buffer");
4460 exit(-1);
4461 }
4462 memset(buf, 0, size);
4463
4464 for (i = 0; i < hd.max_legaleses; ++i) {
4465 if (i == hd.pub.legaleses) break;
4466 assert(strlen(hd.legalese[i]) + 1 <= hd.legalese_size);
4467 strcpy((NV_CHAR *)&buf[pos], hd.legalese[i]);
4468 pos += hd.legalese_size;
4469 }
4470 memcpy(&buf[pos], "__END__", 7);
4471
4472 chk_fwrite(buf, size, 1, fp);
4473 free(buf);
4474
4475 /* Write constituent names. */
4476
4477 pos = 0;
4478 size = hd.pub.constituents * hd.constituent_size;
4479
4480 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4481 perror("Allocating constituent write buffer");
4482 exit(-1);
4483 }
4484 memset(buf, 0, size);
4485
4486 for (i = 0; i < hd.pub.constituents; ++i) {
4487 assert(strlen(hd.constituent[i]) + 1 <= hd.constituent_size);
4488 strcpy((NV_CHAR *)&buf[pos], hd.constituent[i]);
4489 pos += hd.constituent_size;
4490 }
4491
4492 chk_fwrite(buf, pos, 1, fp);
4493 free(buf);
4494
4495 /* NOTE : Using bit_pack for integers. */
4496
4497 /* Write speeds. */
4498
4499 pos = 0;
4500 size = bits2bytes(hd.pub.constituents * hd.speed_bits);
4501
4502 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4503 perror("Allocating speed write buffer");
4504 exit(-1);
4505 }
4506 memset(buf, 0, size);
4507
4508 for (i = 0; i < hd.pub.constituents; ++i) {
4509 temp_int = NINT(hd.speed[i] * hd.speed_scale) - hd.speed_offset;
4510 assert(temp_int >= 0);
4511 bit_pack(buf, pos, hd.speed_bits, temp_int);
4512 pos += hd.speed_bits;
4513 }
4514
4515 chk_fwrite(buf, size, 1, fp);
4516 free(buf);
4517
4518 /* Write equilibrium arguments. */
4519
4520 pos = 0;
4521 size = bits2bytes(hd.pub.constituents * hd.pub.number_of_years *
4522 hd.equilibrium_bits);
4523
4524 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4525 perror("Allocating equilibrium write buffer");
4526 exit(-1);
4527 }
4528 memset(buf, 0, size);
4529
4530 for (i = 0; i < hd.pub.constituents; ++i) {
4531 NV_U_INT32 j;
4532 for (j = 0; j < hd.pub.number_of_years; ++j) {
4533 temp_int = NINT(hd.equilibrium[i][j] * hd.equilibrium_scale) -
4534 hd.equilibrium_offset;
4535 assert(temp_int >= 0);
4536 bit_pack(buf, pos, hd.equilibrium_bits, temp_int);
4537 pos += hd.equilibrium_bits;
4538 }
4539 }
4540
4541 chk_fwrite(buf, size, 1, fp);
4542 free(buf);
4543
4544 /* Write node factors. */
4545
4546 pos = 0;
4547 size =
4548 bits2bytes(hd.pub.constituents * hd.pub.number_of_years * hd.node_bits);
4549
4550 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4551 perror("Allocating node write buffer");
4552 exit(-1);
4553 }
4554 memset(buf, 0, size);
4555
4556 for (i = 0; i < hd.pub.constituents; ++i) {
4557 NV_U_INT32 j;
4558 for (j = 0; j < hd.pub.number_of_years; ++j) {
4559 temp_int = NINT(hd.node_factor[i][j] * hd.node_scale) - hd.node_offset;
4560 assert(temp_int >= 0);
4561 bit_pack(buf, pos, hd.node_bits, temp_int);
4562 pos += hd.node_bits;
4563 }
4564 }
4565
4566 chk_fwrite(buf, size, 1, fp);
4567 free(buf);
4568}
4569
4570/*****************************************************************************\
4571
4572 Function unpack_string - Safely unpack a string into a
4573 fixed-length buffer.
4574
4575 Synopsis unpack_string (buf, bufsize, pos, outbuf, outbuflen, desc);
4576
4577 NV_U_BYTE *buf input buffer
4578 NV_U_INT32 bufsize size of input buffer in bytes
4579 NV_U_INT32 *pos current bit-position in buf
4580 (in-out parameter)
4581 NV_CHAR *outbuf fixed-length string-buffer
4582 NV_U_INT32 outbuflen size of outbuf in bytes
4583 NV_CHAR *desc description of the field being
4584 unpacked for use in warning
4585 messages when truncation occurs
4586
4587 Returns void
4588
4589 Author David Flater
4590 Date 2004-09-30
4591
4592 pos will be left at the start of the next field even if the string
4593 gets truncated.
4594
4595\*****************************************************************************/
4596
4597static void unpack_string(NV_U_BYTE *buf, NV_U_INT32 bufsize, NV_U_INT32 *pos,
4598 NV_CHAR *outbuf, NV_U_INT32 outbuflen,
4599 const NV_CHAR *desc) {
4600 NV_U_INT32 i;
4601 NV_CHAR c = 'x';
4602 assert(buf);
4603 assert(pos);
4604 assert(outbuf);
4605 assert(desc);
4606 assert(outbuflen);
4607 --outbuflen;
4608 bufsize <<= 3;
4609 for (i = 0; c; ++i) {
4610 assert(*pos < bufsize); /* Catch unterminated strings */
4611 c = bit_unpack(buf, *pos, 8);
4612 (*pos) += 8;
4613 if (i < outbuflen) {
4614 outbuf[i] = c;
4615 } else if (i == outbuflen) {
4616 outbuf[i] = '\0';
4617 if (c) {
4618 LOG_ERROR("libtcd warning: truncating overlong %s\n", desc);
4619 LOG_ERROR("The offending string starts with:\n%s\n", outbuf);
4620 }
4621 }
4622 }
4623}
4624
4625/*****************************************************************************\
4626
4627 Function unpack_partial_tide_record - unpacks the "header" portion
4628 of a tide record from the supplied buffer
4629
4630 Synopsis unpack_partial_tide_record (buf, rec, pos);
4631
4632 NV_U_BYTE *buf input buffer
4633 NV_U_INT32 bufsize size of input buffer in bytes
4634 TIDE_RECORD *rec tide record
4635 NV_U_INT32 *pos final position in buffer after
4636 unpacking the header
4637
4638 Returns void
4639
4640 Author Jan C. Depner
4641 Date 08/01/02
4642
4643 See libtcd.html for changelog.
4644
4645\*****************************************************************************/
4646
4647static void unpack_partial_tide_record(NV_U_BYTE *buf, NV_U_INT32 bufsize,
4648 TIDE_RECORD *rec, NV_U_INT32 *pos) {
4649 NV_INT32 temp_int;
4650
4651 assert(buf);
4652 assert(rec);
4653 assert(pos);
4654
4655 *pos = 0;
4656
4657 rec->header.record_size = bit_unpack(buf, *pos, hd.record_size_bits);
4658 *pos += hd.record_size_bits;
4659
4660 rec->header.record_type = bit_unpack(buf, *pos, hd.record_type_bits);
4661 *pos += hd.record_type_bits;
4662
4663 temp_int = signed_bit_unpack(buf, *pos, hd.latitude_bits);
4664 rec->header.latitude = (NV_FLOAT64)temp_int / hd.latitude_scale;
4665 *pos += hd.latitude_bits;
4666
4667 temp_int = signed_bit_unpack(buf, *pos, hd.longitude_bits);
4668 rec->header.longitude = (NV_FLOAT64)temp_int / hd.longitude_scale;
4669 *pos += hd.longitude_bits;
4670
4671 /* This ordering doesn't match everywhere else but there's no technical
4672 reason to change it from its V1 ordering. */
4673
4674 rec->header.tzfile = bit_unpack(buf, *pos, hd.tzfile_bits);
4675 *pos += hd.tzfile_bits;
4676
4677 unpack_string(buf, bufsize, pos, rec->header.name, ONELINER_LENGTH,
4678 "station name");
4679
4680 rec->header.reference_station = signed_bit_unpack(buf, *pos, hd.station_bits);
4681 *pos += hd.station_bits;
4682
4683 assert(*pos <= bufsize * 8);
4684}
4685
4686/*****************************************************************************\
4687
4688 Function read_partial_tide_record - reads the "header" portion
4689 of a tide record from the database. This is used to index
4690 the database on opening.
4691
4692 Synopsis read_partial_tide_record (num, rec);
4693
4694 NV_INT32 num record number
4695 TIDE_RECORD *rec tide record
4696
4697 Returns NV_INT32 record number read
4698
4699 Author Jan C. Depner
4700 Date 08/01/02
4701
4702 See libtcd.html for changelog.
4703
4704\*****************************************************************************/
4705
4706static NV_INT32 read_partial_tide_record(NV_INT32 num, TIDE_RECORD *rec) {
4707 NV_U_BYTE *buf;
4708 NV_U_INT32 maximum_possible_size, pos;
4709
4710 if (!fp) {
4711 LOG_ERROR(
4712 "libtcd error: attempt to access database when database not open\n");
4713 exit(-1);
4714 }
4715
4716 assert(rec);
4717
4718 /* Read just the record size, record type, position, time zone, and
4719 name. */
4720
4721 maximum_possible_size = hd.record_size_bits + hd.record_type_bits +
4722 hd.latitude_bits + hd.longitude_bits +
4723 hd.tzfile_bits + (ONELINER_LENGTH * 8) +
4724 hd.station_bits;
4725 maximum_possible_size = bits2bytes(maximum_possible_size);
4726
4727 if ((buf = (NV_U_BYTE *)calloc(maximum_possible_size, sizeof(NV_U_BYTE))) ==
4728 NULL) {
4729 perror("Allocating partial tide record buffer");
4730 exit(-1);
4731 }
4732
4733 current_record = num;
4734 fseek(fp, tindex[num].address, SEEK_SET);
4735 /* DWF 2007-12-02: This is the one place where a short read would not
4736 necessarily mean catastrophe. We don't know how long the partial
4737 record actually is yet, and it's possible that the full record will
4738 be shorter than maximum_possible_size. */
4739 size_t size = fread(buf, 1, maximum_possible_size, fp);
4740 unpack_partial_tide_record(buf, size, rec, &pos);
4741 free(buf);
4742 return (num);
4743}
4744
4745/*****************************************************************************\
4746
4747 Function read_tide_db_header - reads the tide database header
4748
4749 Synopsis read_tide_db_header ();
4750
4751 Returns NV_BOOL NVTrue if header is correct
4752
4753 Author Jan C. Depner
4754 Date 08/01/02
4755
4756 See libtcd.html for changelog.
4757
4758\*****************************************************************************/
4759
4760static NV_BOOL read_tide_db_header() {
4761 NV_INT32 temp_int;
4762 NV_CHAR varin[ONELINER_LENGTH], *info;
4763 NV_U_INT32 utemp, i, j, pos, size, key_count;
4764 NV_U_BYTE *buf, checksum_c[5];
4765 TIDE_RECORD rec;
4766
4767 if (!fp) {
4768 LOG_ERROR(
4769 "libtcd error: attempt to access database when database not open\n");
4770 exit(-1);
4771 }
4772
4773 strcpy(hd.pub.version, "NO VERSION");
4774
4775 /* Compute the number of key phrases there are to match. */
4776 key_count = sizeof(keys) / sizeof(KEY);
4777
4778 /* Zero out the header structure. */
4779 memset(&hd, 0, sizeof(hd));
4780
4781 /* Handle the ASCII header data. */
4782 while (fgets(varin, sizeof(varin), fp) != NULL) {
4783 if (strlen(varin) == ONELINER_LENGTH - 1) {
4784 if (varin[ONELINER_LENGTH - 2] != '\n') {
4785 LOG_ERROR("libtcd error: header line too long, begins with:\n");
4786 LOG_ERROR("%s\n", varin);
4787 LOG_ERROR("in file %s\n", filename);
4788 LOG_ERROR("Configured limit is %u\n", ONELINER_LENGTH - 1);
4789 fclose(fp);
4790 return NVFalse;
4791 }
4792 }
4793
4794 if (strstr(varin, "[END OF ASCII HEADER DATA]")) break;
4795
4796 /* All other lines must be field = value */
4797 info = strchr(varin, '=');
4798 if (!info) {
4799 LOG_ERROR("libtcd error: invalid tide db header line:\n");
4800 LOG_ERROR("%s", varin);
4801 LOG_ERROR("in file %s\n", filename);
4802 fclose(fp);
4803 return NVFalse;
4804 }
4805 ++info;
4806
4807 /* Scan the fields per "keys" defined in tide_db_header.h. */
4808 for (i = 0; i < key_count; ++i) {
4809 if (strstr(varin, keys[i].keyphrase)) {
4810 if (!strcmp(keys[i].datatype, "cstr"))
4811 strcpy((char *)keys[i].address.cstr, clip_string(info));
4812 else if (!strcmp(keys[i].datatype, "i32")) {
4813 if (sscanf(info, "%d", keys[i].address.i32) != 1) {
4814 LOG_ERROR("libtcd error: invalid tide db header line:\n");
4815 LOG_ERROR("%s", varin);
4816 LOG_ERROR("in file %s\n", filename);
4817 fclose(fp);
4818 return NVFalse;
4819 }
4820 } else if (!strcmp(keys[i].datatype, "ui32")) {
4821 if (sscanf(info, "%u", keys[i].address.ui32) != 1) {
4822 LOG_ERROR("libtcd error: invalid tide db header line:\n");
4823 LOG_ERROR("%s", varin);
4824 LOG_ERROR("in file %s\n", filename);
4825 fclose(fp);
4826 return NVFalse;
4827 }
4828 } else
4829 assert(0);
4830 }
4831 }
4832 }
4833
4834 /* We didn't get a valid version string. */
4835
4836 if (!strcmp(hd.pub.version, "NO VERSION")) {
4837 LOG_ERROR("libtcd error: no version found in tide db header\n");
4838 LOG_ERROR("in file %s\n", filename);
4839 fclose(fp);
4840 return NVFalse;
4841 }
4842
4843 /* If no major or minor rev, they're 0 (pre-1.99) */
4844 if (hd.pub.major_rev > LIBTCD_MAJOR_REV) {
4845 LOG_ERROR(
4846 "libtcd error: major revision in TCD file (%u) exceeds major revision "
4847 "of\n",
4848 hd.pub.major_rev);
4849 LOG_ERROR("libtcd (%u). You must upgrade libtcd to read this file.\n",
4850 LIBTCD_MAJOR_REV);
4851 fclose(fp);
4852 return NVFalse;
4853 }
4854
4855 /* Move to end of ASCII header. */
4856 fseek(fp, hd.header_size, SEEK_SET);
4857
4858 /* Read and check the checksum. */
4859
4860 chk_fread(checksum_c, 4, 1, fp);
4861 utemp = bit_unpack(checksum_c, 0, 32);
4862
4863 if (utemp != header_checksum()) {
4864#ifdef COMPAT114
4865 if (utemp != old_header_checksum()) {
4866 LOG_ERROR("libtcd error: header checksum error in file %s\n", filename);
4867 LOG_ERROR(
4868 "Someone may have modified the ASCII portion of the header (don't do that),\n\
4869or it may just be corrupt.\n");
4870 fclose(fp);
4871 return NVFalse;
4872 }
4873#else
4874 LOG_ERROR("libtcd error: header checksum error in file %s\n", filename);
4875 LOG_ERROR(
4876 "Someone may have modified the ASCII portion of the header (don't do that),\n\
4877or it may be an ancient pre-version-1.02 TCD file, or it may just be corrupt.\n\
4878Pre-version-1.02 TCD files can be read by building libtcd with COMPAT114\n\
4879defined.\n");
4880 fclose(fp);
4881 return NVFalse;
4882#endif
4883 }
4884 fseek(fp, hd.header_size + 4, SEEK_SET);
4885
4886 /* Set the max possible restriction types based on the number of bits
4887 used. */
4888
4889 hd.max_restriction_types = NINT(pow(2.0, (NV_FLOAT64)hd.restriction_bits));
4890
4891 /* Set the max possible tzfiles based on the number of bits used. */
4892
4893 hd.max_tzfiles = NINT(pow(2.0, (NV_FLOAT64)hd.tzfile_bits));
4894
4895 /* Set the max possible countries based on the number of bits used. */
4896
4897 hd.max_countries = NINT(pow(2.0, (NV_FLOAT64)hd.country_bits));
4898
4899 /* Set the max possible datum types based on the number of bits
4900 used. */
4901
4902 hd.max_datum_types = NINT(pow(2.0, (NV_FLOAT64)hd.datum_bits));
4903
4904 /* Set the max possible legaleses based on the number of bits
4905 used. */
4906
4907 if (hd.pub.major_rev < 2)
4908 hd.max_legaleses = 1;
4909 else
4910 hd.max_legaleses = NINT(pow(2.0, (NV_FLOAT64)hd.legalese_bits));
4911
4912 /* NOTE : Using strcpy for character strings (no endian issue). */
4913
4914 /* Read level units. */
4915
4916 hd.level_unit =
4917 (NV_CHAR **)calloc(hd.pub.level_unit_types, sizeof(NV_CHAR *));
4918
4919 if ((buf = (NV_U_BYTE *)calloc(hd.level_unit_size, sizeof(NV_U_BYTE))) ==
4920 NULL) {
4921 perror("Allocating level unit read buffer");
4922 exit(-1);
4923 }
4924
4925 for (i = 0; i < hd.pub.level_unit_types; ++i) {
4926 chk_fread(buf, hd.level_unit_size, 1, fp);
4927 hd.level_unit[i] =
4928 (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
4929 strcpy(hd.level_unit[i], (NV_CHAR *)buf);
4930 }
4931 free(buf);
4932
4933 /* Read direction units. */
4934
4935 hd.dir_unit = (NV_CHAR **)calloc(hd.pub.dir_unit_types, sizeof(NV_CHAR *));
4936
4937 if ((buf = (NV_U_BYTE *)calloc(hd.dir_unit_size, sizeof(NV_U_BYTE))) ==
4938 NULL) {
4939 perror("Allocating dir unit read buffer");
4940 exit(-1);
4941 }
4942
4943 for (i = 0; i < hd.pub.dir_unit_types; ++i) {
4944 chk_fread(buf, hd.dir_unit_size, 1, fp);
4945 hd.dir_unit[i] =
4946 (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
4947 strcpy(hd.dir_unit[i], (NV_CHAR *)buf);
4948 }
4949 free(buf);
4950
4951 /* Read restrictions. */
4952
4953 utemp = ftell(fp);
4954 hd.restriction =
4955 (NV_CHAR **)calloc(hd.max_restriction_types, sizeof(NV_CHAR *));
4956
4957 if ((buf = (NV_U_BYTE *)calloc(hd.restriction_size, sizeof(NV_U_BYTE))) ==
4958 NULL) {
4959 perror("Allocating restriction read buffer");
4960 exit(-1);
4961 }
4962
4963 hd.pub.restriction_types = 0;
4964 for (i = 0; i < hd.max_restriction_types; ++i) {
4965 chk_fread(buf, hd.restriction_size, 1, fp);
4966 if (!strcmp((char *)buf, "__END__")) {
4967 hd.pub.restriction_types = i;
4968 break;
4969 }
4970 hd.restriction[i] =
4971 (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
4972 strcpy(hd.restriction[i], (NV_CHAR *)buf);
4973 }
4974 free(buf);
4975 fseek(fp, utemp + hd.max_restriction_types * hd.restriction_size, SEEK_SET);
4976
4977 /* Skip pedigrees. */
4978 if (hd.pub.major_rev < 2)
4979 fseek(fp, hd.pedigree_size * NINT(pow(2.0, (NV_FLOAT64)hd.pedigree_bits)),
4980 SEEK_CUR);
4981 hd.pub.pedigree_types = 1;
4982
4983 /* Read tzfiles. */
4984
4985 utemp = ftell(fp);
4986 hd.tzfile = (NV_CHAR **)calloc(hd.max_tzfiles, sizeof(NV_CHAR *));
4987
4988 if ((buf = (NV_U_BYTE *)calloc(hd.tzfile_size, sizeof(NV_U_BYTE))) == NULL) {
4989 perror("Allocating tzfile read buffer");
4990 exit(-1);
4991 }
4992
4993 hd.pub.tzfiles = 0;
4994 for (i = 0; i < hd.max_tzfiles; ++i) {
4995 chk_fread(buf, hd.tzfile_size, 1, fp);
4996 if (!strcmp((char *)buf, "__END__")) {
4997 hd.pub.tzfiles = i;
4998 break;
4999 }
5000 hd.tzfile[i] = (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5001 strcpy(hd.tzfile[i], (NV_CHAR *)buf);
5002 }
5003 free(buf);
5004 fseek(fp, utemp + hd.max_tzfiles * hd.tzfile_size, SEEK_SET);
5005
5006 /* Read countries. */
5007
5008 utemp = ftell(fp);
5009 hd.country = (NV_CHAR **)calloc(hd.max_countries, sizeof(NV_CHAR *));
5010
5011 if ((buf = (NV_U_BYTE *)calloc(hd.country_size, sizeof(NV_U_BYTE))) == NULL) {
5012 perror("Allocating country read buffer");
5013 exit(-1);
5014 }
5015
5016 hd.pub.countries = 0;
5017 for (i = 0; i < hd.max_countries; ++i) {
5018 chk_fread(buf, hd.country_size, 1, fp);
5019 if (!strcmp((char *)buf, "__END__")) {
5020 hd.pub.countries = i;
5021 break;
5022 }
5023 hd.country[i] = (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5024 strcpy(hd.country[i], (NV_CHAR *)buf);
5025 }
5026 free(buf);
5027 fseek(fp, utemp + hd.max_countries * hd.country_size, SEEK_SET);
5028
5029 /* Read datums. */
5030
5031 utemp = ftell(fp);
5032 hd.datum = (NV_CHAR **)calloc(hd.max_datum_types, sizeof(NV_CHAR *));
5033
5034 if ((buf = (NV_U_BYTE *)calloc(hd.datum_size, sizeof(NV_U_BYTE))) == NULL) {
5035 perror("Allocating datum read buffer");
5036 exit(-1);
5037 }
5038
5039 hd.pub.datum_types = 0;
5040 for (i = 0; i < hd.max_datum_types; ++i) {
5041 chk_fread(buf, hd.datum_size, 1, fp);
5042 if (!strcmp((char *)buf, "__END__")) {
5043 hd.pub.datum_types = i;
5044 break;
5045 }
5046 hd.datum[i] = (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5047 strcpy(hd.datum[i], (NV_CHAR *)buf);
5048 }
5049 free(buf);
5050 fseek(fp, utemp + hd.max_datum_types * hd.datum_size, SEEK_SET);
5051
5052 /* Read legaleses. */
5053
5054 if (hd.pub.major_rev < 2) {
5055 hd.legalese = (NV_CHAR **)malloc(sizeof(NV_CHAR *));
5056 assert(hd.legalese != NULL);
5057 hd.legalese[0] = (NV_CHAR *)malloc(5 * sizeof(NV_CHAR));
5058 assert(hd.legalese[0] != NULL);
5059 strcpy(hd.legalese[0], "NULL");
5060 hd.pub.legaleses = 1;
5061 } else {
5062 utemp = ftell(fp);
5063 hd.legalese = (NV_CHAR **)calloc(hd.max_legaleses, sizeof(NV_CHAR *));
5064
5065 if ((buf = (NV_U_BYTE *)calloc(hd.legalese_size, sizeof(NV_U_BYTE))) ==
5066 NULL) {
5067 perror("Allocating legalese read buffer");
5068 exit(-1);
5069 }
5070
5071 hd.pub.legaleses = 0;
5072 for (i = 0; i < hd.max_legaleses; ++i) {
5073 chk_fread(buf, hd.legalese_size, 1, fp);
5074 if (!strcmp((char *)buf, "__END__")) {
5075 hd.pub.legaleses = i;
5076 break;
5077 }
5078 hd.legalese[i] =
5079 (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5080 strcpy(hd.legalese[i], (NV_CHAR *)buf);
5081 }
5082 free(buf);
5083 fseek(fp, utemp + hd.max_legaleses * hd.legalese_size, SEEK_SET);
5084 }
5085
5086 /* Read constituent names. */
5087
5088 hd.constituent = (NV_CHAR **)calloc(hd.pub.constituents, sizeof(NV_CHAR *));
5089
5090 if ((buf = (NV_U_BYTE *)calloc(hd.constituent_size, sizeof(NV_U_BYTE))) ==
5091 NULL) {
5092 perror("Allocating constituent read buffer");
5093 exit(-1);
5094 }
5095
5096 for (i = 0; i < hd.pub.constituents; ++i) {
5097 chk_fread(buf, hd.constituent_size, 1, fp);
5098 hd.constituent[i] =
5099 (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5100 strcpy(hd.constituent[i], (NV_CHAR *)buf);
5101 }
5102 free(buf);
5103
5104 if (hd.speed_offset < 0 || hd.equilibrium_offset < 0 || hd.node_offset < 0) {
5105 LOG_ERROR("libtcd WARNING: File: %s\n", filename);
5106 LOG_ERROR(
5107 "WARNING: This TCD file was created by a pre-version-1.11 libtcd.\n\
5108Versions of libtcd prior to 1.11 contained a serious bug that can result\n\
5109in overflows in the speeds, equilibrium arguments, or node factors. This\n\
5110database should be rebuilt from the original data if possible.\n");
5111 }
5112
5113 /* NOTE: Using bit_unpack to get integers. */
5114
5115 /* Read speeds. */
5116
5117 hd.speed = (NV_FLOAT64 *)calloc(hd.pub.constituents, sizeof(NV_FLOAT64));
5118
5119 pos = 0;
5120 /* wasted byte bug in V1 */
5121 if (hd.pub.major_rev < 2)
5122 size = ((hd.pub.constituents * hd.speed_bits) / 8) + 1;
5123 else
5124 size = bits2bytes(hd.pub.constituents * hd.speed_bits);
5125
5126 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
5127 perror("Allocating speed read buffer");
5128 exit(-1);
5129 }
5130
5131 chk_fread(buf, size, 1, fp);
5132
5133 for (i = 0; i < hd.pub.constituents; ++i) {
5134 temp_int = bit_unpack(buf, pos, hd.speed_bits);
5135 hd.speed[i] = (NV_FLOAT64)(temp_int + hd.speed_offset) / hd.speed_scale;
5136 pos += hd.speed_bits;
5137 assert(hd.speed[i] >= 0.0);
5138 }
5139 free(buf);
5140
5141 /* Read equilibrium arguments. */
5142
5143 hd.equilibrium =
5144 (NV_FLOAT32 **)calloc(hd.pub.constituents, sizeof(NV_FLOAT32 *));
5145
5146 for (i = 0; i < hd.pub.constituents; ++i) {
5147 hd.equilibrium[i] =
5148 (NV_FLOAT32 *)calloc(hd.pub.number_of_years, sizeof(NV_FLOAT32));
5149 }
5150
5151 pos = 0;
5152 /* wasted byte bug in V1 */
5153 if (hd.pub.major_rev < 2)
5154 size =
5155 ((hd.pub.constituents * hd.pub.number_of_years * hd.equilibrium_bits) /
5156 8) +
5157 1;
5158 else
5159 size = bits2bytes(hd.pub.constituents * hd.pub.number_of_years *
5160 hd.equilibrium_bits);
5161
5162 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
5163 perror("Allocating equilibrium read buffer");
5164 exit(-1);
5165 }
5166
5167 chk_fread(buf, size, 1, fp);
5168
5169 for (i = 0; i < hd.pub.constituents; ++i) {
5170 for (j = 0; j < hd.pub.number_of_years; ++j) {
5171 temp_int = bit_unpack(buf, pos, hd.equilibrium_bits);
5172 hd.equilibrium[i][j] =
5173 (NV_FLOAT32)(temp_int + hd.equilibrium_offset) / hd.equilibrium_scale;
5174 pos += hd.equilibrium_bits;
5175 }
5176 }
5177 free(buf);
5178
5179 /* Read node factors. */
5180
5181 hd.node_factor =
5182 (NV_FLOAT32 **)calloc(hd.pub.constituents, sizeof(NV_FLOAT32 *));
5183
5184 for (i = 0; i < hd.pub.constituents; ++i) {
5185 hd.node_factor[i] =
5186 (NV_FLOAT32 *)calloc(hd.pub.number_of_years, sizeof(NV_FLOAT32));
5187 }
5188
5189 pos = 0;
5190 /* wasted byte bug in V1 */
5191 if (hd.pub.major_rev < 2)
5192 size =
5193 ((hd.pub.constituents * hd.pub.number_of_years * hd.node_bits) / 8) + 1;
5194 else
5195 size =
5196 bits2bytes(hd.pub.constituents * hd.pub.number_of_years * hd.node_bits);
5197
5198 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
5199 perror("Allocating node read buffer");
5200 exit(-1);
5201 }
5202
5203 chk_fread(buf, size, 1, fp);
5204
5205 for (i = 0; i < hd.pub.constituents; ++i) {
5206 for (j = 0; j < hd.pub.number_of_years; ++j) {
5207 temp_int = bit_unpack(buf, pos, hd.node_bits);
5208 hd.node_factor[i][j] =
5209 (NV_FLOAT32)(temp_int + hd.node_offset) / hd.node_scale;
5210 pos += hd.node_bits;
5211 assert(hd.node_factor[i][j] > 0.0);
5212 }
5213 }
5214 free(buf);
5215
5216 /* Read the header portion of all of the records in the file and save
5217 the record size, address, and name. */
5218
5219 /* DWF added test for zero 2003-11-16 -- happens on create new db */
5220 if (hd.pub.number_of_records) {
5221 if ((tindex = (TIDE_INDEX *)calloc(hd.pub.number_of_records,
5222 sizeof(TIDE_INDEX))) == NULL) {
5223 perror("Allocating tide index");
5224 exit(-1);
5225 }
5226 /* Set the first address to be immediately after the header */
5227 tindex[0].address = ftell(fp);
5228 } else
5229 tindex = NULL; /* May as well be explicit... */
5230
5231 for (i = 0; i < hd.pub.number_of_records; ++i) {
5232 /* Set the address for the next record so that
5233 read_partial_tide_record will know where to go. */
5234
5235 if (i) tindex[i].address = tindex[i - 1].address + rec.header.record_size;
5236
5237 read_partial_tide_record(i, &rec);
5238
5239 /* Save the header info in the index. */
5240
5241 tindex[i].record_size = rec.header.record_size;
5242 tindex[i].record_type = rec.header.record_type;
5243 tindex[i].reference_station = rec.header.reference_station;
5244 assert(rec.header.tzfile >= 0);
5245 tindex[i].tzfile = rec.header.tzfile;
5246 tindex[i].lat = NINT(rec.header.latitude * hd.latitude_scale);
5247 tindex[i].lon = NINT(rec.header.longitude * hd.longitude_scale);
5248
5249 if ((tindex[i].name = (NV_CHAR *)calloc(strlen(rec.header.name) + 1,
5250 sizeof(NV_CHAR))) == NULL) {
5251 perror("Allocating index name memory");
5252 exit(-1);
5253 }
5254
5255 strcpy(tindex[i].name, rec.header.name);
5256 }
5257
5258 current_record = -1;
5259 current_index = -1;
5260
5261 return (NVTrue);
5262}
5263
5264/*****************************************************************************\
5265
5266 Function open_tide_db - opens the tide database
5267
5268 Synopsis open_tide_db (file);
5269
5270 NV_CHAR *file database file name
5271
5272 Returns NV_BOOL NVTrue if file opened
5273
5274 Author Jan C. Depner
5275 Date 08/01/02
5276
5277 See libtcd.html for changelog.
5278
5279\*****************************************************************************/
5280
5281NV_BOOL open_tide_db(const NV_CHAR *file) {
5282 assert(file);
5283 current_record = -1;
5284 current_index = -1;
5285 if (fp) {
5286 if (!strcmp(file, filename) && !modified)
5287 return NVTrue;
5288 else
5289 close_tide_db();
5290 }
5291 if ((fp = fopen(file, "rb+")) == NULL) {
5292 if ((fp = fopen(file, "rb")) == NULL) return (NVFalse);
5293 }
5294 boundscheck_monologue(file);
5295 strcpy(filename, file);
5296 return (read_tide_db_header());
5297}
5298
5299/*****************************************************************************\
5300
5301 Function close_tide_db - closes the tide database
5302
5303 Synopsis close_tide_db ();
5304
5305 Returns void
5306
5307 Author Jan C. Depner
5308 Date 08/01/02
5309
5310 See libtcd.html for changelog.
5311
5312 If the global modified flag is true, the database header is rewritten
5313 before the database is closed. The modified flag is then cleared.
5314
5315\*****************************************************************************/
5316
5317void close_tide_db() {
5318 NV_U_INT32 i;
5319
5320 if (!fp) {
5321 LOG_ERROR("libtcd warning: close_tide_db called when no database open\n");
5322 return;
5323 }
5324
5325 /* If we've changed something in the file, write the header to reset
5326 the last modified time. */
5327
5328 if (modified) write_tide_db_header();
5329
5330 /* Free all of the temporary memory. */
5331
5332 assert(hd.constituent);
5333 for (i = 0; i < hd.pub.constituents; ++i) {
5334 if (hd.constituent[i] != NULL) free(hd.constituent[i]);
5335 }
5336 free(hd.constituent);
5337 hd.constituent = NULL;
5338
5339 if (hd.speed != NULL) free(hd.speed);
5340
5341 assert(hd.equilibrium);
5342 for (i = 0; i < hd.pub.constituents; ++i) {
5343 if (hd.equilibrium[i] != NULL) free(hd.equilibrium[i]);
5344 }
5345 free(hd.equilibrium);
5346 hd.equilibrium = NULL;
5347
5348 assert(hd.node_factor);
5349 for (i = 0; i < hd.pub.constituents; ++i) {
5350 if (hd.node_factor[i] != NULL) free(hd.node_factor[i]);
5351 }
5352 free(hd.node_factor);
5353 hd.node_factor = NULL;
5354
5355 assert(hd.level_unit);
5356 for (i = 0; i < hd.pub.level_unit_types; ++i) {
5357 if (hd.level_unit[i] != NULL) free(hd.level_unit[i]);
5358 }
5359 free(hd.level_unit);
5360 hd.level_unit = NULL;
5361
5362 assert(hd.dir_unit);
5363 for (i = 0; i < hd.pub.dir_unit_types; ++i) {
5364 if (hd.dir_unit[i] != NULL) free(hd.dir_unit[i]);
5365 }
5366 free(hd.dir_unit);
5367 hd.dir_unit = NULL;
5368
5369 assert(hd.restriction);
5370 for (i = 0; i < hd.max_restriction_types; ++i) {
5371 if (hd.restriction[i] != NULL) free(hd.restriction[i]);
5372 }
5373 free(hd.restriction);
5374 hd.restriction = NULL;
5375
5376 assert(hd.legalese);
5377 for (i = 0; i < hd.max_legaleses; ++i) {
5378 if (hd.legalese[i] != NULL) free(hd.legalese[i]);
5379 }
5380 free(hd.legalese);
5381 hd.legalese = NULL;
5382
5383 assert(hd.tzfile);
5384 for (i = 0; i < hd.max_tzfiles; ++i) {
5385 if (hd.tzfile[i] != NULL) free(hd.tzfile[i]);
5386 }
5387 free(hd.tzfile);
5388 hd.tzfile = NULL;
5389
5390 assert(hd.country);
5391 for (i = 0; i < hd.max_countries; ++i) {
5392 if (hd.country[i] != NULL) free(hd.country[i]);
5393 }
5394 free(hd.country);
5395 hd.country = NULL;
5396
5397 assert(hd.datum);
5398 for (i = 0; i < hd.max_datum_types; ++i) {
5399 if (hd.datum[i] != NULL) free(hd.datum[i]);
5400 }
5401 free(hd.datum);
5402 hd.datum = NULL;
5403
5404 /* tindex will still be null on create_tide_db */
5405 if (tindex) {
5406 for (i = 0; i < hd.pub.number_of_records; ++i) {
5407 if (tindex[i].name) free(tindex[i].name);
5408 }
5409 free(tindex);
5410 tindex = NULL;
5411 }
5412
5413 fclose(fp);
5414 fp = NULL;
5415 modified = NVFalse;
5416
5417 /* Don't nullify the filename; there are places in the code where
5418 open_tide_db (filename) is invoked after close_tide_db(). This
5419 does not break the cache logic in open_tide_db because tindex
5420 is still nullified. */
5421}
5422
5423/*****************************************************************************\
5424
5425 Function create_tide_db - creates the tide database
5426
5427 Synopsis create_tide_db (file, constituents, constituent, speed,
5428 start_year, num_years, equilibrium, node_factor);
5429
5430 NV_CHAR *file database file name
5431 NV_U_INT32 constituents number of constituents
5432 NV_CHAR *constituent[] constituent names
5433 NV_FLOAT64 *speed speed values
5434 NV_INT32 start_year start year
5435 NV_U_INT32 num_years number of years
5436 NV_FLOAT32 *equilibrium[] equilibrium arguments
5437 NV_FLOAT32 *node_factor[] node factors
5438
5439 Returns NV_BOOL NVTrue if file created
5440
5441 Author Jan C. Depner
5442 Date 08/01/02
5443
5444 See libtcd.html for changelog.
5445
5446\*****************************************************************************/
5447
5448NV_BOOL create_tide_db(const NV_CHAR *file, NV_U_INT32 constituents,
5449 NV_CHAR const *const constituent[],
5450 const NV_FLOAT64 *speed, NV_INT32 start_year,
5451 NV_U_INT32 num_years,
5452 NV_FLOAT32 const *const equilibrium[],
5453 NV_FLOAT32 const *const node_factor[]) {
5454 NV_U_INT32 i, j;
5455 NV_FLOAT64 min_value, max_value;
5456 NV_INT32 temp_int;
5457
5458 /* Validate input */
5459 assert(file);
5460 assert(constituent);
5461 assert(speed);
5462 assert(equilibrium);
5463 assert(node_factor);
5464 for (i = 0; i < constituents; ++i) {
5465 if (speed[i] < 0.0) {
5466 LOG_ERROR(
5467 "libtcd create_tide_db: somebody tried to set a negative speed "
5468 "(%f)\n",
5469 speed[i]);
5470 return NVFalse;
5471 }
5472 for (j = 0; j < num_years; ++j) {
5473 if (node_factor[i][j] <= 0.0) {
5474 LOG_ERROR(
5475 "libtcd create_tide_db: somebody tried to set a negative or zero "
5476 "node factor (%f)\n",
5477 node_factor[i][j]);
5478 return NVFalse;
5479 }
5480 }
5481 }
5482
5483 if (fp) close_tide_db();
5484
5485 if ((fp = fopen(file, "wb+")) == NULL) {
5486 perror(file);
5487 return (NVFalse);
5488 }
5489
5490 /* Zero out the header structure. */
5491
5492 memset(&hd, 0, sizeof(hd));
5493
5494 hd.pub.major_rev = LIBTCD_MAJOR_REV;
5495 hd.pub.minor_rev = LIBTCD_MINOR_REV;
5496
5497 hd.header_size = DEFAULT_HEADER_SIZE;
5498 hd.pub.number_of_records = DEFAULT_NUMBER_OF_RECORDS;
5499
5500 hd.pub.start_year = start_year;
5501 hd.pub.number_of_years = num_years;
5502
5503 hd.pub.constituents = constituents;
5504
5505 /* Constituent names. */
5506
5507 hd.constituent = (NV_CHAR **)calloc(hd.pub.constituents, sizeof(NV_CHAR *));
5508 for (i = 0; i < hd.pub.constituents; ++i) {
5509 hd.constituent[i] =
5510 (NV_CHAR *)calloc(strlen(constituent[i]) + 1, sizeof(NV_CHAR));
5511 strcpy(hd.constituent[i], constituent[i]);
5512 }
5513
5514 /* A constituent count is stored with each reference station record,
5515 and it uses constituent_bits, so we need to be able to store
5516 the count itself (not just the values 0..count-1). */
5517 hd.constituent_bits = calculate_bits(hd.pub.constituents);
5518
5519 /* Set all of the speed attributes. */
5520
5521 hd.speed = (NV_FLOAT64 *)calloc(hd.pub.constituents, sizeof(NV_FLOAT64));
5522
5523 hd.speed_scale = DEFAULT_SPEED_SCALE;
5524 min_value = 99999999.0;
5525 max_value = -99999999.0;
5526 for (i = 0; i < hd.pub.constituents; ++i) {
5527 if (speed[i] < min_value) min_value = speed[i];
5528 if (speed[i] > max_value) max_value = speed[i];
5529
5530 hd.speed[i] = speed[i];
5531 }
5532
5533 /* DWF fixed sign reversal 2003-11-16 */
5534 /* DWF harmonized rounding with the way it is done in write_tide_db_header
5535 2007-01-22 */
5536 hd.speed_offset = (NINT(min_value * hd.speed_scale));
5537 temp_int = NINT(max_value * hd.speed_scale) - hd.speed_offset;
5538 assert(temp_int >= 0);
5539 hd.speed_bits = calculate_bits((NV_U_INT32)temp_int);
5540 /* Generally 31. With signed ints we don't have any bits to spare. */
5541 assert(hd.speed_bits < 32);
5542
5543 /* Set all of the equilibrium attributes. */
5544
5545 hd.equilibrium =
5546 (NV_FLOAT32 **)calloc(hd.pub.constituents, sizeof(NV_FLOAT32 *));
5547
5548 hd.equilibrium_scale = DEFAULT_EQUILIBRIUM_SCALE;
5549 min_value = 99999999.0;
5550 max_value = -99999999.0;
5551 for (i = 0; i < hd.pub.constituents; ++i) {
5552 hd.equilibrium[i] =
5553 (NV_FLOAT32 *)calloc(hd.pub.number_of_years, sizeof(NV_FLOAT32));
5554 for (j = 0; j < hd.pub.number_of_years; ++j) {
5555 if (equilibrium[i][j] < min_value) min_value = equilibrium[i][j];
5556 if (equilibrium[i][j] > max_value) max_value = equilibrium[i][j];
5557
5558 hd.equilibrium[i][j] = equilibrium[i][j];
5559 }
5560 }
5561
5562 /* DWF fixed sign reversal 2003-11-16 */
5563 /* DWF harmonized rounding with the way it is done in write_tide_db_header
5564 2007-01-22 */
5565 hd.equilibrium_offset = (NINT(min_value * hd.equilibrium_scale));
5566 temp_int = NINT(max_value * hd.equilibrium_scale) - hd.equilibrium_offset;
5567 assert(temp_int >= 0);
5568 hd.equilibrium_bits = calculate_bits((NV_U_INT32)temp_int);
5569
5570 /* Set all of the node factor attributes. */
5571
5572 hd.node_factor =
5573 (NV_FLOAT32 **)calloc(hd.pub.constituents, sizeof(NV_FLOAT32 *));
5574
5575 hd.node_scale = DEFAULT_NODE_SCALE;
5576 min_value = 99999999.0;
5577 max_value = -99999999.0;
5578 for (i = 0; i < hd.pub.constituents; ++i) {
5579 hd.node_factor[i] =
5580 (NV_FLOAT32 *)calloc(hd.pub.number_of_years, sizeof(NV_FLOAT32));
5581 for (j = 0; j < hd.pub.number_of_years; ++j) {
5582 if (node_factor[i][j] < min_value) min_value = node_factor[i][j];
5583 if (node_factor[i][j] > max_value) max_value = node_factor[i][j];
5584
5585 hd.node_factor[i][j] = node_factor[i][j];
5586 }
5587 }
5588
5589 /* DWF fixed sign reversal 2003-11-16 */
5590 /* DWF harmonized rounding with the way it is done in write_tide_db_header
5591 2007-01-22 */
5592 hd.node_offset = (NINT(min_value * hd.node_scale));
5593 temp_int = NINT(max_value * hd.node_scale) - hd.node_offset;
5594 assert(temp_int >= 0);
5595 hd.node_bits = calculate_bits((NV_U_INT32)temp_int);
5596
5597 /* Default city. */
5598
5599 hd.amplitude_bits = DEFAULT_AMPLITUDE_BITS;
5600 hd.amplitude_scale = DEFAULT_AMPLITUDE_SCALE;
5601 hd.epoch_bits = DEFAULT_EPOCH_BITS;
5602 hd.epoch_scale = DEFAULT_EPOCH_SCALE;
5603
5604 hd.record_type_bits = DEFAULT_RECORD_TYPE_BITS;
5605 hd.latitude_bits = DEFAULT_LATITUDE_BITS;
5606 hd.latitude_scale = DEFAULT_LATITUDE_SCALE;
5607 hd.longitude_bits = DEFAULT_LONGITUDE_BITS;
5608 hd.longitude_scale = DEFAULT_LONGITUDE_SCALE;
5609 hd.record_size_bits = DEFAULT_RECORD_SIZE_BITS;
5610
5611 hd.station_bits = DEFAULT_STATION_BITS;
5612
5613 hd.datum_offset_bits = DEFAULT_DATUM_OFFSET_BITS;
5614 hd.datum_offset_scale = DEFAULT_DATUM_OFFSET_SCALE;
5615 hd.date_bits = DEFAULT_DATE_BITS;
5616 hd.months_on_station_bits = DEFAULT_MONTHS_ON_STATION_BITS;
5617 hd.confidence_value_bits = DEFAULT_CONFIDENCE_VALUE_BITS;
5618
5619 hd.time_bits = DEFAULT_TIME_BITS;
5620 hd.level_add_bits = DEFAULT_LEVEL_ADD_BITS;
5621 hd.level_add_scale = DEFAULT_LEVEL_ADD_SCALE;
5622 hd.level_multiply_bits = DEFAULT_LEVEL_MULTIPLY_BITS;
5623 hd.level_multiply_scale = DEFAULT_LEVEL_MULTIPLY_SCALE;
5624 hd.direction_bits = DEFAULT_DIRECTION_BITS;
5625
5626 hd.constituent_size = DEFAULT_CONSTITUENT_SIZE;
5627 hd.level_unit_size = DEFAULT_LEVEL_UNIT_SIZE;
5628 hd.dir_unit_size = DEFAULT_DIR_UNIT_SIZE;
5629 hd.restriction_size = DEFAULT_RESTRICTION_SIZE;
5630 hd.tzfile_size = DEFAULT_TZFILE_SIZE;
5631 hd.country_size = DEFAULT_COUNTRY_SIZE;
5632 hd.datum_size = DEFAULT_DATUM_SIZE;
5633 hd.legalese_size = DEFAULT_LEGALESE_SIZE;
5634
5635 /* Level units. */
5636
5637 hd.pub.level_unit_types = DEFAULT_LEVEL_UNIT_TYPES;
5638 hd.level_unit_bits = calculate_bits(hd.pub.level_unit_types - 1);
5639
5640 hd.level_unit =
5641 (NV_CHAR **)calloc(hd.pub.level_unit_types, sizeof(NV_CHAR *));
5642 for (i = 0; i < hd.pub.level_unit_types; ++i) {
5643 hd.level_unit[i] =
5644 (NV_CHAR *)calloc(strlen(level_unit[i]) + 1, sizeof(NV_CHAR));
5645 strcpy(hd.level_unit[i], level_unit[i]);
5646 }
5647
5648 /* Direction units. */
5649
5650 hd.pub.dir_unit_types = DEFAULT_DIR_UNIT_TYPES;
5651 hd.dir_unit_bits = calculate_bits(hd.pub.dir_unit_types - 1);
5652
5653 hd.dir_unit = (NV_CHAR **)calloc(hd.pub.dir_unit_types, sizeof(NV_CHAR *));
5654 for (i = 0; i < hd.pub.dir_unit_types; ++i) {
5655 hd.dir_unit[i] =
5656 (NV_CHAR *)calloc(strlen(dir_unit[i]) + 1, sizeof(NV_CHAR));
5657 strcpy(hd.dir_unit[i], dir_unit[i]);
5658 }
5659
5660 /* Restrictions. */
5661
5662 hd.restriction_bits = DEFAULT_RESTRICTION_BITS;
5663 hd.max_restriction_types = NINT(pow(2.0, (NV_FLOAT64)hd.restriction_bits));
5664 hd.pub.restriction_types = DEFAULT_RESTRICTION_TYPES;
5665
5666 hd.restriction =
5667 (NV_CHAR **)calloc(hd.max_restriction_types, sizeof(NV_CHAR *));
5668 for (i = 0; i < hd.max_restriction_types; ++i) {
5669 if (i == hd.pub.restriction_types) break;
5670
5671 hd.restriction[i] =
5672 (NV_CHAR *)calloc(strlen(restriction[i]) + 1, sizeof(NV_CHAR));
5673 strcpy(hd.restriction[i], restriction[i]);
5674 }
5675
5676 /* Legaleses. */
5677
5678 hd.legalese_bits = DEFAULT_LEGALESE_BITS;
5679 hd.max_legaleses = NINT(pow(2.0, (NV_FLOAT64)hd.legalese_bits));
5680 hd.pub.legaleses = DEFAULT_LEGALESES;
5681
5682 hd.legalese = (NV_CHAR **)calloc(hd.max_legaleses, sizeof(NV_CHAR *));
5683 for (i = 0; i < hd.max_legaleses; ++i) {
5684 if (i == hd.pub.legaleses) break;
5685
5686 hd.legalese[i] =
5687 (NV_CHAR *)calloc(strlen(legalese[i]) + 1, sizeof(NV_CHAR));
5688 strcpy(hd.legalese[i], legalese[i]);
5689 }
5690
5691 /* Tzfiles. */
5692
5693 hd.tzfile_bits = DEFAULT_TZFILE_BITS;
5694 hd.max_tzfiles = NINT(pow(2.0, (NV_FLOAT64)hd.tzfile_bits));
5695 hd.pub.tzfiles = DEFAULT_TZFILES;
5696
5697 hd.tzfile = (NV_CHAR **)calloc(hd.max_tzfiles, sizeof(NV_CHAR *));
5698 for (i = 0; i < hd.max_tzfiles; ++i) {
5699 if (i == hd.pub.tzfiles) break;
5700
5701 hd.tzfile[i] = (NV_CHAR *)calloc(strlen(tzfile[i]) + 1, sizeof(NV_CHAR));
5702 strcpy(hd.tzfile[i], tzfile[i]);
5703 }
5704
5705 /* Countries. */
5706
5707 hd.country_bits = DEFAULT_COUNTRY_BITS;
5708 hd.max_countries = NINT(pow(2.0, (NV_FLOAT64)hd.country_bits));
5709 hd.pub.countries = DEFAULT_COUNTRIES;
5710
5711 hd.country = (NV_CHAR **)calloc(hd.max_countries, sizeof(NV_CHAR *));
5712 for (i = 0; i < hd.max_countries; ++i) {
5713 if (i == hd.pub.countries) break;
5714
5715 hd.country[i] = (NV_CHAR *)calloc(strlen(country[i]) + 1, sizeof(NV_CHAR));
5716 strcpy(hd.country[i], country[i]);
5717 }
5718
5719 /* Datums. */
5720
5721 hd.datum_bits = DEFAULT_DATUM_BITS;
5722 hd.max_datum_types = NINT(pow(2.0, (NV_FLOAT64)hd.datum_bits));
5723 hd.pub.datum_types = DEFAULT_DATUM_TYPES;
5724
5725 hd.datum = (NV_CHAR **)calloc(hd.max_datum_types, sizeof(NV_CHAR *));
5726 for (i = 0; i < hd.max_datum_types; ++i) {
5727 if (i == hd.pub.datum_types) break;
5728
5729 hd.datum[i] = (NV_CHAR *)calloc(strlen(datum[i]) + 1, sizeof(NV_CHAR));
5730 strcpy(hd.datum[i], datum[i]);
5731 }
5732
5733 /* Write the header to the file and close. */
5734
5735 modified = NVTrue;
5736 close_tide_db();
5737
5738 /* Re-open it and read the header from the file. */
5739
5740 i = (open_tide_db(file));
5741
5742 /* Set the correct end of file position since the one in the header is
5743 set to 0. */
5744 hd.end_of_file = ftell(fp);
5745 /* DWF 2004-08-15: if the original program exits without adding any
5746 records, that doesn't help! Rewrite the header with correct
5747 end_of_file. */
5748 write_tide_db_header();
5749
5750 return (i);
5751}
5752
5753/*****************************************************************************\
5754 DWF 2004-10-13
5755 Used in check_tide_record.
5756\*****************************************************************************/
5757static NV_BOOL check_date(NV_U_INT32 date) {
5758 if (date) {
5759 unsigned m, d;
5760 date %= 10000;
5761 m = date / 100;
5762 d = date % 100;
5763 if (m < 1 || m > 12 || d < 1 || d > 31) return NVFalse;
5764 }
5765 return NVTrue;
5766}
5767
5768/*****************************************************************************\
5769 DWF 2004-10-13
5770 Returns true iff a record is valid enough to write. Reports all problems
5771 to LOG_ERROR. The checks are not designed to be airtight (e.g., if you
5772 use 360 degrees instead of 0 we'll let it slide).
5773
5774 Mild side effects may occur:
5775 Note that the units-to-level-units COMPAT114 trick is wedged in here.
5776\*****************************************************************************/
5777static NV_BOOL check_tide_record(TIDE_RECORD *rec) {
5778 NV_U_INT32 i;
5779 NV_BOOL ret = NVTrue;
5780
5781 if (!rec) {
5782 LOG_ERROR("libtcd error: null pointer passed to check_tide_record\n");
5783 return NVFalse;
5784 }
5785
5786 /* These are all static fields--if a buffer overflow has occurred on one
5787 of these, other fields might be invalid, but the problem started here. */
5788 boundscheck_oneliner(rec->header.name);
5789 boundscheck_oneliner(rec->source);
5790 boundscheck_monologue(rec->comments);
5791 boundscheck_monologue(rec->notes);
5792 boundscheck_oneliner(rec->station_id_context);
5793 boundscheck_oneliner(rec->station_id);
5794 boundscheck_monologue(rec->xfields);
5795
5796#ifdef COMPAT114
5797 if (rec->header.record_type == REFERENCE_STATION && rec->units > 0)
5798 rec->level_units = rec->units;
5799#endif
5800
5801 if (rec->header.latitude < -90.0 || rec->header.latitude > 90.0 ||
5802 rec->header.longitude < -180.0 || rec->header.longitude > 180.0) {
5803 LOG_ERROR("libtcd error: bad coordinates in tide record\n");
5804 ret = NVFalse;
5805 }
5806
5807 if (rec->header.tzfile < 0 ||
5808 rec->header.tzfile >= (NV_INT32)hd.pub.tzfiles) {
5809 LOG_ERROR("libtcd error: bad tzfile in tide record\n");
5810 ret = NVFalse;
5811 }
5812
5813 if (rec->header.name[0] == '\0') {
5814 LOG_ERROR("libtcd error: null name in tide record\n");
5815 ret = NVFalse;
5816 }
5817
5818 if (rec->country < 0 || rec->country >= (NV_INT32)hd.pub.countries) {
5819 LOG_ERROR("libtcd error: bad country in tide record\n");
5820 ret = NVFalse;
5821 }
5822
5823 if (rec->restriction >= hd.pub.restriction_types) {
5824 LOG_ERROR("libtcd error: bad restriction in tide record\n");
5825 ret = NVFalse;
5826 }
5827
5828 if (rec->legalese >= hd.pub.legaleses) {
5829 LOG_ERROR("libtcd error: bad legalese in tide record\n");
5830 ret = NVFalse;
5831 }
5832
5833 if (!check_date(rec->date_imported)) {
5834 LOG_ERROR("libtcd error: bad date_imported in tide record\n");
5835 ret = NVFalse;
5836 }
5837
5838 if (rec->direction_units >= hd.pub.dir_unit_types) {
5839 LOG_ERROR("libtcd error: bad direction_units in tide record\n");
5840 ret = NVFalse;
5841 }
5842
5843 if (rec->min_direction < 0 || rec->min_direction > 361) {
5844 LOG_ERROR("libtcd error: min_direction out of range in tide record\n");
5845 ret = NVFalse;
5846 }
5847
5848 if (rec->max_direction < 0 || rec->max_direction > 361) {
5849 LOG_ERROR("libtcd error: max_direction out of range in tide record\n");
5850 ret = NVFalse;
5851 }
5852
5853 if (rec->level_units >= hd.pub.level_unit_types) {
5854 LOG_ERROR("libtcd error: bad units in tide record\n");
5855 ret = NVFalse;
5856 }
5857
5858 switch (rec->header.record_type) {
5859 case REFERENCE_STATION:
5860 if (rec->header.reference_station != -1) {
5861 LOG_ERROR("libtcd error: type 1 record, reference_station != -1\n");
5862 ret = NVFalse;
5863 }
5864
5865 if (rec->datum_offset < -13421.7728 || rec->datum_offset > 13421.7727) {
5866 LOG_ERROR("libtcd error: datum_offset out of range in tide record\n");
5867 ret = NVFalse;
5868 }
5869
5870 if (rec->datum < 0 || rec->datum >= (NV_INT32)hd.pub.datum_types) {
5871 LOG_ERROR("libtcd error: bad datum in tide record\n");
5872 ret = NVFalse;
5873 }
5874
5875 if (rec->zone_offset < -4096 || rec->zone_offset > 4095 ||
5876 rec->zone_offset % 100 >= 60) {
5877 LOG_ERROR("libtcd error: bad zone_offset in tide record\n");
5878 ret = NVFalse;
5879 }
5880
5881 if (!check_date(rec->expiration_date)) {
5882 LOG_ERROR("libtcd error: bad expiration_date in tide record\n");
5883 ret = NVFalse;
5884 }
5885
5886 if (rec->months_on_station > 1023) {
5887 LOG_ERROR(
5888 "libtcd error: months_on_station out of range in tide record\n");
5889 ret = NVFalse;
5890 }
5891
5892 if (!check_date(rec->last_date_on_station)) {
5893 LOG_ERROR("libtcd error: bad last_date_on_station in tide record\n");
5894 ret = NVFalse;
5895 }
5896
5897 if (rec->confidence > 15) {
5898 LOG_ERROR("libtcd error: confidence out of range in tide record\n");
5899 ret = NVFalse;
5900 }
5901
5902 /* Only issue each error once. */
5903 for (i = 0; i < hd.pub.constituents; ++i) {
5904 if (rec->amplitude[i] < 0.0 || rec->amplitude[i] > 52.4287) {
5905 LOG_ERROR(
5906 "libtcd error: constituent amplitude out of range in tide "
5907 "record\n");
5908 ret = NVFalse;
5909 break;
5910 }
5911 }
5912 for (i = 0; i < hd.pub.constituents; ++i) {
5913 if (rec->epoch[i] < 0.0 || rec->epoch[i] > 360.0) {
5914 LOG_ERROR(
5915 "libtcd error: constituent epoch out of range in tide record\n");
5916 ret = NVFalse;
5917 break;
5918 }
5919 }
5920
5921 break;
5922
5923 case SUBORDINATE_STATION:
5924 if (rec->header.reference_station < 0 ||
5925 rec->header.reference_station >= (NV_INT32)hd.pub.number_of_records) {
5926 LOG_ERROR("libtcd error: bad reference_station in tide record\n");
5927 ret = NVFalse;
5928 }
5929
5930 if (rec->min_time_add < -4096 || rec->min_time_add > 4095 ||
5931 rec->min_time_add % 100 >= 60) {
5932 LOG_ERROR("libtcd error: bad min_time_add in tide record\n");
5933 ret = NVFalse;
5934 }
5935
5936 if (rec->min_level_add < -65.536 || rec->min_level_add > 65.535) {
5937 LOG_ERROR("libtcd error: min_level_add out of range in tide record\n");
5938 ret = NVFalse;
5939 }
5940
5941 if (rec->min_level_multiply < 0.0 || rec->min_level_multiply > 65.535) {
5942 LOG_ERROR(
5943 "libtcd error: min_level_multiply out of range in tide record\n");
5944 ret = NVFalse;
5945 }
5946
5947 if (rec->max_time_add < -4096 || rec->max_time_add > 4095 ||
5948 rec->max_time_add % 100 >= 60) {
5949 LOG_ERROR("libtcd error: bad max_time_add in tide record\n");
5950 ret = NVFalse;
5951 }
5952
5953 if (rec->max_level_add < -65.536 || rec->max_level_add > 65.535) {
5954 LOG_ERROR("libtcd error: max_level_add out of range in tide record\n");
5955 ret = NVFalse;
5956 }
5957
5958 if (rec->max_level_multiply < 0.0 || rec->max_level_multiply > 65.535) {
5959 LOG_ERROR(
5960 "libtcd error: max_level_multiply out of range in tide record\n");
5961 ret = NVFalse;
5962 }
5963
5964 if (rec->flood_begins != NULLSLACKOFFSET &&
5965 (rec->flood_begins < -4096 || rec->flood_begins > 4095 ||
5966 rec->flood_begins % 100 >= 60)) {
5967 LOG_ERROR("libtcd error: bad flood_begins in tide record\n");
5968 ret = NVFalse;
5969 }
5970
5971 if (rec->ebb_begins != NULLSLACKOFFSET &&
5972 (rec->ebb_begins < -4096 || rec->ebb_begins > 4095 ||
5973 rec->ebb_begins % 100 >= 60)) {
5974 LOG_ERROR("libtcd error: bad ebb_begins in tide record\n");
5975 ret = NVFalse;
5976 }
5977
5978 break;
5979
5980 default:
5981 LOG_ERROR("libtcd error: invalid record_type in tide record\n");
5982 ret = NVFalse;
5983 }
5984
5985 if (ret == NVFalse) dump_tide_record(rec);
5986 return ret;
5987}
5988
5989/*****************************************************************************\
5990 DWF 2004-10-13
5991 Calculate size of a tide record as it would be encoded in the TCD file.
5992 Size is stored in record_size field. Return is number of constituents
5993 that will be encoded.
5994\*****************************************************************************/
5995static NV_U_INT32 figure_size(TIDE_RECORD *rec) {
5996 NV_U_INT32 i, count = 0, name_size, source_size, comments_size, notes_size,
5997 station_id_context_size, station_id_size, xfields_size;
5998
5999 assert(rec);
6000
6001 /* Figure out how many bits we'll need for this record. */
6002
6003 name_size = strlen(clip_string(rec->header.name)) + 1;
6004 source_size = strlen(clip_string(rec->source)) + 1;
6005 comments_size = strlen(clip_string(rec->comments)) + 1;
6006 notes_size = strlen(clip_string(rec->notes)) + 1;
6007 station_id_context_size = strlen(clip_string(rec->station_id_context)) + 1;
6008 station_id_size = strlen(clip_string(rec->station_id)) + 1;
6009 /* No clipping on xfields -- trailing \n required by syntax */
6010 xfields_size = strlen(rec->xfields) + 1;
6011
6012 rec->header.record_size =
6013 hd.record_size_bits + hd.record_type_bits + hd.latitude_bits +
6014 hd.longitude_bits + hd.station_bits + hd.tzfile_bits + (name_size * 8) +
6015
6016 hd.country_bits + (source_size * 8) + hd.restriction_bits +
6017 (comments_size * 8) + (notes_size * 8) + hd.legalese_bits +
6018 (station_id_context_size * 8) + (station_id_size * 8) + hd.date_bits +
6019 (xfields_size * 8) + hd.dir_unit_bits + hd.direction_bits +
6020 hd.direction_bits + hd.level_unit_bits;
6021
6022 switch (rec->header.record_type) {
6023 case REFERENCE_STATION:
6024 rec->header.record_size += hd.datum_offset_bits + hd.datum_bits +
6025 hd.time_bits + hd.date_bits +
6026 hd.months_on_station_bits + hd.date_bits +
6027 hd.confidence_value_bits + hd.constituent_bits;
6028
6029 for (i = 0; i < hd.pub.constituents; ++i) {
6030 assert(rec->amplitude[i] >= 0.0);
6031 if (rec->amplitude[i] >= AMPLITUDE_EPSILON) ++count;
6032 }
6033
6034 rec->header.record_size +=
6035 (count * hd.constituent_bits + count * hd.amplitude_bits +
6036 count * hd.epoch_bits);
6037
6038 break;
6039
6040 case SUBORDINATE_STATION:
6041 rec->header.record_size += hd.time_bits + hd.level_add_bits +
6042 hd.level_multiply_bits + hd.time_bits +
6043 hd.level_add_bits + hd.level_multiply_bits +
6044 hd.time_bits + hd.time_bits;
6045 break;
6046
6047 default:
6048 assert(0);
6049 }
6050
6051 rec->header.record_size = bits2bytes(rec->header.record_size);
6052 return count;
6053}
6054
6055/*****************************************************************************\
6056DWF 2004-10-14
6057\*****************************************************************************/
6058static void pack_string(NV_U_BYTE *buf, NV_U_INT32 *pos, NV_CHAR *s) {
6059 NV_U_INT32 i, temp_size;
6060 assert(buf);
6061 assert(pos);
6062 assert(s);
6063 temp_size = strlen(s) + 1;
6064 for (i = 0; i < temp_size; ++i) {
6065 bit_pack(buf, *pos, 8, s[i]);
6066 *pos += 8;
6067 }
6068}
6069
6070/*****************************************************************************\
6071
6072 Function pack_tide_record - convert TIDE_RECORD to packed form
6073
6074 Synopsis pack_tide_record (rec, bufptr, bufsize);
6075
6076 TIDE_RECORD *rec tide record (in)
6077 NV_U_BYTE **bufptr packed record (out)
6078 NV_U_INT32 *bufsize size of buf in bytes (out)
6079
6080 buf is allocated by pack_tide_record and should be
6081 freed by the caller.
6082
6083 Returns void
6084
6085 Author Extracted from write_tide_record by David Flater
6086 Date 2006-05-26
6087
6088\*****************************************************************************/
6089
6090static void pack_tide_record(TIDE_RECORD *rec, NV_U_BYTE **bufptr,
6091 NV_U_INT32 *bufsize) {
6092 NV_U_INT32 i, pos, constituent_count;
6093 NV_INT32 temp_int;
6094 NV_U_BYTE *buf;
6095
6096 /* Validate input */
6097 assert(rec);
6098 /* Cursory check for buffer overflows. Should not happen here --
6099 check_tide_record does a more thorough job when called by add_tide_record
6100 and update_tide_record. */
6101 boundscheck_oneliner(rec->header.name);
6102 boundscheck_oneliner(rec->source);
6103 boundscheck_monologue(rec->comments);
6104 boundscheck_monologue(rec->notes);
6105 boundscheck_oneliner(rec->station_id_context);
6106 boundscheck_oneliner(rec->station_id);
6107 boundscheck_monologue(rec->xfields);
6108
6109 constituent_count = figure_size(rec);
6110
6111 if (!(*bufptr =
6112 (NV_U_BYTE *)calloc(rec->header.record_size, sizeof(NV_U_BYTE)))) {
6113 perror("libtcd can't allocate memory in pack_tide_record");
6114 exit(-1);
6115 }
6116 buf = *bufptr; /* To conserve asterisks */
6117
6118 /* Bit pack the common section. "pos" is the bit position within the
6119 buffer "buf". */
6120
6121 pos = 0;
6122
6123 bit_pack(buf, pos, hd.record_size_bits, rec->header.record_size);
6124 pos += hd.record_size_bits;
6125
6126 bit_pack(buf, pos, hd.record_type_bits, rec->header.record_type);
6127 pos += hd.record_type_bits;
6128
6129 temp_int = NINT(rec->header.latitude * hd.latitude_scale);
6130 bit_pack(buf, pos, hd.latitude_bits, temp_int);
6131 pos += hd.latitude_bits;
6132
6133 temp_int = NINT(rec->header.longitude * hd.longitude_scale);
6134 bit_pack(buf, pos, hd.longitude_bits, temp_int);
6135 pos += hd.longitude_bits;
6136
6137 /* This ordering doesn't match everywhere else but there's no technical
6138 reason to change it from its V1 ordering. To do so would force
6139 another conditional in unpack_partial_tide_record. */
6140
6141 bit_pack(buf, pos, hd.tzfile_bits, rec->header.tzfile);
6142 pos += hd.tzfile_bits;
6143
6144 pack_string(buf, &pos, clip_string(rec->header.name));
6145
6146 bit_pack(buf, pos, hd.station_bits, rec->header.reference_station);
6147 pos += hd.station_bits;
6148
6149 bit_pack(buf, pos, hd.country_bits, rec->country);
6150 pos += hd.country_bits;
6151
6152 pack_string(buf, &pos, clip_string(rec->source));
6153
6154 bit_pack(buf, pos, hd.restriction_bits, rec->restriction);
6155 pos += hd.restriction_bits;
6156
6157 pack_string(buf, &pos, clip_string(rec->comments));
6158 pack_string(buf, &pos, clip_string(rec->notes));
6159
6160 bit_pack(buf, pos, hd.legalese_bits, rec->legalese);
6161 pos += hd.legalese_bits;
6162
6163 pack_string(buf, &pos, clip_string(rec->station_id_context));
6164 pack_string(buf, &pos, clip_string(rec->station_id));
6165
6166 bit_pack(buf, pos, hd.date_bits, rec->date_imported);
6167 pos += hd.date_bits;
6168
6169 /* No clipping on xfields -- trailing \n required by syntax */
6170 pack_string(buf, &pos, rec->xfields);
6171
6172 bit_pack(buf, pos, hd.dir_unit_bits, rec->direction_units);
6173 pos += hd.dir_unit_bits;
6174
6175 bit_pack(buf, pos, hd.direction_bits, rec->min_direction);
6176 pos += hd.direction_bits;
6177
6178 bit_pack(buf, pos, hd.direction_bits, rec->max_direction);
6179 pos += hd.direction_bits;
6180
6181 /* The units-to-level-units compatibility hack is in check_tide_record */
6182 bit_pack(buf, pos, hd.level_unit_bits, rec->level_units);
6183 pos += hd.level_unit_bits;
6184
6185 /* Bit pack record type 1 records. */
6186
6187 if (rec->header.record_type == REFERENCE_STATION) {
6188 temp_int = NINT(rec->datum_offset * hd.datum_offset_scale);
6189 bit_pack(buf, pos, hd.datum_offset_bits, temp_int);
6190 pos += hd.datum_offset_bits;
6191
6192 bit_pack(buf, pos, hd.datum_bits, rec->datum);
6193 pos += hd.datum_bits;
6194
6195 bit_pack(buf, pos, hd.time_bits, rec->zone_offset);
6196 pos += hd.time_bits;
6197
6198 bit_pack(buf, pos, hd.date_bits, rec->expiration_date);
6199 pos += hd.date_bits;
6200
6201 bit_pack(buf, pos, hd.months_on_station_bits, rec->months_on_station);
6202 pos += hd.months_on_station_bits;
6203
6204 bit_pack(buf, pos, hd.date_bits, rec->last_date_on_station);
6205 pos += hd.date_bits;
6206
6207 bit_pack(buf, pos, hd.confidence_value_bits, rec->confidence);
6208 pos += hd.confidence_value_bits;
6209
6210 bit_pack(buf, pos, hd.constituent_bits, constituent_count);
6211 pos += hd.constituent_bits;
6212
6213 for (i = 0; i < hd.pub.constituents; ++i) {
6214 if (rec->amplitude[i] >= AMPLITUDE_EPSILON) {
6215 bit_pack(buf, pos, hd.constituent_bits, i);
6216 pos += hd.constituent_bits;
6217
6218 temp_int = NINT(rec->amplitude[i] * hd.amplitude_scale);
6219 assert(temp_int);
6220 bit_pack(buf, pos, hd.amplitude_bits, temp_int);
6221 pos += hd.amplitude_bits;
6222
6223 temp_int = NINT(rec->epoch[i] * hd.epoch_scale);
6224 bit_pack(buf, pos, hd.epoch_bits, temp_int);
6225 pos += hd.epoch_bits;
6226 }
6227 }
6228 }
6229
6230 /* Bit pack record type 2 records. */
6231 else if (rec->header.record_type == SUBORDINATE_STATION) {
6232 bit_pack(buf, pos, hd.time_bits, rec->min_time_add);
6233 pos += hd.time_bits;
6234
6235 temp_int = NINT(rec->min_level_add * hd.level_add_scale);
6236 bit_pack(buf, pos, hd.level_add_bits, temp_int);
6237 pos += hd.level_add_bits;
6238
6239 temp_int = NINT(rec->min_level_multiply * hd.level_multiply_scale);
6240 bit_pack(buf, pos, hd.level_multiply_bits, temp_int);
6241 pos += hd.level_multiply_bits;
6242
6243 bit_pack(buf, pos, hd.time_bits, rec->max_time_add);
6244 pos += hd.time_bits;
6245
6246 temp_int = NINT(rec->max_level_add * hd.level_add_scale);
6247 bit_pack(buf, pos, hd.level_add_bits, temp_int);
6248 pos += hd.level_add_bits;
6249
6250 temp_int = NINT(rec->max_level_multiply * hd.level_multiply_scale);
6251 bit_pack(buf, pos, hd.level_multiply_bits, temp_int);
6252 pos += hd.level_multiply_bits;
6253
6254 bit_pack(buf, pos, hd.time_bits, rec->flood_begins);
6255 pos += hd.time_bits;
6256
6257 bit_pack(buf, pos, hd.time_bits, rec->ebb_begins);
6258 pos += hd.time_bits;
6259 }
6260
6261 else {
6262 LOG_ERROR("libtcd error: Record type %d is undefined\n",
6263 rec->header.record_type);
6264 exit(-1);
6265 }
6266
6267 *bufsize = rec->header.record_size;
6268 assert(*bufsize == bits2bytes(pos));
6269}
6270
6271/*****************************************************************************\
6272
6273 Function write_tide_record - writes a tide record to the database
6274
6275 Synopsis write_tide_record (num, rec);
6276
6277 NV_INT32 num record number:
6278 >= 0 overwrite record num
6279 -1 write at current file position
6280 TIDE_RECORD *rec tide record
6281
6282 Returns NV_BOOL NVTrue if successful
6283
6284 Author Jan C. Depner
6285 Date 08/01/02
6286
6287 See libtcd.html for changelog.
6288
6289 hd.end_of_file is not updated by this function in any event.
6290
6291\*****************************************************************************/
6292
6293static NV_BOOL write_tide_record(NV_INT32 num, TIDE_RECORD *rec) {
6294 NV_U_BYTE *buf = NULL;
6295 NV_U_INT32 bufsize = 0;
6296
6297 if (!fp) {
6298 LOG_ERROR(
6299 "libtcd error: attempt to access database when database not open\n");
6300 return NVFalse;
6301 }
6302 write_protect();
6303
6304 pack_tide_record(rec, &buf, &bufsize);
6305
6306 if (num == -1)
6307 ;
6308 else if (num >= 0)
6309 fseek(fp, tindex[num].address, SEEK_SET);
6310 else
6311 assert(0);
6312
6313 chk_fwrite(buf, bufsize, 1, fp);
6314 free(buf);
6315 modified = NVTrue;
6316 return NVTrue;
6317}
6318
6319/*****************************************************************************\
6320
6321 Function read_next_tide_record - reads the next tide record from
6322 the database
6323
6324 Synopsis read_next_tide_record (rec);
6325
6326 TIDE_RECORD *rec tide record
6327
6328 Returns NV_INT32 record number of the tide record
6329
6330 Author Jan C. Depner
6331 Date 08/01/02
6332
6333 See libtcd.html for changelog.
6334
6335\*****************************************************************************/
6336
6337NV_INT32 read_next_tide_record(TIDE_RECORD *rec) {
6338 return (read_tide_record(current_record + 1, rec));
6339}
6340
6341/*****************************************************************************\
6342
6343 Function unpack_tide_record - convert TIDE_RECORD from packed form
6344
6345 Synopsis unpack_tide_record (buf, bufsize, rec);
6346
6347 NV_U_BYTE *buf packed record (in)
6348 NV_U_INT32 bufsize size of buf in bytes (in)
6349 TIDE_RECORD *rec tide record (in-out)
6350
6351 rec must be allocated by the caller.
6352
6353 Returns void
6354
6355 Author Extracted from read_tide_record by David Flater
6356 Date 2006-05-26
6357
6358 rec->header.record_number is initialized from the global current_record.
6359
6360\*****************************************************************************/
6361
6362static void unpack_tide_record(NV_U_BYTE *buf, NV_U_INT32 bufsize,
6363 TIDE_RECORD *rec) {
6364 NV_INT32 temp_int;
6365 NV_U_INT32 i, j, pos, count;
6366
6367 assert(rec);
6368
6369 /* Initialize record */
6370 memset(rec, 0, sizeof(TIDE_RECORD));
6371 {
6372 int r = find_dir_units("degrees true");
6373 assert(r > 0);
6374 rec->direction_units = (NV_U_BYTE)r;
6375 }
6376 rec->min_direction = rec->max_direction = 361;
6377 rec->flood_begins = rec->ebb_begins = NULLSLACKOFFSET;
6378 rec->header.record_number = current_record;
6379
6380 unpack_partial_tide_record(buf, bufsize, rec, &pos);
6381
6382 switch (rec->header.record_type) {
6383 case REFERENCE_STATION:
6384 case SUBORDINATE_STATION:
6385 break;
6386 default:
6387 LOG_ERROR("libtcd fatal error: tried to read type %d tide record.\n",
6388 rec->header.record_type);
6389 LOG_ERROR(
6390 "This version of libtcd only supports types 1 and 2. Perhaps you "
6391 "should\nupgrade.\n");
6392 exit(-1);
6393 }
6394
6395 switch (hd.pub.major_rev) {
6396 /************************* TCD V1 *****************************/
6397 case 0:
6398 case 1:
6399
6400 /* "pos" is the bit position within the buffer "buf". */
6401
6402 rec->country = bit_unpack(buf, pos, hd.country_bits);
6403 pos += hd.country_bits;
6404
6405 /* pedigree */
6406 pos += hd.pedigree_bits;
6407
6408 unpack_string(buf, bufsize, &pos, rec->source, ONELINER_LENGTH,
6409 "source field");
6410
6411 rec->restriction = bit_unpack(buf, pos, hd.restriction_bits);
6412 pos += hd.restriction_bits;
6413
6414 unpack_string(buf, bufsize, &pos, rec->comments, MONOLOGUE_LENGTH,
6415 "comments field");
6416
6417 if (rec->header.record_type == REFERENCE_STATION) {
6418 rec->level_units = bit_unpack(buf, pos, hd.level_unit_bits);
6419#ifdef COMPAT114
6420 rec->units = rec->level_units;
6421#endif
6422 pos += hd.level_unit_bits;
6423
6424 temp_int = signed_bit_unpack(buf, pos, hd.datum_offset_bits);
6425 rec->datum_offset = (NV_FLOAT32)temp_int / hd.datum_offset_scale;
6426 pos += hd.datum_offset_bits;
6427
6428 rec->datum = bit_unpack(buf, pos, hd.datum_bits);
6429 pos += hd.datum_bits;
6430
6431 rec->zone_offset = signed_bit_unpack(buf, pos, hd.time_bits);
6432 pos += hd.time_bits;
6433
6434 rec->expiration_date = bit_unpack(buf, pos, hd.date_bits);
6435 pos += hd.date_bits;
6436
6437 rec->months_on_station =
6438 bit_unpack(buf, pos, hd.months_on_station_bits);
6439 pos += hd.months_on_station_bits;
6440
6441 rec->last_date_on_station = bit_unpack(buf, pos, hd.date_bits);
6442 pos += hd.date_bits;
6443
6444 rec->confidence = bit_unpack(buf, pos, hd.confidence_value_bits);
6445 pos += hd.confidence_value_bits;
6446
6447 for (i = 0; i < hd.pub.constituents; ++i) {
6448 rec->amplitude[i] = 0.0;
6449 rec->epoch[i] = 0.0;
6450 }
6451
6452 count = bit_unpack(buf, pos, hd.constituent_bits);
6453 pos += hd.constituent_bits;
6454
6455 for (i = 0; i < count; ++i) {
6456 j = bit_unpack(buf, pos, hd.constituent_bits);
6457 pos += hd.constituent_bits;
6458
6459 rec->amplitude[j] =
6460 (NV_FLOAT32)bit_unpack(buf, pos, hd.amplitude_bits) /
6461 hd.amplitude_scale;
6462 pos += hd.amplitude_bits;
6463
6464 rec->epoch[j] =
6465 (NV_FLOAT32)bit_unpack(buf, pos, hd.epoch_bits) / hd.epoch_scale;
6466 pos += hd.epoch_bits;
6467 }
6468 } else if (rec->header.record_type == SUBORDINATE_STATION) {
6469 rec->level_units = bit_unpack(buf, pos, hd.level_unit_bits);
6470 pos += hd.level_unit_bits;
6471
6472 rec->direction_units = bit_unpack(buf, pos, hd.dir_unit_bits);
6473 pos += hd.dir_unit_bits;
6474
6475 /* avg_level_units */
6476 pos += hd.level_unit_bits;
6477
6478 rec->min_time_add = signed_bit_unpack(buf, pos, hd.time_bits);
6479 pos += hd.time_bits;
6480
6481 temp_int = signed_bit_unpack(buf, pos, hd.level_add_bits);
6482 rec->min_level_add = (NV_FLOAT32)temp_int / hd.level_add_scale;
6483 pos += hd.level_add_bits;
6484
6485 /* Signed in V1 */
6486 temp_int = signed_bit_unpack(buf, pos, hd.level_multiply_bits);
6487 rec->min_level_multiply =
6488 (NV_FLOAT32)temp_int / hd.level_multiply_scale;
6489 pos += hd.level_multiply_bits;
6490
6491 /* min_avg_level */
6492 pos += hd.level_add_bits;
6493
6494 rec->min_direction = bit_unpack(buf, pos, hd.direction_bits);
6495 pos += hd.direction_bits;
6496
6497 rec->max_time_add = signed_bit_unpack(buf, pos, hd.time_bits);
6498 pos += hd.time_bits;
6499
6500 temp_int = signed_bit_unpack(buf, pos, hd.level_add_bits);
6501 rec->max_level_add = (NV_FLOAT32)temp_int / hd.level_add_scale;
6502 pos += hd.level_add_bits;
6503
6504 /* Signed in V1 */
6505 temp_int = signed_bit_unpack(buf, pos, hd.level_multiply_bits);
6506 rec->max_level_multiply =
6507 (NV_FLOAT32)temp_int / hd.level_multiply_scale;
6508 pos += hd.level_multiply_bits;
6509
6510 /* max_avg_level */
6511 pos += hd.level_add_bits;
6512
6513 rec->max_direction = bit_unpack(buf, pos, hd.direction_bits);
6514 pos += hd.direction_bits;
6515
6516 rec->flood_begins = signed_bit_unpack(buf, pos, hd.time_bits);
6517 pos += hd.time_bits;
6518
6519 rec->ebb_begins = signed_bit_unpack(buf, pos, hd.time_bits);
6520 pos += hd.time_bits;
6521 } else {
6522 assert(0);
6523 }
6524 break;
6525
6526 /************************* TCD V2 *****************************/
6527 case 2:
6528 rec->country = bit_unpack(buf, pos, hd.country_bits);
6529 pos += hd.country_bits;
6530
6531 unpack_string(buf, bufsize, &pos, rec->source, ONELINER_LENGTH,
6532 "source field");
6533
6534 rec->restriction = bit_unpack(buf, pos, hd.restriction_bits);
6535 pos += hd.restriction_bits;
6536
6537 unpack_string(buf, bufsize, &pos, rec->comments, MONOLOGUE_LENGTH,
6538 "comments field");
6539 unpack_string(buf, bufsize, &pos, rec->notes, MONOLOGUE_LENGTH,
6540 "notes field");
6541
6542 rec->legalese = bit_unpack(buf, pos, hd.legalese_bits);
6543 pos += hd.legalese_bits;
6544
6545 unpack_string(buf, bufsize, &pos, rec->station_id_context,
6546 ONELINER_LENGTH, "station_id_context field");
6547 unpack_string(buf, bufsize, &pos, rec->station_id, ONELINER_LENGTH,
6548 "station_id field");
6549
6550 rec->date_imported = bit_unpack(buf, pos, hd.date_bits);
6551 pos += hd.date_bits;
6552
6553 unpack_string(buf, bufsize, &pos, rec->xfields, MONOLOGUE_LENGTH,
6554 "xfields field");
6555
6556 rec->direction_units = bit_unpack(buf, pos, hd.dir_unit_bits);
6557 pos += hd.dir_unit_bits;
6558
6559 rec->min_direction = bit_unpack(buf, pos, hd.direction_bits);
6560 pos += hd.direction_bits;
6561
6562 rec->max_direction = bit_unpack(buf, pos, hd.direction_bits);
6563 pos += hd.direction_bits;
6564
6565 rec->level_units = bit_unpack(buf, pos, hd.level_unit_bits);
6566#ifdef COMPAT114
6567 rec->units = rec->level_units;
6568#endif
6569 pos += hd.level_unit_bits;
6570
6571 if (rec->header.record_type == REFERENCE_STATION) {
6572 temp_int = signed_bit_unpack(buf, pos, hd.datum_offset_bits);
6573 rec->datum_offset = (NV_FLOAT32)temp_int / hd.datum_offset_scale;
6574 pos += hd.datum_offset_bits;
6575
6576 rec->datum = bit_unpack(buf, pos, hd.datum_bits);
6577 pos += hd.datum_bits;
6578
6579 rec->zone_offset = signed_bit_unpack(buf, pos, hd.time_bits);
6580 pos += hd.time_bits;
6581
6582 rec->expiration_date = bit_unpack(buf, pos, hd.date_bits);
6583 pos += hd.date_bits;
6584
6585 rec->months_on_station =
6586 bit_unpack(buf, pos, hd.months_on_station_bits);
6587 pos += hd.months_on_station_bits;
6588
6589 rec->last_date_on_station = bit_unpack(buf, pos, hd.date_bits);
6590 pos += hd.date_bits;
6591
6592 rec->confidence = bit_unpack(buf, pos, hd.confidence_value_bits);
6593 pos += hd.confidence_value_bits;
6594
6595 for (i = 0; i < hd.pub.constituents; ++i) {
6596 rec->amplitude[i] = 0.0;
6597 rec->epoch[i] = 0.0;
6598 }
6599
6600 count = bit_unpack(buf, pos, hd.constituent_bits);
6601 pos += hd.constituent_bits;
6602
6603 for (i = 0; i < count; ++i) {
6604 j = bit_unpack(buf, pos, hd.constituent_bits);
6605 pos += hd.constituent_bits;
6606
6607 rec->amplitude[j] =
6608 (NV_FLOAT32)bit_unpack(buf, pos, hd.amplitude_bits) /
6609 hd.amplitude_scale;
6610 pos += hd.amplitude_bits;
6611
6612 rec->epoch[j] =
6613 (NV_FLOAT32)bit_unpack(buf, pos, hd.epoch_bits) / hd.epoch_scale;
6614 pos += hd.epoch_bits;
6615 }
6616 } else if (rec->header.record_type == SUBORDINATE_STATION) {
6617 rec->min_time_add = signed_bit_unpack(buf, pos, hd.time_bits);
6618 pos += hd.time_bits;
6619
6620 temp_int = signed_bit_unpack(buf, pos, hd.level_add_bits);
6621 rec->min_level_add = (NV_FLOAT32)temp_int / hd.level_add_scale;
6622 pos += hd.level_add_bits;
6623
6624 /* Made unsigned in V2 */
6625 temp_int = bit_unpack(buf, pos, hd.level_multiply_bits);
6626 rec->min_level_multiply =
6627 (NV_FLOAT32)temp_int / hd.level_multiply_scale;
6628 pos += hd.level_multiply_bits;
6629
6630 rec->max_time_add = signed_bit_unpack(buf, pos, hd.time_bits);
6631 pos += hd.time_bits;
6632
6633 temp_int = signed_bit_unpack(buf, pos, hd.level_add_bits);
6634 rec->max_level_add = (NV_FLOAT32)temp_int / hd.level_add_scale;
6635 pos += hd.level_add_bits;
6636
6637 /* Made unsigned in V2 */
6638 temp_int = bit_unpack(buf, pos, hd.level_multiply_bits);
6639 rec->max_level_multiply =
6640 (NV_FLOAT32)temp_int / hd.level_multiply_scale;
6641 pos += hd.level_multiply_bits;
6642
6643 rec->flood_begins = signed_bit_unpack(buf, pos, hd.time_bits);
6644 pos += hd.time_bits;
6645
6646 rec->ebb_begins = signed_bit_unpack(buf, pos, hd.time_bits);
6647 pos += hd.time_bits;
6648 } else {
6649 assert(0);
6650 }
6651 break;
6652
6653 default:
6654 assert(0);
6655 }
6656
6657 assert(pos <= bufsize * 8);
6658}
6659
6660/*****************************************************************************\
6661
6662 Function read_tide_record - reads tide record "num" from the
6663 database
6664
6665 Synopsis read_tide_record (num, rec);
6666
6667 NV_INT32 num record number (in)
6668 TIDE_RECORD *rec tide record (in-out)
6669
6670 rec must be allocated by the caller.
6671
6672 Returns NV_INT32 num if success, -1 if failure
6673
6674 Author Jan C. Depner
6675 Date 08/01/02
6676
6677 See libtcd.html for changelog.
6678
6679\*****************************************************************************/
6680
6681NV_INT32 read_tide_record(NV_INT32 num, TIDE_RECORD *rec) {
6682 NV_U_BYTE *buf;
6683 NV_U_INT32 bufsize;
6684
6685 if (!fp) {
6686 LOG_ERROR(
6687 "libtcd error: attempt to access database when database not open\n");
6688 return -1;
6689 }
6690
6691 if (num < 0 || num >= (NV_INT32)hd.pub.number_of_records) return -1;
6692 assert(rec);
6693
6694 bufsize = tindex[num].record_size;
6695 if ((buf = (NV_U_BYTE *)calloc(bufsize, sizeof(NV_U_BYTE))) == NULL) {
6696 perror("Allocating read_tide_record buffer");
6697 exit(-1);
6698 }
6699
6700 current_record = num;
6701 require(fseek(fp, tindex[num].address, SEEK_SET) == 0);
6702 chk_fread(buf, tindex[num].record_size, 1, fp);
6703 unpack_tide_record(buf, bufsize, rec);
6704 free(buf);
6705 return num;
6706}
6707
6708/*****************************************************************************\
6709
6710 Function add_tide_record - adds a tide record to the database
6711
6712 Synopsis add_tide_record (rec);
6713
6714 TIDE_RECORD *rec tide record
6715
6716 Returns NV_BOOL NVTrue if successful
6717
6718 Author Jan C. Depner
6719 Date 08/01/02
6720
6721 See libtcd.html for changelog.
6722
6723\*****************************************************************************/
6724
6725NV_BOOL add_tide_record(TIDE_RECORD *rec, DB_HEADER_PUBLIC *db) {
6726 NV_INT32 pos;
6727
6728 if (!fp) {
6729 LOG_ERROR(
6730 "libtcd error: attempt to access database when database not open\n");
6731 return NVFalse;
6732 }
6733 write_protect();
6734
6735 if (!check_tide_record(rec)) return NVFalse;
6736
6737 fseek(fp, hd.end_of_file, SEEK_SET);
6738 pos = ftell(fp);
6739 assert(pos > 0);
6740
6741 rec->header.record_number = hd.pub.number_of_records++;
6742
6743 if (write_tide_record(-1, rec)) {
6744 if ((tindex = (TIDE_INDEX *)realloc(
6745 tindex, hd.pub.number_of_records * sizeof(TIDE_INDEX))) == NULL) {
6746 perror("Allocating more index records");
6747 exit(-1);
6748 }
6749
6750 tindex[rec->header.record_number].address = pos;
6751 tindex[rec->header.record_number].record_size = rec->header.record_size;
6752 tindex[rec->header.record_number].record_type = rec->header.record_type;
6753 tindex[rec->header.record_number].reference_station =
6754 rec->header.reference_station;
6755 assert(rec->header.tzfile >= 0);
6756 tindex[rec->header.record_number].tzfile = rec->header.tzfile;
6757 tindex[rec->header.record_number].lat =
6758 NINT(rec->header.latitude * hd.latitude_scale);
6759 tindex[rec->header.record_number].lon =
6760 NINT(rec->header.longitude * hd.longitude_scale);
6761
6762 if ((tindex[rec->header.record_number].name = (NV_CHAR *)calloc(
6763 strlen(rec->header.name) + 1, sizeof(NV_CHAR))) == NULL) {
6764 perror("Allocating index name memory");
6765 exit(-1);
6766 }
6767
6768 strcpy(tindex[rec->header.record_number].name, rec->header.name);
6769 pos = ftell(fp);
6770 assert(pos > 0);
6771 hd.end_of_file = pos;
6772 modified = NVTrue;
6773
6774 /* Get the new number of records. */
6775 if (db) *db = hd.pub;
6776
6777 return NVTrue;
6778 }
6779
6780 return NVFalse;
6781}
6782
6783#if 0
6784/*****************************************************************************\
6785
6786 Function delete_tide_record - deletes a record and all subordinate
6787 records from the database
6788
6789 Synopsis delete_tide_record (num);
6790
6791 NV_INT32 num record number
6792
6793 Returns NV_BOOL NVTrue if successful
6794
6795 Author Jan C. Depner (redone by David Flater)
6796 Date 08/01/02 (2006-05-26)
6797
6798 See libtcd.html for changelog.
6799
6800\*****************************************************************************/
6801
6802NV_BOOL delete_tide_record (NV_INT32 num, DB_HEADER_PUBLIC *db)
6803{
6804 NV_INT32 i, newrecnum, *map;
6805 NV_U_BYTE **allrecs_packed;
6806
6807 if (!fp) {
6808 LOG_ERROR ("libtcd error: attempt to access database when database not open\n");
6809 return NVFalse;
6810 }
6811 write_protect();
6812
6813 if (num < 0 || num >= (NV_INT32)hd.pub.number_of_records) return NVFalse;
6814
6815 /* Allocate workspace */
6816
6817 if (!(map = (NV_INT32 *) malloc (hd.pub.number_of_records * sizeof(NV_INT32)))) {
6818 perror ("libtcd: delete_tide_record: can't malloc");
6819 return NVFalse;
6820 }
6821 if (!(allrecs_packed = (NV_U_BYTE **) malloc (hd.pub.number_of_records * sizeof(NV_U_BYTE*)))) {
6822 perror ("libtcd: delete_tide_record: can't malloc");
6823 free (map);
6824 return NVFalse;
6825 }
6826
6827 /* First pass: read in database, build record number map and mark records
6828 for deletion */
6829
6830 require (fseek (fp, tindex[0].address, SEEK_SET) == 0);
6831 for (newrecnum=0,i=0; i<(NV_INT32)hd.pub.number_of_records; ++i) {
6832 assert (ftell(fp) == tindex[i].address);
6833 if (i == num || (tindex[i].record_type == SUBORDINATE_STATION && tindex[i].reference_station == num)) {
6834 map[i] = -1;
6835 allrecs_packed[i] = NULL;
6836 require (fseek (fp, tindex[i].record_size, SEEK_CUR) == 0);
6837 } else {
6838 map[i] = newrecnum++;
6839 if (!(allrecs_packed[i] = (NV_U_BYTE *) malloc (tindex[i].record_size))) {
6840 perror ("libtcd: delete_tide_record: can't malloc");
6841 for (--i; i>=0; --i)
6842 free (allrecs_packed[i]);
6843 free (allrecs_packed);
6844 free (map);
6845 return NVFalse;
6846 }
6847 chk_fread (allrecs_packed[i], tindex[i].record_size, 1, fp);
6848 }
6849 }
6850
6851 /* Second pass: rewrite database and fix substation linkage */
6852
6853 require (fseek (fp, tindex[0].address, SEEK_SET) == 0);
6854 require (ftruncate (fileno(fp), tindex[0].address) == 0);
6855
6856 for (i=0; i<(NV_INT32)hd.pub.number_of_records; ++i)
6857 if (map[i] >= 0) {
6858 if (tindex[i].record_type == SUBORDINATE_STATION) {
6859 assert (tindex[i].reference_station >= 0);
6860 assert (tindex[i].reference_station <= (NV_INT32)hd.pub.number_of_records);
6861 if (map[tindex[i].reference_station] != tindex[i].reference_station) {
6862 /* Fix broken reference station linkage */
6863 TIDE_RECORD rec;
6864 unpack_tide_record (allrecs_packed[i], tindex[i].record_size, &rec);
6865 free (allrecs_packed[i]);
6866 rec.header.reference_station = map[tindex[i].reference_station];
6867 pack_tide_record (&rec, &(allrecs_packed[i]), &(tindex[i].record_size));
6868 }
6869 }
6870 chk_fwrite (allrecs_packed[i], tindex[i].record_size, 1, fp);
6871 free (allrecs_packed[i]);
6872 }
6873
6874 /* Free workspace (packed records were freed above) */
6875
6876 free (allrecs_packed);
6877 free (map);
6878
6879 /* Flush, reopen, renew. The index is now garbage; close and reopen
6880 to reindex. */
6881
6882 hd.end_of_file = ftell(fp);
6883 hd.pub.number_of_records = newrecnum;
6884 modified = NVTrue;
6885 close_tide_db ();
6886 open_tide_db (filename);
6887
6888 if (db)
6889 *db = hd.pub;
6890
6891 return NVTrue;
6892}
6893
6894#endif
6895
6896/*****************************************************************************\
6897
6898 Function update_tide_record - updates a tide record in the database
6899
6900 Synopsis update_tide_record (num, rec);
6901
6902 NV_INT32 num record number
6903 TIDE_RECORD *rec tide record
6904
6905 Returns NV_BOOL NVTrue if successful
6906
6907 Author Jan C. Depner
6908 Date 08/01/02
6909
6910 See libtcd.html for changelog.
6911
6912\*****************************************************************************/
6913
6914#ifdef COMPAT114
6915NV_BOOL update_tide_record(NV_INT32 num, TIDE_RECORD *rec)
6916#else
6917NV_BOOL update_tide_record(NV_INT32 num, TIDE_RECORD *rec, DB_HEADER_PUBLIC *db)
6918#endif
6919{
6920 NV_INT32 pos, size;
6921 TIDE_RECORD tmp_rec;
6922 NV_U_BYTE *block = NULL;
6923
6924 if (!fp) {
6925 LOG_ERROR(
6926 "libtcd error: attempt to access database when database not open\n");
6927 return NVFalse;
6928 }
6929 write_protect();
6930
6931 if (num < 0 || num >= (NV_INT32)hd.pub.number_of_records) return NVFalse;
6932
6933 if (!check_tide_record(rec)) return NVFalse;
6934
6935 figure_size(rec);
6936 read_tide_record(num, &tmp_rec);
6937 if (rec->header.record_size != tmp_rec.header.record_size) {
6938 /* Aaaaaaarrrrrgggggghhhh!!!! We have to move stuff! */
6939
6940 /* Save where we are - end of record being modified. */
6941 pos = ftell(fp);
6942 assert(pos > 0);
6943
6944 /* Figure out how big a block we need to move. */
6945 size = hd.end_of_file - pos;
6946 assert(size >= 0);
6947
6948 /* Allocate memory and read the block. */
6949 if (size) {
6950 if ((block = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
6951 perror("Allocating block");
6952 return NVFalse;
6953 }
6954 chk_fread(block, size, 1, fp);
6955 }
6956
6957 /* Write out the modified record. */
6958 write_tide_record(num, rec);
6959
6960 /* If we weren't at the end of file, move the block. */
6961 if (size) {
6962 chk_fwrite(block, size, 1, fp);
6963 free(block);
6964 }
6965
6966 hd.end_of_file = ftell(fp);
6967
6968 /* Close the file and reopen it to index the records again. */
6969 close_tide_db();
6970 open_tide_db(filename);
6971 }
6972
6973 /* The easy way. No change to the record size. */
6974 else {
6975 write_tide_record(num, rec);
6976
6977 /* Save the header info in the index. */
6978 tindex[num].record_size = rec->header.record_size;
6979 tindex[num].record_type = rec->header.record_type;
6980 tindex[num].reference_station = rec->header.reference_station;
6981 tindex[num].tzfile = rec->header.tzfile;
6982 tindex[num].lat = NINT(rec->header.latitude * hd.latitude_scale);
6983 tindex[num].lon = NINT(rec->header.longitude * hd.longitude_scale);
6984
6985 /* AH maybe? */
6986 /* DWF: agree, same size record does not imply that name length
6987 is identical. */
6988 if (strcmp(tindex[num].name, rec->header.name) != 0) {
6989 free(tindex[num].name);
6990 tindex[num].name =
6991 (NV_CHAR *)calloc(strlen(rec->header.name) + 1, sizeof(NV_CHAR));
6992 strcpy(tindex[num].name, rec->header.name);
6993 }
6994 }
6995
6996#ifndef COMPAT114
6997 if (db) *db = hd.pub;
6998#endif
6999
7000 return (NVTrue);
7001}
7002
7003/*****************************************************************************\
7004
7005 Function infer_constituents - computes inferred constituents when
7006 M2, S2, K1, and O1 are given. This function fills the
7007 remaining unfilled constituents. The inferred constituents
7008 are developed or decided based on article 230 of
7009 "Manual of Harmonic Analysis and Prediction of Tides",
7010 Paul Schureman, C & GS special publication no. 98,
7011 October 1971. This function is really just for NAVO
7012 since we go to weird places and put in tide gages for
7013 ridiculously short periods of time so we only get a
7014 few major constituents developed. This function was
7015 modified from the NAVO FORTRAN program pred_tide_corr,
7016 subroutine infer.ftn, 08-oct-86.
7017
7018 Synopsis infer_constituents (rec);
7019
7020 TIDE_RECORD rec tide record
7021
7022 Returns NV_BOOL NVFalse if not enough constituents
7023 available to infer others
7024
7025 Author Jan C. Depner
7026 Date 08/01/02
7027
7028 See libtcd.html for changelog.
7029
7030\*****************************************************************************/
7031
7032NV_BOOL infer_constituents(TIDE_RECORD *rec) {
7033 NV_U_INT32 i, j;
7034 NV_INT32 m2, s2, k1, o1;
7035 NV_FLOAT32 epoch_m2, epoch_s2, epoch_k1, epoch_o1;
7036
7037 assert(rec);
7038 require((m2 = find_constituent("M2")) >= 0);
7039 require((s2 = find_constituent("S2")) >= 0);
7040 require((k1 = find_constituent("K1")) >= 0);
7041 require((o1 = find_constituent("O1")) >= 0);
7042
7043 if (rec->amplitude[m2] == 0.0 || rec->amplitude[s2] == 0.0 ||
7044 rec->amplitude[k1] == 0.0 || rec->amplitude[o1] == 0.0)
7045 return (NVFalse);
7046
7047 epoch_m2 = rec->epoch[m2];
7048 epoch_s2 = rec->epoch[s2];
7049 epoch_k1 = rec->epoch[k1];
7050 epoch_o1 = rec->epoch[o1];
7051
7052 for (i = 0; i < hd.pub.constituents; ++i) {
7053 if (rec->amplitude[i] == 0.0 && rec->epoch[i] == 0.0) {
7054 for (j = 0; j < INFERRED_SEMI_DIURNAL_COUNT; ++j) {
7055 if (!strcmp(inferred_semi_diurnal[j], get_constituent(i))) {
7056 /* Compute the inferred semi-diurnal constituent. */
7057
7058 rec->amplitude[i] =
7059 (semi_diurnal_coeff[j] / coeff[0]) * rec->amplitude[m2];
7060
7061 if (fabs((NV_FLOAT64)(epoch_s2 - epoch_m2)) > 180.0) {
7062 if (epoch_s2 < epoch_m2) {
7063 epoch_s2 += 360.0;
7064 } else {
7065 epoch_m2 += 360.0;
7066 }
7067 }
7068 rec->epoch[i] = epoch_m2 + ((hd.speed[i] - hd.speed[m2]) /
7069 (hd.speed[s2] - hd.speed[m2])) *
7070 (epoch_s2 - epoch_m2);
7071 }
7072 }
7073
7074 for (j = 0; j < INFERRED_DIURNAL_COUNT; ++j) {
7075 if (!strcmp(inferred_diurnal[j], get_constituent(i))) {
7076 /* Compute the inferred diurnal constituent. */
7077
7078 rec->amplitude[i] =
7079 (diurnal_coeff[j] / coeff[1]) * rec->amplitude[o1];
7080
7081 if (fabs((NV_FLOAT64)(epoch_k1 - epoch_o1)) > 180.0) {
7082 if (epoch_k1 < epoch_o1) {
7083 epoch_k1 += 360.0;
7084 } else {
7085 epoch_o1 += 360.0;
7086 }
7087 }
7088 rec->epoch[i] = epoch_o1 + ((hd.speed[i] - hd.speed[o1]) /
7089 (hd.speed[k1] - hd.speed[o1])) *
7090 (epoch_k1 - epoch_o1);
7091 }
7092 }
7093 }
7094 }
7095
7096 return (NVTrue);
7097}
7098
7099/* $Id: bit_pack.c 1805 2007-01-22 15:36:20Z flaterco $ */
7100
7101#include <math.h>
7102#include <stdio.h>
7103#include <assert.h>
7104
7105static NV_U_BYTE mask[8] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe},
7106 notmask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
7107
7108/*****************************************************************************\
7109
7110 DISTRIBUTION STATEMENT
7111
7112 This source file is unclassified, distribution unlimited, public
7113 domain. It is distributed in the hope that it will be useful, but
7114 WITHOUT ANY WARRANTY; without even the implied warranty of
7115 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7116
7117\*****************************************************************************/
7118
7119/***************************************************************************\
7120* *
7121* Function calculate_bits - Computes the number of bits needed *
7122* to store a specified value. *
7123* *
7124* Synopsis calculate_bits (value); *
7125* *
7126* NV_U_INT32 value the value to store *
7127* *
7128* Returns NV_U_INT32 number of bits needed *
7129* *
7130* If value = 0, return is 0. *
7131* No bits are needed to store a field whose only possible value is 0. *
7132* *
7133* Author Jan C. Depner *
7134* *
7135* Rewritten by DWF 2007-01-21 *
7136* - "Range" was ambiguous and off-by-one errors existed in tide_db.c *
7137* - Use of log10(x)/log10(2) was vulnerable to roundoff error *
7138* - Conversion to floating point was unnecessary *
7139* - Was giving the answer 0 for the input value 1 *
7140* - God only knows what it did for the input value 0 (the logarithm *
7141* is undefined) *
7142* *
7143\***************************************************************************/
7144
7145NV_U_INT32 calculate_bits(NV_U_INT32 value) {
7146 NV_U_INT32 bits = 32;
7147 NV_U_INT32 theBit = 0x80000000;
7148
7149 while (value < theBit) {
7150 theBit >>= 1;
7151 --bits;
7152 }
7153 assert(bits <= 32);
7154 return bits;
7155}
7156
7157/***************************************************************************\
7158* *
7159* Function bit_pack - Packs a long value into consecutive bits in *
7160* buffer. *
7161* *
7162* Synopsis bit_pack (buffer, start, numbits, value); *
7163* *
7164* NV_U_BYTE buffer[] address of buffer to use *
7165* NV_U_INT32 start start bit position in buffer *
7166* NV_U_INT32 numbits number of bits to store *
7167* NV_INT32 value value to store *
7168* *
7169* Description Packs the value 'value' into 'numbits' bits in 'buffer' *
7170* starting at bit position 'start'. The majority of *
7171* this code is based on Appendix C of Naval Ocean *
7172* Research and Development Activity Report #236, 'Data *
7173* Base Structure to Support the Production of the Digital *
7174* Bathymetric Data Base', Nov. 1989, James E. Braud, *
7175* John L. Breckenridge, James E. Current, Jerry L. *
7176* Landrum. *
7177* *
7178* Returns void *
7179* *
7180* Author Jan C. Depner *
7181* *
7182\***************************************************************************/
7183
7184void bit_pack(NV_U_BYTE buffer[], NV_U_INT32 start, NV_U_INT32 numbits,
7185 NV_INT32 value) {
7186 NV_INT32 start_byte, end_byte, start_bit, end_bit, i;
7187
7188 i = start + numbits;
7189
7190 /* Right shift the start and end by 3 bits, this is the same as */
7191 /* dividing by 8 but is faster. This is computing the start and end */
7192 /* bytes for the field. */
7193
7194 start_byte = start >> 3;
7195 end_byte = i >> 3;
7196
7197 /* AND the start and end bit positions with 7, this is the same as */
7198 /* doing a mod with 8 but is faster. Here we are computing the start */
7199 /* and end bits within the start and end bytes for the field. */
7200
7201 start_bit = start & 7;
7202 end_bit = i & 7;
7203
7204 /* Compute the number of bytes covered. */
7205
7206 i = end_byte - start_byte - 1;
7207
7208 /* If the value is to be stored in one byte, store it. */
7209
7210 if (start_byte == end_byte) {
7211 /* Rather tricky. We are masking out anything prior to the start */
7212 /* bit and after the end bit in order to not corrupt data that has */
7213 /* already been stored there. */
7214
7215 buffer[start_byte] &= mask[start_bit] | notmask[end_bit];
7216
7217 /* Now we mask out anything in the value that is prior to the */
7218 /* start bit and after the end bit. This is, of course, after we */
7219 /* have shifted the value left past the end bit. */
7220
7221 buffer[start_byte] |=
7222 (value << (8 - end_bit)) & (notmask[start_bit] & mask[end_bit]);
7223 }
7224
7225 /* If the value covers more than 1 byte, store it. */
7226
7227 else {
7228 /* Here we mask out data prior to the start bit of the first byte. */
7229
7230 buffer[start_byte] &= mask[start_bit];
7231
7232 /* Get the upper bits of the value and mask out anything prior to */
7233 /* the start bit. As an example of what's happening here, if we */
7234 /* wanted to store a 14 bit field and the start bit for the first */
7235 /* byte is 3, we would be storing the upper 5 bits of the value in */
7236 /* the first byte. */
7237
7238 buffer[start_byte++] |=
7239 (value >> (numbits - (8 - start_bit))) & notmask[start_bit];
7240
7241 /* Loop while decrementing the byte counter. */
7242
7243 while (i--) {
7244 /* Clear the entire byte. */
7245
7246 buffer[start_byte] &= 0;
7247
7248 /* Get the next 8 bits from the value. */
7249
7250 buffer[start_byte++] |= (value >> ((i << 3) + end_bit)) & 255;
7251 }
7252
7253 /* For the last byte we mask out anything after the end bit. */
7254
7255 buffer[start_byte] &= notmask[end_bit];
7256
7257 /* Get the last part of the value and stuff it in the end byte. */
7258 /* The left shift effectively erases anything above 8 - end_bit */
7259 /* bits in the value so that it will fit in the last byte. */
7260
7261 buffer[start_byte] |= (value << (8 - end_bit));
7262 }
7263}
7264
7265/***************************************************************************\
7266* *
7267* Function bit_unpack - Unpacks a long value from consecutive bits *
7268* in buffer. *
7269* *
7270* Synopsis bit_unpack (buffer, start, numbits); *
7271* *
7272* NV_U_BYTE buffer[] address of buffer to use *
7273* NV_U_INT32 start start bit position in buffer *
7274* NV_U_INT32 numbits number of bits to retrieve *
7275* *
7276* Description Unpacks the value from 'numbits' bits in 'buffer' *
7277* starting at bit position 'start'. The value is assumed *
7278* to be unsigned. The majority of this code is based on *
7279* Appendix C of Naval Ocean Research and Development *
7280* Activity Report #236, 'Data Base Structure to Support *
7281* the Production of the Digital Bathymetric Data Base', *
7282* Nov. 1989, James E. Braud, John L. Breckenridge, James *
7283* E. Current, Jerry L. Landrum. *
7284* *
7285* Returns NV_U_INT32 value retrieved from buffer *
7286* *
7287* Author Jan C. Depner *
7288* *
7289\***************************************************************************/
7290
7291NV_U_INT32 bit_unpack(NV_U_BYTE buffer[], NV_U_INT32 start,
7292 NV_U_INT32 numbits) {
7293 NV_INT32 start_byte, end_byte, start_bit, end_bit, i;
7294 NV_U_INT32 value;
7295
7296 i = start + numbits;
7297
7298 /* Right shift the start and end by 3 bits, this is the same as */
7299 /* dividing by 8 but is faster. This is computing the start and end */
7300 /* bytes for the field. */
7301
7302 start_byte = start >> 3;
7303 end_byte = i >> 3;
7304
7305 /* AND the start and end bit positions with 7, this is the same as */
7306 /* doing a mod with 8 but is faster. Here we are computing the start */
7307 /* and end bits within the start and end bytes for the field. */
7308
7309 start_bit = start & 7;
7310 end_bit = i & 7;
7311
7312 /* Compute the number of bytes covered. */
7313
7314 i = end_byte - start_byte - 1;
7315
7316 /* If the value is stored in one byte, retrieve it. */
7317
7318 if (start_byte == end_byte) {
7319 /* Mask out anything prior to the start bit and after the end bit. */
7320
7321 value =
7322 (NV_U_INT32)buffer[start_byte] & (notmask[start_bit] & mask[end_bit]);
7323
7324 /* Now we shift the value to the right. */
7325
7326 value >>= (8 - end_bit);
7327 }
7328
7329 /* If the value covers more than 1 byte, retrieve it. */
7330
7331 else {
7332 /* Here we mask out data prior to the start bit of the first byte */
7333 /* and shift to the left the necessary amount. */
7334
7335 value = (NV_U_INT32)(buffer[start_byte++] & notmask[start_bit])
7336 << (numbits - (8 - start_bit));
7337
7338 /* Loop while decrementing the byte counter. */
7339
7340 while (i--) {
7341 /* Get the next 8 bits from the buffer. */
7342
7343 value += (NV_U_INT32)buffer[start_byte++] << ((i << 3) + end_bit);
7344 }
7345
7346 /* For the last byte we mask out anything after the end bit and */
7347 /* then shift to the right (8 - end_bit) bits. */
7348 if (mask[end_bit]) {
7349 value += (NV_U_INT32)(buffer[start_byte] & mask[end_bit]) >> (8 - end_bit);
7350 }
7351 }
7352
7353 return (value);
7354}
7355
7356/***************************************************************************\
7357* *
7358* Function signed_bit_unpack - Unpacks a signed long value from *
7359* consecutive bits in buffer. *
7360* *
7361* Synopsis signed_bit_unpack (buffer, start, numbits); *
7362* *
7363* NV_U_BYTE buffer[] address of buffer to use *
7364* NV_U_INT32 start start bit position in buffer *
7365* NV_U_INT32 numbits number of bits to retrieve *
7366* *
7367* Description Unpacks the value from 'numbits' bits in 'buffer' *
7368* starting at bit position 'start'. The value is assumed *
7369* to be signed. The majority of this code is based on *
7370* Appendix C of Naval Ocean Research and Development *
7371* Activity Report #236, 'Data Base Structure to Support *
7372* the Production of the Digital Bathymetric Data Base', *
7373* Nov. 1989, James E. Braud, John L. Breckenridge, James *
7374* E. Current, Jerry L. Landrum. *
7375* *
7376* Returns NV_INT32 value retrieved from buffer *
7377* *
7378* Author Jan C. Depner *
7379* *
7380\***************************************************************************/
7381
7382NV_INT32 signed_bit_unpack(NV_U_BYTE buffer[], NV_U_INT32 start,
7383 NV_U_INT32 numbits) {
7384 static NV_INT32 extend_mask = 0x7fffffff;
7385 NV_INT32 value;
7386
7387 /* This function is not used anywhere that this case could arise. */
7388 assert(numbits > 0);
7389
7390 value = bit_unpack(buffer, start, numbits);
7391
7392 if (value & (1 << (numbits - 1))) value |= (extend_mask << numbits);
7393
7394 return (value);
7395}
Definition: IDX_entry.h:41
Definition: tcmgr.h:603
Runtime representation of a plugin block.