/* */
This source file includes following definitions.
- load_filemap_contents
- cmp
- create_filemap_index
- unload_filemap
- htags_load_filemap
- htags_unload_filemap
- htags_path2url
- main
1 /*
2 * Htags Hyper-text Reference Kit.
3 *
4 * This file is placed into the public domain by the author,
5 * 2005, 2006 Tama Communications Corporation.
6 *
7 * Two library function, qsort(3) and bsearch(3), are required.
8 */
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/param.h>
14 #include <sys/stat.h>
15
16 #if defined(_WIN32) || defined(__DJGPP__)
17 # define OPENMODE O_BINARY
18 #else
19 # define OPENMODE 0
20 #endif
21
22 int htags_load_filemap(const char *);
23 void htags_unload_filemap(void);
24 int htags_path2url(const char *, int, char *, int);
25
26 /** @file
27 * @NAME{htags} Hyper-text Reference Kit.
28 *
29 * Usage by example.
30 *
31 * Getting the URL of @FILE{i386/i386/identcpu.c} at 120, in variable url.
32 *
33 * @code
34 * char url[MAXPATHLEN];
35 * -- Load filemap generated by htags(1).
36 * ret = htags_load_filemap("HTML/FILEMAP");
37 * if (ret != 0)
38 * ERROR;
39 * -- Get URL of the specified file name and line number.
40 * ret = htags_path2url("i386/i386/identcpu.c", 120, url, sizeof(url));
41 * if (ret != 0)
42 * ERROR;
43 * url == 'S/1238.html#L120'
44 * -- release resource
45 * htags_unload_filemap();
46 * @endcode
47 *
48 * Since the URL is a relative path from the HTML directory, you should
49 * modify it so that your application program works well.
50 */
51 /**
52 * in memory FILEMAP
53 *
54 * Alphabetical sorted table.
55 */
56 struct map
57 {
58 const char *name;
59 const char *path;
60 };
61 /**
62 * @name Global variables.
63 *
64 * These variables are set by htags_load_filemap(), and referred by <br>
65 * htags_path2url() and htags_unload_filemap().
66 */
67 /** @{ */
68 static char *global_contents; /**< filemap contents */
69 static struct map *global_map; /**< file -\> url mapping table */
70 static int global_maplines; /**< the lines of #global_map */
71 /** @} */
72
73 /*----------------------------------------------------------------------*/
74 /* Local functions */
75 /*----------------------------------------------------------------------*/
76 /**
77 * load contents of FILEMAP into the memory.
78 *
79 * @param[in] file path of FILEMAP
80 * @param[out] area file contents (malloced)
81 * @param[out] size size of @a area
82 * @return 0 succesful <br>
83 * -1: out of memory. <br>
84 * -2: FILEMAP not found. <br>
85 * -3: cannot fstat FILEMAP. <br>
86 * -4: cannot read FILEMAP.
87 */
88 static int
89 load_filemap_contents(const char *file, char **area, int *size)
90 {
91 struct stat st;
92 char *p = NULL;
93 int status = 0;
94 int fd = -1;
95
96 /* Load FILEMAP contents */
97 status = -2;
98 if ((fd = open(file, OPENMODE)) < 0)
99 goto err;
100 status = -3;
101 if (fstat(fd, &st) < 0)
102 goto err;
103 status = -1;
104 if ((p = (char *)malloc(st.st_size)) == NULL)
105 goto err;
106 status = -4;
107 if (read(fd, p, st.st_size) != st.st_size)
108 goto err;
109 close(fd);
110 *area = p;
111 *size = st.st_size;
112 return 0;
113 err:
114 if (fd != -1)
115 close(fd);
116 if (p != NULL)
117 free(p);
118 return status;
119 }
120
121 /**
122 * comparison function for @CODE{bsearch()}.
123 */
124 static int
125 cmp(const void *s1, const void *s2)
126 {
127 return strcmp(((struct map *)s1)->name, ((struct map *)s2)->name);
128 }
129 /**
130 * creates index for in core FILEMAP.
131 *
132 * @param[in] area filemap contents
133 * @param[in] size size of @a area
134 * @param[out] map map structure
135 * @param[out] lines @a map lines
136 * @return 0: succesful <br>
137 * -1: out of memory. <br>
138 * -5: illegal format.
139 */
140 static int
141 create_filemap_index(char *area, int size, struct map **map, int *lines)
142 {
143 char *p, *endp = area + size;
144 struct map *m;
145 int n = 0;
146 int status;
147 int i;
148
149 /* Count line number */
150 for (p = area; p < endp; p++)
151 if (*p == '\n')
152 n++;
153 status = -1;
154 if ((m = (struct map *)malloc(sizeof(struct map) * n)) == NULL)
155 return -1;
156 /*
157 * FILEMAP format:
158 * <NAME>\t<PATH>\n
159 */
160 p = area;
161 for (i = 0; i < n; i++) {
162 m[i].name = p;
163 while (*p && *p != '\t')
164 p++;
165 if (*p == '\0')
166 goto ferr;
167 *p++ = '\0';
168 m[i].path = p;
169 while (*p && *p != '\r' && *p != '\n')
170 p++;
171 if (*p == '\0')
172 goto ferr;
173 if (*p == '\r')
174 *p++ = '\0';
175 if (*p == '\n')
176 *p++ = '\0';
177 }
178 qsort(m, n, sizeof(struct map), cmp);
179 *map = m;
180 *lines = n;
181 return 0;
182 ferr:
183 free(m);
184 return -5;
185 }
186
187 /**
188 * unloads FILEMAP.
189 */
190 static void
191 unload_filemap(void)
192 {
193 (void)free(global_map);
194 global_map = NULL;
195 (void)free(global_contents);
196 global_contents = NULL;
197 }
198 /*----------------------------------------------------------------------*/
199 /* Global functions */
200 /*----------------------------------------------------------------------*/
201 /**
202 * loads FILEMAP.
203 *
204 * @param[in] filemap FILEMAP file
205 * @par Globals used (output):
206 * #global_contents filemap contents (for free) <br>
207 * #global_map filemap index. <br>
208 * #global_maplines lines of filemap index.
209 *
210 * @return 0: succesful <br>
211 * -1: out of memory. <br>
212 * -2: FILEMAP not found. <br>
213 * -3: cannot fstat FILEMAP. <br>
214 * -4: cannot read FILEMAP. <br>
215 * -5: format error.
216 */
217 int
218 htags_load_filemap(const char *filemap)
219 {
220 int status = 0;
221 char *area;
222 int size, lines;
223 struct map *map;
224
225 status = load_filemap_contents(filemap, &area, &size);
226 if (status < 0)
227 return status;
228 status = create_filemap_index(area, size, &map, &lines);
229 if (status < 0) {
230 (void)free(area);
231 return status;
232 }
233 global_contents = area;
234 global_map = map;
235 global_maplines = lines;
236 return 0;
237 }
238 /**
239 * unloads FILEMAP.
240 */
241 void
242 htags_unload_filemap(void)
243 {
244 unload_filemap();
245 }
246
247 /**
248 * convert file path name into the URL in the hypertext.
249 *
250 * @param[in] path path name in the filesystem.
251 * @param[in] line 0: ignored, !=0: line number in @a path.
252 * @param[out] url result url
253 * @param[in] size size of @a url
254 * @par Globals used (input):
255 * #global_contents filemap contents (for free) <br>
256 * #global_map filemap index. <br>
257 * #global_maplines lines of filemap index.
258 *
259 * @return 0: succesful <br>
260 * 1: path not found <br>
261 * -1: filemap not loaded yet
262 *
263 * URL: @CODE{S/\<file id\>.html\#\<line number\>}
264 */
265 int
266 htags_path2url(const char *path, int line, char *url, int size)
267 {
268 struct map tmp;
269 struct map *result;
270
271 if (global_contents == NULL || global_map == NULL)
272 return -1;
273 tmp.name = path;
274 result = (struct map *)bsearch(&tmp, global_map, global_maplines, sizeof(struct map), cmp);
275 if (result == NULL)
276 return 1;
277 if (line > 0)
278 snprintf(url, size, "%s#L%d", result->path, line);
279 else
280 snprintf(url, size, "%s", result->path);
281 return 0;
282 }
283
284 #ifdef TEST
285
286 /**
287 * @par Usage:
288 * @NAME{htags_path2url} @ARG{filemap} @ARG{path} [@ARG{line}]
289 *
290 * @par Examples:
291 * @code
292 * $ htags_path2url HTML/FILEMAP i386/i386/identcpu.c 120
293 * i386/i386/identcpu.c, line 120 => S/1238.html#L120
294 * $ _
295 * @endcode
296 */
297 int
298 main(int argc, char **argv)
299 {
300 char url[MAXPATHLEN];
301 char *path, *html;
302 int line = 0;
303 int ret;
304
305 if (argc < 3) {
306 fprintf(stderr, "Usage: htags_path2url filemap path [line]\n");
307 exit(1);
308 }
309 html = argv[1];
310 path = argv[2];
311 if (argc > 3)
312 line = atoi(argv[3]);
313 ret = htags_load_filemap(html);
314 if (ret != 0) {
315 fprintf(stderr, "htags_load_filemap failed.(");
316 switch (ret) {
317 case -1: fprintf(stderr, "out of memory"); break;
318 case -2: fprintf(stderr, "FILEMAP not found."); break;
319 case -3: fprintf(stderr, "cannot fstat FILEMAP."); break;
320 case -4: fprintf(stderr, "cannot read FILEMAP."); break;
321 case -5: fprintf(stderr, "format error."); break;
322 default: fprintf(stderr, "unknown error."); break;
323 }
324 fprintf(stderr, ")\n");
325 exit(1);
326 }
327 ret = htags_path2url(path, line, url, sizeof(url));
328 if (ret != 0) {
329 fprintf(stderr, "htags_path2url failed.(");
330 switch (ret) {
331 case 1: fprintf(stderr, "path not found."); break;
332 case -1: fprintf(stderr, "out of memory."); break;
333 }
334 fprintf(stderr, ")\n");
335 exit(1);
336 }
337 fprintf(stdout, "%s, line %d => %s\n", path, line, url);
338 htags_unload_filemap();
339 return 0;
340 }
341 #endif
/* */