File: details.cpp

package info (click to toggle)
pluto-find-orb 0.0~git20180227-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 2,668 kB
  • sloc: cpp: 30,743; makefile: 263
file content (281 lines) | stat: -rw-r--r-- 9,721 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/* details.cpp : code to store/access 'observational details' (header)
data for 80-column MPC-formatted astrometry,  as documented at

http://www.minorplanetcenter.net/iau/info/ObsDetails.html */

#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include "stackall.h"
#include "details.h"

typedef struct
{
   char **lines;
   size_t n_lines;
   bool observations_found;
} mpc_code_details_t;

typedef struct
{
   void *stack;
   mpc_code_details_t *code_details;
   int n_code_details;
   int curr_idx;        /* index into code_details for last COD line seen */
} observation_details_t;

#define min_n_code_details 16
#define min_code_lines 16

void *init_observation_details( void)
{
   void *stack = create_stack( 2000);
   observation_details_t *rval = (observation_details_t *)
                     stack_calloc( stack, sizeof( observation_details_t));

   rval->stack = stack;
   rval->curr_idx = -1;    /* i.e.,  "no COD line yet" */
   rval->code_details = (mpc_code_details_t *)stack_calloc( stack,
                              min_n_code_details * sizeof( mpc_code_details_t));
   return( rval);
}

      /* A useful piece of bit-twiddling. X & (X-1) clears the lowest */
      /* bit of X.  If X is a power of two,  you've only got one bit  */
      /* to clear,  and the result is zero. */
#define is_power_of_two( X)   (!((X) & ((X) - 1)))

/* Binary-search to find the desired MPC code in the 'code_details' array.
Or where that code ought to be put in,  if we're adding a new code (in
which case *cmp will be nonzero.) */

static int code_cmp( const char *a, const char *b)
{
   int rval;

   while( *a == *b && *a)
      {
      a++;
      b++;
      }
   if( *a <= ' ' && *b <= ' ')
      rval = 0;
   else
      rval = *a - *b;
   return( rval);
}

static int find_code_details( const observation_details_t *det,
                 const char *mpc_code, int *cmp)
{
   int loc = -1, stepsize = (int)0x8000, compare = 1, loc1;

   while( compare && (stepsize >>= 1))
      if( (loc1 = loc + stepsize) < det->n_code_details)
         {
         assert( det->code_details[loc1].lines);
         compare = code_cmp( mpc_code, det->code_details[loc1].lines[0] + 4);
         if( compare >= 0)
            loc = loc1;
         }
   *cmp = compare;
   return( loc);
}

const char **get_code_details( const void *obs_details, const char *mpc_code)
{
   const observation_details_t *det = (const observation_details_t *)obs_details;
   int idx, compare;

#ifdef DEBUG_PRINTFS
   printf( "We've got %d details :", det->n_code_details);
   for( idx = 0; idx < det->n_code_details; idx++)
      printf( " '%s'", det->code_details[idx].lines[0]);
   printf( " And that's it\n");
#endif
   idx = find_code_details( det, mpc_code, &compare);
   if( !compare)
      return( (const char **)det->code_details[idx].lines);
   else
      return( NULL);
}

static int reset_mpc_code( observation_details_t *det, const char *mpc_code)
{
   int compare, idx = find_code_details( det, mpc_code, &compare);

#ifdef DEBUG_PRINTFS
   printf( "Resetting MPC code: idx %d, compare %d, %d details\n",
               idx, compare, det->n_code_details);
#endif
   if( compare)   /* not an MPC code we've already encountered */
      {
      idx++;
      det->n_code_details++;
      if( is_power_of_two( det->n_code_details) && det->n_code_details >= min_n_code_details)
         {
         mpc_code_details_t *new_array = (mpc_code_details_t *)
                  stack_alloc( det->stack, 2 * det->n_code_details * sizeof( mpc_code_details_t));

         memcpy( new_array, det->code_details, det->n_code_details * sizeof( mpc_code_details_t));
         det->code_details = new_array;
         }
#ifdef DEBUG_PRINTFS
      printf( "Moving memory\n");
#endif
      memmove( det->code_details + idx + 1, det->code_details + idx,
                  (det->n_code_details - idx) * sizeof( mpc_code_details_t));
#ifdef DEBUG_PRINTFS
      printf( "Moved memory\n");
#endif
      }
   det->code_details[idx].observations_found = false;
   det->code_details[idx].n_lines = 0;
   det->code_details[idx].lines = (char **)stack_calloc( det->stack,
                     (min_code_lines + 1) * sizeof( char *));
   det->curr_idx = idx;
#ifdef DEBUG_PRINTFS
   printf( "Done\n");
#endif
   return( 0);
}

static int probable_mpc_record( const char *buff)
{
   int i, rval = 1;     /* assume it's a valid record */

   if( buff[12] != ' ' && buff[12] != '*' && buff[12] != '-')
      rval = 0;
   for( i = 77; i < 80; i++)
      if( buff[i] <= ' ' || buff[i] > 'z')
         rval = 0;
   return( rval);
}

