File: | src/lib/libcurses/tinfo/write_entry.c |
Warning: | line 227, column 1 Potential memory leak |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: write_entry.c,v 1.13 2010/01/12 23:22:06 nicm Exp $ */ | |||
2 | ||||
3 | /**************************************************************************** | |||
4 | * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * | |||
5 | * * | |||
6 | * Permission is hereby granted, free of charge, to any person obtaining a * | |||
7 | * copy of this software and associated documentation files (the * | |||
8 | * "Software"), to deal in the Software without restriction, including * | |||
9 | * without limitation the rights to use, copy, modify, merge, publish, * | |||
10 | * distribute, distribute with modifications, sublicense, and/or sell * | |||
11 | * copies of the Software, and to permit persons to whom the Software is * | |||
12 | * furnished to do so, subject to the following conditions: * | |||
13 | * * | |||
14 | * The above copyright notice and this permission notice shall be included * | |||
15 | * in all copies or substantial portions of the Software. * | |||
16 | * * | |||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * | |||
18 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * | |||
19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * | |||
20 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * | |||
21 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * | |||
22 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * | |||
23 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * | |||
24 | * * | |||
25 | * Except as contained in this notice, the name(s) of the above copyright * | |||
26 | * holders shall not be used in advertising or otherwise to promote the * | |||
27 | * sale, use or other dealings in this Software without prior written * | |||
28 | * authorization. * | |||
29 | ****************************************************************************/ | |||
30 | ||||
31 | /**************************************************************************** | |||
32 | * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * | |||
33 | * and: Eric S. Raymond <esr@snark.thyrsus.com> * | |||
34 | * and: Thomas E. Dickey 1996-on * | |||
35 | ****************************************************************************/ | |||
36 | ||||
37 | /* | |||
38 | * write_entry.c -- write a terminfo structure onto the file system | |||
39 | */ | |||
40 | ||||
41 | #include <curses.priv.h> | |||
42 | #include <hashed_db.h> | |||
43 | ||||
44 | #include <sys/stat.h> | |||
45 | ||||
46 | #include <tic.h> | |||
47 | #include <term_entry.h> | |||
48 | ||||
49 | #ifndef S_ISDIR | |||
50 | #define S_ISDIR(mode)((mode & 0170000) == 0040000) ((mode & S_IFMT0170000) == S_IFDIR0040000) | |||
51 | #endif | |||
52 | ||||
53 | #if 1 | |||
54 | #define TRACE_OUT(p) DEBUG(2, p) | |||
55 | #else | |||
56 | #define TRACE_OUT(p) /*nothing */ | |||
57 | #endif | |||
58 | ||||
59 | MODULE_ID("$Id: write_entry.c,v 1.13 2010/01/12 23:22:06 nicm Exp $") | |||
60 | ||||
61 | static int total_written; | |||
62 | ||||
63 | static int make_db_root(const char *); | |||
64 | static int write_object(TERMTYPE *, char *, unsigned *, unsigned); | |||
65 | ||||
66 | #if !USE_HASHED_DB0 | |||
67 | static void | |||
68 | write_file(char *filename, TERMTYPE *tp) | |||
69 | { | |||
70 | char buffer[MAX_ENTRY_SIZE4096]; | |||
71 | unsigned limit = sizeof(buffer); | |||
72 | unsigned offset = 0; | |||
73 | ||||
74 | FILE *fp = (_nc_access(filename, W_OK0x02) == 0) ? fopen(filename, "wb") : 0; | |||
75 | if (fp == 0) { | |||
76 | perror(filename); | |||
77 | _nc_syserr_abort("can't open %s/%s", _nc_tic_dir(0), filename); | |||
78 | } | |||
79 | DEBUG(1, ("Created %s", filename)); | |||
80 | ||||
81 | if (write_object(tp, buffer, &offset, limit) == ERR(-1) | |||
82 | || fwrite(buffer, sizeof(char), offset, fp) != offset) { | |||
83 | _nc_syserr_abort("error writing %s/%s", _nc_tic_dir(0), filename); | |||
84 | } | |||
85 | ||||
86 | fclose(fp); | |||
87 | } | |||
88 | ||||
89 | /* | |||
90 | * Check for access rights to destination directories | |||
91 | * Create any directories which don't exist. | |||
92 | * | |||
93 | * Note: there's no reason to return the result of make_db_root(), since | |||
94 | * this function is called only in instances where that has to succeed. | |||
95 | */ | |||
96 | static void | |||
97 | check_writeable(int code) | |||
98 | { | |||
99 | static const char dirnames[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | |||
100 | static bool_Bool verified[sizeof(dirnames)]; | |||
101 | ||||
102 | char dir[sizeof(LEAF_FMT"%c")]; | |||
103 | char *s = 0; | |||
104 | ||||
105 | if (code == 0 || (s = strchr(dirnames, code)) == 0) | |||
106 | _nc_err_abort("Illegal terminfo subdirectory \"" LEAF_FMT"%c" "\"", code); | |||
107 | ||||
108 | if (verified[s - dirnames]) | |||
109 | return; | |||
110 | ||||
111 | snprintf(dir, sizeof(dir), LEAF_FMT"%c", code); | |||
112 | if (make_db_root(dir) < 0) { | |||
113 | _nc_err_abort("%s/%s: permission denied", _nc_tic_dir(0), dir); | |||
114 | } | |||
115 | ||||
116 | verified[s - dirnames] = TRUE1; | |||
117 | } | |||
118 | #endif /* !USE_HASHED_DB */ | |||
119 | ||||
120 | static int | |||
121 | make_db_path(char *dst, const char *src, unsigned limit) | |||
122 | { | |||
123 | int rc = -1; | |||
124 | const char *top = _nc_tic_dir(0); | |||
125 | ||||
126 | if (src == top || _nc_is_abs_path(src)) { | |||
127 | if (strlen(src) + 1 <= limit) { | |||
128 | (void) strlcpy(dst, src, limit); | |||
129 | rc = 0; | |||
130 | } | |||
131 | } else { | |||
132 | if (strlen(top) + strlen(src) + 2 <= limit) { | |||
133 | (void) snprintf(dst, limit, "%s/%s", top, src); | |||
134 | rc = 0; | |||
135 | } | |||
136 | } | |||
137 | #if USE_HASHED_DB0 | |||
138 | if (rc == 0) { | |||
139 | if (_nc_is_dir_path(dst)) { | |||
140 | rc = -1; | |||
141 | } else { | |||
142 | unsigned have = strlen(dst); | |||
143 | if (have > 3 && strcmp(dst + have - 3, DBM_SUFFIX)) { | |||
144 | if (have + 3 <= limit) | |||
145 | strlcat(dst, DBM_SUFFIX, limit); | |||
146 | else | |||
147 | rc = -1; | |||
148 | } | |||
149 | } | |||
150 | } | |||
151 | #endif | |||
152 | return rc; | |||
153 | } | |||
154 | ||||
155 | /* | |||
156 | * Make a database-root if it doesn't exist. | |||
157 | */ | |||
158 | static int | |||
159 | make_db_root(const char *path) | |||
160 | { | |||
161 | int rc; | |||
162 | char fullpath[PATH_MAX1024]; | |||
163 | ||||
164 | if ((rc = make_db_path(fullpath, path, sizeof(fullpath))) == 0) { | |||
165 | #if USE_HASHED_DB0 | |||
166 | DB *capdbp; | |||
167 | ||||
168 | if ((capdbp = _nc_db_open(fullpath, TRUE1)) == NULL((void*)0)) | |||
169 | rc = -1; | |||
170 | else if (_nc_db_close(capdbp) < 0) | |||
171 | rc = -1; | |||
172 | #else | |||
173 | struct stat statbuf; | |||
174 | ||||
175 | if ((rc = stat(path, &statbuf)) < 0) { | |||
176 | rc = mkdir(path, 0777); | |||
177 | } else if (_nc_access(path, R_OK0x04 | W_OK0x02 | X_OK0x01) < 0) { | |||
178 | rc = -1; /* permission denied */ | |||
179 | } else if (!(S_ISDIR(statbuf.st_mode)((statbuf.st_mode & 0170000) == 0040000))) { | |||
180 | rc = -1; /* not a directory */ | |||
181 | } | |||
182 | #endif | |||
183 | } | |||
184 | return rc; | |||
185 | } | |||
186 | ||||
187 | /* | |||
188 | * Set the write directory for compiled entries. | |||
189 | */ | |||
190 | NCURSES_EXPORT(void)void | |||
191 | _nc_set_writedir(char *dir) | |||
192 | { | |||
193 | const char *destination; | |||
194 | char actual[PATH_MAX1024]; | |||
195 | ||||
196 | if (dir == 0 | |||
| ||||
197 | && use_terminfo_vars()(!issetugid())) | |||
198 | dir = getenv("TERMINFO"); | |||
199 | ||||
200 | if (dir
| |||
201 | (void) _nc_tic_dir(dir); | |||
202 | ||||
203 | destination = _nc_tic_dir(0); | |||
204 | if (make_db_root(destination) < 0) { | |||
205 | char *home = _nc_home_terminfo(); | |||
206 | ||||
207 | if (home != 0) { | |||
208 | destination = home; | |||
209 | if (make_db_root(destination) < 0) | |||
210 | _nc_err_abort("%s: permission denied (errno %d)", | |||
211 | destination, errno(*__errno())); | |||
212 | } | |||
213 | } | |||
214 | ||||
215 | /* | |||
216 | * Note: because of this code, this logic should be exercised | |||
217 | * *once only* per run. | |||
218 | */ | |||
219 | #if USE_HASHED_DB0 | |||
220 | make_db_path(actual, destination, sizeof(actual)); | |||
221 | #else | |||
222 | if (chdir(_nc_tic_dir(destination)) < 0 | |||
223 | || getcwd(actual, sizeof(actual)) == 0) | |||
224 | _nc_err_abort("%s: not a directory", destination); | |||
225 | #endif | |||
226 | _nc_keep_tic_dir(strdup(actual)); | |||
227 | } | |||
| ||||
228 | ||||
229 | /* | |||
230 | * Save the compiled version of a description in the filesystem. | |||
231 | * | |||
232 | * make a copy of the name-list | |||
233 | * break it up into first-name and all-but-last-name | |||
234 | * creat(first-name) | |||
235 | * write object information to first-name | |||
236 | * close(first-name) | |||
237 | * for each name in all-but-last-name | |||
238 | * link to first-name | |||
239 | * | |||
240 | * Using 'time()' to obtain a reference for file timestamps is unreliable, | |||
241 | * e.g., with NFS, because the filesystem may have a different time | |||
242 | * reference. We check for pre-existence of links by latching the first | |||
243 | * timestamp from a file that we create. | |||
244 | * | |||
245 | * The _nc_warning() calls will report a correct line number only if | |||
246 | * _nc_curr_line is properly set before the write_entry() call. | |||
247 | */ | |||
248 | ||||
249 | NCURSES_EXPORT(void)void | |||
250 | _nc_write_entry(TERMTYPE *const tp) | |||
251 | { | |||
252 | #if USE_HASHED_DB0 | |||
253 | ||||
254 | char buffer[MAX_ENTRY_SIZE4096 + 1]; | |||
255 | unsigned limit = sizeof(buffer); | |||
256 | unsigned offset = 0; | |||
257 | ||||
258 | #else /* !USE_HASHED_DB */ | |||
259 | ||||
260 | struct stat statbuf; | |||
261 | char filename[PATH_MAX1024]; | |||
262 | char linkname[PATH_MAX1024]; | |||
263 | #if USE_SYMLINKS0 | |||
264 | char symlinkname[PATH_MAX1024]; | |||
265 | #if !HAVE_LINK1 | |||
266 | #undef HAVE_LINK1 | |||
267 | #define HAVE_LINK1 1 | |||
268 | #endif | |||
269 | #endif /* USE_SYMLINKS */ | |||
270 | ||||
271 | static int call_count; | |||
272 | static time_t start_time; /* time at start of writes */ | |||
273 | ||||
274 | #endif /* USE_HASHED_DB */ | |||
275 | ||||
276 | char name_list[MAX_TERMINFO_LENGTH4096]; | |||
277 | char *first_name, *other_names; | |||
278 | char *ptr; | |||
279 | ||||
280 | assert(strlen(tp->term_names) != 0)((void)0); | |||
281 | assert(strlen(tp->term_names) < sizeof(name_list))((void)0); | |||
282 | ||||
283 | (void) strlcpy(name_list, tp->term_names, sizeof(name_list)); | |||
284 | DEBUG(7, ("Name list = '%s'", name_list)); | |||
285 | ||||
286 | first_name = name_list; | |||
287 | ||||
288 | ptr = &name_list[strlen(name_list) - 1]; | |||
289 | other_names = ptr + 1; | |||
290 | ||||
291 | while (ptr > name_list && *ptr != '|') | |||
292 | ptr--; | |||
293 | ||||
294 | if (ptr != name_list) { | |||
295 | *ptr = '\0'; | |||
296 | ||||
297 | for (ptr = name_list; *ptr != '\0' && *ptr != '|'; ptr++) | |||
298 | continue; | |||
299 | ||||
300 | if (*ptr == '\0') | |||
301 | other_names = ptr; | |||
302 | else { | |||
303 | *ptr = '\0'; | |||
304 | other_names = ptr + 1; | |||
305 | } | |||
306 | } | |||
307 | ||||
308 | DEBUG(7, ("First name = '%s'", first_name)); | |||
309 | DEBUG(7, ("Other names = '%s'", other_names)); | |||
310 | ||||
311 | _nc_set_type(first_name); | |||
312 | ||||
313 | #if USE_HASHED_DB0 | |||
314 | if (write_object(tp, buffer + 1, &offset, limit - 1) != ERR(-1)) { | |||
315 | DB *capdb = _nc_db_open(_nc_tic_dir(0), TRUE1); | |||
316 | DBT key, data; | |||
317 | ||||
318 | if (capdb != 0) { | |||
319 | buffer[0] = 0; | |||
320 | ||||
321 | memset(&key, 0, sizeof(key)); | |||
322 | key.data = tp->term_names; | |||
323 | key.size = strlen(tp->term_names); | |||
324 | ||||
325 | memset(&data, 0, sizeof(data)); | |||
326 | data.data = buffer; | |||
327 | data.size = offset + 1; | |||
328 | ||||
329 | _nc_db_put(capdb, &key, &data); | |||
330 | ||||
331 | buffer[0] = 2; | |||
332 | ||||
333 | key.data = name_list; | |||
334 | key.size = strlen(name_list); | |||
335 | ||||
336 | strlcpy(buffer + 1, tp->term_names, sizeof(buffer) - 1); | |||
337 | data.size = strlen(tp->term_names) + 1; | |||
338 | ||||
339 | _nc_db_put(capdb, &key, &data); | |||
340 | ||||
341 | while (*other_names != '\0') { | |||
342 | ptr = other_names++; | |||
343 | while (*other_names != '|' && *other_names != '\0') | |||
344 | other_names++; | |||
345 | ||||
346 | if (*other_names != '\0') | |||
347 | *(other_names++) = '\0'; | |||
348 | ||||
349 | key.data = ptr; | |||
350 | key.size = strlen(ptr); | |||
351 | ||||
352 | _nc_db_put(capdb, &key, &data); | |||
353 | } | |||
354 | _nc_db_close(capdb); | |||
355 | } | |||
356 | } | |||
357 | #else /* !USE_HASHED_DB */ | |||
358 | if (call_count++ == 0) { | |||
359 | start_time = 0; | |||
360 | } | |||
361 | ||||
362 | if (strlen(first_name) >= sizeof(filename) - 3) | |||
363 | _nc_warning("terminal name too long."); | |||
364 | ||||
365 | snprintf(filename, sizeof(filename), LEAF_FMT"%c" "/%s", first_name[0], first_name); | |||
366 | ||||
367 | /* | |||
368 | * Has this primary name been written since the first call to | |||
369 | * write_entry()? If so, the newer write will step on the older, | |||
370 | * so warn the user. | |||
371 | */ | |||
372 | if (start_time > 0 && | |||
373 | stat(filename, &statbuf) >= 0 | |||
374 | && statbuf.st_mtimest_mtim.tv_sec >= start_time) { | |||
375 | _nc_warning("name multiply defined."); | |||
376 | } | |||
377 | ||||
378 | check_writeable(first_name[0]); | |||
379 | write_file(filename, tp); | |||
380 | ||||
381 | if (start_time == 0) { | |||
382 | if (stat(filename, &statbuf) < 0 | |||
383 | || (start_time = statbuf.st_mtimest_mtim.tv_sec) == 0) { | |||
384 | _nc_syserr_abort("error obtaining time from %s/%s", | |||
385 | _nc_tic_dir(0), filename); | |||
386 | } | |||
387 | } | |||
388 | while (*other_names != '\0') { | |||
389 | ptr = other_names++; | |||
390 | assert(ptr < buffer + sizeof(buffer) - 1)((void)0); | |||
391 | while (*other_names != '|' && *other_names != '\0') | |||
392 | other_names++; | |||
393 | ||||
394 | if (*other_names != '\0') | |||
395 | *(other_names++) = '\0'; | |||
396 | ||||
397 | if (strlen(ptr) > sizeof(linkname) - 3) { | |||
398 | _nc_warning("terminal alias %s too long.", ptr); | |||
399 | continue; | |||
400 | } | |||
401 | if (strchr(ptr, '/') != 0) { | |||
402 | _nc_warning("cannot link alias %s.", ptr); | |||
403 | continue; | |||
404 | } | |||
405 | ||||
406 | check_writeable(ptr[0]); | |||
407 | snprintf(linkname, sizeof(linkname), LEAF_FMT"%c" "/%s", ptr[0], ptr); | |||
408 | ||||
409 | if (strcmp(filename, linkname) == 0) { | |||
410 | _nc_warning("self-synonym ignored"); | |||
411 | } else if (stat(linkname, &statbuf) >= 0 && | |||
412 | statbuf.st_mtimest_mtim.tv_sec < start_time) { | |||
413 | _nc_warning("alias %s multiply defined.", ptr); | |||
414 | } else if (_nc_access(linkname, W_OK0x02) == 0) | |||
415 | #if HAVE_LINK1 | |||
416 | { | |||
417 | int code; | |||
418 | #if USE_SYMLINKS0 | |||
419 | strlcpy(symlinkname, "../", sizeof(symlinkname)); | |||
420 | strlcat(symlinkname, filename, sizeof(symlinkname)); | |||
421 | #endif /* USE_SYMLINKS */ | |||
422 | #if HAVE_REMOVE1 | |||
423 | code = remove(linkname); | |||
424 | #else | |||
425 | code = unlink(linkname); | |||
426 | #endif | |||
427 | if (code != 0 && errno(*__errno()) == ENOENT2) | |||
428 | code = 0; | |||
429 | #if USE_SYMLINKS0 | |||
430 | if (symlink(symlinkname, linkname) < 0) | |||
431 | #else | |||
432 | if (link(filename, linkname) < 0) | |||
433 | #endif /* USE_SYMLINKS */ | |||
434 | { | |||
435 | /* | |||
436 | * If there wasn't anything there, and we cannot | |||
437 | * link to the target because it is the same as the | |||
438 | * target, then the source must be on a filesystem | |||
439 | * that uses caseless filenames, such as Win32, etc. | |||
440 | */ | |||
441 | if (code == 0 && errno(*__errno()) == EEXIST17) | |||
442 | _nc_warning("can't link %s to %s", filename, linkname); | |||
443 | else if (code == 0 && (errno(*__errno()) == EPERM1 || errno(*__errno()) == ENOENT2)) | |||
444 | write_file(linkname, tp); | |||
445 | else { | |||
446 | #if MIXEDCASE_FILENAMES1 | |||
447 | _nc_syserr_abort("can't link %s to %s", filename, linkname); | |||
448 | #else | |||
449 | _nc_warning("can't link %s to %s (errno=%d)", filename, | |||
450 | linkname, errno(*__errno())); | |||
451 | #endif | |||
452 | } | |||
453 | } else { | |||
454 | DEBUG(1, ("Linked %s", linkname)); | |||
455 | } | |||
456 | } | |||
457 | #else /* just make copies */ | |||
458 | write_file(linkname, tp); | |||
459 | #endif /* HAVE_LINK */ | |||
460 | } | |||
461 | #endif /* USE_HASHED_DB */ | |||
462 | } | |||
463 | ||||
464 | static unsigned | |||
465 | fake_write(char *dst, | |||
466 | unsigned *offset, | |||
467 | unsigned limit, | |||
468 | char *src, | |||
469 | unsigned want, | |||
470 | unsigned size) | |||
471 | { | |||
472 | int have = (limit - *offset); | |||
473 | ||||
474 | want *= size; | |||
475 | if (have > 0) { | |||
476 | if ((int) want > have) | |||
477 | want = have; | |||
478 | memcpy(dst + *offset, src, want); | |||
479 | *offset += want; | |||
480 | } else { | |||
481 | want = 0; | |||
482 | } | |||
483 | return (int) (want / size); | |||
484 | } | |||
485 | ||||
486 | #define Write(buf, size, count)fake_write(buffer, offset, limit, (char *) buf, count, size) fake_write(buffer, offset, limit, (char *) buf, count, size) | |||
487 | ||||
488 | #undef LITTLE_ENDIAN /* BSD/OS defines this as a feature macro */ | |||
489 | #define HI(x)((x) / 256) ((x) / 256) | |||
490 | #define LO(x)((x) % 256) ((x) % 256) | |||
491 | #define LITTLE_ENDIAN(p, x)(p)[0] = ((x) % 256), (p)[1] = ((x) / 256) (p)[0] = LO(x)((x) % 256), (p)[1] = HI(x)((x) / 256) | |||
492 | ||||
493 | #define WRITE_STRING(str)(fake_write(buffer, offset, limit, (char *) str, strlen(str) + 1, sizeof(char)) == strlen(str) + 1) (Write(str, sizeof(char), strlen(str) + 1)fake_write(buffer, offset, limit, (char *) str, strlen(str) + 1, sizeof(char)) == strlen(str) + 1) | |||
494 | ||||
495 | static int | |||
496 | compute_offsets(char **Strings, unsigned strmax, short *offsets) | |||
497 | { | |||
498 | size_t nextfree = 0; | |||
499 | unsigned i; | |||
500 | ||||
501 | for (i = 0; i < strmax; i++) { | |||
502 | if (Strings[i] == ABSENT_STRING(char *)0) { | |||
503 | offsets[i] = -1; | |||
504 | } else if (Strings[i] == CANCELLED_STRING(char *)(-1)) { | |||
505 | offsets[i] = -2; | |||
506 | } else { | |||
507 | offsets[i] = nextfree; | |||
508 | nextfree += strlen(Strings[i]) + 1; | |||
509 | TRACE_OUT(("put Strings[%d]=%s(%d)", (int) i, | |||
510 | _nc_visbuf(Strings[i]), (int) nextfree)); | |||
511 | } | |||
512 | } | |||
513 | return nextfree; | |||
514 | } | |||
515 | ||||
516 | static void | |||
517 | convert_shorts(unsigned char *buf, short *Numbers, unsigned count) | |||
518 | { | |||
519 | unsigned i; | |||
520 | for (i = 0; i < count; i++) { | |||
521 | if (Numbers[i] == ABSENT_NUMERIC(-1)) { /* HI/LO won't work */ | |||
522 | buf[2 * i] = buf[2 * i + 1] = 0377; | |||
523 | } else if (Numbers[i] == CANCELLED_NUMERIC(-2)) { /* HI/LO won't work */ | |||
524 | buf[2 * i] = 0376; | |||
525 | buf[2 * i + 1] = 0377; | |||
526 | } else { | |||
527 | LITTLE_ENDIAN(buf + 2 * i, Numbers[i])(buf + 2 * i)[0] = ((Numbers[i]) % 256), (buf + 2 * i)[1] = ( (Numbers[i]) / 256); | |||
528 | TRACE_OUT(("put Numbers[%d]=%d", i, Numbers[i])); | |||
529 | } | |||
530 | } | |||
531 | } | |||
532 | ||||
533 | #define even_boundary(value)((value) % 2 != 0 && fake_write(buffer, offset, limit , (char *) &zero, 1, sizeof(char)) != 1) \ | |||
534 | ((value) % 2 != 0 && Write(&zero, sizeof(char), 1)fake_write(buffer, offset, limit, (char *) &zero, 1, sizeof (char)) != 1) | |||
535 | ||||
536 | #if NCURSES_XNAMES1 | |||
537 | static unsigned | |||
538 | extended_Booleans(TERMTYPE *tp) | |||
539 | { | |||
540 | unsigned short result = 0; | |||
541 | unsigned short i; | |||
542 | ||||
543 | for (i = 0; i < tp->ext_Booleans; ++i) { | |||
544 | if (tp->Booleans[BOOLCOUNT44 + i] == TRUE1) | |||
545 | result = (i + 1); | |||
546 | } | |||
547 | return result; | |||
548 | } | |||
549 | ||||
550 | static unsigned | |||
551 | extended_Numbers(TERMTYPE *tp) | |||
552 | { | |||
553 | unsigned short result = 0; | |||
554 | unsigned short i; | |||
555 | ||||
556 | for (i = 0; i < tp->ext_Numbers; ++i) { | |||
557 | if (tp->Numbers[NUMCOUNT39 + i] != ABSENT_NUMERIC(-1)) | |||
558 | result = (i + 1); | |||
559 | } | |||
560 | return result; | |||
561 | } | |||
562 | ||||
563 | static unsigned | |||
564 | extended_Strings(TERMTYPE *tp) | |||
565 | { | |||
566 | unsigned short result = 0; | |||
567 | unsigned short i; | |||
568 | ||||
569 | for (i = 0; i < tp->ext_Strings; ++i) { | |||
570 | if (tp->Strings[STRCOUNT414 + i] != ABSENT_STRING(char *)0) | |||
571 | result = (i + 1); | |||
572 | } | |||
573 | return result; | |||
574 | } | |||
575 | ||||
576 | /* | |||
577 | * _nc_align_termtype() will extend entries that are referenced in a use= | |||
578 | * clause - discard the unneeded data. | |||
579 | */ | |||
580 | static bool_Bool | |||
581 | extended_object(TERMTYPE *tp) | |||
582 | { | |||
583 | bool_Bool result = FALSE0; | |||
584 | ||||
585 | if (_nc_user_definable) { | |||
586 | result = ((extended_Booleans(tp) | |||
587 | + extended_Numbers(tp) | |||
588 | + extended_Strings(tp)) != 0); | |||
589 | } | |||
590 | return result; | |||
591 | } | |||
592 | #endif | |||
593 | ||||
594 | static int | |||
595 | write_object(TERMTYPE *tp, char *buffer, unsigned *offset, unsigned limit) | |||
596 | { | |||
597 | char *namelist; | |||
598 | size_t namelen, boolmax, nummax, strmax; | |||
599 | char zero = '\0'; | |||
600 | size_t i; | |||
601 | short nextfree; | |||
602 | short offsets[MAX_ENTRY_SIZE4096 / 2]; | |||
603 | unsigned char buf[MAX_ENTRY_SIZE4096]; | |||
604 | unsigned last_bool = BOOLWRITE37; | |||
605 | unsigned last_num = NUMWRITE33; | |||
606 | unsigned last_str = STRWRITE394; | |||
607 | ||||
608 | #if NCURSES_XNAMES1 | |||
609 | /* | |||
610 | * Normally we limit the list of values to exclude the "obsolete" | |||
611 | * capabilities. However, if we are accepting extended names, add | |||
612 | * these as well, since they are used for supporting translation | |||
613 | * to/from termcap. | |||
614 | */ | |||
615 | if (_nc_user_definable) { | |||
616 | last_bool = BOOLCOUNT44; | |||
617 | last_num = NUMCOUNT39; | |||
618 | last_str = STRCOUNT414; | |||
619 | } | |||
620 | #endif | |||
621 | ||||
622 | namelist = tp->term_names; | |||
623 | namelen = strlen(namelist) + 1; | |||
624 | ||||
625 | boolmax = 0; | |||
626 | for (i = 0; i < last_bool; i++) { | |||
627 | if (tp->Booleans[i] == TRUE1) | |||
628 | boolmax = i + 1; | |||
629 | } | |||
630 | ||||
631 | nummax = 0; | |||
632 | for (i = 0; i < last_num; i++) { | |||
633 | if (tp->Numbers[i] != ABSENT_NUMERIC(-1)) | |||
634 | nummax = i + 1; | |||
635 | } | |||
636 | ||||
637 | strmax = 0; | |||
638 | for (i = 0; i < last_str; i++) { | |||
639 | if (tp->Strings[i] != ABSENT_STRING(char *)0) | |||
640 | strmax = i + 1; | |||
641 | } | |||
642 | ||||
643 | nextfree = compute_offsets(tp->Strings, strmax, offsets); | |||
644 | ||||
645 | /* fill in the header */ | |||
646 | LITTLE_ENDIAN(buf, MAGIC)(buf)[0] = ((0432) % 256), (buf)[1] = ((0432) / 256); | |||
647 | LITTLE_ENDIAN(buf + 2, min(namelen, MAX_NAME_SIZE + 1))(buf + 2)[0] = ((((namelen) > (512 + 1) ? (512 + 1) : (namelen ))) % 256), (buf + 2)[1] = ((((namelen) > (512 + 1) ? (512 + 1) : (namelen))) / 256); | |||
648 | LITTLE_ENDIAN(buf + 4, boolmax)(buf + 4)[0] = ((boolmax) % 256), (buf + 4)[1] = ((boolmax) / 256); | |||
649 | LITTLE_ENDIAN(buf + 6, nummax)(buf + 6)[0] = ((nummax) % 256), (buf + 6)[1] = ((nummax) / 256 ); | |||
650 | LITTLE_ENDIAN(buf + 8, strmax)(buf + 8)[0] = ((strmax) % 256), (buf + 8)[1] = ((strmax) / 256 ); | |||
651 | LITTLE_ENDIAN(buf + 10, nextfree)(buf + 10)[0] = ((nextfree) % 256), (buf + 10)[1] = ((nextfree ) / 256); | |||
652 | ||||
653 | /* write out the header */ | |||
654 | TRACE_OUT(("Header of %s @%d", namelist, *offset)); | |||
655 | if (Write(buf, 12, 1)fake_write(buffer, offset, limit, (char *) buf, 1, 12) != 1 | |||
656 | || Write(namelist, sizeof(char), namelen)fake_write(buffer, offset, limit, (char *) namelist, namelen, sizeof(char)) != namelen) | |||
657 | return (ERR(-1)); | |||
658 | ||||
659 | for (i = 0; i < boolmax; i++) | |||
660 | if (tp->Booleans[i] == TRUE1) | |||
661 | buf[i] = TRUE1; | |||
662 | else | |||
663 | buf[i] = FALSE0; | |||
664 | if (Write(buf, sizeof(char), boolmax)fake_write(buffer, offset, limit, (char *) buf, boolmax, sizeof (char)) != boolmax) | |||
665 | return (ERR(-1)); | |||
666 | ||||
667 | if (even_boundary(namelen + boolmax)((namelen + boolmax) % 2 != 0 && fake_write(buffer, offset , limit, (char *) &zero, 1, sizeof(char)) != 1)) | |||
668 | return (ERR(-1)); | |||
669 | ||||
670 | TRACE_OUT(("Numerics begin at %04x", *offset)); | |||
671 | ||||
672 | /* the numerics */ | |||
673 | convert_shorts(buf, tp->Numbers, nummax); | |||
674 | if (Write(buf, 2, nummax)fake_write(buffer, offset, limit, (char *) buf, nummax, 2) != nummax) | |||
675 | return (ERR(-1)); | |||
676 | ||||
677 | TRACE_OUT(("String offsets begin at %04x", *offset)); | |||
678 | ||||
679 | /* the string offsets */ | |||
680 | convert_shorts(buf, offsets, strmax); | |||
681 | if (Write(buf, 2, strmax)fake_write(buffer, offset, limit, (char *) buf, strmax, 2) != strmax) | |||
682 | return (ERR(-1)); | |||
683 | ||||
684 | TRACE_OUT(("String table begins at %04x", *offset)); | |||
685 | ||||
686 | /* the strings */ | |||
687 | for (i = 0; i < strmax; i++) | |||
688 | if (VALID_STRING(tp->Strings[i])((tp->Strings[i]) != (char *)(-1) && (tp->Strings [i]) != (char *)0)) | |||
689 | if (!WRITE_STRING(tp->Strings[i])(fake_write(buffer, offset, limit, (char *) tp->Strings[i] , strlen(tp->Strings[i]) + 1, sizeof(char)) == strlen(tp-> Strings[i]) + 1)) | |||
690 | return (ERR(-1)); | |||
691 | ||||
692 | #if NCURSES_XNAMES1 | |||
693 | if (extended_object(tp)) { | |||
694 | unsigned extcnt = NUM_EXT_NAMES(tp)((tp)->ext_Booleans + (tp)->ext_Numbers + (tp)->ext_Strings ); | |||
695 | ||||
696 | if (even_boundary(nextfree)((nextfree) % 2 != 0 && fake_write(buffer, offset, limit , (char *) &zero, 1, sizeof(char)) != 1)) | |||
697 | return (ERR(-1)); | |||
698 | ||||
699 | nextfree = compute_offsets(tp->Strings + STRCOUNT414, | |||
700 | tp->ext_Strings, | |||
701 | offsets); | |||
702 | TRACE_OUT(("after extended string capabilities, nextfree=%d", nextfree)); | |||
703 | ||||
704 | if (tp->ext_Strings >= SIZEOF(offsets)(sizeof(offsets)/sizeof(offsets[0]))) | |||
705 | return (ERR(-1)); | |||
706 | ||||
707 | nextfree += compute_offsets(tp->ext_Names, | |||
708 | extcnt, | |||
709 | offsets + tp->ext_Strings); | |||
710 | TRACE_OUT(("after extended capnames, nextfree=%d", nextfree)); | |||
711 | strmax = tp->ext_Strings + extcnt; | |||
712 | ||||
713 | /* | |||
714 | * Write the extended header | |||
715 | */ | |||
716 | LITTLE_ENDIAN(buf + 0, tp->ext_Booleans)(buf + 0)[0] = ((tp->ext_Booleans) % 256), (buf + 0)[1] = ( (tp->ext_Booleans) / 256); | |||
717 | LITTLE_ENDIAN(buf + 2, tp->ext_Numbers)(buf + 2)[0] = ((tp->ext_Numbers) % 256), (buf + 2)[1] = ( (tp->ext_Numbers) / 256); | |||
718 | LITTLE_ENDIAN(buf + 4, tp->ext_Strings)(buf + 4)[0] = ((tp->ext_Strings) % 256), (buf + 4)[1] = ( (tp->ext_Strings) / 256); | |||
719 | LITTLE_ENDIAN(buf + 6, strmax)(buf + 6)[0] = ((strmax) % 256), (buf + 6)[1] = ((strmax) / 256 ); | |||
720 | LITTLE_ENDIAN(buf + 8, nextfree)(buf + 8)[0] = ((nextfree) % 256), (buf + 8)[1] = ((nextfree) / 256); | |||
721 | TRACE_OUT(("WRITE extended-header @%d", *offset)); | |||
722 | if (Write(buf, 10, 1)fake_write(buffer, offset, limit, (char *) buf, 1, 10) != 1) | |||
723 | return (ERR(-1)); | |||
724 | ||||
725 | TRACE_OUT(("WRITE %d booleans @%d", tp->ext_Booleans, *offset)); | |||
726 | if (tp->ext_Booleans | |||
727 | && Write(tp->Booleans + BOOLCOUNT, sizeof(char),fake_write(buffer, offset, limit, (char *) tp->Booleans + 44 , tp->ext_Booleans, sizeof(char)) | |||
728 | tp->ext_Booleans)fake_write(buffer, offset, limit, (char *) tp->Booleans + 44 , tp->ext_Booleans, sizeof(char)) != tp->ext_Booleans) | |||
729 | return (ERR(-1)); | |||
730 | ||||
731 | if (even_boundary(tp->ext_Booleans)((tp->ext_Booleans) % 2 != 0 && fake_write(buffer, offset, limit, (char *) &zero, 1, sizeof(char)) != 1)) | |||
732 | return (ERR(-1)); | |||
733 | ||||
734 | TRACE_OUT(("WRITE %d numbers @%d", tp->ext_Numbers, *offset)); | |||
735 | if (tp->ext_Numbers) { | |||
736 | convert_shorts(buf, tp->Numbers + NUMCOUNT39, tp->ext_Numbers); | |||
737 | if (Write(buf, 2, tp->ext_Numbers)fake_write(buffer, offset, limit, (char *) buf, tp->ext_Numbers , 2) != tp->ext_Numbers) | |||
738 | return (ERR(-1)); | |||
739 | } | |||
740 | ||||
741 | /* | |||
742 | * Convert the offsets for the ext_Strings and ext_Names tables, | |||
743 | * in that order. | |||
744 | */ | |||
745 | convert_shorts(buf, offsets, strmax); | |||
746 | TRACE_OUT(("WRITE offsets @%d", *offset)); | |||
747 | if (Write(buf, 2, strmax)fake_write(buffer, offset, limit, (char *) buf, strmax, 2) != strmax) | |||
748 | return (ERR(-1)); | |||
749 | ||||
750 | /* | |||
751 | * Write the string table after the offset tables so we do not | |||
752 | * have to do anything about alignment. | |||
753 | */ | |||
754 | for (i = 0; i < tp->ext_Strings; i++) { | |||
755 | if (VALID_STRING(tp->Strings[i + STRCOUNT])((tp->Strings[i + 414]) != (char *)(-1) && (tp-> Strings[i + 414]) != (char *)0)) { | |||
756 | TRACE_OUT(("WRITE ext_Strings[%d]=%s", (int) i, | |||
757 | _nc_visbuf(tp->Strings[i + STRCOUNT]))); | |||
758 | if (!WRITE_STRING(tp->Strings[i + STRCOUNT])(fake_write(buffer, offset, limit, (char *) tp->Strings[i + 414], strlen(tp->Strings[i + 414]) + 1, sizeof(char)) == strlen (tp->Strings[i + 414]) + 1)) | |||
759 | return (ERR(-1)); | |||
760 | } | |||
761 | } | |||
762 | ||||
763 | /* | |||
764 | * Write the extended names | |||
765 | */ | |||
766 | for (i = 0; i < extcnt; i++) { | |||
767 | TRACE_OUT(("WRITE ext_Names[%d]=%s", (int) i, tp->ext_Names[i])); | |||
768 | if (!WRITE_STRING(tp->ext_Names[i])(fake_write(buffer, offset, limit, (char *) tp->ext_Names[ i], strlen(tp->ext_Names[i]) + 1, sizeof(char)) == strlen( tp->ext_Names[i]) + 1)) | |||
769 | return (ERR(-1)); | |||
770 | } | |||
771 | ||||
772 | } | |||
773 | #endif /* NCURSES_XNAMES */ | |||
774 | ||||
775 | total_written++; | |||
776 | return (OK(0)); | |||
777 | } | |||
778 | ||||
779 | /* | |||
780 | * Returns the total number of entries written by this process | |||
781 | */ | |||
782 | NCURSES_EXPORT(int)int | |||
783 | _nc_tic_written(void) | |||
784 | { | |||
785 | return total_written; | |||
786 | } |