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