1 // StarPlot - A program for interactively viewing 3D maps of stellar positions.
2 // Copyright (C) 2000  Kevin B. McCarty
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 
18 /*
19   names.cc
20   Contains the functions for the starconvert utility which allow it to
21   extract star names and designations from a text record.
22 */
23 
24 #include "convert.h"
25 #include "../classes/constellations.h"
26 #include "../classes/greek.h"
27 
28 #include <iostream>
29 using std::cerr;
30 using std::cout;
31 using std::endl;
32 
33 bool bayer_comm(StringList *, name, StringList *);
34 bool flam_comm (StringList *, name, StringList *);
35 bool cspec_comm(StringList *, name, StringList *);
dm_comm(StringList *,name,StringList *)36 bool dm_comm   (StringList *, name, StringList *) { return false; } // no-op
37 bool other_comm(StringList *, name, StringList *);
38 
39 bool bayer(const string &, name, StringList *);
40 bool flam (const string &, name, StringList *);
41 bool cspec(const string &, name, StringList *);
42 bool dm   (const string &, name, StringList *);
43 bool other(const string &, name, StringList *);
44 
45 // arrays of function pointers to the above for ease of calling in get_names()
46 
47 bool (*commentfns[NUM_NAME_TYPES])(StringList *, name, StringList *) =
48 { bayer_comm, flam_comm, cspec_comm, dm_comm, other_comm };
49 
50 bool (*recordfns[NUM_NAME_TYPES])(const string &, name, StringList *) =
51 { bayer, flam, cspec, dm, other };
52 
get_constnum(const string & s)53 static int get_constnum(const string &s)
54 {
55   if (s.size() <= 3 /* too short */)
56     return -1;
57 
58   string temp = s.substr(s.size() - 3);
59   int constnum = 0;
60 
61   while (constnum < NUM_CONSTELLATIONS &&
62 	 ! starstrings::case_compare1_n(uc_constellations[constnum], temp, 3))
63     constnum++;
64   return (constnum < NUM_CONSTELLATIONS) ? constnum : -1;
65 }
66 
get_greeknum(const string & s)67 static int get_greeknum(const string &s)
68 {
69   int greeknum = 0;
70   while (greeknum < NUM_GREEK_LETTERS
71          && ! starstrings::case_compare1_n(Greek[greeknum].abbrev, s,
72                                           Greek[greeknum].abbrev.size()))
73     greeknum++;
74   return (greeknum < NUM_GREEK_LETTERS) ? greeknum : -1;
75 }
76 
77 
78 // get_names(): This is the top-level function which loops through the
79 //  name specifications and calls the appropriate function for each spec.
80 //  It then takes care of all the substitutions, if any.
81 
get_names(const string & record,const namedata & nmd,StringList * sn,StringList * sc)82 void get_names(const string &record, const namedata &nmd,
83 	       StringList *sn, StringList *sc)
84                // sn: starnames; sc: starcomments
85 {
86   *sn = StringList();
87 
88   // first find all the names
89   for (unsigned int i = 0; i < nmd.names.size(); i++) {
90     if (nmd.names[i].isNameCommented)
91       commentfns[nmd.names[i].type](sc, nmd.names[i], sn);
92     else
93       recordfns[nmd.names[i].type](record, nmd.names[i], sn);
94   }
95 
96   // then perform any substitutions
97   citerate (std::vector<substitution>, nmd.substs, subst_ptr) {
98     if ((nmd.isSubstCaseSensitive && (*subst_ptr).subst1 == (*sn)[0]) ||
99         (!nmd.isSubstCaseSensitive &&
100 	 starstrings::case_compare1((*subst_ptr).subst1, (*sn)[0])))
101       sn->insert(sn->begin() + (*subst_ptr).insert_posn, (*subst_ptr).subst2);
102   }
103 }
104 
105 
106 // The following functions do the actual work of extracting names from records
107 //  and comments.  They return true if successful at extracting a name, false
108 //  otherwise.
109 
bayer(const string & record,name namespec,StringList * starnames)110 bool bayer(const string &record, name namespec, StringList *starnames)
111 {
112   if (namespec.s.start >= record.size())
113     return false;
114   if (namespec.s.len < 6) // 3 chars for Greek letter, 3 for constellation
115     return false;
116 
117   int constnum, greeknum;
118   string bname = record.substr(namespec.s.start, namespec.s.len);
119 
120   starstrings::stripspace(bname);
121   if (bname.size() < 5) return false;
122   if ((greeknum = get_greeknum(bname)) < 0) return false;
123   if ((constnum = get_constnum(bname)) < 0) return false;
124 
125   unsigned int posn;
126   if ((posn = bname.find_first_of(DIGITS)) < bname.size()) {
127     int supscript = starmath::atoi(bname.substr(posn));
128     starnames->push_back(Greek[greeknum].name+"("+starstrings::itoa(supscript)
129 		         + ") " + constellations[constnum]);
130   }
131   else
132     starnames->push_back(Greek[greeknum].name + " " + constellations[constnum]);
133 
134   return true;
135 }
136 
137 
flam(const string & record,name namespec,StringList * starnames)138 bool flam(const string &record, name namespec, StringList *starnames)
139 {
140   if (namespec.s.start >= record.size())
141     return false;
142   if (namespec.s.len < 6) // 3 chars for number, 3 for constellation
143     return false;
144 
145   int constnum, flamnum;
146   string fname = record.substr(namespec.s.start, namespec.s.len);
147   starstrings::stripspace(fname);
148 
149   if (fname.size() < 4) return false;
150   if (std::isalpha(fname[fname.size() - 4]))
151     // purported "constellation abbreviation" is part of a longer word
152     return false;
153   if ((constnum = get_constnum(fname)) < 0) return false;
154 
155   flamnum = starmath::atoi(fname);
156   if (flamnum <= 0 || flamnum > 140 /* what's the largest Flamsteed number? */)
157     return false;
158 
159   starnames->push_back(starstrings::itoa(flamnum)+" "+constellations[constnum]);
160   return true;
161 }
162 
163 
164 // "cspec" for other "constellation specific" names, e.g. Q Car, RR Lyr
cspec(const string & record,name namespec,StringList * starnames)165 bool cspec(const string &record, name namespec, StringList *starnames)
166 {
167   if (namespec.s.start >= record.size())
168     return false;
169   if (namespec.s.len < 4) // 3 chars for constellation + at least 1 more
170     return false;
171 
172   int constnum;
173   string cname = record.substr(namespec.s.start, namespec.s.len);
174 
175   starstrings::stripspace(cname);
176   if (cname.size() < 4)			    return false; // too short
177   if ((constnum = get_constnum(cname)) < 0) return false;
178   if (get_greeknum(cname) >= 0)             return false; // Bayer designation
179   if (starmath::atoi(cname))                return false; // Flamsteed desig.
180 
181   cname = cname.substr(0, cname.size() - 3);
182   starstrings::stripspace(cname);
183 
184   starnames->push_back(cname + " " + constellations[constnum]);
185   return true;
186 }
187 
188 
dm(const string & record,name namespec,StringList * starnames)189 bool dm(const string &record, name namespec, StringList *starnames)
190 {
191   if (namespec.s.start >= record.size())
192     return false;
193   if (namespec.s.len < 9) return false;
194 
195   string dname = record.substr(namespec.s.start, namespec.s.len);
196   starstrings::stripspace(dname);
197   string catalog, degrees, number, sign;
198 
199   // which catalog: CP, SD, BD or CP
200   catalog = dname.substr(0, 2);
201   starstrings::toupper(catalog);
202   if (catalog != "BD" && catalog != "CD" && catalog != "CP" && catalog != "SD")
203   {
204     // hack to work around weird format of these entries in Hipparcos catalog
205     if ((catalog[0] == 'B' || catalog[0] == 'C' || catalog[0] == 'S')
206 	&& !std::isalpha(catalog[1]))
207       catalog[1] = 'D';
208     else if (catalog[0] == 'P' && !std::isalpha(catalog[1]))
209       catalog = "CP";
210     else
211       return false;
212   }
213 
214   // value of degree sign (+ or -)
215   if (dname.find('-') < dname.size())
216     sign = "-";
217   else sign = "+";
218 
219   // degree part of identifier
220   if (dname.find_first_of(DIGITS) >= dname.size() - 3)
221     return false;
222   degrees = dname.substr(dname.find_first_of(DIGITS), 2);
223   starstrings::stripspace(degrees);
224   if (degrees.size() == 1) // if `degrees' is one digit, pad with zero
225     degrees = string("0") + degrees;
226 
227   // numerical part of identifier
228   number = dname.substr(dname.find_first_of(DIGITS) + 2);
229   starstrings::stripspace(number);
230   if (starstrings::isempty(number))
231     return false;
232 
233   starnames->push_back(catalog + " " + sign + degrees + DEGREE_UTF8 + number);
234   return true;
235 }
236 
237 
other(const string & record,name namespec,StringList * starnames)238 bool other(const string &record, name namespec, StringList *starnames)
239 {
240   if (namespec.s.start >= record.size())
241     return false;
242   if (namespec.s.len <= 0) return false;
243 
244   string sname = record.substr(namespec.s.start, namespec.s.len);
245   starstrings::stripspace(sname);
246   if (starstrings::isempty(sname))
247     return false;
248 
249   if (!starstrings::isempty(namespec.name_prefixes[0]))
250     sname = namespec.name_prefixes[0] + " " + sname;
251   else if (sname.size() < 3)
252     return false;
253 
254   // remove gratuitous internal spaces, e.g. "Gl   3" -> "Gl 3"
255   StringList s = StringList(sname, ' ');
256   s.eraseempty();
257   starnames->push_back(s.flatten());
258   return true;
259 }
260 
261 
262 // We'll use the existing Bayer / Flamsteed functions in the comment versions
263 //  via the miracle of function pointers.
264 
var_comm(StringList * starcomments,name namespec,StringList * starnames,bool (* star_fn)(const string &,name,StringList *))265 bool var_comm(StringList *starcomments, name namespec, StringList *starnames,
266 	      bool (*star_fn)(const string &, name, StringList *))
267 {
268   if (starcomments->size() < 2) return false;
269   unsigned int oldlen = starnames->size();
270   name testspec;
271   testspec.s.start = 0;
272 
273   for (unsigned int i = 1; i < starcomments->size(); i++) {
274     string teststring = (*starcomments)[i - 1] + " " + (*starcomments)[i];
275     testspec.s.len = teststring.size();
276 
277     if ((*star_fn)(teststring, testspec, starnames)) {
278       i--;
279       starcomments->erase(starcomments->begin() + i + 1);
280       starcomments->erase(starcomments->begin() + i);
281     }
282   }
283   return (oldlen - starnames->size() > 0);
284 }
285 
286 
bayer_comm(StringList * starcomments,name namespec,StringList * starnames)287 bool bayer_comm(StringList *starcomments, name namespec, StringList *starnames)
288 { return var_comm(starcomments, namespec, starnames, bayer); }
289 
flam_comm(StringList * starcomments,name namespec,StringList * starnames)290 bool flam_comm(StringList *starcomments, name namespec, StringList *starnames)
291 { return var_comm(starcomments, namespec, starnames, flam); }
292 
cspec_comm(StringList * starcomments,name namespec,StringList * starnames)293 bool cspec_comm(StringList *starcomments, name namespec, StringList *starnames)
294 { return var_comm(starcomments, namespec, starnames, cspec); }
295 
296 
other_comm(StringList * starcomments,name namespec,StringList * starnames)297 bool other_comm(StringList *starcomments, name namespec, StringList *starnames)
298 {
299   if (starcomments->size() < 2) return false;
300   unsigned int oldlen = starnames->size();
301 
302   citerate (StringList, namespec.name_prefixes, prefix_ptr) {
303     StringList prefix = StringList(*prefix_ptr, '=');
304     prefix.stripspace();
305 
306     if (! starstrings::isempty(prefix[0])) {
307       if (prefix.size() < 2) prefix.push_back(prefix[0]);
308 
309       for (unsigned int i = 1; i < starcomments->size(); i++) {
310 	if ((*starcomments)[i - 1] == prefix[0]) {
311 	  starnames->push_back(prefix[1] + " " + (*starcomments)[i]);
312 	  i--;
313 	  starcomments->erase(starcomments->begin() + i + 1);
314 	  starcomments->erase(starcomments->begin() + i);
315 	}
316       }
317     }
318   }
319   return (oldlen - starnames->size() > 0);
320 }
321 
322