/* The binary file format is broken; it assumes the records are large enough to hold the administrivia that's dumped into the first two records (they are sized based on ksize, but no check is made that ksize is large enough to hold the non-ksize-based stuff in the first two records). We follow this broken format in order to generate compatible binary data files; we do check that ksize is large enough, and that double is 8 bytes and int 4, which the binary format assumes. We do not check endianness, nor that floats/doubles are IEEE. */ #include #include #include #include #include extern const char *__progname; static int ksize; static char ttl[3][84]; static double ss[3]; static int ncon; static char cnam[400][6]; static double cval[400]; static double au; static double emrat; static int numde; static int ipt[12][3]; static int lpt[3]; static int nrout; static int nrw; static int ncoeff; static double db[3000]; static int first; static double db2z; static FILE *out; static char *line = 0; static int linelen = 0; static int linealloc = 0; static int lineno = 0; static void plaint(const char *, ...) __attribute__((__format__(__printf__,1,2))); static void plaint(const char *fmt, ...) { va_list ap; va_start(ap,fmt); fprintf(stderr,"%s: %d: ",__progname,lineno); vfprintf(stderr,fmt,ap); fprintf(stderr,"\n"); va_end(ap); } static char *getline(int mustget) { int c; lineno ++; linelen = 0; while (1) { c = getchar(); if (c == EOF) { if (mustget) { plaint("unexpected EOF"); exit(1); } if (linelen > 0) plaint("partial last line ignored"); return(0); } if (linealloc >= linelen) line = realloc(line,linealloc=linelen+16); if (c == '\n') { line[linelen] = '\0'; return(line); } line[linelen++] = c; } } static void nxtgrp(int expected) { char *lp; while (1) { getline(1); for (lp=line;*lp;lp++) if (!isspace(*lp)) break; if (*lp) break; } if (strncmp(line,"GROUP",5) || (atoi(line+5) != expected)) { plaint("missing GROUP %d header",expected); exit(1); } if (expected != 1070) getline(1); } static int readi6(int off) { static char b[7] = { [6] = 0 }; if (off >= linelen) return(0); strncpy(&b[0],line+off,6); return(atoi(&b[0])); } static double readd26(int off) { static char b[27] = { [26] = 0 }; int i; if (off >= linelen) return(0); strncpy(&b[0],line+off,26); i = strcspn(&b[0],"dD"); if (b[i]) b[i] = 'e'; return(atof(&b[0])); } static void read_cnam(void) { int nbuf; char *lp; int i; if (ncon > 400) { plaint("ncon (%d) too large",ncon); exit(1); } nbuf = 0; i = 0; while (i < ncon) { if (nbuf < 1) { getline(1); lp = line; nbuf = strlen(line) >> 3; continue; } bcopy(lp+2,&cnam[i][0],6); i ++; nbuf --; lp += 8; } } static void read_floats(int n, double *vp) { int nbuf; char *lp; int i; int o; nbuf = 0; i = 0; while (i < n) { if (nbuf < 1) { getline(1); lp = line; nbuf = strlen(line) / 26; o = 0; continue; } vp[i] = readd26(o); i ++; nbuf --; o += 26; } } static void read_cval(int n) { if (n > 400) { plaint("group 1041 n (%d) too large",n); exit(1); } read_floats(n,cval); } static int allspaces(char *p, int n) { for (;n>0;n--,p++) if (!isspace(*p)) return(0); return(1); } static void find_cpar(const char *name, double *vp) { int i; int nl; nl = strlen(name); for (i=0;i ipt[mxx][0]) mxx = i; nd = (mxx == 11) ? 2 : 3; desksize = 2 * (ipt[mxx][0] + (nd*ipt[mxx][1]*ipt[mxx][2]) - 1); if (ksize != desksize) { plaint("ksize wrong for ipt (%d != 2*(%d+(%d*%d*%d)-1)=%d, mxx=%d)",ksize,ipt[mxx][0],nd,ipt[mxx][1],ipt[mxx][2],desksize,mxx); } } int main(void); int main(void) { int i; int j; int ignoreblock; if (sizeof(double) != 8) { plaint("sizeof(double) != 8"); exit(1); } if (sizeof(int) != 4) { plaint("sizeof(int) != 4"); exit(1); } getline(1); if (strncmp(line,"KSIZE=",6)) { plaint("missing KSIZE"); exit(1); } ksize = atoi(line+6); printf("ksize = %d\n",ksize); if ( (ksize*4 < (3*14*6)+(400*6)+(3*8)+4+8+8+(4*3*12)+4+(3*4)) || (ksize*4 < 400*8) ) { plaint("ksize too small"); exit(1); } nxtgrp(1010); for (i=0;i<3;i++) { getline(1); j = strlen(line); if (j >= 84) { bcopy(line,&ttl[i][0],84); j = 84; } else { bcopy(line,&ttl[i][0],j); memset(&ttl[i][j],' ',84-j); } printf("%.*s\n",j,&ttl[i][0]); } nxtgrp(1030); getline(1); if (strlen(line) < 24) { plaint("SS line too short"); exit(1); } i = line[12]; line[12] = '\0'; sscanf(line,"%lg",&ss[0]); line[12] = i; i = line[24]; line[24] = '\0'; sscanf(line+12,"%lg",&ss[1]); line[24] = i; sscanf(line+24,"%lg",&ss[2]); nxtgrp(1040); getline(1); ncon = atoi(line); read_cnam(); nxtgrp(1041); getline(1); i = atoi(line); if (i != ncon) { plaint("groups 1040 and 1041 have different counts"); exit(1); } read_cval(i); find_cpar("AU",&au); find_cpar("EMRAT",&emrat); { double v; find_cpar("DENUM",&v); numde = v; } nxtgrp(1050); read_ipt_lpt(); check_ipt(); nxtgrp(1070); out = fopen("JPLEPH","w"); nrout = 0; first = 1; while (1) { if (! getline(0)) break; nrw = readi6(0); ncoeff = readi6(6); if (nrw == 0) continue; if (ncoeff > 3000) { plaint("ncoeff (%d) too large",ncoeff); exit(1); } if (ncoeff < 6) { plaint("ncoeff (%d) too small",ncoeff); exit(1); } if (ncoeff*2 != ksize) { plaint("ncoeff(%d) * 2 != ksize(%d)",ncoeff,ksize); exit(1); } ignoreblock = 0; read_floats(3,db); if (first) { ss[0] = db[0]; ss[2] = db[1] - db[0]; } else if (db[0] < db2z) { /* There's sometimes overlap between the end of one file and the beginning of the next, for some incomprehensible reason. We really *ought* to check that the overlap is exact, but this is what the FORTRAN code did.... */ ignoreblock = 1; } else { if (db[0] != db2z) { plaint("records do not abut (prev end %.1f, cur start %.1f)",db2z,db[0]); exit(1); } if (ss[2] != db[1]-db[0]) { plaint("warning: time delta wrong (%g should be %g)",db[1]-db[0],ss[2]); } } read_floats(ncoeff-3,db+3); if (! ignoreblock) { db2z = db[1]; ss[1] = db[1]; fseek(out,ksize*4*(nrout+2),SEEK_SET); fwrite(db,8,ncoeff,out); nrout ++; if ((nrout % 10) == 0) { printf("%d\r",nrout); fflush(stdout); } } first = 0; } printf("record count = %d\n",nrout); fseek(out,0,SEEK_SET); fwrite(&ttl[0][0],1,3*84,out); fwrite(&cnam[0][0],1,400*6,out); fwrite(&ss[0],8,3,out); fwrite(&ncon,4,1,out); fwrite(&au,8,1,out); fwrite(&emrat,8,1,out); fwrite(&ipt[0][0],4,3*12,out); fwrite(&numde,4,1,out); fwrite(&lpt[0],4,3,out); fseek(out,ksize*4,SEEK_SET); fwrite(&cval[0],8,400,out); fclose(out); exit(0); }