ref: d1cebf608b05e45b148108ac6c16ae94f6862097
dir: /sys/src/cmd/scat/scat.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <draw.h> #include <event.h> #include "sky.h" #include "strings.c" enum { NNGC=7840, /* number of NGC numbers [1..NNGC] */ NIC = 5386, /* number of IC numbers */ NNGCrec=NNGC+NIC, /* number of records in the NGC catalog (including IC's, starting at NNGC */ NMrec=122, /* number of M records */ NM=110, /* number of M numbers */ NAbell=2712, /* number of records in the Abell catalog */ NName=1000, /* number of prose names; estimated maximum (read from editable text file) */ NBayer=1517, /* number of bayer entries */ NSAO=258998, /* number of SAO stars */ MAXcon=1932, /* maximum number of patches in a constellation */ Ncon=88, /* number of constellations */ Npatch=92053, /* highest patch number */ }; char ngctype[NNGCrec]; Mindexrec mindex[NMrec]; Namerec name[NName]; Bayerec bayer[NBayer]; long con[MAXcon]; ushort conindex[Ncon+1]; long patchaddr[Npatch+1]; Record *rec; Record *orec; Record *cur; char *dir=DIR; int saodb; int ngcdb; int abelldb; int ngctypedb; int mindexdb; int namedb; int bayerdb; int condb; int conindexdb; int patchdb; char parsed[3]; long nrec; long nreca; long norec; long noreca; Biobuf bin; Biobuf bout; main(int argc, char *argv[]) { char *line; Binit(&bin, 0, OREAD); Binit(&bout, 1, OWRITE); if(argc != 1) dir = argv[1]; astro("", 1); while(line = Brdline(&bin, '\n')){ line[Blinelen(&bin)-1] = 0; lookup(line, 1); Bflush(&bout); } if(display != nil){ closedisplay(display); /* automatic refresh of rio window is triggered by mouse */ close(open("/dev/mouse", OREAD)); } return 0; } void reset(void) { nrec = 0; cur = rec; } void grow(void) { nrec++; if(nreca < nrec){ nreca = nrec+50; rec = realloc(rec, nreca*sizeof(Record)); if(rec == 0){ fprint(2, "scat: realloc fails\n"); exits("realloc"); } } cur = rec+nrec-1; } void copy(void) { if(noreca < nreca){ noreca = nreca; orec = realloc(orec, nreca*sizeof(Record)); if(orec == 0){ fprint(2, "scat: realloc fails\n"); exits("realloc"); } } memmove(orec, rec, nrec*sizeof(Record)); norec = nrec; } int eopen(char *s) { char buf[128]; int f; sprint(buf, "%s/%s.scat", dir, s); f = open(buf, 0); if(f<0){ fprint(2, "scat: can't open %s\n", buf); exits("open"); } return f; } void Eread(int f, char *name, void *addr, long n) { if(read(f, addr, n) != n){ /* BUG! */ fprint(2, "scat: read error on %s\n", name); exits("read"); } } char* skipbl(char *s) { while(*s!=0 && (*s==' ' || *s=='\t')) s++; return s; } char* skipstr(char *s, char *t) { while(*s && *s==*t) s++, t++; return skipbl(s); } /* produce little-endian long at address l */ long Long(long *l) { uchar *p; p = (uchar*)l; return (long)p[0]|((long)p[1]<<8)|((long)p[2]<<16)|((long)p[3]<<24); } /* produce little-endian long at address l */ int Short(short *s) { uchar *p; p = (uchar*)s; return p[0]|(p[1]<<8); } void nameopen(void) { Biobuf b; int i; char *l, *p; if(namedb == 0){ namedb = eopen("name"); Binit(&b, namedb, OREAD); for(i=0; i<NName; i++){ l = Brdline(&b, '\n'); if(l == 0) break; p = strchr(l, '\t'); if(p == 0){ Badformat: Bprint(&bout, "warning: name.scat bad format; line %d\n", i+1); break; } *p++ = 0; strcpy(name[i].name, l); if(strncmp(p, "ngc", 3) == 0) name[i].ngc = atoi(p+3); else if(strncmp(p, "ic", 2) == 0) name[i].ngc = atoi(p+2)+NNGC; else if(strncmp(p, "sao", 3) == 0) name[i].sao = atoi(p+3); else if(strncmp(p, "abell", 5) == 0) name[i].abell = atoi(p+5); else goto Badformat; } if(i == NName) Bprint(&bout, "warning: too many names in name.scat (max %d); extra ignored\n", NName); close(namedb); bayerdb = eopen("bayer"); Eread(bayerdb, "bayer", bayer, sizeof bayer); close(bayerdb); for(i=0; i<NBayer; i++) bayer[i].sao = Long(&bayer[i].sao); } } void saoopen(void) { if(saodb == 0){ nameopen(); saodb = eopen("sao"); } } void ngcopen(void) { if(ngcdb == 0){ nameopen(); ngcdb = eopen("ngc2000"); ngctypedb = eopen("ngc2000type"); Eread(ngctypedb, "ngctype", ngctype, sizeof ngctype); close(ngctypedb); } } void abellopen(void) { /* nothing extra to do with abell: it's directly indexed by number */ if(abelldb == 0) abelldb = eopen("abell"); } void patchopen(void) { Biobuf *b; long l, m; char buf[100]; if(patchdb == 0){ patchdb = eopen("patch"); sprint(buf, "%s/patchindex.scat", dir); b = Bopen(buf, OREAD); if(b == 0){ fprint(2, "can't open %s\n", buf); exits("open"); } for(m=0,l=0; l<=Npatch; l++) patchaddr[l] = m += Bgetc(b)*4; Bterm(b); } } void mopen(void) { int i; if(mindexdb == 0){ mindexdb = eopen("mindex"); Eread(mindexdb, "mindex", mindex, sizeof mindex); close(mindexdb); for(i=0; i<NMrec; i++) mindex[i].ngc = Short(&mindex[i].ngc); } } void constelopen(void) { int i; if(condb == 0){ condb = eopen("con"); conindexdb = eopen("conindex"); Eread(conindexdb, "conindex", conindex, sizeof conindex); close(conindexdb); for(i=0; i<Ncon+1; i++) conindex[i] = Short((short*)&conindex[i]); } } void lowercase(char *s) { for(; *s; s++) if('A'<=*s && *s<='Z') *s += 'a'-'A'; } int loadngc(long index) { static int failed; long j; ngcopen(); j = (index-1)*sizeof(NGCrec); grow(); cur->type = NGC; cur->index = index; seek(ngcdb, j, 0); /* special case: NGC data may not be available */ if(read(ngcdb, &cur->ngc, sizeof(NGCrec)) != sizeof(NGCrec)){ if(!failed){ fprint(2, "scat: NGC database not available\n"); failed++; } cur->type = NONGC; cur->ngc.ngc = 0; cur->ngc.ra = 0; cur->ngc.dec = 0; cur->ngc.diam = 0; cur->ngc.mag = 0; return 0; } cur->ngc.ngc = Short(&cur->ngc.ngc); cur->ngc.ra = Long(&cur->ngc.ra); cur->ngc.dec = Long(&cur->ngc.dec); cur->ngc.diam = Long(&cur->ngc.diam); cur->ngc.mag = Short(&cur->ngc.mag); return 1; } int loadabell(long index) { long j; abellopen(); j = index-1; grow(); cur->type = Abell; cur->index = index; seek(abelldb, j*sizeof(Abellrec), 0); Eread(abelldb, "abell", &cur->abell, sizeof(Abellrec)); cur->abell.abell = Short(&cur->abell.abell); if(cur->abell.abell != index){ fprint(2, "bad format in abell catalog\n"); exits("abell"); } cur->abell.ra = Long(&cur->abell.ra); cur->abell.dec = Long(&cur->abell.dec); cur->abell.glat = Long(&cur->abell.glat); cur->abell.glong = Long(&cur->abell.glong); cur->abell.rad = Long(&cur->abell.rad); cur->abell.mag10 = Short(&cur->abell.mag10); cur->abell.pop = Short(&cur->abell.pop); cur->abell.dist = Short(&cur->abell.dist); return 1; } int loadsao(int index) { if(index<=0 || index>NSAO) return 0; saoopen(); grow(); cur->type = SAO; cur->index = index; seek(saodb, (index-1)*sizeof(SAOrec), 0); Eread(saodb, "sao", &cur->sao, sizeof(SAOrec)); cur->sao.ra = Long(&cur->sao.ra); cur->sao.dec = Long(&cur->sao.dec); cur->sao.dra = Long(&cur->sao.dra); cur->sao.ddec = Long(&cur->sao.ddec); cur->sao.mag = Short(&cur->sao.mag); cur->sao.mpg = Short(&cur->sao.mpg); cur->sao.hd = Long(&cur->sao.hd); return 1; } int loadplanet(int index, Record *r) { if(index<0 || index>NPlanet || planet[index].name[0]=='\0') return 0; grow(); cur->type = Planet; cur->index = index; /* check whether to take new or existing record */ if(r == nil) memmove(&cur->planet, &planet[index], sizeof(Planetrec)); else memmove(&cur->planet, &r->planet, sizeof(Planetrec)); return 1; } int loadpatch(long index) { int i; patchopen(); if(index<=0 || index>Npatch) return 0; grow(); cur->type = Patch; cur->index = index; seek(patchdb, patchaddr[index-1], 0); cur->patch.nkey = (patchaddr[index]-patchaddr[index-1])/4; Eread(patchdb, "patch", cur->patch.key, cur->patch.nkey*4); for(i=0; i<cur->patch.nkey; i++) cur->patch.key[i] = Long(&cur->patch.key[i]); return 1; } int loadtype(int t) { int i; ngcopen(); for(i=0; i<NNGCrec; i++) if(t == (ngctype[i])){ grow(); cur->type = NGCN; cur->index = i+1; } return 1; } void flatten(void) { int i, j, notflat; Record *or; long key; loop: copy(); reset(); notflat = 0; for(i=0,or=orec; i<norec; i++,or++){ switch(or->type){ default: fprint(2, "bad type %d in flatten\n", or->type); break; case NONGC: break; case Planet: case Abell: case NGC: case SAO: grow(); memmove(cur, or, sizeof(Record)); break; case NGCN: if(loadngc(or->index)) notflat = 1; break; case NamedSAO: loadsao(or->index); notflat = 1; break; case NamedNGC: if(loadngc(or->index)) notflat = 1; break; case NamedAbell: loadabell(or->index); notflat = 1; break; case PatchC: loadpatch(or->index); notflat = 1; break; case Patch: for(j=1; j<or->patch.nkey; j++){ key = or->patch.key[j]; if((key&0x3F) == SAO) loadsao((key>>8)&0xFFFFFF); else if((key&0x3F) == Abell) loadabell((key>>8)&0xFFFFFF); else loadngc((key>>16)&0xFFFF); } break; } } if(notflat) goto loop; } int ism(int index) { int i; for(i=0; i<NMrec; i++) if(mindex[i].ngc == index) return 1; return 0; } char* alpha(char *s, char *t) { int n; n = strlen(t); if(strncmp(s, t, n)==0 && (s[n]<'a' || 'z'<s[n])) return skipbl(s+n); return 0; } char* text(char *s, char *t) { int n; n = strlen(t); if(strncmp(s, t, n)==0 && (s[n]==0 || s[n]==' ' || s[n]=='\t')) return skipbl(s+n); return 0; } int cull(char *s, int keep, int dobbox) { int i, j, nobj, keepthis; Record *or; char *t; int dogrtr, doless, dom, dosao, dongc, doabell; int mgrtr, mless; char obj[100]; memset(obj, 0, sizeof(obj)); nobj = 0; dogrtr = 0; doless = 0; dom = 0; dongc = 0; dosao = 0; doabell = 0; mgrtr = mless= 0; if(dobbox) goto Cull; for(;;){ if(s[0] == '>'){ dogrtr = 1; mgrtr = 10 * strtod(s+1, &t); if(mgrtr==0 && t==s+1){ fprint(2, "bad magnitude\n"); return 0; } s = skipbl(t); continue; } if(s[0] == '<'){ doless = 1; mless = 10 * strtod(s+1, &t); if(mless==0 && t==s+1){ fprint(2, "bad magnitude\n"); return 0; } s = skipbl(t); continue; } if(t = text(s, "m")){ dom = 1; s = t; continue; } if(t = text(s, "sao")){ dosao = 1; s = t; continue; } if(t = text(s, "ngc")){ dongc = 1; s = t; continue; } if(t = text(s, "abell")){ doabell = 1; s = t; continue; } for(i=0; names[i].name; i++) if(t = alpha(s, names[i].name)){ if(nobj > 100){ fprint(2, "too many object types\n"); return 0; } obj[nobj++] = names[i].type; s = t; goto Continue; } break; Continue:; } if(*s){ fprint(2, "syntax error in object list\n"); return 0; } Cull: flatten(); copy(); reset(); if(dom) mopen(); if(dosao) saoopen(); if(dongc || nobj) ngcopen(); if(doabell) abellopen(); for(i=0,or=orec; i<norec; i++,or++){ keepthis = !keep; if(dobbox && inbbox(or->ngc.ra, or->ngc.dec)) keepthis = keep; if(doless && or->ngc.mag <= mless) keepthis = keep; if(dogrtr && or->ngc.mag >= mgrtr) keepthis = keep; if(dom && (or->type==NGC && ism(or->ngc.ngc))) keepthis = keep; if(dongc && or->type==NGC) keepthis = keep; if(doabell && or->type==Abell) keepthis = keep; if(dosao && or->type==SAO) keepthis = keep; for(j=0; j<nobj; j++) if(or->type==NGC && or->ngc.type==obj[j]) keepthis = keep; if(keepthis){ grow(); memmove(cur, or, sizeof(Record)); } } return 1; } int compar(void *va, void *vb) { Record *a=va, *b=vb; if(a->type == b->type) return a->index - b->index; return a->type - b->type; } void sort(void) { int i; Record *r, *s; if(nrec == 0) return; qsort(rec, nrec, sizeof(Record), compar); r = rec+1; s = rec; for(i=1; i<nrec; i++,r++){ /* may have multiple instances of a planet in the scene */ if(r->type==s->type && r->index==s->index && r->type!=Planet) continue; memmove(++s, r, sizeof(Record)); } nrec = (s+1)-rec; } char greekbuf[128]; char* togreek(char *s) { char *t; int i, n; Rune r; t = greekbuf; while(*s){ for(i=1; i<=24; i++){ n = strlen(greek[i]); if(strncmp(s, greek[i], n)==0 && (s[n]==' ' || s[n]=='\t')){ s += n; t += runetochar(t, &greeklet[i]); goto Cont; } } n = chartorune(&r, s); for(i=0; i<n; i++) *t++ = *s++; Cont:; } *t = 0; return greekbuf; } char* fromgreek(char *s) { char *t; int i, n; Rune r; t = greekbuf; while(*s){ n = chartorune(&r, s); for(i=1; i<=24; i++){ if(r == greeklet[i]){ strcpy(t, greek[i]); t += strlen(greek[i]); s += n; goto Cont; } } for(i=0; i<n; i++) *t++ = *s++; Cont:; } *t = 0; return greekbuf; } #ifdef OLD /* * Old version */ int coords(int deg) { int i; int x, y; Record *or; long dec, ra, ndec, nra; int rdeg; flatten(); copy(); reset(); deg *= 2; for(i=0,or=orec; i<norec; i++,or++){ if(or->type == Planet) /* must keep it here */ loadplanet(or->index, or); dec = or->ngc.dec/MILLIARCSEC; ra = or->ngc.ra/MILLIARCSEC; rdeg = deg/cos((dec*PI)/180); for(y=-deg; y<=+deg; y++){ ndec = dec*2+y; if(ndec/2>=90 || ndec/2<=-90) continue; /* fp errors hurt here, so we round 1' to the pole */ if(ndec >= 0) ndec = ndec*500*60*60 + 60000; else ndec = ndec*500*60*60 - 60000; for(x=-rdeg; x<=+rdeg; x++){ nra = ra*2+x; if(nra/2 < 0) nra += 360*2; if(nra/2 >= 360) nra -= 360*2; /* fp errors hurt here, so we round up 1' */ nra = nra/2*MILLIARCSEC + 60000; loadpatch(patcha(angle(nra), angle(ndec))); } } } sort(); return 1; } #endif /* * New version attempts to match the boundaries of the plot better. */ int coords(int deg) { int i; int x, y, xx; Record *or; long min, circle; double factor; flatten(); circle = 360*MILLIARCSEC; deg *= MILLIARCSEC; /* find center */ folded = 0; bbox(0, 0, 0); /* now expand */ factor = cos(angle((decmax+decmin)/2)); if(factor < .2) factor = .2; factor = floor(1/factor); folded = 0; bbox(factor*deg, deg, 1); Bprint(&bout, "%s to ", hms(angle(ramin))); Bprint(&bout, "%s\n", hms(angle(ramax))); Bprint(&bout, "%s to ", dms(angle(decmin))); Bprint(&bout, "%s\n", dms(angle(decmax))); copy(); reset(); for(i=0,or=orec; i<norec; i++,or++) if(or->type == Planet) /* must keep it here */ loadplanet(or->index, or); min = ramin; if(ramin > ramax) min -= circle; for(x=min; x<=ramax; x+=250*60*60){ xx = x; if(xx < 0) xx += circle; for(y=decmin; y<=decmax; y+=250*60*60) if(-circle/4 < y && y < circle/4) loadpatch(patcha(angle(xx), angle(y))); } sort(); cull(nil, 1, 1); return 1; } void pplate(char *flags) { int i; long c; int na, rah, ram, d1, d2; double r0; int ra, dec; long ramin, ramax, decmin, decmax; /* all in degrees */ Record *r; int folded; Angle racenter, deccenter, rasize, decsize, a[4]; Picture *pic; rasize = -1.0; decsize = -1.0; na = 0; for(;;){ while(*flags==' ') flags++; if(('0'<=*flags && *flags<='9') || *flags=='+' || *flags=='-'){ if(na >= 3) goto err; a[na++] = getra(flags); while(*flags && *flags!=' ') flags++; continue; } if(*flags){ err: Bprint(&bout, "syntax error in plate\n"); return; } break; } switch(na){ case 0: break; case 1: rasize = a[0]; decsize = rasize; break; case 2: rasize = a[0]; decsize = a[1]; break; case 3: case 4: racenter = a[0]; deccenter = a[1]; rasize = a[2]; if(na == 4) decsize = a[3]; else decsize = rasize; if(rasize<0.0 || decsize<0.0){ Bprint(&bout, "negative sizes\n"); return; } goto done; } folded = 0; /* convert to milliarcsec */ c = 1000*60*60; Again: if(nrec == 0){ Bprint(&bout, "empty\n"); return; } ramin = 0x7FFFFFFF; ramax = -0x7FFFFFFF; decmin = 0x7FFFFFFF; decmax = -0x7FFFFFFF; for(r=rec,i=0; i<nrec; i++,r++){ if(r->type == Patch){ radec(r->index, &rah, &ram, &dec); ra = 15*rah+ram/4; r0 = c/cos(RAD(dec)); ra *= c; dec *= c; if(dec == 0) d1 = c, d2 = c; else if(dec < 0) d1 = c, d2 = 0; else d1 = 0, d2 = c; }else if(r->type==SAO || r->type==NGC || r->type==Abell){ ra = r->ngc.ra; dec = r->ngc.dec; d1 = 0, d2 = 0, r0 = 0; }else if(r->type==NGCN){ loadngc(r->index); continue; }else if(r->type==NamedSAO){ loadsao(r->index); continue; }else if(r->type==NamedNGC){ loadngc(r->index); continue; }else if(r->type==NamedAbell){ loadabell(r->index); continue; }else continue; if(dec+d2 > decmax) decmax = dec+d2; if(dec-d1 < decmin) decmin = dec-d1; if(folded){ ra -= 180*c; if(ra < 0) ra += 360*c; } if(ra+r0 > ramax) ramax = ra+r0; if(ra < ramin) ramin = ra; } if(!folded && ramax-ramin>270*c){ folded = 1; goto Again; } racenter = angle(ramin+(ramax-ramin)/2); deccenter = angle(decmin+(decmax-decmin)/2); if(rasize<0 || decsize<0){ rasize = angle(ramax-ramin)*cos(deccenter); decsize = angle(decmax-decmin); } done: if(DEG(rasize)>1.1 || DEG(decsize)>1.1){ Bprint(&bout, "plate too big: %s", ms(rasize)); Bprint(&bout, " x %s\n", ms(decsize)); Bprint(&bout, "trimming to 30'x30'\n"); rasize = RAD(0.5); decsize = RAD(0.5); } Bprint(&bout, "%s %s ", hms(racenter), dms(deccenter)); Bprint(&bout, "%s", ms(rasize)); Bprint(&bout, " x %s\n", ms(decsize)); Bflush(&bout); flatten(); pic = image(racenter, deccenter, rasize, decsize); if(pic == 0) return; Bprint(&bout, "plate %s locn %d %d %d %d\n", pic->name, pic->minx, pic->miny, pic->maxx, pic->maxy); Bflush(&bout); displaypic(pic); } void lookup(char *s, int doreset) { int i, j, k; int rah, ram, deg; char *starts, *inputline=s, *t, *u; Record *r; long n; double x; Angle ra; lowercase(s); s = skipbl(s); if(*s == 0) goto Print; if(t = alpha(s, "flat")){ if(*t){ fprint(2, "flat takes no arguments\n"); return; } if(nrec == 0){ fprint(2, "no records\n"); return; } flatten(); goto Print; } if(t = alpha(s, "print")){ if(*t){ fprint(2, "print takes no arguments\n"); return; } for(i=0,r=rec; i<nrec; i++,r++) prrec(r); return; } if(t = alpha(s, "add")){ lookup(t, 0); return; } if(t = alpha(s, "sao")){ n = strtoul(t, &u, 10); if(n<=0 || n>NSAO) goto NotFound; t = skipbl(u); if(*t){ fprint(2, "syntax error in sao\n"); return; } if(doreset) reset(); if(!loadsao(n)) goto NotFound; goto Print; } if(t = alpha(s, "ngc")){ n = strtoul(t, &u, 10); if(n<=0 || n>NNGC) goto NotFound; t = skipbl(u); if(*t){ fprint(2, "syntax error in ngc\n"); return; } if(doreset) reset(); if(!loadngc(n)) goto NotFound; goto Print; } if(t = alpha(s, "ic")){ n = strtoul(t, &u, 10); if(n<=0 || n>NIC) goto NotFound; t = skipbl(u); if(*t){ fprint(2, "syntax error in ic\n"); return; } if(doreset) reset(); if(!loadngc(n+NNGC)) goto NotFound; goto Print; } if(t = alpha(s, "abell")){ n = strtoul(t, &u, 10); if(n<=0 || n>NAbell) goto NotFound; if(doreset) reset(); if(!loadabell(n)) goto NotFound; goto Print; } if(t = alpha(s, "m")){ n = strtoul(t, &u, 10); if(n<=0 || n>NM) goto NotFound; mopen(); for(j=n-1; mindex[j].m<n; j++) ; if(doreset) reset(); while(mindex[j].m == n){ if(mindex[j].ngc){ grow(); cur->type = NGCN; cur->index = mindex[j].ngc; } j++; } goto Print; } for(i=1; i<=Ncon; i++) if(t = alpha(s, constel[i])){ if(*t){ fprint(2, "syntax error in constellation\n"); return; } constelopen(); seek(condb, 4L*conindex[i-1], 0); j = conindex[i]-conindex[i-1]; Eread(condb, "con", con, 4*j); if(doreset) reset(); for(k=0; k<j; k++){ grow(); cur->type = PatchC; cur->index = Long(&con[k]); } goto Print; } if(t = alpha(s, "expand")){ n = 0; if(*t){ if(*t<'0' && '9'<*t){ Expanderr: fprint(2, "syntax error in expand\n"); return; } n = strtoul(t, &u, 10); t = skipbl(u); if(*t) goto Expanderr; } coords(n); goto Print; } if(t = alpha(s, "plot")){ if(nrec == 0){ Bprint(&bout, "empty\n"); return; } plot(t); return; } if(t = alpha(s, "astro")){ astro(t, 0); return; } if(t = alpha(s, "plate")){ pplate(t); return; } if(t = alpha(s, "gamma")){ while(*t==' ') t++; u = t; x = strtod(t, &u); if(u > t) gam.gamma = x; Bprint(&bout, "%.2f\n", gam.gamma); return; } if(t = alpha(s, "keep")){ if(!cull(t, 1, 0)) return; goto Print; } if(t = alpha(s, "drop")){ if(!cull(t, 0, 0)) return; goto Print; } for(i=0; planet[i].name[0]; i++){ if(t = alpha(s, planet[i].name)){ if(doreset) reset(); loadplanet(i, nil); goto Print; } } for(i=0; names[i].name; i++){ if(t = alpha(s, names[i].name)){ if(*t){ fprint(2, "syntax error in type\n"); return; } if(doreset) reset(); loadtype(names[i].type); goto Print; } } switch(s[0]){ case '"': starts = ++s; while(*s != '"') if(*s++ == 0){ fprint(2, "bad star name\n"); return; } *s = 0; if(doreset) reset(); j = nrec; saoopen(); starts = fromgreek(starts); for(i=0; i<NName; i++) if(equal(starts, name[i].name)){ grow(); if(name[i].sao){ rec[j].type = NamedSAO; rec[j].index = name[i].sao; } if(name[i].ngc){ rec[j].type = NamedNGC; rec[j].index = name[i].ngc; } if(name[i].abell){ rec[j].type = NamedAbell; rec[j].index = name[i].abell; } strcpy(rec[j].named.name, name[i].name); j++; } if(parsename(starts)) for(i=0; i<NBayer; i++) if(bayer[i].name[0]==parsed[0] && (bayer[i].name[1]==parsed[1] || parsed[1]==0) && bayer[i].name[2]==parsed[2]){ grow(); rec[j].type = NamedSAO; rec[j].index = bayer[i].sao; strncpy(rec[j].named.name, starts, sizeof(rec[j].named.name)); j++; } if(j == 0){ *s = '"'; goto NotFound; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': strtoul(s, &t, 10); if(*t != 'h'){ BadCoords: fprint(2, "bad coordinates %s\n", inputline); break; } ra = DEG(getra(s)); while(*s && *s!=' ' && *s!='\t') s++; rah = ra/15; ra = ra-rah*15; ram = ra*4; deg = strtol(s, &t, 10); if(t == s) goto BadCoords; /* degree sign etc. is optional */ if((uchar)*t == L'°') deg = DEG(getra(s)); if(doreset) reset(); if(abs(deg)>=90 || rah>=24) goto BadCoords; if(!loadpatch(patch(rah, ram, deg))) goto NotFound; break; default: fprint(2, "unknown command %s\n", inputline); return; } Print: if(nrec == 0) Bprint(&bout, "empty\n"); else if(nrec <= 2) for(i=0; i<nrec; i++) prrec(rec+i); else Bprint(&bout, "%ld items\n", nrec); return; NotFound: fprint(2, "%s not found\n", inputline); return; } char *ngctypes[] = { [Galaxy] "Gx", [PlanetaryN] "Pl", [OpenCl] "OC", [GlobularCl] "Gb", [DiffuseN] "Nb", [NebularCl] "C+N", [Asterism] "Ast", [Knot] "Kt", [Triple] "***", [Double] "D*", [Single] "*", [Uncertain] "?", [Nonexistent] "-", [Unknown] " ", [PlateDefect] "PD", }; char* ngcstring(int d) { if(d<Galaxy || d>PlateDefect) return "can't happen"; return ngctypes[d]; } short descindex[NINDEX]; void printnames(Record *r) { int i, ok, done; done = 0; for(i=0; i<NName; i++){ /* stupid linear search! */ ok = 0; if(r->type==SAO && r->index==name[i].sao) ok = 1; if(r->type==NGC && r->ngc.ngc==name[i].ngc) ok = 1; if(r->type==Abell && r->abell.abell==name[i].abell) ok = 1; if(ok){ if(done++ == 0) Bprint(&bout, "\t"); Bprint(&bout, " \"%s\"", togreek(name[i].name)); } } if(done) Bprint(&bout, "\n"); } int equal(char *s1, char *s2) { int c; while(*s1){ if(*s1==' '){ while(*s1==' ') s1++; continue; } while(*s2==' ') s2++; c=*s2; if('A'<=*s2 && *s2<='Z') c^=' '; if(*s1!=c) return 0; s1++, s2++; } return 1; } int parsename(char *s) { char *blank; int i; blank = strchr(s, ' '); if(blank==0 || strchr(blank+1, ' ') || strlen(blank+1)!=3) return 0; blank++; parsed[0] = parsed[1] = parsed[2] = 0; if('0'<=s[0] && s[0]<='9'){ i = atoi(s); parsed[0] = i; if(i > 100) return 0; }else{ for(i=1; i<=24; i++) if(strncmp(greek[i], s, strlen(greek[i]))==0){ parsed[0]=100+i; goto out; } return 0; out: if('0'<=s[strlen(greek[i])] && s[strlen(greek[i])]<='9') parsed[1]=s[strlen(greek[i])]-'0'; } for(i=1; i<=88; i++) if(strcmp(constel[i], blank)==0){ parsed[2] = i; return 1; } return 0; } char* dist_grp(int dg) { switch(dg){ default: return "unknown"; case 1: return "13.3-14.0"; case 2: return "14.1-14.8"; case 3: return "14.9-15.6"; case 4: return "15.7-16.4"; case 5: return "16.5-17.2"; case 6: return "17.3-18.0"; case 7: return ">18.0"; } } char* rich_grp(int dg) { switch(dg){ default: return "unknown"; case 0: return "30-40"; case 1: return "50-79"; case 2: return "80-129"; case 3: return "130-199"; case 4: return "200-299"; case 5: return ">=300"; } } char* nameof(Record *r) { NGCrec *n; SAOrec *s; Abellrec *a; static char buf[128]; int i; switch(r->type){ default: return nil; case SAO: s = &r->sao; if(s->name[0] == 0) return nil; if(s->name[0] >= 100){ i = snprint(buf, sizeof buf, "%C", greeklet[s->name[0]-100]); if(s->name[1]) i += snprint(buf+i, sizeof buf-i, "%d", s->name[1]); }else i = snprint(buf, sizeof buf, " %d", s->name[0]); snprint(buf+i, sizeof buf-i, " %s", constel[s->name[2]]); break; case NGC: n = &r->ngc; if(n->type >= Uncertain) return nil; if(n->ngc <= NNGC) snprint(buf, sizeof buf, "NGC%4d ", n->ngc); else snprint(buf, sizeof buf, "IC%4d ", n->ngc-NNGC); break; case Abell: a = &r->abell; snprint(buf, sizeof buf, "Abell%4d", a->abell); break; } return buf; } void prrec(Record *r) { NGCrec *n; SAOrec *s; Abellrec *a; Planetrec *p; int i, rah, ram, dec, nn; long key; if(r) switch(r->type){ default: fprint(2, "can't prrec type %d\n", r->type); exits("type"); case Planet: p = &r->planet; Bprint(&bout, "%s", p->name); Bprint(&bout, "\t%s %s", hms(angle(p->ra)), dms(angle(p->dec))); Bprint(&bout, " %3.2f° %3.2f°", p->az/(double)MILLIARCSEC, p->alt/(double)MILLIARCSEC); Bprint(&bout, " %s", ms(angle(p->semidiam))); if(r->index <= 1) Bprint(&bout, " %g", p->phase); Bprint(&bout, "\n"); break; case NGC: n = &r->ngc; if(n->ngc <= NNGC) Bprint(&bout, "NGC%4d ", n->ngc); else Bprint(&bout, "IC%4d ", n->ngc-NNGC); Bprint(&bout, "%s ", ngcstring(n->type)); if(n->mag == UNKNOWNMAG) Bprint(&bout, "----"); else Bprint(&bout, "%.1f%c", n->mag/10.0, n->magtype); Bprint(&bout, "\t%s %s\t%c%.1f'\n", hm(angle(n->ra)), dm(angle(n->dec)), n->diamlim, DEG(angle(n->diam))*60.); prdesc(n->desc, desctab, descindex); printnames(r); break; case Abell: a = &r->abell; Bprint(&bout, "Abell%4d %.1f %.2f° %dMpc", a->abell, a->mag10/10.0, DEG(angle(a->rad)), a->dist); Bprint(&bout, "\t%s %s\t%.2f %.2f\n", hm(angle(a->ra)), dm(angle(a->dec)), DEG(angle(a->glat)), DEG(angle(a->glong))); Bprint(&bout, "\tdist grp: %s rich grp: %s %d galaxies/°²\n", dist_grp(a->distgrp), rich_grp(a->richgrp), a->pop); printnames(r); break; case SAO: s = &r->sao; Bprint(&bout, "SAO%6ld ", r->index); if(s->mag==UNKNOWNMAG) Bprint(&bout, "---"); else Bprint(&bout, "%.1f", s->mag/10.0); if(s->mpg==UNKNOWNMAG) Bprint(&bout, ",---"); else Bprint(&bout, ",%.1f", s->mpg/10.0); Bprint(&bout, " %s %s %.4fs %.3f\"", hms(angle(s->ra)), dms(angle(s->dec)), DEG(angle(s->dra))*(4*60), DEG(angle(s->ddec))*(60*60)); Bprint(&bout, " %.3s %c %.2s %ld %d", s->spec, s->code, s->compid, s->hd, s->hdcode); if(s->name[0]) Bprint(&bout, " \"%s\"", nameof(r)); Bprint(&bout, "\n"); printnames(r); break; case Patch: radec(r->index, &rah, &ram, &dec); Bprint(&bout, "%dh%dm %d°", rah, ram, dec); key = r->patch.key[0]; Bprint(&bout, " %s", constel[key&0xFF]); if((key>>=8) & 0xFF) Bprint(&bout, " %s", constel[key&0xFF]); if((key>>=8) & 0xFF) Bprint(&bout, " %s", constel[key&0xFF]); if((key>>=8) & 0xFF) Bprint(&bout, " %s", constel[key&0xFF]); for(i=1; i<r->patch.nkey; i++){ key = r->patch.key[i]; switch(key&0x3F){ case SAO: Bprint(&bout, " SAO%ld", (key>>8)&0xFFFFFF); break; case Abell: Bprint(&bout, " Abell%ld", (key>>8)&0xFFFFFF); break; default: /* NGC */ nn = (key>>16)&0xFFFF; if(nn > NNGC) Bprint(&bout, " IC%d", nn-NNGC); else Bprint(&bout, " NGC%d", nn); Bprint(&bout, "(%s)", ngcstring(key&0x3F)); break; } } Bprint(&bout, "\n"); break; case NGCN: if(r->index <= NNGC) Bprint(&bout, "NGC%ld\n", r->index); else Bprint(&bout, "IC%ld\n", r->index-NNGC); break; case NamedSAO: Bprint(&bout, "SAO%ld \"%s\"\n", r->index, togreek(r->named.name)); break; case NamedNGC: if(r->index <= NNGC) Bprint(&bout, "NGC%ld \"%s\"\n", r->index, togreek(r->named.name)); else Bprint(&bout, "IC%ld \"%s\"\n", r->index-NNGC, togreek(r->named.name)); break; case NamedAbell: Bprint(&bout, "Abell%ld \"%s\"\n", r->index, togreek(r->named.name)); break; case PatchC: radec(r->index, &rah, &ram, &dec); Bprint(&bout, "%dh%dm %d\n", rah, ram, dec); break; } }