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