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