]> Pileus Git - ~andy/rsl/blob - uf_to_radar.c
RSL v1.44
[~andy/rsl] / uf_to_radar.c
1 /*
2     NASA/TRMM, Code 910.1.
3     This is the TRMM Office Radar Software Library.
4     Copyright (C) 1996, 1997
5             John H. Merritt
6             Space Applications Corporation
7             Vienna, Virginia
8
9     This library is free software; you can redistribute it and/or
10     modify it under the terms of the GNU Library General Public
11     License as published by the Free Software Foundation; either
12     version 2 of the License, or (at your option) any later version.
13
14     This library is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17     Library General Public License for more details.
18
19     You should have received a copy of the GNU Library General Public
20     License along with this library; if not, write to the Free
21     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <math.h>
28
29 /* This allows us to use RSL_ftype, RSL_f_list, RSL_invf_list from rsl.h. */
30 #define USE_RSL_VARS
31 #include "rsl.h"
32
33 extern int radar_verbose_flag;
34 /* Changed old buffer size (16384) for larger dualpol files.  BLK 5/18/2011 */
35 typedef short UF_buffer[20000]; /* Some UF files are bigger than 4096
36                                  * that the UF doc's specify.
37                                  */
38
39 #define UF_MORE 0
40 #define UF_DONE 1
41
42 static float (*f)(Range x);
43 static Range (*invf)(float x);
44
45 Volume *reset_nsweeps_in_volume(Volume *volume)
46 {
47   int i;
48   if (volume == NULL) return NULL;
49   for (i=volume->h.nsweeps; i>0; i--)
50     if (volume->sweep[i-1] != NULL) {
51       volume->h.nsweeps = i;
52       break;
53     }
54   return volume;
55 }
56 Radar *reset_nsweeps_in_all_volumes(Radar *radar)
57 {
58   int i;
59   if (radar == NULL) return NULL;
60   for (i=0; i<radar->h.nvolumes; i++)
61     radar->v[i] = reset_nsweeps_in_volume(radar->v[i]);
62   return radar;
63 }
64
65 Volume *copy_sweeps_into_volume(Volume *new_volume, Volume *old_volume)
66 {
67   int i;
68   int nsweeps;
69   if (old_volume == NULL) return new_volume;
70   if (new_volume == NULL) return new_volume;
71   nsweeps = new_volume->h.nsweeps; /* Save before copying old header. */
72   new_volume->h = old_volume->h;
73   new_volume->h.nsweeps = nsweeps;
74   for (i=0; i<old_volume->h.nsweeps; i++)
75     new_volume->sweep[i] = old_volume->sweep[i]; /* Just copy pointers. */
76   /* Free the old sweep array, not the pointers to sweeps. */
77   free(old_volume->sweep);
78   return new_volume;
79 }
80
81 void swap2(short *buf, int n)
82 {
83   short *end_addr;
84   end_addr = buf + n;
85   while (buf < end_addr) {
86     swap_2_bytes(buf);
87     buf++;
88   }
89 }
90
91 static void put_start_time_in_radar_header(Radar *radar)
92 {
93   /* Get the earliest ray time and store it in radar header.
94    * The search is necessary because rays are not always in chronological order.
95    * For example, we have received data in which rays were apparently sorted by
96    * azimuth in some upstream software.  This results in the ray times being out
97    * of order, because a sweep rarely actually begins at zero degrees.
98    *
99    * Written by Bart Kelley, SSAI, June 19, 2013
100    */
101
102   int i = 0;
103   Sweep *sweep;
104   Ray   *ray;
105
106   int prevdate, thisdate;
107   float prevtime, thistime;
108
109   /* Get first sweep of first available field. */
110   for (i=0; i < MAX_RADAR_VOLUMES; i++) {
111       if ((sweep = radar->v[i]->sweep[0]) != NULL) break;
112   }
113   /* This shouldn't happen. */
114   if (i >= MAX_RADAR_VOLUMES) {
115       printf("put_start_time_in_radar_header: No radar volumes contained "
116               "sweep at index 0.\n");
117       return;
118   }
119
120   /* Get first ray and its time. */
121   i = 0;
122   while (!sweep->ray[i] && i < sweep->h.nrays) i++;
123   ray = sweep->ray[i];
124   prevdate = ray->h.year * 10000 + ray->h.month * 100 + ray->h.day;
125   prevtime = ray->h.hour * 10000 + ray->h.minute * 100 + ray->h.sec;
126
127   /* Compare times of remaining rays for earliest time. */
128   for (i=0; i<sweep->h.nrays; i++) {
129     ray = sweep->ray[i];
130     thisdate = ray->h.year * 10000 + ray->h.month * 100 + ray->h.day;
131     thistime = ray->h.hour * 10000 + ray->h.minute * 100 + ray->h.sec;
132     if (thisdate == prevdate) {
133       if (thistime < prevtime) prevtime = thistime;
134     }
135     else if (thisdate < prevdate) {
136       prevdate = thisdate;
137       prevtime = thistime;
138     }
139   }
140
141   radar->h.year = prevdate / 10000;
142   radar->h.month = prevdate / 100 % 100;
143   radar->h.day = prevdate % 100;
144   radar->h.hour = (int) prevtime / 10000;
145   radar->h.minute = (int) prevtime / 100 % 100;
146   radar->h.sec = fmod(prevtime,100.);
147 }
148
149 /********************************************************************/
150 /*********************************************************************/
151 /*                                                                   */
152 /*                  uf_into_radar                                    */
153 /*                                                                   */
154 /*  By: John Merritt                                                 */
155 /*      Space Applications Corporation                               */
156 /*      August 26, 1994                                              */
157 /*********************************************************************/
158 int uf_into_radar(UF_buffer uf, Radar **the_radar)
159 {
160   
161 /* Missing data flag : -32768 when a signed short. */
162 #define UF_NO_DATA 0X8000
163   
164   /* Any convensions may be observed, however, Radial Velocity must be VE. */
165   /* Typically:
166    *    DM = Reflectivity (dB(mW)).
167    *    DZ = Reflectivity (dBZ).
168    *    VR = Radial Velocity.
169    *    CZ = Corrected Reflectivity. (Quality controlled: AP removed, etc.)
170    *    SW = Spectrum Width.
171    *    DR = Differential Reflectivity.
172    *    XZ = X-band Reflectivity.
173    *
174    * These fields may appear in any order in the UF file.
175    *
176    * RETURN:
177    *   UF_DONE if we're done with the UF ingest.
178    *   UF_MORE if we need more UF data.
179    */
180   
181   /* These are pointers to various locations within the UF buffer 'uf'.
182    * They are used to index the different components of the UF structure in
183    * a manor consistant with the UF documentation.  For instance, uf_ma[1]
184    * will be equivalenced to the second word (2 bytes/each) of the UF
185    * buffer.
186    */
187   short *uf_ma;  /* Mandatory header block. */
188   short *uf_lu;  /* Local Use header block.  */
189   short *uf_dh;  /* Data header.  */
190   short *uf_fh;  /* Field header. */
191   short *uf_data; /* Data. */
192   
193   /* The length of each header. */
194   int len_data, len_lu;
195   
196   int current_fh_index; 
197   float scale_factor;
198   
199   int nfields, isweep, ifield, iray, i, j, m;
200   static int pulled_time_from_first_ray = 0;
201   static int need_scan_mode = 1;
202   char *field_type; /* For printing the field type upon error. */
203   short proj_name[4];
204   Ray *ray;
205   Sweep *sweep;
206   Radar *radar;
207   float x;
208   short missing_data;
209   Volume *new_volume;
210   int nbins;
211   float frequency;
212   extern int rsl_qfield[];
213   extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */
214   extern int rsl_qsweep_max;
215
216   radar = *the_radar;
217
218 /*
219  * The organization of the Radar structure is by volumes, then sweeps, then
220  * rays, then gates.  This is different from the UF file organization.
221  * The UF format is sweeps, rays, then gates for all field types (volumes).
222  */
223
224
225 /* Set up all the UF pointers. */
226   uf_ma = uf;
227   uf_lu = uf + uf_ma[3] - 1;
228   uf_dh = uf + uf_ma[4] - 1;
229
230   nfields =  uf_dh[0];
231   isweep = uf_ma[9] - 1;
232
233   if (rsl_qsweep != NULL) {
234     if (isweep > rsl_qsweep_max) return UF_DONE;
235     if (rsl_qsweep[isweep] == 0) return UF_MORE;
236   }
237
238
239 /* Here is a sticky part.  We must make sure that if we encounter any
240  * additional fields that were not previously present, that we are able
241  * to load them.  This will require us to copy the entire radar structure
242  * and whack off the old one.  But, we must be sure that it really is a
243  * new field.  This is not so trivial as a couple of lines of code; I will
244  * have to think about this a little bit more.  See STICKYSOLVED below.
245  */
246 #ifdef STICKYSOLVED
247   if (radar == NULL) radar = RSL_new_radar(nfields);
248   /* Sticky solution here. */
249 #else
250   if (radar == NULL) {
251     radar = RSL_new_radar(MAX_RADAR_VOLUMES);
252     *the_radar = radar;
253     pulled_time_from_first_ray = 0;
254     for (i=0; i<MAX_RADAR_VOLUMES; i++)
255       if (rsl_qfield[i]) /* See RSL_select_fields in volume.c */
256         radar->v[i] = RSL_new_volume(20);
257   }
258   
259 #endif
260
261   if (need_scan_mode) {
262     /* PPI and RHI are enum constants defined in rsl.h */
263     if (uf_ma[34] == 1) radar->h.scan_mode = PPI;
264     else if (uf_ma[34] == 3) radar->h.scan_mode = RHI;
265     else {
266       fprintf(stderr,"Warning: UF sweep mode = %d\n", uf_ma[34]);
267       fprintf(stderr,"    Expected 1 or 3 (PPI or RHI)\n");
268       fprintf(stderr,"    Setting radar->h.scan_mode to PPI\n");
269       radar->h.scan_mode = PPI;
270     }
271     need_scan_mode = 0;
272   }
273
274 /* For LITTLE ENDIAN:
275  * WE "UNSWAP" character strings.  Because there are so few of them,
276  * it is easier to catch them here.  The entire UF buffer is swapped prior
277  * to entry to here, therefore, undo-ing these swaps; sets the
278  * character strings right.
279  */
280
281   for (i=0; i<nfields; i++) {
282     if (little_endian()) swap_2_bytes(&uf_dh[3+2*i]); /* Unswap. */
283     ifield = -1;
284     field_type = (char *)&uf_dh[3+2*i];
285     for (j=0; j<MAX_RADAR_VOLUMES; j++) {
286       if (strncmp(field_type, RSL_ftype[j], 2) == 0) {
287         ifield = j;
288         break;
289       }
290     }
291     if (ifield < 0) { /* DON'T know how to handle this yet. */
292       fprintf(stderr, "Unknown field type %c%c\n", (char)field_type[0],
293               (char)field_type[1]);
294       continue;
295     }
296
297     f = RSL_f_list[ifield];
298     invf = RSL_invf_list[ifield];
299
300     /* Do we place the data into this volume? */
301     if (radar->v[ifield] == NULL) continue; /* Nope. */
302
303     if (isweep >= radar->v[ifield]->h.nsweeps) { /* Exceeded sweep limit.
304                                                   * Allocate more sweeps.
305                                                   * Copy all previous sweeps.
306                                                   */
307       if (radar_verbose_flag)
308         fprintf(stderr,"Exceeded sweep allocation of %d. Adding 20 more.\n", isweep);
309       new_volume = RSL_new_volume(radar->v[ifield]->h.nsweeps+20);
310       new_volume = copy_sweeps_into_volume(new_volume, radar->v[ifield]);
311       radar->v[ifield] = new_volume;
312     }
313
314     if (radar->v[ifield]->sweep[isweep] == NULL) {
315       if (radar_verbose_flag)
316         fprintf(stderr,"Allocating new sweep for field %d, isweep %d\n", ifield, isweep);
317       radar->v[ifield]->sweep[isweep] = RSL_new_sweep(1000);
318       radar->v[ifield]->sweep[isweep]->h.nrays = 0; /* Increment this for each
319                                                      * ray encountered.
320                                                      */
321       radar->v[ifield]->h.f = f;
322       radar->v[ifield]->h.invf = invf;
323       radar->v[ifield]->sweep[isweep]->h.f = f;
324       radar->v[ifield]->sweep[isweep]->h.invf = invf;
325       radar->v[ifield]->sweep[isweep]->h.sweep_num = uf_ma[9];
326       radar->v[ifield]->sweep[isweep]->h.elev = uf_ma[35] / 64.0;
327     }
328     
329     
330
331     current_fh_index = uf_dh[4+2*i];
332     uf_fh = uf + current_fh_index - 1;
333     sweep = radar->v[ifield]->sweep[isweep];
334     iray =  sweep->h.nrays;
335     nbins = uf_fh[5];
336     radar->v[ifield]->sweep[isweep]->ray[iray] = RSL_new_ray(nbins);
337     ray   = radar->v[ifield]->sweep[isweep]->ray[iray];
338     sweep->h.nrays += 1;
339
340
341     if (ray) {
342         /* 
343          * ---- Beginning of MANDATORY HEADER BLOCK.
344          */
345       ray->h.ray_num = uf_ma[7];
346       if (little_endian()) swap2(&uf_ma[10], 8);
347       memcpy(radar->h.radar_name, &uf_ma[10], 8);
348       if (little_endian()) swap2(&uf_ma[10], 8/2);
349       memcpy(radar->h.name, &uf_ma[14], 8);
350       if (little_endian()) swap2(&uf_ma[14], 8/2);
351         
352       /* All components of lat/lon are the same sign.  If not, then
353        * what ever wrote the UF was in error.  A simple RSL program
354        * can repair the damage, however, not here.
355        */
356       ray->h.lat = uf_ma[18] + uf_ma[19]/60.0 + uf_ma[20]/64.0/3600;
357       ray->h.lon = uf_ma[21] + uf_ma[22]/60.0 + uf_ma[23]/64.0/3600;
358       ray->h.alt      = uf_ma[24];
359       ray->h.year     = uf_ma[25];
360       if (ray->h.year < 1900) {
361         ray->h.year += 1900;
362         if (ray->h.year < 1980) ray->h.year += 100; /* Year >= 2000. */
363       }
364       ray->h.month    = uf_ma[26];
365       ray->h.day      = uf_ma[27];
366       ray->h.hour     = uf_ma[28];
367       ray->h.minute   = uf_ma[29];
368       ray->h.sec      = uf_ma[30];
369       ray->h.azimuth  = uf_ma[32] / 64.0;
370
371       /* If Local Use Header is present and contains azimuth, use that
372        * azimuth for VR and SW. This is for WSR-88D, which runs separate
373        * scans for DZ and VR/SW at the lower elevations, which means DZ
374        * VR/SW and have different azimuths in the "same" ray.
375        */
376       len_lu = uf_ma[4] - uf_ma[3];
377       if (len_lu == 2 && (ifield == VR_INDEX || ifield == SW_INDEX)) {
378           if (strncmp((char *)uf_lu,"ZA",2) == 0 ||
379               strncmp((char *)uf_lu,"AZ",2) == 0)
380           ray->h.azimuth = uf_lu[1] / 64.0;
381       }
382       if (ray->h.azimuth < 0.) ray->h.azimuth += 360.; /* make it 0 to 360. */
383       ray->h.elev     = uf_ma[33] / 64.0;
384       ray->h.elev_num = sweep->h.sweep_num;
385       ray->h.fix_angle  = sweep->h.elev = uf_ma[35] / 64.0;
386       ray->h.azim_rate  = uf_ma[36] / 64.0;
387       ray->h.sweep_rate = ray->h.azim_rate * (60.0/360.0);
388       missing_data      = uf_ma[44];
389
390       if (pulled_time_from_first_ray == 0) {
391         radar->h.height = uf_ma[24];
392         radar->h.latd = uf_ma[18];
393         radar->h.latm = uf_ma[19];
394         radar->h.lats = uf_ma[20] / 64.0;
395         radar->h.lond = uf_ma[21];
396         radar->h.lonm = uf_ma[22];
397         radar->h.lons = uf_ma[23] / 64.0;
398         /* Note that radar header time is now handled at end of ingest by
399          * function put_start_time_in_radar_header().  The values below are
400          * replaced. --BLK, 6/19/13
401          */
402         radar->h.year  = ray->h.year;
403         radar->h.month = ray->h.month;
404         radar->h.day   = ray->h.day;
405         radar->h.hour  = ray->h.hour;
406         radar->h.minute = ray->h.minute;
407         radar->h.sec    = ray->h.sec;
408         strcpy(radar->h.radar_type, "uf");
409         pulled_time_from_first_ray = 1;
410       }
411       /*
412        * ---- End of MANDATORY HEADER BLOCK.
413        */
414       
415       /* ---- Optional header used for MCTEX files. */
416         /* If this is a MCTEX file, the first 4 words following the
417              mandatory header contain the string 'MCTEX'. */
418       memcpy(proj_name, (short *)(uf + uf_ma[2] - 1), 8);
419       if (little_endian()) swap2(proj_name, 4);
420
421
422       /* ---- Local Use Header (if present) was checked during Mandatory
423        *      Header processing above.
424        */
425       
426       /* ---- Begining of FIELD HEADER. */
427       uf_fh = uf+current_fh_index - 1;
428       scale_factor      = uf_fh[1];
429       ray->h.range_bin1 = uf_fh[2] * 1000.0 + uf_fh[3]; 
430       ray->h.gate_size  = uf_fh[4];
431
432       ray->h.nbins      = uf_fh[5];
433       ray->h.pulse_width  = uf_fh[6]/(RSL_SPEED_OF_LIGHT/1.0e6);
434
435         if (strncmp((char *)proj_name, "MCTEX", 5) == 0)  /* MCTEX? */
436         {
437             /* The beamwidth values are not correct in Mctex UF files. */
438             ray->h.beam_width = 1.0;
439             sweep->h.beam_width = ray->h.beam_width;
440             sweep->h.horz_half_bw = ray->h.beam_width/2.0;
441             sweep->h.vert_half_bw = ray->h.beam_width/2.0;
442         }
443         else  /* Not MCTEX */
444         {
445             ray->h.beam_width = uf_fh[7] / 64.0;
446             sweep->h.beam_width = uf_fh[7]  / 64.0;
447             sweep->h.horz_half_bw = uf_fh[7] / 128.0; /* DFF 4/4/95 */
448             sweep->h.vert_half_bw = uf_fh[8] / 128.0; /* DFF 4/4/95 */
449         }           
450         /*      fprintf (stderr, "uf_fh[7] = %d, [8] = %d\n", (int)uf_fh[7], (int)uf_fh[8]); */
451         if((int)uf_fh[7] == -32768) {
452             ray->h.beam_width     = 1;
453             sweep->h.beam_width   = 1;
454             sweep->h.horz_half_bw = .5;
455             sweep->h.vert_half_bw = .5;
456         }
457           
458       frequency = uf_fh[9];
459       /* This corrects an error in v1.43 and earlier where frequency was
460        * multiplied by 64.  Correct units for UF are MHz; radar structure
461        * uses GHz.
462        */
463       if (frequency < 1000.) frequency = frequency/64.;
464       else frequency = frequency/1000.;
465       ray->h.frequency    = frequency;
466       ray->h.wavelength   = uf_fh[11] / 64.0 / 100.0;  /* cm to m. */
467       ray->h.pulse_count  = uf_fh[12];
468       if (ifield == DZ_INDEX || ifield == ZT_INDEX) {
469         radar->v[ifield]->h.calibr_const  = uf_fh[16] / 100.0;
470                             /* uf value scaled by 100 */
471       }
472       else {
473         radar->v[ifield]->h.calibr_const  = 0.0;
474       }
475       if (uf_fh[17] == (short)UF_NO_DATA) x = 0;
476       else x = uf_fh[17] / 1000000.0;  /* PRT in seconds. */
477       if (x != 0) {
478         ray->h.prf = 1/x;
479         ray->h.unam_rng = RSL_SPEED_OF_LIGHT / (2.0 * ray->h.prf * 1000.0);
480       }
481       else {
482         ray->h.prf = 0.0;
483         ray->h.unam_rng = 0.0;
484       }
485
486       if (VR_INDEX == ifield || VE_INDEX == ifield) {
487         ray->h.nyq_vel = uf_fh[19] / scale_factor;
488       }
489       
490       /* ---- End of FIELD HEADER. */
491       
492       ray->h.f = f;
493       ray->h.invf = invf;
494
495       /* ---- Begining of FIELD DATA. */
496       uf_data = uf+uf_fh[0] - 1;
497
498       len_data = ray->h.nbins;  /* Known because of RSL_new_ray. */
499       for (m=0; m<len_data; m++) {
500         if (uf_data[m] == (short)UF_NO_DATA)
501           ray->range[m] = invf(BADVAL); /* BADVAL */
502         else {
503           if(uf_data[m] == missing_data)
504             ray->range[m] = invf(NOECHO); /* NOECHO */
505           else
506             ray->range[m] = invf((float)uf_data[m]/scale_factor);
507         }
508       }
509     }
510   }
511   return UF_MORE;
512 }
513
514
515 /*********************************************************************/
516 /*                                                                   */
517 /*                  swap_uf_buffer                                   */
518 /*                                                                   */
519 /*  By: John Merritt                                                 */
520 /*      Space Applications Corporation                               */
521 /*      October 4, 1994                                              */
522 /*********************************************************************/
523 void swap_uf_buffer(UF_buffer uf)
524 {
525   short *addr_end;
526
527   addr_end = uf + sizeof(UF_buffer)/sizeof(short);
528   while (uf < addr_end)
529     swap_2_bytes(uf++);
530 }
531
532 enum UF_type {NOT_UF, TRUE_UF, TWO_BYTE_UF, FOUR_BYTE_UF};
533
534
535 /*********************************************************************/
536 /*                                                                   */
537 /*                  RSL_uf_to_radar_fp                               */
538 /*                                                                   */
539 /*  By: John Merritt                                                 */
540 /*      Space Applications Corporation                               */
541 /*      September 22, 1995                                           */
542 /*********************************************************************/
543 Radar *RSL_uf_to_radar_fp(FILE *fp)
544 {
545   union {
546     char buf[6];
547     short sword;
548     int word;
549   } magic;
550   Radar *radar;
551   int nbytes;
552   short sbytes;
553   UF_buffer uf;
554   enum UF_type uf_type;
555 #define NEW_BUFSIZ 16384
556
557
558   radar = NULL;
559   /* setvbuf(fp,NULL,_IOFBF,(size_t)NEW_BUFSIZ); * Faster i/o? */
560   if (fread(magic.buf, sizeof(char), 6, fp) <= 0) return NULL;
561 /*
562  * Check for fortran record length delimeters, NCAR kludge.
563  */
564   if (strncmp("UF", magic.buf, 2) == 0) uf_type = TRUE_UF;
565   else if (strncmp("UF", &magic.buf[2], 2) == 0) uf_type = TWO_BYTE_UF;
566   else if (strncmp("UF", &magic.buf[4], 2) == 0) uf_type = FOUR_BYTE_UF;
567   else uf_type = NOT_UF;
568   
569   switch (uf_type) {
570   case FOUR_BYTE_UF:
571     if (radar_verbose_flag) fprintf(stderr,"UF file with 4 byte FORTRAN record delimeters.\n");
572     /* Handle first record specially, since we needed magic information. */
573     nbytes = magic.word;
574     if (little_endian()) swap_4_bytes(&nbytes);
575     memcpy(uf, &magic.buf[4], 2);
576     (void)fread(&uf[1], sizeof(char), nbytes-2, fp);
577     if (little_endian()) swap_uf_buffer(uf);
578     (void)fread(&nbytes, sizeof(int), 1, fp);
579     if (uf_into_radar(uf, &radar) == UF_DONE) break;
580     /* Now the rest of the file. */
581     while(fread(&nbytes, sizeof(int), 1, fp) > 0) {
582       if (little_endian()) swap_4_bytes(&nbytes);
583       
584       (void)fread(uf, sizeof(char), nbytes, fp);
585       if (little_endian()) swap_uf_buffer(uf);
586       
587       (void)fread(&nbytes, sizeof(int), 1, fp);
588       
589       if (uf_into_radar(uf, &radar) == UF_DONE) break;
590     }
591     break;
592
593   case TWO_BYTE_UF:
594     if (radar_verbose_flag) fprintf(stderr,"UF file with 2 byte FORTRAN record delimeters.\n");
595     /* Handle first record specially, since we needed magic information. */
596     sbytes = magic.sword;
597     if (little_endian()) swap_2_bytes(&sbytes);
598     memcpy(uf, &magic.buf[2], 4);
599     (void)fread(&uf[2], sizeof(char), sbytes-4, fp);
600     if (little_endian()) swap_uf_buffer(uf);
601     (void)fread(&sbytes, sizeof(short), 1, fp);
602     uf_into_radar(uf, &radar);
603     /* Now the rest of the file. */
604     while(fread(&sbytes, sizeof(short), 1, fp) > 0) {
605       if (little_endian()) swap_2_bytes(&sbytes);
606       
607       (void)fread(uf, sizeof(char), sbytes, fp);
608       if (little_endian()) swap_uf_buffer(uf);
609       
610       (void)fread(&sbytes, sizeof(short), 1, fp);
611       
612       if (uf_into_radar(uf, &radar) == UF_DONE) break;
613     }
614     break;
615
616   case TRUE_UF:
617     if (radar_verbose_flag) fprintf(stderr,"UF file with no FORTRAN record delimeters.  Good.\n");
618     /* Handle first record specially, since we needed magic information. */
619     memcpy(&sbytes, &magic.buf[2], 2); /* Record length is in word #2. */
620     if (little_endian()) swap_2_bytes(&sbytes); /* # of 2 byte words. */
621
622     memcpy(uf, &magic.buf[0], 6);
623     (void)fread(&uf[3], sizeof(short), sbytes-3, fp);
624     if (little_endian()) swap_uf_buffer(uf);
625     uf_into_radar(uf, &radar);
626     /* Now the rest of the file. */
627     while(fread(uf, sizeof(short), 2, fp) > 0) {
628       memcpy(&sbytes, &uf[1], 2);  /* Record length is in word #2. */
629       if (little_endian()) swap_2_bytes(&sbytes);
630       
631       (void)fread(&uf[2], sizeof(short), sbytes-2, fp);  /* Have words 1,2. */
632       if (little_endian()) swap_uf_buffer(uf);
633       
634       if (uf_into_radar(uf, &radar) == UF_DONE) break;
635     }
636     break;
637     
638   case NOT_UF: return NULL; break;
639   }
640   radar = reset_nsweeps_in_all_volumes(radar);
641   put_start_time_in_radar_header(radar);
642   radar = RSL_prune_radar(radar);
643
644   return radar;
645 }
646
647
648 /*********************************************************************/
649 /*                                                                   */
650 /*                  RSL_uf_to_radar                                  */
651 /*                                                                   */
652 /*  By: John Merritt                                                 */
653 /*      Space Applications Corporation                               */
654 /*      September 22, 1995                                           */
655 /*********************************************************************/
656 Radar *RSL_uf_to_radar(char *infile)
657 {
658 /*
659  * This routine ingests a UF file and fills the Radar structure.
660  * This routine allocates space via the system routine malloc.
661  *
662  * If *infile is NULL, read from stdin.
663  */
664   FILE *fp;
665   Radar *radar;
666   
667   radar = NULL;
668   if (infile == NULL) {
669     int save_fd;
670     save_fd = dup(0);
671     fp = fdopen(save_fd, "r");
672   }  else if ((fp = fopen(infile, "r")) == NULL) {
673     perror(infile);
674     return radar;
675   }
676   fp = uncompress_pipe(fp); /* Transparently gunzip. */
677   radar = RSL_uf_to_radar_fp(fp);
678   rsl_pclose(fp);
679     
680   return radar;
681 }