Added source code for RINEX to CRINEX conversion (taken on the net + minor changes)
[gps] / rnx2crx.c
1 /***********************************************************************/
2 /*     program name : RNX2CRX                                          */
3 /*                                                                     */
4 /*     RINEX file compression program for UNIX/MS-DOS system.          */
5 /*     convert the RINEX format to Compact RINEX format                */
6 /*     Created by Yuki HATANAKA / Geographical Survey Institute, Japan */
7 /*                                                                     */
8 /*     ver.                                                            */
9 /*     4.0.0       2007.02.05 test version   Y. Hatanaka               */
10 /*                  - CRINEX 1/3 for RINEX 2.x/3.x                     */
11 /*     4.0.1       2007.05.08                                          */
12 /*                  - elimination of supports for VMS and SUN OS 4.1.x */
13 /*                  - output not to the current directory but the same */
14 /*                    directory as the input file.                     */
15 /*                  - the same code for DOS and UNIX                   */
16 /*     4.0.2       2007.06.07                                          */
17 /*                  - fixing incompatibility of argument and format    */
18 /*                    string of printf.                                */
19 /*     4.0.3       2007.06.21                                          */
20 /*                  - nothing was changed from 4.0.2 except for the    */
21 /*                    version string to be the same as crx2rnx.c       */
22 /*                                                                     */
23 /*     Copyright (c) 2007 Geographical Survey Institute                */
24 /*     All rights reserved.                                            */
25 /*                                                                     */
26 /***********************************************************************/
27
28 #define VERSION  "ver.4.0.3"
29
30 /**** Exit codes are defined here.   ****/
31 #define EXIT_WARNING 2
32
33 #ifndef EXIT_FAILURE
34 #define EXIT_FAILURE 1
35 #endif
36
37 #ifndef EXIT_SUCCESS
38 #define EXIT_SUCCESS 0
39 #endif
40
41 /****  Don't change the lines from here. ****/
42 #include <limits.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <time.h>
48
49 /*** define macro to  ***/
50 #define FLUSH_BUFF printf("%s",top_buff), *(p_buff = top_buff)='\0'
51 #define CLEAR_BUFF *(p_buff = top_buff)='\0'
52
53 #define CRX_VERSION1 "1.0"    /* CRINEX version for RINEX 2.x */
54 #define CRX_VERSION2 "3.0"    /* CRINEX version for RINEX 3.x */
55 #define PROGNAME "RNX2CRX"
56 #define MAXSAT     90         /* Maximum number of satellites observed at one epoch */
57 #define MAXTYPE    50         /* Maximum number of data types for a GNSS system */
58 #define MAXCLM   1024         /* Maximum columns in one line   (>MAXTYPE*19+3)  */
59 #define MAX_BUFF_SIZE 131072  /* Muximum size of output buffer (>MAXSAT*(MAXTYPE*19+4)+60 */
60 #define ARC_ORDER 3           /* order of difference to take    */
61
62 /* define data structure for fields of clock offset and obsercvation records */
63 /* Those data will be handled as integers after eliminating decimal points.  */
64 /* Since their size may exceeds range between LONG_MIN and LONG_MAX,         */
65 /* they will be read with being divided properly into upper and lower digits */
66 typedef struct clock_format{
67     long u[ARC_ORDER+1];      /* upper X digits */
68     long l[ARC_ORDER+1];      /* lower 8 digits (can be 9-10 digits for deltas)*/
69 } clock_format;
70
71 typedef struct data_format{
72     long u[ARC_ORDER+1];      /* upper X digits */
73     long l[ARC_ORDER+1];      /* lower 5 digits (can be 6-7 digits for deltas) */
74     int order;
75 } data_format;
76
77 /* define global variables */
78 long ep_count=0;
79 long ep_reset=0;
80 long nl_count=0;
81 int rinex_version;          /* =2 or 3 */
82 int nsat,ntype,ntype_gnss[UCHAR_MAX],ntype_record[MAXSAT],clk_order = -1;
83 int exit_status = EXIT_SUCCESS;
84 int skip_strange_epoch = 0; /* default : stop with error */
85
86 clock_format clk1,clk0 = {{0,0,0,0}, {0,0,0,0}};
87 data_format y0[MAXSAT][MAXTYPE], y1[MAXSAT][MAXTYPE];
88 char flag0[MAXSAT][MAXTYPE*2], flag[MAXSAT][MAXTYPE*2];
89 char out_buff[MAX_BUFF_SIZE]= {'x','\0'};  /**** a character is put as a stopper to aviod memory overflow ****/
90 char *top_buff=&out_buff[1],*p_buff;       /**** therefore, actual baffer start from the second character ****/
91
92 char oldline[MAXCLM] = {'&','\0'};
93 int nsat_old = 0;
94
95 /* declaration of functions */
96 void parse_args(int argc, char *argv[]);
97 void header();
98 int  get_next_epoch(char *p_line);
99 void skip_to_next(char *p_line);
100 void initialize_all(char *oldline,int *nsat_old, int count);
101 void put_event_data(char *p_line);
102 void read_clock(char *line,int shift_cl);
103 void process_clock();
104 int  set_sat_table(char *p_new, char *p_old, int nsat_old,int *sattbl);
105 int  read_more_sat(int n, char *p);
106 void data(int *sattbl);
107 char *strdiff(char *s1, char *s2, char *ds);
108 int  rnx_getline(data_format *py1, char *flag, char *sat_id, int *ntype_rec);
109 void read_value(char *p, long *pu, long *pl);
110 void take_diff(data_format *py1, data_format *py0);
111 void putdiff(long dddu, long dddl);
112 void put_clock(long du, long dl, int clk_order);
113 int  read_chk_line(char *line);
114 void error_exit(int error_no, char *string);
115 void flush_buff();
116
117 /*---------------------------------------------------------------------*/
118 main(int argc, char *argv[]){
119     char newline[MAXCLM],dummy[MAXCLM];
120     char *p,*p_event,*p_nsat,*p_satlst,*p_satold,*p_clock;
121     int sattbl[MAXSAT],i,j,shift_clk;
122        /* sattbl[i]: order (at the previous epoch) of i-th satellite */
123        /* (at the current epoch). -1 is set for the new satellites   */
124
125     parse_args(argc,argv);
126     for(i=0;i<UCHAR_MAX;i++)ntype_gnss[i]=-1;  /** -1 unless GNSS type is not defined **/
127     header();
128     if (rinex_version==2){
129         p_event  =&newline[28];  /** pointer to event flug **/
130         p_nsat   =&newline[29];  /** pointer to n_sat **/
131         p_satlst =&newline[32];  /** pointer to satellite list **/
132         p_satold =&oldline[32];  /** pointer to n_sat **/
133         p_clock  =&newline[68];  /** pointer to clock offset data **/
134         shift_clk = 1;
135     }else{
136         p_event  =&newline[31];
137         p_nsat   =&newline[32];
138         p_satlst =&newline[41];
139         p_satold =&oldline[41];
140         p_clock  =&newline[41];
141         shift_clk = 4;
142     }
143
144     for(CLEAR_BUFF;;FLUSH_BUFF){
145         SKIP:
146         if( ! get_next_epoch(newline) ) return exit_status;
147
148         /*** if event flag > 1, then (1)output event data  */
149         /*** (2)initialize all data arcs, and continue to next epoch ***/
150         if( atoi(strncpy(dummy,p_event,1)) > 1) {
151             put_event_data(newline);
152             initialize_all(oldline,&nsat_old,0);
153             continue;
154         }
155
156         if(strchr(newline,'\0') > p_clock){
157             read_clock(p_clock,shift_clk);        /**** read clock offset ****/
158         }else{
159             clk_order = -1;                       /*** reset data arc for clock offset ***/
160         }
161
162         nsat=atoi(p_nsat);
163         if(nsat > MAXSAT) error_exit(8,newline);
164         if(nsat > 12 && rinex_version == 2) read_more_sat(nsat,p_satlst);  /*** read continuation lines ***/
165         if( ep_reset > 0 && ++ep_count > ep_reset ) initialize_all(oldline,&nsat_old,1);
166
167         /**** get observation ****/
168         for(i=0,p=p_satlst ; i<nsat ; i++,p+=3) {
169             if( rnx_getline(y1[i],flag[i],p,&ntype_record[i]) ) {
170                 CLEAR_BUFF;
171                 exit_status = EXIT_WARNING;
172                 goto SKIP;
173             }
174         }
175         *p='\0';    /*** terminate satellite list ***/
176
177         if(set_sat_table(p_satlst,p_satold,nsat_old,sattbl) ){
178             CLEAR_BUFF;
179             exit_status = EXIT_WARNING;
180             continue;
181         }
182
183         /***********************************************************/
184         /**** print change of the line & clock offset differene ****/
185         /**** and data difference                               ****/
186         /***********************************************************/
187         p_buff=strdiff(oldline,newline,p_buff);
188         if(clk_order > -1) {
189             if(clk_order > 0) process_clock();            /**** process clock offset ****/
190             put_clock(clk1.u[clk_order],clk1.l[clk_order],clk_order);
191         }else{
192             *p_buff++ = '\n';
193         }
194         data(sattbl); *p_buff = '\0';
195         /**************************************/
196         /**** save current epoch to buffer ****/
197         /**************************************/
198         nsat_old = nsat;
199         sprintf(oldline,"%s",newline);
200         clk0 = clk1;
201         for(i=0;i<nsat;i++){
202             strcpy(flag0[i],flag[i]);
203             for(j=0;j<ntype_record[i];j++) y0[i][j] = y1[i][j];
204         }
205     }
206 }
207 /*---------------------------------------------------------------------*/
208 void parse_args(int argc, char *argv[]){
209     char *p,*infile,outfile[MAXCLM],*progname;
210     int nfile=0, force=0, help=0;
211     int nfout = 0;  /*** =0 default output file name ***/
212                     /*** =1 standaed output          ***/
213     FILE *ifp;
214
215     progname = argv[0];
216     argc--;argv++;
217     for(;argc>0;argc--,argv++){
218         if((*argv)[0] != '-'){
219             infile = *argv;
220             nfile++;
221         }else if(strcmp(*argv,"-")   == 0){
222             nfout  = 1;                /* output to standard output */
223         }else if(strcmp(*argv,"-f")  == 0){
224             force = 1;                 /* overwrite if the output file exists */
225         }else if(strcmp(*argv,"-s")  == 0){
226             skip_strange_epoch = 1;
227         }else if(strcmp(*argv,"-e")  == 0){
228             argc--;argv++;
229             sscanf(*argv,"%ld",&ep_reset);
230         }else if(strcmp(*argv,"-h")  == 0){
231             help = 1;
232         }else{
233             help = 1;
234         }
235     }
236
237     if(help == 1 || nfile > 1 || nfile < 0) error_exit(2,progname);
238     if(nfile == 0) return;       /*** stdin & stdout will be used ***/
239
240     /***********************/
241     /*** open input file ***/
242     /***********************/
243     p=strrchr(infile,'.');
244     if(p == NULL || (*(p+3) != 'O' && *(p+3) != 'o') || *(p+4) != '\0') error_exit(4,p);
245     if((ifp=fopen(infile,"r")) == NULL) error_exit(5,infile);
246
247     /************************/
248     /*** open output file ***/
249     /************************/
250     if(nfout == 0){
251         strcpy(outfile,infile);
252         p=strrchr(outfile,'.');
253         if(*(p+3) == 'o'){ *(p+3) = 'd'; }
254         else             { *(p+3) = 'D'; }
255         if((freopen(outfile,"r",stdout)) != NULL && force == 0){
256             fprintf(stderr,"The file %s already exists. Overwrite?(n)",outfile);
257             if(getchar() != 'y') exit(EXIT_SUCCESS);
258         }
259         freopen(outfile,"w",stdout);
260     }
261     fclose(ifp);
262     freopen(infile,"r",stdin);
263 }
264 /*---------------------------------------------------------------------*/
265 void header(){
266     char line[MAXCLM], line2[41], timestring[20];
267     time_t tc = time(NULL);
268     struct tm *tp;
269
270     if( (tp = gmtime(&tc)) == NULL) tp = localtime(&tc);
271     strftime(timestring, 20, "%d-%b-%y %H:%M", tp);
272
273     /*** Check RINEX VERSION / TYPE ***/
274     read_chk_line(line);
275     if(strncmp(&line[60],"RINEX VERSION / TYPE",20) != 0 ||
276        strncmp(&line[20],"O",1)     != 0 ) error_exit(15,line);
277
278     rinex_version=atoi(line);
279     if      ( rinex_version == 2 ){printf("%-20.20s",CRX_VERSION1);}
280     else if ( rinex_version == 3 ){printf("%-20.20s",CRX_VERSION2);}
281     else                          {error_exit(15,line);}
282     printf("%-40.40s%-20.20s\n","COMPACT RINEX FORMAT","CRINEX VERS   / TYPE");
283
284     sprintf(line2,"%s %s",PROGNAME,VERSION);
285     printf("%-40.40s%-20.20sCRINEX PROG / DATE\n",line2,timestring);
286     printf("%s\n",line);
287     do{
288         read_chk_line(line);
289         printf("%s\n",line);
290         if       (strncmp(&line[60],"# / TYPES OF OBSERV",19) == 0 && line[5] != ' '){
291             ntype=atoi(line);                                        /** for RINEX2 **/
292         } else if(strncmp(&line[60],"SYS / # / OBS TYPES",19) == 0){ /** for RINEX3 **/
293             if (line[0] != ' ') ntype_gnss[line[0]]=atoi(&line[3]);
294             if (ntype_gnss[line[0]] > MAXTYPE) error_exit(16,line);
295         }
296     }while( strncmp(&line[60],"END OF HEADER",13) != 0);
297 }
298 /*---------------------------------------------------------------------*/
299 int  get_next_epoch(char *p_line){
300 /**** find next epoch line.                                                          ****/
301 /**** If the line seems to be abnormal(2), print warning message                     ****/
302 /**** and skip until next epoch is found                                             ****/
303 /**** return value  0 : end of the file                                              ****/
304 /****               1 : normal end                                                   ****/
305 /****               2 : trouble in the line (if 19th character isn't '.' , then      ****/
306 /****                                then clear output buffer for previous epoch)    ****/
307     char *p;
308
309     nl_count++;
310     if( fgets(p_line,MAXCLM,stdin) == NULL ) return 0;  /*** EOF: exit program successfully ***/
311
312     if( (p = strchr(p_line,'\n')) == NULL) {
313         if( *p_line == '\032' ) return 0;              /** DOS EOF **/
314         if( *p_line != '\0' || feof(stdin) == 0 ) {
315              if( ! skip_strange_epoch ) error_exit(12,p_line);
316              skip_to_next(p_line);
317              return 2;
318         }
319         fprintf(stderr,"WARNING: null characters are detected at the end of file --> neglected.\n");
320         exit_status = EXIT_WARNING;
321         return 0;
322     }
323     if( *(p-1) == '\r' )p--;                      /*** check DOS CR/LF ***/
324
325     if (rinex_version == 2) {
326         while(*--p == ' ' && p>p_line);*++p = '\0';   /*** chop blank ***/
327         if( strlen(p_line)<29   || *p_line!=' '
328                 || *(p_line+27) != ' ' || ! isdigit(*(p_line+28))
329                 || (*(p_line+29) != ' ' && *(p_line+29) != '\0') ) {
330             /**** ------- something strange is found in the epoch line ****/
331             if( ! skip_strange_epoch ) error_exit(6,p_line);
332             if(*(p_line+18) != '.')  CLEAR_BUFF;
333             skip_to_next(p_line);
334             return 2;
335         }
336     }else{
337         if( *p_line!='>' ){
338             if( ! skip_strange_epoch ) error_exit(6,p_line);
339             CLEAR_BUFF;
340             skip_to_next(p_line);
341             return 2;
342         }
343         while(p<(p_line+41)) *p++=' '; /*** pad blank ***/
344         *p='\0';
345     }
346     return 1;
347 }
348 /*---------------------------------------------------------------------*/
349 void skip_to_next(char *p_line){
350     int nchar;
351     fprintf(stderr," WARNING at line %ld: strange format. skip to next epoch.\n",nl_count);
352     exit_status = EXIT_WARNING;
353
354     if (rinex_version == 2) {
355         do {                               /**** try to find next epoch line ****/
356             read_chk_line(p_line);
357             nchar = strlen(p_line);
358            } while( nchar <29 || *p_line!=' ' || *(p_line+3)  != ' ' 
359                    || *(p_line+6)  != ' ' || *(p_line+9)  != ' ' 
360                    || *(p_line+12) != ' ' || *(p_line+15) != ' '
361                    || *(p_line+26) != ' ' || *(p_line+27) != ' ' 
362                    || ! isdigit(*(p_line+28)) || ! isspace(*(p_line+29))
363                    || (nchar>68 && *(p_line+70)!='.') );
364     }else{    /*** for RINEX3 ***/
365         do {
366             read_chk_line(p_line);
367             nchar = strlen(p_line);
368         } while( *p_line!='>');
369     }
370     initialize_all(oldline,&nsat_old,0);             /**** initialize all data ***/
371 }
372 /*---------------------------------------------------------------------*/
373 void initialize_all(char *oldline,int *nsat_old,int count){
374     strcpy(oldline,"&");        /**** initialize the epoch data arc ****/
375     clk_order = -1;             /**** initialize the clock data arc ****/
376     *nsat_old = 0;              /**** initialize the all satellite arcs ****/
377     ep_count = count;
378 }
379 /*---------------------------------------------------------------------*/
380 void put_event_data(char *p_line){
381 /**** This routine is called when enent flag >1 is set.  ****/
382 /****      read # of event information lines and output  ****/
383     int i,n;
384     char *p;
385
386     if (rinex_version == 2 ) {
387         if(*(p_line+26) == '.') error_exit(6,p_line);
388         printf("&%s\n",(p_line+1));
389         if( strlen(p_line) > 29 ){
390             n=atoi((p_line+29));     /** n: nnumber of lines to follow **/
391             for(i=0;i<n;i++){
392                 read_chk_line(p_line);
393                 printf("%s\n",p_line);
394                 if(strncmp((p_line+60),"# / TYPES OF OBSERV",19) == 0 && *(p_line+5) != ' ') {
395                     *flag[0]='\0';
396                     ntype=atoi(p_line);
397                     if (ntype > MAXTYPE) error_exit(16,p_line);
398                 }
399             }
400         }
401     } else {
402         if( strlen(p_line)<35 ||  *(p_line+29) == '.') error_exit(6,p_line);
403         /* chop blanks that were padded in get_next_epoch */
404         p = strchr(p_line+35,'\0');while(*--p == ' ');*++p = '\0';
405         printf("%s\n",p_line);
406         n=atoi((p_line+32));         /** n: number of lines to follow **/
407         for(i=0;i<n;i++){
408             read_chk_line(p_line);
409             printf("%s\n",p_line);
410             if(strncmp((p_line+60),"SYS / # / OBS TYPES",19) == 0 && *p_line != ' '){
411                 *flag[0]='\0';
412                 ntype_gnss[*p_line]=atoi((p_line+3));
413                 if (ntype_gnss[*p_line] > MAXTYPE) error_exit(16,p_line);
414             }
415         }
416     }
417 }
418 /*---------------------------------------------------------------------*/
419 void read_clock(char *p_clock,int shift_clk){
420 /****  read the clock offset value ****/
421 /**  *p_clock : pointer to begining of clock data **/
422     char *p_dot;      /** pointer for decimal point **/
423     p_dot = p_clock + 2;
424     if(*p_dot != '.')error_exit(7,p_clock);
425
426     strncpy(p_dot,p_dot+1,shift_clk);    /**** shift digits because of too  ****/
427     *(p_dot+shift_clk)= '.';             /**** many digits for fractional part ****/
428     sscanf(p_clock,"%ld.%ld",&clk1.u[0],&clk1.l[0]);
429     if(*p_clock == '-' || *(p_clock+1) == '-') clk1.l[0] = -clk1.l[0];
430     if(clk_order < ARC_ORDER) clk_order++;
431     *p_clock = '\0';
432 }
433 /*---------------------------------------------------------------------*/
434 void process_clock(){
435     int i;
436     for(i=0;i<clk_order;i++){
437         clk1.u[i+1] = clk1.u[i]-clk0.u[i];
438         clk1.l[i+1] = clk1.l[i]-clk0.l[i];
439     }
440 }
441 /*---------------------------------------------------------------------*/
442 int  set_sat_table(char *p_new, char *p_old, int nsat_old,int *sattbl){
443     /**** sattbl : order of the satellites in the previous epoch   ****/
444     /**** if *sattbl is set to  -1, the data arc for the satellite ****/
445     /**** will be initialized                                      ****/
446     int i,j;
447     char *ps;
448
449     for (i=0;i< nsat;i++,p_new+=3){
450         *sattbl = -1;
451         ps = p_old;
452         for(j=0;j<nsat_old;j++,ps+=3){
453             if(strncmp(p_new,ps,3) == 0){
454                 *sattbl = j;
455                 break;
456             }
457         }
458         /*** check double entry ***/
459         for(j=i+1,ps=p_new+3 ; j<nsat ; j++,ps+=3){
460             if(strncmp(p_new,ps,3) == 0){
461                 if( ! skip_strange_epoch ) error_exit(13,p_new);
462                 fprintf(stderr,"WARNING:Duplicated sattellite in one epoch at line %ld. ... skip\n",nl_count);
463                 return 1;
464             }
465         }
466         sattbl++;
467     }
468     return 0;
469 }
470 /*---------------------------------------------------------------------*/
471 int  read_more_sat(int n, char *p){
472 /**** read continuation line of satellite list (for RINEX2) ****/
473     char line[MAXCLM];
474     
475     do {
476         p += 36;
477         if( read_chk_line(line) ) return 1;
478          /**** append satellite table ****/
479         if(line[2] == ' '){
480             sprintf(p,"%s",&line[32]);
481         }else{                        /*** for the files before clarification of format ***/
482             sprintf(p,"%s",&line[0]); /*** by W.Gurtner (IGS mail #1577)                ***/
483         }
484         n -= 12;
485     } while(n>12);
486     return 0;
487 }
488 /*---------------------------------------------------------------------*/
489 void data(int *sattbl){
490 /********************************************************************/
491 /*  Function : output the 3rd order difference of data              */
492 /*       u : upper X digits of the data                             */
493 /*       l : lower 5 digits of the data                             */
494 /*            ( y = u*100 + l/1000 )                                */
495 /*   py->u : upper digits of the 3rd order difference of the data   */
496 /*   py->l : lower digits of the 3rd order difference of the data   */
497 /********************************************************************/
498     data_format *py1;
499     int  i,j,*i0;
500     char *p;
501
502     for(i=0,i0 = sattbl ; i<nsat ; i++,i0++){
503         for(j=0,py1=y1[i] ; j<ntype_record[i] ; j++,py1++){
504             if( py1->order >= 0 ){       /*** if the numerical data field is non-blank ***/
505                 if(*i0 < 0 || y0[*i0][j].order == -1){
506                     /**** initialize the data arc ****/
507                     py1->order =0; p_buff += sprintf(p_buff,"%d&",ARC_ORDER);
508                 }else{
509                     take_diff(py1,&(y0[*i0][j]));
510                     if(labs( py1->u[py1->order]) > 100000){
511                         /**** initialization of the arc for large cycle slip  ****/
512                         py1->order =0; p_buff += sprintf(p_buff,"%d&",ARC_ORDER);
513                     }
514                 }
515                 putdiff(py1->u[py1->order],py1->l[py1->order]);
516             }else if(*i0 >= 0 && rinex_version == 2){
517                 /**** CRINEX1 (RINEX2) initialize flags for blank field, not put '&' ****/
518                 flag0[*i0][j*2] = flag0[*i0][j*2+1] = ' ';
519             }
520             if(j < ntype_record[i]-1) *p_buff++ = ' ';   /** ' ' :field separator **/
521         }
522         *(p_buff++) = ' ';  /* write field separator */
523         if(*i0 < 0){             /* if new satellite initialize all LLI & SN flags */
524             if(rinex_version == 2){
525                 p_buff=strdiff("",    flag[i],p_buff);
526             }else{          /*  replace space with '&' for CRINEX3(RINEX3)  */
527                 for(p=flag[i]; *p != '\0' ; p++) *p_buff++ = (*p == ' ')? '&':*p;
528                 *p_buff++ = '\n'; *p_buff = '\0';
529             }
530         }else{
531             p_buff=strdiff(flag0[*i0],flag[i],p_buff);
532         }
533     }
534 }
535 /*---------------------------------------------------------------------*/
536 char *strdiff(char *s1, char *s2, char *ds){
537 /********************************************************************/
538 /**   copy only the difference of string s2 from string s1         **/
539 /**   '&' is marked when some character changed to a space         **/
540 /**   trailing blank is eliminated and '/n' is added               **/
541 /********************************************************************/
542     for(; *s1 != '\0'  && *s2 != '\0' ; s2++){
543         if(*s2 == *(s1++))
544             *ds++ = ' ';
545         else if(*s2 == ' ')
546             *ds++ = '&';
547         else
548             *ds++ = *s2;
549     }
550     strcpy(ds,s1);
551     for(;*ds;ds++){ if(*ds != ' ') *ds = '&'; }
552     while(*s2) *ds++ = *s2++;
553
554     for(ds-- ; *ds == ' ' ; ds--);    /*** find pointer of last non-space character ***/
555     *++ds = '\n'; *++ds = '\0';       /*** chop spaces at the end of the line ***/
556     return ds;
557 }
558 /*---------------------------------------------------------------------*/
559 int rnx_getline(data_format *py1, char *flag, char *sat_id, int *ntype_rec){
560 /**** read data line for one satellite and       ****/
561 /**** set data difference and flags to valiables ****/
562     char line[MAXCLM],*p,*pmax,*p_1st_rec;
563     int i,j,nfield,max_field;
564
565     if( read_chk_line(line) ) return 1;
566     if(rinex_version == 2 ) {             /** for RINEX2 **/
567         max_field=5;                               /** muximum data types in one line **/
568         *ntype_rec=ntype;                          /** # of data types for the satelite **/
569         p_1st_rec=line;                            /** pointer to the start of the first record **/
570     }else{                                /** for RINEX3 **/
571         strncpy(sat_id,line,3);                    /** put satellite ID to the list of satellites **/
572         max_field=*ntype_rec=ntype_gnss[line[0]];  /*** # of data type for the GNSS system ***/
573         if(max_field<0) error_exit(21,line);
574         p_1st_rec=line+3;
575     }
576     for(i=0,p=p_1st_rec;i<*ntype_rec;i+=max_field){                 /* for each line */
577         nfield = (*ntype_rec-i < max_field ? *ntype_rec-i:max_field); /*** expected # of data fields in the line ***/
578         pmax = p_1st_rec + 16*nfield;
579
580         /*** Cut or pad spaces. Detect error if there is any character after *pmax ***/
581         p = strchr(line,'\0');
582         if(p < pmax ) {
583             while(p<pmax) *p++ = ' ';*p='\0';
584         }else{
585             for(*p = ' ' ; p > pmax && *p == ' ' ; p--);
586             if(p > pmax) {
587                 if( ! skip_strange_epoch ) error_exit(9,line);
588                 fprintf(stderr,"WARNING: mismatch of number of the data types at line %ld. ... skip\n",nl_count);
589                 return 1;
590             }
591         }
592
593         /*** parse the line (read value into py1) ***/
594         for(j=0,p=p_1st_rec; j<nfield; j++,p+=16,py1++){
595             if( *(p+10) == '.' ){
596                 *flag++ = *(p+14);
597                 *flag++ = *(p+15);
598                 *(p+14) = '\0';
599                 read_value(p,&(py1->u[0]),&(py1->l[0]));
600                 py1->order = 0;
601             }else if( strncmp(p,"              ",14) == 0 ){
602                 if( rinex_version == 2 && strncmp((p+14),"  ",2) != 0 ) error_exit(20,line);
603                 *flag++ = *(p+14);
604                 *flag++ = *(p+15);
605                 py1->order = -1;
606             }else{
607                 if( ! skip_strange_epoch ) error_exit(10,p);
608                 fprintf(stderr,"WARNING: abnormal data field at line %ld....skip\n",nl_count);
609                 return 1;
610             }
611         }
612         if(i+max_field < *ntype_rec){
613             if( read_chk_line(line) ) return 1;   /* read continuation line */
614         }
615     }
616     *flag = '\0';
617     return 0;
618 }
619 /*---------------------------------------------------------------------*/
620 void read_value(char *p, long *pu, long *pl){
621 /**** divide the data into lower 5 digits and upper digits     ****/
622 /**** input p :  pointer to one record (14 characters + '\0')  ****/
623 /**** output  *pu, *pl: upper and lower digits the data        ****/
624
625     char *p7,*p8,*p9;
626     p7 =p +7;
627     p8 =p7+1;
628     p9 =p8+1;
629
630     *(p9+1)=*p9;              /* shift two digits: ex. 123.456 -> 1223456,  -.345 ->   -345 */
631     *p9=*p8;                  /*                       -12.345 -> -112345, -1.234 -> --1234 */
632     *pl = atol(p9);           /*                         0.123 ->  . 0123, -0.123 -> --0123 */
633     
634     if(*p7 == ' '){
635         *pu = 0;
636     }else if(*p7 == '-'){
637         *pu = 0;
638         *pl = -*pl;
639     }else{
640         *p8='.';
641         *pu = atol(p);
642         if(*pu < 0) *pl = -*pl;
643     }
644 }
645 /*---------------------------------------------------------------------*/
646 void take_diff(data_format *py1, data_format *py0){
647     int k;
648
649     py1->order = py0->order;
650     if(py1->order < ARC_ORDER) (py1->order)++;
651     if(py1->order > 0){
652         for(k=0;k<py1->order;k++){
653             py1->u[k+1] = py1->u[k] - py0->u[k];
654             py1->l[k+1] = py1->l[k] - py0->l[k];
655         }
656     }
657 }
658 /*---------------------------------------------------------------------*/
659 void putdiff(long dddu, long dddl){
660
661     dddu += dddl/100000 ; dddl %= 100000;
662     if(dddu<0 && dddl>0){
663         dddu++ ; dddl -= 100000;
664     }else if(dddu>0 && dddl<0){
665         dddu-- ; dddl += 100000;
666     }
667
668     if(dddu == 0){
669         p_buff += sprintf(p_buff,"%ld",dddl);
670     }else{
671         p_buff += sprintf(p_buff,"%ld%05.5ld",dddu,labs(dddl));
672     }
673 }
674 /*---------------------------------------------------------------------*/
675 void put_clock(long du, long dl, int c_order){
676 /***********************************/
677 /****  output clock diff. data  ****/
678 /***********************************/
679     du += dl/100000000 ; dl %= 100000000;
680     if(du<0 && dl>0){
681         du++ ; dl -= 100000000;
682     }else if(du>0 && dl<0){
683         du-- ; dl += 100000000;
684     }
685     if(c_order == 0) p_buff += sprintf(p_buff,"%d&",ARC_ORDER);
686     if(du == 0){
687         p_buff += sprintf(p_buff,"%ld\n",dl);
688     }else{
689         p_buff += sprintf(p_buff,"%ld%08.8ld\n",du,labs(dl));
690     }
691 }
692 /*---------------------------------------------------------------------*/
693 int  read_chk_line(char *line){
694     char *p;
695 /***************************************/
696 /* Read and check one line.            */
697 /* The end of the line should be '\n'. */
698 /***************************************/
699     nl_count++;
700     if( fgets(line,MAXCLM,stdin) == NULL ) error_exit(11,line);
701     if( (p = strchr(line,'\n')) == NULL) {
702         if( fgetc(stdin) == EOF ) {
703             error_exit(11,line);
704         }else{
705             if( ! skip_strange_epoch ) error_exit(12,line);
706             fprintf(stderr,"WARNING: null character is found or the line is too long (>%d) at line %ld.\n",MAXCLM,nl_count);
707             return 1;
708         }
709     }
710     if( *(p-1) == '\r' )p--;   /*** check DOS CR/LF ***/
711     while(*--p == ' ' && p>line); *++p = '\0';   /** Chop blank **/
712     return 0;
713 }
714 /*---------------------------------------------------------------------*/
715 void error_exit(int error_no, char *string){
716     if(error_no == 1 ){
717         fprintf(stderr,"Usage: %s input file [-o output file] [-f] [-e # of epochs] [-s] [-h]\n",string);
718         fprintf(stderr,"    output file name can be omitted if input file name is *.[yy]o\n");
719     }else if(error_no == 2 ){
720         fprintf(stderr,"Usage: %s [file] [-] [-f] [-e # of epochs] [-s] [-h]\n",string);
721         fprintf(stderr,"    stdin and stdout are used if input file name is not given.\n");
722     }
723     if(error_no == 1 || error_no == 2){
724         fprintf(stderr,"    -       : output to stdout\n");
725         fprintf(stderr,"    -f      : force overwrite of output file\n");
726         fprintf(stderr,"    -e #    : initialize the compression operation at every # epochs\n");
727         fprintf(stderr,"              When some part of the Compact RINEX file is lost, the data\n");
728         fprintf(stderr,"              can not be recovered thereafter until all the data arc are\n");
729         fprintf(stderr,"              initialized for differential operation. This option may be used to\n");
730         fprintf(stderr,"              increase chances to recover parts of data by using an option of\n");
731         fprintf(stderr,"              CRX2RNX(ver. 4.0 or after) with cost of increase of file size.\n");
732         fprintf(stderr,"    -s      : warn and skip strange epochs (default: stop with error status)\n");
733         fprintf(stderr,"    -h      : display this message\n\n");
734         fprintf(stderr,"    exit code = %d (success)\n",EXIT_SUCCESS);
735         fprintf(stderr,"              = %d (error)\n",  EXIT_FAILURE);
736         fprintf(stderr,"              = %d (warning)\n",EXIT_WARNING);
737         fprintf(stderr,"    [version : %s]\n",VERSION);
738         exit(EXIT_FAILURE);
739     }
740     if(error_no == 4 ){
741         fprintf(stderr,"ERROR : invalid file name  %s\n",string);
742         fprintf(stderr,"The extention of the input file name should be [.xxo].\n");
743         fprintf(stderr,"If the file name doesn't obey this naming convention, use this program as a filter. \n");
744         fprintf(stderr,"    for example)  cat file.in | %s - > file.out\n",PROGNAME);
745         exit(EXIT_FAILURE);
746     }
747     if(error_no == 5 ){
748         fprintf(stderr,"ERROR : can't open %s\n",string);
749         exit(EXIT_FAILURE);
750     }
751     if(error_no == 6 ){
752         fprintf(stderr,"ERROR when reading line %ld.\n",nl_count);
753         fprintf(stderr,"     start>%s<end\n",string);
754         exit(EXIT_FAILURE);
755     }
756     if(error_no == 7 ){
757         fprintf(stderr,"ERROR at line %ld: invalid format for clock offset.\n",nl_count);
758         fprintf(stderr,"     start>%s<end\n",string);
759         exit(EXIT_FAILURE);
760     }
761     if(error_no == 8 ){
762         fprintf(stderr,"ERROR at line %ld : exceeed maximum number of satellites(%d).\n",nl_count,MAXSAT);
763         fprintf(stderr,"     start>%s<end\n",string);
764         exit(EXIT_FAILURE);
765     }
766     if(error_no == 9 ){
767         fprintf(stderr,"ERROR at line %ld : mismatch of number of the data types.\n",nl_count);
768         fprintf(stderr,"     start>%s<end\n",string);
769         exit(EXIT_FAILURE);
770     }
771     if(error_no == 10){
772         fprintf(stderr,"ERROR at line %ld : abnormal data field.\n",nl_count);
773         fprintf(stderr,"     start>%s<end\n",string);
774         exit(EXIT_FAILURE);
775     }
776     if(error_no == 11){
777         fprintf(stderr,"ERROR : The RINEX file seems to be trancated in the middle.\n");
778         fprintf(stderr,"        The conversion is interrupted after reading line %ld :\n",nl_count);
779         fprintf(stderr,"        start>%s<end\n",string);
780         exit(EXIT_FAILURE);
781     }
782     if(error_no == 12 ){
783         fprintf(stderr,"ERROR at line %ld. : null character is found or the line is too long (>%d).\n",nl_count,MAXCLM);
784         fprintf(stderr,"     start>%s<end\n",string);
785         exit(EXIT_FAILURE);
786     }
787     if(error_no == 13 ){
788         fprintf(stderr,"ERROR at line %ld. : Duplicated sattellite in one epoch.\n",nl_count);
789         fprintf(stderr,"     start>%s<end\n",string);
790         exit(EXIT_FAILURE);
791     }
792     if(error_no == 15 ){
793         fprintf(stderr,"The first line is :\n%s\n\n",string);
794         fprintf(stderr,"ERROR : The file format is not valid. This program is applicable\n");
795         fprintf(stderr,"        only to RINEX Version 2/3 Observation file.\n");
796         exit(EXIT_FAILURE);
797     }
798     if(error_no == 16 ){
799         fprintf(stderr,"ERROR at line %ld. : Number of data types exceed MAXTYPE(%d).\n",nl_count,MAXTYPE);
800         fprintf(stderr,"     start>%s<end\n",string);
801         exit(EXIT_FAILURE);
802     }
803     if(error_no == 20 ){
804         fprintf(stderr,"ERROR at line %ld. : data is blank but there is flag.\n",nl_count);
805         fprintf(stderr,"     start>%s<end\n",string);
806         exit(EXIT_FAILURE);
807     }
808     if(error_no == 21 ){
809         fprintf(stderr,"ERROR at line %ld. : GNSS type is not defined in the header.\n",nl_count);
810         fprintf(stderr,"     start>%s<end\n",string);
811         exit(EXIT_FAILURE);
812     }
813 }