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