int add_line_to_observation_details( void *obs_details, const char *iline)
{
   observation_details_t *det = (observation_details_t *)obs_details;
   size_t len = strlen( iline);
   const char *valid_lines = "COD CON OBS MEA TEL NET BND COM NUM ACK AC2 ";
   int i, compare = 1, rval;

   while( len && (iline[len - 1] == 10 || iline[len - 1] == 13))
      len--;               /* drop trailing carriage returns/line feeds */
   if( !memcmp( iline, "COD ", 4))
      reset_mpc_code( det, iline + 4);
   if( det->curr_idx < 0)        /* no COD line seen yet */
      return( OBS_DETAILS_IRRELEVANT_LINE);
   assert( det->curr_idx < det->n_code_details);
   if( len == 80 && probable_mpc_record( iline))
      {
      const int idx = find_code_details( det, iline + 77, &compare);

      if( !compare)
         {
         mpc_code_details_t *mptr = det->code_details + idx;

#ifdef DEBUG_PRINTFS
         if( !mptr->observations_found)
            printf( "Got an observation for '%s'\n", mptr->lines[0]);
#endif
         mptr->observations_found = true;
         }
      return( OBS_DETAILS_MPC_80_COLUMN_LINE);
      }
   if( len < 4 || iline[3] != ' ')
      return( OBS_DETAILS_IRRELEVANT_LINE);
   for( i = 0; compare && valid_lines[i]; i += 4)
      compare = memcmp( iline, valid_lines + i, 4);

   if( !compare)    /* yup,  it's a valid header line */
      {
      mpc_code_details_t *mptr = det->code_details + det->curr_idx;
      const bool reallocation_needed = (mptr->observations_found
             || (is_power_of_two( mptr->n_lines)
                 && mptr->n_lines >= min_code_lines));

      if( reallocation_needed)
         {
         size_t new_size = min_code_lines;
         char **tptr;

         while( new_size < mptr->n_lines)
            new_size <<= 1;
         tptr = (char **)stack_calloc( det->stack,
                           (2 * new_size + 1) * sizeof( char *));
         memcpy( tptr, mptr->lines, mptr->n_lines * sizeof( char *));
         mptr->lines = tptr;
         }
      mptr->lines[mptr->n_lines] = (char *)stack_calloc( det->stack, len + 1);
      memcpy( mptr->lines[mptr->n_lines], iline, len);
      mptr->n_lines++;
      rval = OBS_DETAILS_HEADER_LINE;
      }
   else
      rval = OBS_DETAILS_IRRELEVANT_LINE;
   return( rval);
}


void free_observation_details( void *obs_details)
{
   observation_details_t *det = (observation_details_t *)obs_details;

   destroy_stack( det->stack);
}

/* init_observation_details allocates the stack (see 'stackall.h/cpp'),
allocates its own return value from that stack,  sets up an initial
'code_details' array,  and nothing else.

Each line read from the file is then fed through get_code_details().  If the
line starts with COD,  we look for it in the existing code_details() array
(using get_code_details()) and either find it there or insert a new entry in
the array.  (For speed, 'code_details' is sorted so we can binary-search.)

   When we see COD,  we make sure that 'lines' is allocated to (say) eight
lines,  n_lines is zeroed,  and 'observations_found' is set to false.

   If it looks like an 80-column MPC observation that matches the current
MPC code,  we set 'observations_found' for that code to be true.

   If it's a CON, OBS, MEA, TEL,  etc. line,  and 'observations_found' is
false,  we can just add the new line to the mpc_code_details_t structure
for that MPC code.  (CON/OBS/MEA lines accumulate;  the others replace as
we see them.)

   If 'observations_found' is true,  we have to allocate a new
mpc_code_details_t structure and copy over the old one and change the
'code_details' pointer accordingly,  and _then_ add the new line. (After
which,  'observations_found' is reset to false.)

   The reason for this is that if we have an observation file such as...

COD XYZ
OBS B. Frank
NET GSC-1.1
(six observations from XYZ)
NET Gaia-DR2
COM Later observations
(three more observations from XYZ)

   ...we'll set up an mpc_code_details_t structure for XYZ when we see
the COD line,  and add the OBS and NET lines.  The first six observations
will be associated with that structure.

   When the second NET line is read,  though,  observations_found == true
tells us we need to allocate a new mpc_code_details_t,  copy over the
existing text,  replace the NET line,  and set (in the new struct)
observations_found = false.  Then we add in the COM line,  and the next
three observations are associated with the new structure.

   The result is that (in the above case) we only allocate two 'details'
structures,  and most of the lines they point to overlap.

   get_code_details() just does a binary search within the code_details
array.

   free_observation_details() should be a single line,  calling stack_free
for the 'stack' variable.  (Everything allocated here ought to be on the
stack-based allocator.)       */