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