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