home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xephem / part19 / db.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-15  |  17.9 KB  |  780 lines

  1. /* code to manage what the outside world sees as the db_ interface.
  2.  */
  3.  
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include <malloc.h>
  7. #include <math.h>
  8. #if defined(__STDC__)
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #endif
  12. #include "astro.h"
  13. #include "circum.h"
  14. #include "preferences.h"
  15.  
  16.  
  17. #if defined(__STDC__) || defined(__cplusplus)
  18. #define P_(s) s
  19. #else
  20. #define P_(s) ()
  21. #endif
  22.  
  23. extern Now *mm_get_now P_((void));
  24. extern int obj_cir P_((Now *np, Obj *op));
  25. extern void cal_mjd P_((int mn, double dy, int yr, double *Mjd));
  26. extern void f_dec_sexsign P_((double x, int *h, int *m, int *s));
  27. extern void f_sscandate P_((char *bp, int pref, int *m, double *d, int *y));
  28. extern void f_sscansex P_((char *bp, int *d, int *m, int *s));
  29. extern void mjd_cal P_((double Mjd, int *mn, double *dy, int *yr));
  30. extern void sex_dec P_((int hd, int m, int s, double *d));
  31. extern void xe_msg P_((char *msg, int app_modal));
  32. extern void zero_mem P_((char *loc, unsigned len));
  33.  
  34. int db_n P_((void));
  35. Obj *db_basic P_((int id));
  36. void db_setuserobj P_((int id, Obj *op));
  37. void db_invalidate P_((void));
  38. Obj *db_next P_((Obj *op, HowNext how));
  39. void db_update P_((Obj *op));
  40. int db_read P_((FILE *fp, int append));
  41. int db_set_field P_((char bp[], int id, PrefDateFormat pref, Obj *op));
  42. static Obj *db_new P_((int t));
  43. static db_crack_line P_((char *s));
  44. static void db_init P_((void));
  45. static int nxt_db P_((char buf[], int blen, FILE *fp));
  46. static void crack_year P_((char *bp, PrefDateFormat pref, double *p));
  47. /* don't know why but my compiler complains with this one in here
  48. static get_fields P_((char *s, char delim, char *fields[]));
  49. */
  50. static get_fields ();
  51.  
  52. #undef P_
  53.  
  54. #define    MAXDBLINE    256    /* longest allowable database file line */
  55. #define    FLDSEP        ','    /* major field separator */
  56. #define    SUBFLD        '|'    /* subfield separator */
  57.  
  58. #define    ASIZ(a)    (sizeof(a)/sizeof(a[0]))
  59.  
  60. /* This counter is incremented when we want to mark all the Obj derived entries
  61.  * as being out-of-date. This works because then each of the age's will be !=
  62.  * db_age. This is to eliminate ever calling obj_cir() under the same
  63.  * circumstances for a given db object.
  64.  * N.B. For this to work, call db_update() before using a Obj *.
  65.  */
  66. static Objage_t db_age;
  67.  
  68. /* the "database".
  69.  * there is a malloced array of each each type of object.
  70.  * N.B. first NOBJ (see astro.h) objects are kept as a special case.
  71.  * each array has nmem entries, nobj of which are valid; we realloc in groups
  72.  * of DBMEMCHUNKS as a malloc cache.
  73.  */
  74. #define    DBMEMCHUNKS    200    /* number of things we realloc more at once */
  75. static char *db[NOBJTYPES];    /* actually arrays of each subtype */
  76. static int nobj[NOBJTYPES];    /* number of entries in db[type] valid */
  77. static int nmem[NOBJTYPES];    /* total number of entries in db[type] */
  78. static Obj basic[NOBJ];        /* special storage for the basic objects */
  79. static int totnobj;        /* grand total number of objects */
  80. static int objsize[NOBJTYPES];    /* sizeof each type */
  81.  
  82. /* return number of objects in the database.
  83.  * N.B. this is expected to be very inexpensive to call.
  84.  */
  85. int
  86. db_n()
  87. {
  88.     if (!totnobj)
  89.         db_init();
  90.     return (totnobj);
  91. }
  92.  
  93. /* given one of the basic ids in astro.h return pointer to its Obj in the
  94.  * database.
  95.  */
  96. Obj *
  97. db_basic(id)
  98. int id;
  99. {
  100.     Obj *op;
  101.  
  102.     if (!totnobj)
  103.         db_init();
  104.  
  105.     if (id < 0 || id >= NOBJ) {
  106.         printf ("db_basic(): bad id: %d\n", id);
  107.         exit (1);
  108.     }
  109.  
  110.     op = &basic[id];
  111.     if (op->type != UNDEFOBJ)
  112.         db_update(op);
  113.     return (op);
  114. }
  115.  
  116. /* the user defined object named by id to op.
  117.  */
  118. void
  119. db_setuserobj(id, op)
  120. int id;    /* OBJX or OBJY */
  121. Obj *op;
  122. {
  123.     if (id == OBJX || id == OBJY)
  124.         basic[id] = *op;
  125.     else {
  126.         printf ("db_setuserobj(): bad id: %d\n", id);
  127.         exit (1);
  128.     }
  129. }
  130.  
  131. /* mark all db objects as old
  132.  */
  133. void
  134. db_invalidate()
  135. {
  136.     if (!totnobj)
  137.         db_init();
  138.  
  139.     db_age++;
  140. }
  141.  
  142. /* given an Obj * into the the db storage, return the "next" one.
  143.  * the idea is to call this function repeatedly to scan for all objects.
  144.  * if op is NULL, return the "first" one.
  145.  * return NULL if there are no more.
  146.  * the series can be limited as to how the basic (NOBJ) set should be included
  147.  *   by adjusting the how parameter.
  148.  * N.B. nothing should be assumed as to the order these are returned.
  149.  * N.B. the s_ fields are *not* updated -- all db_update() when you need that.
  150.  */
  151. Obj *
  152. db_next (op, how)
  153. Obj *op;
  154. HowNext how;
  155. {
  156.     static char me[] = "db_next()";
  157.     int i;
  158.  
  159.     if (!totnobj)
  160.         db_init();
  161.  
  162.     switch (how) {
  163.     case OBJS_JUST_BASIC:
  164.         if (op == NULL)
  165.         return (&basic[0]);
  166.         if (op >= &basic[0] && op < &basic[NOBJ-1])
  167.         return (&basic[op-basic+1]);
  168.         if (op == &basic[NOBJ-1])
  169.         return (NULL);
  170.         break;
  171.     case OBJS_ALL:
  172.         if (op == NULL)
  173.         return (&basic[0]);
  174.         if (op >= &basic[0] && op < &basic[NOBJ-1])
  175.         return (&basic[op-basic+1]);
  176.         /* continue on to remaining stuff ... */
  177.     case OBJS_ALLBUT_BASIC:
  178.         if (op == NULL || op == &basic[NOBJ-1]) {
  179.         for (i = 0; i < NOBJTYPES; i++)
  180.             if (nobj[i] > 0)
  181.             return ((Obj *)db[i]);
  182.         return (NULL);
  183.         }
  184.         for (i = 0; i < NOBJTYPES; i++) {
  185.         char *cp, *lastp;
  186.         if (nobj[i] == 0)
  187.             continue;
  188.         lastp = db[i] + objsize[i]*(nobj[i]-1);
  189.         cp = (char *)op;
  190.         if (cp >= db[i] && cp < lastp)
  191.             return ((Obj *)(cp + objsize[i]));
  192.         if (cp == lastp) {
  193.             while (++i < NOBJTYPES)
  194.             if (nobj[i] > 0)
  195.                 return ((Obj *)db[i]);
  196.             return (NULL);
  197.         }
  198.         }
  199.         break;
  200.     default:
  201.         printf ("%s: bad how: %d\n", me, how);
  202.         exit (1);
  203.     }
  204.  
  205.     printf ("%s: bad op = 0x%x\n", me, (unsigned) op);
  206.     exit(1);
  207.     return (NULL);    /* just for lint */
  208. }
  209.     
  210.  
  211. /* see that all the s_* fields in the given object are up to date.
  212.  * always recompute the user defined objects because we don't know when
  213.  * they might have been changed.
  214.  * N.B. it is ok to call this even if op is not actually in the database
  215.  *   although we guarante an actual update occurs if it't not.
  216.  */
  217. void
  218. db_update(op)
  219. Obj *op;
  220. {
  221.     static char me[] = "db_update()";
  222.  
  223.     if (!totnobj)
  224.         db_init();
  225.  
  226.     if (op->type == UNDEFOBJ) {
  227.         printf ("%s: called with UNDEFOBJ pointer\n", me);
  228.         exit (1);
  229.     } 
  230.     if (op->type <= 0 || op->type >= NOBJTYPES) {
  231.         printf ("%s: called with bad pointer\n", me);
  232.         exit (1);
  233.     } 
  234.  
  235.     if (op->o_age != db_age || op == &basic[OBJX] || op == &basic[OBJY]) {
  236.         if (obj_cir (mm_get_now(), op) < 0) {
  237.         printf ("%s: bad object\n", me);
  238.         exit(1);
  239.         }
  240.         op->o_age = db_age;
  241.     }
  242. }
  243.  
  244. /* read the given database file into memory.
  245.  * if append is set, add to the existing list, else discard all but the
  246.  * basic NOBJ set first.
  247.  * return 0 if all ok, else -1.
  248.  */
  249. db_read (fp, append)
  250. FILE *fp;
  251. int append;
  252. {
  253.     char buf[MAXDBLINE];
  254.     int nobjsave[NOBJTYPES];
  255.     int nnew;
  256.     int i;
  257.  
  258.     if (!totnobj)
  259.         db_init();
  260.  
  261.     if (!append) {
  262.         /* not appending so discard all existing objects */
  263.         for (i = 0; i < NOBJTYPES; i++) {
  264.         if (db[i]) {
  265.             free (db[i]);
  266.             db[i] = NULL;
  267.         }
  268.         nmem[i] = 0;
  269.         nobj[i] = 0;
  270.         }
  271.         totnobj = NOBJ;
  272.     }
  273.  
  274.     /* save the current number of objects in case we have trouble so
  275.      * we can effectively reset the db back to what it is before.
  276.      */
  277.     for (i = 0; i < NOBJTYPES; i++)
  278.         nobjsave[i] = nobj[i];
  279.  
  280.     /* read each line from the file and add to the db */
  281.     for (nnew = 0;
  282.         nxt_db (buf, sizeof(buf), fp) == 0 && db_crack_line (buf) == 0;
  283.         nnew++)
  284.         continue;
  285.     
  286.     if (!feof(fp)) {
  287.         /* couldn't read entire file -- discard everything we've added.
  288.          * ok to leave the raw memory allocated.
  289.          */
  290.         for (i = 0; i < NOBJTYPES; i++)
  291.         nobj[i] = nobjsave[i];
  292.         return (-1);
  293.     }
  294.  
  295.     totnobj += nnew;
  296.     return (0);
  297. }
  298.  
  299. /* given a text buffer and a field id, and a PREF_DATE_FORMAT,
  300.  *   set the corresponding member in *op.
  301.  * return 0 if ok, else -1.
  302.  */
  303. db_set_field (bp, id, pref, op)
  304. char bp[];
  305. PrefDateFormat pref;
  306. Obj *op;
  307. {
  308.     switch (id) {
  309.     case O_NAME: {
  310.         (void) strncpy (op->o_name, bp, sizeof(op->o_name)-1);
  311.         op->o_name[sizeof(op->o_name)-1] = '\0';
  312.         break;
  313.     }
  314.     case F_RA: {
  315.         int h, m, s;
  316.         double f_ra;
  317.         f_dec_sexsign (radhr(op->f_RA), &h, &m, &s);
  318.         f_sscansex (bp, &h, &m, &s);
  319.         f_ra = op->f_RA;
  320.         sex_dec (h, m, s, &f_ra);
  321.         op->f_RA = hrrad(f_ra);
  322.         break;
  323.     }
  324.     case F_DEC: {
  325.         int dg, m, s;
  326.         double tdec;
  327.         f_dec_sexsign (raddeg(op->f_dec), &dg, &m, &s);
  328.         f_sscansex (bp, &dg, &m, &s);
  329.         tdec = op->f_dec;
  330.         sex_dec (dg, m, s, &tdec);
  331.         op->f_dec = degrad(tdec);
  332.         break;
  333.     }
  334.     case F_MAG:
  335.         op->f_mag = atof (bp) * MAGSCALE;
  336.         break;
  337.     case F_SIZE:
  338.         op->f_size = atof (bp);
  339.         break;
  340.     case F_EPOCH: {
  341.         double fepoch;
  342.         fepoch = op->f_epoch;
  343.         crack_year (bp, pref, &fepoch);
  344.         op->f_epoch = fepoch;
  345.         break;
  346.     }
  347.     case F_CLASS:
  348.         switch (bp[0]) {
  349.         case 'C': case 'U': case 'O': case 'G': case 'H': case 'A':
  350.         case 'N': case 'F': case 'K': case 'P': case 'Q': case 'T':
  351.         case 'B': case 'D': case 'M': case 'S': case 'V':
  352.         op->f_class = bp[0];
  353.         break;
  354.         default:
  355.         return (-1);
  356.         }
  357.         break;
  358.     case F_SPECT: {
  359.         int i, j;
  360.         /* fill f_spect all the way */
  361.         for (i = j = 0; i < sizeof(op->f_spect); i++)
  362.         if ((op->f_spect[i] = bp[j]) != 0)
  363.             j++;
  364.         break;
  365.     }
  366.  
  367.     case E_INC:
  368.         op->e_inc = atof (bp);
  369.         break;
  370.     case E_LAN:
  371.         op->e_Om = atof (bp);
  372.         break;
  373.     case E_AOP:
  374.         op->e_om = atof (bp);
  375.         break;
  376.     case E_A:
  377.         op->e_a = atof (bp);
  378.         break;
  379.     case E_N:
  380.         op->e_n = atof (bp);
  381.         break;
  382.     case E_E:
  383.         op->e_e = atof (bp);
  384.         break;
  385.     case E_M:
  386.         op->e_M = atof (bp);
  387.         break;
  388.     case E_CEPOCH:
  389.         crack_year (bp, pref, &op->e_cepoch);
  390.         break;
  391.     case E_EPOCH:
  392.         crack_year (bp, pref, &op->e_epoch);
  393.         break;
  394.     case E_M1:
  395.         switch (bp[0]) {
  396.         case 'g':
  397.         op->e_mag.whichm = MAG_gk;
  398.         bp++;
  399.         break;
  400.         case 'H':
  401.         op->e_mag.whichm = MAG_HG;
  402.         bp++;
  403.         break;
  404.         default:
  405.         /* leave type unchanged if no or unrecognized prefix */
  406.         break;
  407.         }
  408.         op->e_mag.m1 = atof(bp);
  409.         break;
  410.     case E_M2:
  411.         switch (bp[0]) {
  412.         case 'k':
  413.         op->e_mag.whichm = MAG_gk;
  414.         bp++;
  415.         break;
  416.         case 'G':
  417.         op->e_mag.whichm = MAG_HG;
  418.         bp++;
  419.         break;
  420.         default:
  421.         /* leave type unchanged if no or unrecognized prefix */
  422.         break;
  423.         }
  424.         op->e_mag.m2 = atof(bp);
  425.         break;
  426.     case E_SIZE:
  427.         op->e_size = atof (bp);
  428.         break;
  429.  
  430.     case H_EP:
  431.         crack_year (bp, pref, &op->h_ep);
  432.         break;
  433.     case H_INC:
  434.         op->h_inc = atof (bp);
  435.         break;
  436.     case H_LAN:
  437.         op->h_Om = atof (bp);
  438.         break;
  439.     case H_AOP:
  440.         op->h_om = atof (bp);
  441.         break;
  442.     case H_E:
  443.         op->h_e = atof (bp);
  444.         break;
  445.     case H_QP:
  446.         op->h_qp = atof (bp);
  447.         break;
  448.     case H_EPOCH:
  449.         crack_year (bp, pref, &op->h_epoch);
  450.         break;
  451.     case H_G:
  452.         op->h_g = atof (bp);
  453.         break;
  454.     case H_K:
  455.         op->h_k = atof (bp);
  456.         break;
  457.     case H_SIZE:
  458.         op->h_size = atof (bp);
  459.         break;
  460.  
  461.     case P_EP:
  462.         crack_year (bp, pref, &op->p_ep);
  463.         break;
  464.     case P_INC:
  465.         op->p_inc = atof (bp);
  466.         break;
  467.     case P_AOP:
  468.         op->p_om = atof (bp);
  469.         break;
  470.     case P_QP:
  471.         op->p_qp = atof (bp);
  472.         break;
  473.     case P_LAN:
  474.         op->p_Om = atof (bp);
  475.         break;
  476.     case P_EPOCH:
  477.         crack_year (bp, pref, &op->p_epoch);
  478.         break;
  479.     case P_G:
  480.         op->p_g = atof (bp);
  481.         break;
  482.     case P_K:
  483.         op->p_k = atof (bp);
  484.         break;
  485.     case P_SIZE:
  486.         op->p_size = atof (bp);
  487.         break;
  488.     default:
  489.         printf ("BUG! db_set_field: bad id: %d\n", id);
  490.         exit (1);
  491.     }
  492.  
  493.     return (0);
  494. }
  495.  
  496. /* allocate and return zero'd room for a new object with the given type.
  497.  * N.B we do *not* validate t.
  498.  * reurn NULL if can't get more room.
  499.  */
  500. static Obj *
  501. db_new (t)
  502. int t;
  503. {
  504.     int size = objsize[t];
  505.     int newidx;
  506.  
  507.     /* allocate more room if this type can't hold another one */
  508.     if (nobj[t] >= nmem[t]) {
  509.         int oldn = nmem[t];
  510.         int newn = oldn + DBMEMCHUNKS;
  511.         char *newp = db[t] ? realloc (db[t], size*newn)
  512.                    : malloc (size*newn);
  513.         if (!newp)
  514.         return (NULL);
  515.         zero_mem (newp + size*oldn, size*DBMEMCHUNKS);
  516.         nmem[t] = newn;
  517.         db[t] = newp;
  518.     }
  519.  
  520.     /* the next index to use is the current number of entries */
  521.     newidx = nobj[t]++;
  522.  
  523.     /* find the address of the new entry */
  524.     return ((Obj *)(db[t] + size*newidx));
  525. }
  526.  
  527. /* crack the given database line and add to corresponding db list.
  528.  * return 0 if ok else put up a message and return -1.
  529.  */
  530. static
  531. db_crack_line (s)
  532. char *s;
  533. {
  534.     static char nomem[] = "Insufficient memory to load this database\n";
  535. #define    MAXFLDS    20        /* must be more than on any expected line */
  536.     char *flds[MAXFLDS];    /* point to each field for easy reference */
  537.     char *sflds[MAXFLDS];    /* point to each sub field for easy reference */
  538.     char copy[MAXDBLINE];    /* work copy; leave s untouched */
  539.     char msg[512];        /* misc message buffer */
  540.     int nf, nsf;        /* number of fields and subfields */
  541.     Obj *op;
  542.     int i;
  543.  
  544.     /* do all the parsing on a copy */
  545.     (void) strcpy (copy, s);
  546.  
  547.     /* parse into main fields */
  548.     nf = get_fields (copy, FLDSEP, flds);
  549.  
  550.     /* need at least 2: name and type */
  551.     if (nf < 2) {
  552.         (void)sprintf(msg, "Too few fields in Database line: `%.480s'\n",s);
  553.         xe_msg (msg, 0);
  554.         return (-1);
  555.     }
  556.  
  557.     /* switch out on type of object - the second field */
  558.     switch (flds[1][0]) {
  559.     case 'f': {
  560.         static int ids[] = {F_RA, F_DEC, F_MAG, F_EPOCH};
  561.         if (nf != 6 && nf != 7) {
  562.         (void)sprintf(msg,
  563.             "Need ra,dec,mag,[epoch][,siz] for fixed object `%.460s'\n",
  564.                                     flds[0]);
  565.         xe_msg (msg, 0);
  566.         return (-1);
  567.         }
  568.         op = db_new(FIXED);
  569.         if (!op) {
  570.         xe_msg (nomem, 1);
  571.         return (-1);
  572.         }
  573.         op->type = FIXED;
  574.         nsf = get_fields(flds[1], SUBFLD, sflds);
  575.         if (nsf > 1 && db_set_field (sflds[1], F_CLASS, PREF_MDY, op) < 0) {
  576.         (void) sprintf(msg,"Bad class `%c' for fixed object `%.450s'\n",
  577.                                 *sflds[1], flds[0]);
  578.         xe_msg (msg, 0);
  579.         return (-1);
  580.         }
  581.         if (nsf > 2)
  582.         (void) db_set_field (sflds[2], F_SPECT, PREF_MDY, op);
  583.         for (i = 2; i < ASIZ(ids)+2; i++)
  584.         (void) db_set_field (flds[i], ids[i-2], PREF_MDY, op);
  585.         if (nf == 7)
  586.         (void) db_set_field (flds[6], F_SIZE, PREF_MDY, op);
  587.         break;
  588.     }
  589.  
  590.     case 'e': {
  591.         static int ids[] = {E_INC, E_LAN, E_AOP, E_A, E_N, E_E, E_M,
  592.                         E_CEPOCH, E_EPOCH, E_M1, E_M2
  593.         };
  594.         if (nf != 13 && nf != 14) {
  595.         (void)sprintf (msg,
  596.             "Need i,O,o,a,n,e,M,E,D,H/g,G/k[,siz] for elliptical object `%.450s'\n",
  597.                                     flds[0]);
  598.         xe_msg(msg, 0);
  599.         return (-1);
  600.         }
  601.         op = db_new(ELLIPTICAL);
  602.         if (!op) {
  603.         xe_msg (nomem, 1);
  604.         return (-1);
  605.         }
  606.         op->type = ELLIPTICAL;
  607.         for (i = 2; i < ASIZ(ids)+2; i++)
  608.         (void) db_set_field (flds[i], ids[i-2], PREF_MDY, op);
  609.         if (nf == 14)
  610.         (void) db_set_field (flds[13], E_SIZE, PREF_MDY, op);
  611.         break;
  612.     }
  613.  
  614.     case 'h': {
  615.         static int ids[]= {H_EP,H_INC,H_LAN,H_AOP,H_E,H_QP,H_EPOCH,H_G,H_K};
  616.         if (nf != 11 && nf != 12) {
  617.         (void)sprintf (msg,
  618.             "Need T,i,O,o,e,q,D,g,k[,siz] for hyperbolic object `%.450s'\n",
  619.                                     flds[0]);
  620.         xe_msg(msg, 0);
  621.         return (-1);
  622.         }
  623.         op = db_new(HYPERBOLIC);
  624.         if (!op) {
  625.         xe_msg (nomem, 1);
  626.         return (-1);
  627.         }
  628.         op->type = HYPERBOLIC;
  629.         for (i = 2; i < ASIZ(ids)+2; i++)
  630.         (void) db_set_field (flds[i], ids[i-2], PREF_MDY, op);
  631.         if (nf == 12)
  632.         (void) db_set_field (flds[11], H_SIZE, PREF_MDY, op);
  633.         break;
  634.     }
  635.  
  636.     case 'p': {
  637.         static int ids[] = {P_EP,P_INC,P_AOP,P_QP,P_LAN,P_EPOCH,P_G,P_K};
  638.         if (nf != 10 && nf != 11) {
  639.         (void)sprintf (msg,
  640.             "Need T,i,o,q,O,D,g,k[,siz] for parabolic object `%.450s'\n",
  641.                                     flds[0]);
  642.         xe_msg(msg, 0);
  643.         return (-1);
  644.         }
  645.         op = db_new(PARABOLIC);
  646.         if (!op) {
  647.         xe_msg (nomem, 1);
  648.         return (-1);
  649.         }
  650.         op->type = PARABOLIC;
  651.         for (i = 2; i < ASIZ(ids)+2; i++)
  652.         (void) db_set_field (flds[i], ids[i-2], PREF_MDY, op);
  653.         if (nf == 11)
  654.         (void) db_set_field (flds[10], P_SIZE, PREF_MDY, op);
  655.         break;
  656.     }
  657.  
  658.     default:
  659.         (void)sprintf (msg,
  660.         "Unknown type for Object %s: `%.480s'\n", flds[0], flds[1]);
  661.         xe_msg(msg, 0);
  662.         return (-1);
  663.     }
  664.  
  665.     /* load up name */
  666.     (void) db_set_field (flds[0], O_NAME, PREF_MDY, op);
  667.  
  668.     return (0);
  669. }
  670.  
  671. /* set up the basic database.
  672.  */
  673. static void
  674. db_init()
  675. {
  676.     /* these must match the order in astro.h */
  677.     static char *planet_names[] = {
  678.         "Mercury", "Venus", "Mars", "Jupiter", "Saturn",
  679.         "Uranus", "Neptune", "Pluto", "Sun", "Moon",
  680.     };
  681.  
  682.     int i;
  683.  
  684.     /* init the planets */
  685.     for (i = MERCURY; i <= MOON; i++) {
  686.         Obj *op = &basic[i];
  687.         op->type = PLANET;
  688.         (void) strncpy (op->o_name, planet_names[i], sizeof(op->o_name)-1);
  689.         op->pl.code = i;
  690.     }
  691.  
  692.     /* the total includes the planets and the 2 undefined user objs too */
  693.     totnobj = NOBJ;
  694.  
  695.     /* init the object size array */
  696.     objsize[UNDEFOBJ] =    0;
  697.     objsize[FIXED] =    sizeof(ObjF);
  698.     objsize[ELLIPTICAL] =    sizeof(ObjE);
  699.     objsize[HYPERBOLIC] =    sizeof(ObjH);
  700.     objsize[PARABOLIC] =    sizeof(ObjP);
  701.     objsize[PLANET] =    sizeof(ObjPl);
  702. }
  703.  
  704. /* read database file fp and put next valid entry (sans trailing \n) into buf.
  705.  * we only count those lines that begin with alpha or numeric chars.
  706.  * return 0 if ok.
  707.  * if eof: return -1; caller will find that feof(fp) is true;
  708.  * other errors: print a message and return -1.
  709.  */
  710. static int
  711. nxt_db (buf, blen, fp)
  712. char buf[];
  713. int blen;
  714. FILE *fp;
  715. {
  716.     char c;
  717.     int l;
  718.  
  719.     for (;;) {
  720.         if (fgets (buf, blen, fp) == 0)
  721.         return (-1);
  722.         l = strlen(buf);
  723.         if (buf[l-1] != '\n') {
  724.         xe_msg ("Databse file line length is too long\n", 1);
  725.         return (-1);
  726.         }
  727.         c = buf[0];
  728.         if (isalpha(c) || isdigit(c)) {
  729.         buf[l-1] = '\0';
  730.         return (0);
  731.         }
  732.     }
  733. }
  734.  
  735. /* given either a decimal year (xxxx[.xxx]) or a calendar (x/x/x)
  736.  * and a DateFormat preference convert it to an mjd and store it at *p.
  737.  */
  738. static void
  739. crack_year (bp, pref, p)
  740. char *bp;
  741. PrefDateFormat pref;
  742. double *p;
  743. {
  744.     int m, y;
  745.     double d;
  746.  
  747.     mjd_cal (*p, &m, &d, &y);    /* init with current */
  748.     f_sscandate (bp, pref, &m, &d, &y);
  749.     cal_mjd (m, d, y, p);
  750. }
  751.  
  752. /* given a null-terminated string, fill in fields[] with the starting addresses
  753.  * of each field delimited by delim or '\0'.
  754.  * N.B. each character matching delim is REPLACED BY '\0' IN PLACE.
  755.  * N.B. 0-length fields count, so even if *s=='\0' we return 1.
  756.  * return the number of fields.
  757.  */
  758. static
  759. get_fields (s, delim, fields)
  760. char *s;
  761. char delim;
  762. char *fields[];
  763. {
  764.     int n;
  765.     char c;
  766.  
  767.     *fields = s;
  768.     n = 0;
  769.     do {
  770.         c = *s++;
  771.         if (c == delim || c == '\0') {
  772.         s[-1] = '\0';
  773.         *++fields = s;
  774.         n++;
  775.         }
  776.     } while (c);
  777.  
  778.     return (n);
  779. }
  780.