1 /*!
2    \file lib/gis/find_file.c
3 
4    \brief GIS library - Find GRASS data base files
5 
6    (C) 2001-2009 by the GRASS Development Team
7 
8    This program is free software under the
9    GNU General Public License (>=v2).
10    Read the file COPYING that comes with GRASS
11    for details.
12 
13    \author Original author CERL
14  */
15 
16 #include <string.h>
17 #include <unistd.h>
18 #include <grass/gis.h>
19 #include <grass/glocale.h>
20 
find_element(int misc,const char * dir,const char * element)21 static const char *find_element(int misc, const char *dir, const char *element)
22 {
23     static const char *cell_elements[] = {
24 	"cellhd",
25 	"cell",
26 	"cats",
27 	"colr",
28 	"hist",
29 	"cell_misc",
30 	"fcell",
31 	"g3dcell",
32 	NULL
33     };
34     static const char *dig_elements[] = {
35 	"dig",
36 	"dig_att",
37 	"dig_plus",
38 	"dig_cats",
39 	"dig_misc",
40 	"reg",
41 	NULL
42     };
43     const char *search = misc ? dir : element;
44     int i;
45 
46     for (i = 1; cell_elements[i]; i++)
47 	if (strcmp(search, cell_elements[i]) == 0)
48 	    return cell_elements[0];
49     for (i = 1; dig_elements[i]; i++)
50 	if (strcmp(search, dig_elements[i]) == 0)
51 	    return dig_elements[0];
52     return element;
53 }
54 
find_file(int misc,const char * dir,const char * element,const char * name,const char * mapset)55 static const char *find_file(int misc, const char *dir,
56 			     const char *element, const char *name,
57 			     const char *mapset)
58 {
59     char path[GPATH_MAX];
60     char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
61     const char *pname, *pmapset;
62     int n;
63 
64     if (*name == 0)
65 	return NULL;
66     *path = 0;
67 
68     /*
69      * if name is in the fully qualified format, split it into
70      * name, mapset (overrides what was in mapset)
71      */
72     if (G_name_is_fully_qualified(name, xname, xmapset)) {
73 	pname = xname;
74 	pmapset = xmapset;
75     }
76     else {
77 	pname = name;
78 	pmapset = mapset;
79     }
80 
81     if (strcmp(element, "vector") == 0 &&
82 	pmapset && strcasecmp(pmapset, "ogr") == 0) {
83 	/* don't check for virtual OGR mapset */
84 	return G_store(pmapset);
85     }
86 
87     /*
88      * reject illegal names and mapsets
89      */
90     if (G_legal_filename(pname) == -1)
91 	return NULL;
92 
93     if (pmapset && *pmapset && G_legal_filename(pmapset) == -1)
94 	return NULL;
95 
96     /*
97      * if no specific mapset is to be searched
98      * then search all mapsets in the mapset search list
99      */
100     if (pmapset == NULL || *pmapset == 0) {
101 	int cnt = 0;
102 	const char *pselmapset = NULL;
103 	const char *pelement = find_element(misc, dir, element);
104 
105 	for (n = 0; (pmapset = G_get_mapset_name(n)); n++) {
106 	    if (misc && element == pelement)
107 		G_file_name_misc(path, dir, pelement, pname, pmapset);
108 	    else
109 		G_file_name(path, pelement, pname, pmapset);
110 	    if (access(path, 0) == 0) {
111 		if (!pselmapset)
112 		    pselmapset = pmapset;
113 		else if (element == pelement)
114 		    G_important_message(_("Data element '%s/%s' was found in more mapsets (also found in <%s>)"),
115                                         element, pname, pmapset);
116 		cnt++;
117 	    }
118 	}
119 	if (cnt > 0) {
120 	    if (misc)
121 		G_file_name_misc(path, dir, element, pname, pselmapset);
122 	    else
123 		G_file_name(path, element, name, pselmapset);
124 	    if (access(path, 0) == 0) {
125 		/* If the same name exists in more mapsets and print a warning */
126 		if (cnt > 1 && element == pelement)
127 		    G_important_message(_("Using <%s@%s>..."),
128 			      pname, pselmapset);
129 
130 		return G_store(pselmapset);
131 	    }
132 	}
133     }
134     /*
135      * otherwise just look for the file in the specified mapset.
136      * since the name may have been qualified, mapset may point
137      * to the xmapset, so we must should it to
138      * permanent storage via G_store().
139      */
140     else {
141 	if (misc)
142 	    G_file_name_misc(path, dir, element, pname, pmapset);
143 	else
144 	    G_file_name(path, element, pname, pmapset);
145 
146 	if (access(path, 0) == 0)
147 	    return G_store(pmapset);
148     }
149 
150     return NULL;
151 }
152 
153 
154 
find_file1(int misc,const char * dir,const char * element,char * name,const char * mapset)155 static const char *find_file1(
156     int misc,
157     const char *dir,
158     const char *element, char *name, const char *mapset)
159 {
160     char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
161     const char *pname, *pmapset;
162     const char *mp;
163 
164     if (G_name_is_fully_qualified(name, xname, xmapset)) {
165 	pname = xname;
166 	pmapset = xmapset;
167     }
168     else {
169 	pname = name;
170 	pmapset = mapset;
171     }
172 
173     mp = find_file(misc, dir, element, pname, pmapset);
174 
175     if (mp && name != pname)
176 	strcpy(name, pname);
177 
178     return mp;
179 }
180 
181 /*!
182  * \brief Searches for a file from the mapset search list or in a
183  * specified mapset.
184  *
185  * Returns the mapset name where the file was found.
186  *
187  * If the user specifies a fully qualified element (name@mapset)
188  * which exists, then G_find_file() modifies "name"
189  * by removing the "@mapset" part.
190  *
191  * Rejects all names that begin with "."
192  *
193  * If <i>name</i> is of the form nnn in ppp then only mapset ppp
194  * is searched.
195  *
196  * \param element database element (eg, "cell", "cellhd", "colr", etc)
197  * \param name    file name to look for
198  * \param mapset  mapset to search. if mapset is "" will search in mapset search list
199  *
200  * \return pointer to a string with name of mapset where file was
201  * found, or NULL if not found
202  */
G_find_file(const char * element,char * name,const char * mapset)203 const char *G_find_file(const char *element, char *name, const char *mapset)
204 {
205     return find_file1(0, NULL, element, name, mapset);
206 }
207 
208 /*!
209  * \brief Searches for a file from the mapset search list or in a
210  * specified mapset.
211  *
212  * Returns the mapset name where the file was found.
213  *
214  * \param dir     file directory
215  * \param element database element (eg, "cell", "cellhd", "colr", etc)
216  * \param name    file name to look for
217  * \param mapset  mapset to search. if mapset is "" will search in mapset search list
218  *
219  * \return pointer to a string with name of mapset where file was
220  * found, or NULL if not found
221  */
G_find_file_misc(const char * dir,const char * element,char * name,const char * mapset)222 const char *G_find_file_misc(const char *dir,
223 			     const char *element, char *name, const char *mapset)
224 {
225     return find_file1(1, dir, element, name, mapset);
226 }
227 
228 /*!
229  * \brief Searches for a file from the mapset search list or in a
230  * specified mapset. (look but don't touch)
231  *
232  * Returns the mapset name where the file was found.
233  *
234  * Exactly the same as G_find_file() except that if <i>name</i> is in
235  * the form "<i>name@mapset</i>", and is found, G_find_file2() will
236  * not alter <i>name</i> by removing the "@<i>mapset</i>" part.
237  *
238  * Rejects all names that begin with "."
239  *
240  * \param element    database element (eg, "cell", "cellhd", "colr", etc)
241  * \param name       file name to look for
242  * \param mapset     mapset to search. if mapset is "" will search in mapset search list
243  *
244  * \return pointer to a string with name of mapset where file was
245  * found, or NULL if not found
246  */
G_find_file2(const char * element,const char * name,const char * mapset)247 const char *G_find_file2(const char *element, const char *name, const char *mapset)
248 {
249     return find_file(0, NULL, element, name, mapset);
250 }
251 
252 /*!
253  * \brief Searches for a file from the mapset search list or in a
254  * specified mapset. (look but don't touch)
255  *
256  * Returns the mapset name where the file was found.
257  *
258  *
259  * \param dir        file directory
260  * \param element    database element (eg, "cell", "cellhd", "colr", etc)
261  * \param name       file name to look for
262  * \param mapset     mapset to search. if mapset is "" will search in mapset search list
263  *
264  * \return pointer to a string with name of mapset where file was
265  * found, or NULL if not found
266  */
G_find_file2_misc(const char * dir,const char * element,const char * name,const char * mapset)267 const char *G_find_file2_misc(const char *dir,
268 			      const char *element,
269 			      const char *name, const char *mapset)
270 {
271     return find_file(1, dir, element, name, mapset);
272 }
273