forked from OPENDAP/libdap4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Ancillary.cc
209 lines (171 loc) · 7.12 KB
/
Ancillary.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Ancillary.cc
#include "config.h"
// #define DODS_DEBUG
#include "Ancillary.h"
#include "debug.h"
#ifndef WIN32
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#else
#include <fcntl.h>
#include <io.h>
#include <process.h>
// Win32 does not define this. 08/21/02 jhrg
#define F_OK 0
#endif
namespace libdap {
/** This function accepts a dataset path name, and searches for a
matching ancillary data file name with a very specific set of
search rules, given here:
<pre>
directory filename extension
same same `.'given
given same `.'given
same given `.'given
given given `.'given
</pre>
Where ``same'' refers to the input dataset pathname, and ``given''
refers to the function arguments.
For example, If you call this function with a
dataset name of <tt>/a/data</tt>, an extension of <tt>das</tt>, a
directory of
<tt>b</tt>, and a filename of <tt>ralph</tt>, the function will
look (in order)
for the following files:
<pre>
/a/data.das
/b/data.das
/a/ralph.das
/b/ralph.das
</pre>
The function will return a string containing the name of the first
file in the list that exists, if any.
@note This code now checks for <code>pathname.ext</code> 3/17/99 jhrg
@brief Find a file with ancillary data.
@param pathname The input pathname of a dataset.
@param ext The input extension the desired file is to have.
@param dir The input directory in which the desired file may be
found.
@param file The input filename the desired file may have.
@return A string containing the pathname of the file found by
searching with the given components. If no file was found, the
null string is returned.
*/
string Ancillary::find_ancillary_file(const string &pathname, const string &ext, const string &dir,
const string &file) {
string::size_type slash = pathname.rfind('/') + 1;
string directory = pathname.substr(0, slash);
string filename = pathname.substr(slash);
string basename = pathname.substr(slash, pathname.rfind('.') - slash);
DBG(cerr << "find ancillary file params: " << pathname << ", " << ext << ", " << dir << ", " << file << endl);
DBG(cerr << "find ancillary file comp: " << directory << ", " << filename << ", " << basename << endl);
string dot_ext = "." + ext;
string name = directory + basename + dot_ext;
if (access(name.c_str(), F_OK) == 0)
return name;
name = pathname + dot_ext;
if (access(name.c_str(), F_OK) == 0)
return name;
name = directory + ext;
if (access(name.c_str(), F_OK) == 0)
return name;
name = dir + basename + dot_ext;
if (access(name.c_str(), F_OK) == 0)
return name;
name = directory + file + dot_ext;
if (access(name.c_str(), F_OK) == 0)
return name;
name = dir + file + dot_ext;
if (access(name.c_str(), F_OK) == 0)
return name;
name = dir + ext;
if (access(name.c_str(), F_OK) == 0)
return name;
return "";
}
// Given a pathname to a datafile, take that pathname apart and look for an
// ancillary file that describes a group of datafiles of which this datafile
// is a member. Assume that groups follow a simple naming convention where
// files use either leading or trailing digits and a common basename to name
// group members. For example, 00stuff.hdf, 01stuff.hdf, 02stuff.hdf, ..., is
// a group and is has `stuff' as its basename.
/** Assume that <tt>name</tt> refers to a file that is one of a
group of files which share a common `base' name and differ only by
some prefix or suffix digits (e.g. <tt>00base</tt>, <tt>01base</tt>,
... or <tt>base00</tt>, ... have the base name <tt>base</tt>). This
function looks for a file <tt>base.ext</tt>.
@param name The name (full or relative) to one member of a group
of files.
@param ext The extension of the group's ancillary file. Note that
<tt>ext</tt> should include a period (.) if that needs to
separate the base name from the extension.
@return The pathname to the group's ancillary file if found, otherwise
the empty string (""). */
string Ancillary::find_group_ancillary_file(const string &name, const string &ext) {
// Given /usr/local/data/stuff.01.nc
// pathname = /usr/local/data, filename = stuff.01.nc and
// rootname = stuff.01
string::size_type slash = name.find_last_of('/');
string dirname = name.substr(0, slash);
string filename = name.substr(slash + 1);
string rootname = filename.substr(0, filename.find_last_of('.'));
// Instead of using regexs, scan the filename for leading and then
// trailing digits.
string::iterator rootname_iter = rootname.begin();
string::iterator rootname_end_iter = rootname.end();
if (isdigit(*rootname_iter)) {
while (rootname_iter != rootname_end_iter && isdigit(*++rootname_iter))
;
// We want: new_name = dirname + "/" + <base> + ext but without
// creating a bunch of temp objects.
string new_name = dirname;
new_name.append("/");
new_name.append(rootname_iter, rootname_end_iter);
new_name.append(ext);
DBG(cerr << "New Name (iter): " << new_name << endl);
if (access(new_name.c_str(), F_OK) == 0) {
return new_name;
}
}
string::reverse_iterator rootname_riter = rootname.rbegin();
string::reverse_iterator rootname_end_riter = rootname.rend();
if (isdigit(*rootname_riter)) {
while (rootname_riter != rootname_end_riter && isdigit(*++rootname_riter))
;
string new_name = dirname;
new_name.append("/");
// I used reverse iters to scan rootname backwards. To avoid
// reversing the fragment between end_riter and riter, pass append
// regular iters obtained using reverse_iterator::base(). See Meyers
// p. 123. 1/22/2002 jhrg
new_name.append(rootname_end_riter.base(), rootname_riter.base());
new_name.append(ext);
DBG(cerr << "New Name (riter): " << new_name << endl);
if (access(new_name.c_str(), F_OK) == 0) {
return new_name;
}
}
// If we're here either the file does not begin with leading digits or a
// template made by removing those digits was not found.
return "";
}
void Ancillary::read_ancillary_das(DAS &das, const string &pathname, const string &dir, const string &file) {
string name = find_ancillary_file(pathname, "das", dir, file);
DBG(cerr << "In Ancillary::read_ancillary_dds: name:" << name << endl);
FILE *in = fopen(name.c_str(), "r");
if (in) {
das.parse(in);
(void)fclose(in);
}
}
void Ancillary::read_ancillary_dds(DDS &dds, const string &pathname, const string &dir, const string &file) {
string name = find_ancillary_file(pathname, "dds", dir, file);
DBG(cerr << "In Ancillary::read_ancillary_dds: name:" << name << endl);
FILE *in = fopen(name.c_str(), "r");
if (in) {
dds.parse(in);
(void)fclose(in);
}
}
} // namespace libdap