X-Git-Url: http://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Ftinfo%2Fwrite_entry.c;fp=ncurses%2Fwrite_entry.c;h=4829fa936d016d1bb326ea14f17a67b63510b891;hp=c0b245479b2fcbc24675065fe62297e1e73da3b2;hb=0eb88fc5281804773e2a0c7a488a4452463535ce;hpb=661078ddbde3ce0f3b06e95642fbb9b5fef7dca1 diff --git a/ncurses/write_entry.c b/ncurses/tinfo/write_entry.c similarity index 61% rename from ncurses/write_entry.c rename to ncurses/tinfo/write_entry.c index c0b24547..4829fa93 100644 --- a/ncurses/write_entry.c +++ b/ncurses/tinfo/write_entry.c @@ -42,14 +42,19 @@ #include #include -#include #include #ifndef S_ISDIR #define S_ISDIR(mode) ((mode & S_IFMT) == S_IFDIR) #endif -MODULE_ID("$Id: write_entry.c,v 1.22 1998/02/11 12:13:59 tom Exp $") +#if 0 +#define TRACE_OUT(p) DEBUG(2, p) +#else +#define TRACE_OUT(p) /*nothing*/ +#endif + +MODULE_ID("$Id: write_entry.c,v 1.47 1999/07/10 20:29:22 tom Exp $") static int total_written; @@ -57,7 +62,7 @@ static int write_object(FILE *, TERMTYPE *); static void write_file(char *filename, TERMTYPE *tp) { - FILE *fp = fopen(filename, "wb"); + FILE *fp = (_nc_access(filename, W_OK) == 0) ? fopen(filename, "wb") : 0; if (fp == 0) { perror(filename); _nc_syserr_abort("can't open %s/%s", _nc_tic_dir(0), filename); @@ -82,15 +87,20 @@ struct stat statbuf; char fullpath[PATH_MAX]; const char *destination = _nc_tic_dir(0); - if (path == destination || *path == '/') + if (path == destination || *path == '/') { + if (strlen(path) + 1 > sizeof(fullpath)) + return(-1); (void)strcpy(fullpath, path); - else + } else { + if (strlen(destination) + strlen(path) + 2 > sizeof(fullpath)) + return(-1); (void)sprintf(fullpath, "%s/%s", destination, path); + } if ((rc = stat(path, &statbuf)) < 0) { rc = mkdir(path, 0777); } else { - if (access(path, R_OK|W_OK|X_OK) < 0) { + if (_nc_access(path, R_OK|W_OK|X_OK) < 0) { rc = -1; /* permission denied */ } else if (!(S_ISDIR(statbuf.st_mode))) { rc = -1; /* not a directory */ @@ -103,6 +113,7 @@ void _nc_set_writedir(char *dir) /* set the write directory for compiled entries */ { const char *destination; + char actual[PATH_MAX]; if (dir != 0) (void) _nc_tic_dir(dir); @@ -112,15 +123,10 @@ void _nc_set_writedir(char *dir) destination = _nc_tic_dir(0); if (make_directory(destination) < 0) { - char *home; - - /* ncurses extension...fall back on user's private directory */ - if ((home = getenv("HOME")) != (char *)NULL) - { - char *temp = malloc(sizeof(PRIVATE_INFO) + strlen(home)); - (void) sprintf(temp, PRIVATE_INFO, home); - destination = temp; + char *home = _nc_home_terminfo(); + if (home != 0) { + destination = home; if (make_directory(destination) < 0) _nc_err_abort("%s: permission denied (errno %d)", destination, errno); @@ -131,8 +137,10 @@ void _nc_set_writedir(char *dir) * Note: because of this code, this logic should be exercised * *once only* per run. */ - if (chdir(_nc_tic_dir(destination)) < 0) + if (chdir(_nc_tic_dir(destination)) < 0 + || getcwd(actual, sizeof(actual)) == 0) _nc_err_abort("%s: not a directory", destination); + _nc_keep_tic_dir(strdup(actual)); } /* @@ -279,6 +287,10 @@ static time_t start_time; /* time at start of writes */ _nc_warning("terminal alias %s too long.", ptr); continue; } + if (strchr(ptr, '/') != 0) { + _nc_warning("cannot link alias %s.", ptr); + continue; + } check_writeable(ptr[0]); sprintf(linkname, "%c/%s", ptr[0], ptr); @@ -291,25 +303,45 @@ static time_t start_time; /* time at start of writes */ { _nc_warning("alias %s multiply defined.", ptr); } - else + else if (_nc_access(linkname, W_OK) == 0) #if HAVE_LINK { + int code; #if USE_SYMLINKS strcpy(symlinkname, "../"); - strcat(symlinkname, filename); + strncat(symlinkname, filename, sizeof(symlinkname) - 4); + symlinkname[sizeof(symlinkname) - 1] = '\0'; #endif /* USE_SYMLINKS */ #if HAVE_REMOVE - remove(linkname); + code = remove(linkname); #else - unlink(linkname); + code = unlink(linkname); #endif + if (code != 0 && errno == ENOENT) + code = 0; #if USE_SYMLINKS if (symlink(symlinkname, linkname) < 0) #else if (link(filename, linkname) < 0) #endif /* USE_SYMLINKS */ - _nc_syserr_abort("can't link %s to %s", filename, linkname); - DEBUG(1, ("Linked %s", linkname)); + { + /* + * If there wasn't anything there, and we cannot + * link to the target because it is the same as the + * target, then the source must be on a filesystem + * that uses caseless filenames, such as Win32, etc. + */ + if (code == 0 && errno == EEXIST) + _nc_warning("can't link %s to %s", filename, linkname); + else if (code == 0 && errno == EPERM) + write_file(linkname, tp); + else + _nc_syserr_abort("can't link %s to %s", filename, linkname); + } + else + { + DEBUG(1, ("Linked %s", linkname)); + } } #else /* just make copies */ write_file(linkname, tp); @@ -322,6 +354,46 @@ static time_t start_time; /* time at start of writes */ #define LO(x) ((x) % 256) #define LITTLE_ENDIAN(p, x) (p)[0] = LO(x), (p)[1] = HI(x) +#define WRITE_STRING(str) (fwrite(str, sizeof(char), strlen(str) + 1, fp) == strlen(str) + 1) + +static int compute_offsets(char **Strings, int strmax, short *offsets) +{ + size_t nextfree = 0; + int i; + + for (i = 0; i < strmax; i++) { + if (Strings[i] == ABSENT_STRING) { + offsets[i] = -1; + } else if (Strings[i] == CANCELLED_STRING) { + offsets[i] = -2; + } else { + offsets[i] = nextfree; + nextfree += strlen(Strings[i]) + 1; + TRACE_OUT(("put Strings[%d]=%s(%d)", i, _nc_visbuf(Strings[i]), nextfree)); + } + } + return nextfree; +} + +static void convert_shorts(unsigned char *buf, short *Numbers, int count) +{ + int i; + for (i = 0; i < count; i++) { + if (Numbers[i] == -1) { /* HI/LO won't work */ + buf[2*i] = buf[2*i + 1] = 0377; + } else if (Numbers[i] == -2) { /* HI/LO won't work */ + buf[2*i] = 0376; + buf[2*i + 1] = 0377; + } else { + LITTLE_ENDIAN(buf + 2*i, Numbers[i]); + TRACE_OUT(("put Numbers[%d]=%d", i, Numbers[i])); + } + } +} + +#define even_boundary(value) \ + ((value) % 2 != 0 && fwrite(&zero, sizeof(char), 1, fp) != 1) + static int write_object(FILE *fp, TERMTYPE *tp) { char *namelist; @@ -329,38 +401,35 @@ size_t namelen, boolmax, nummax, strmax; char zero = '\0'; size_t i; short nextfree; -short offsets[STRCOUNT]; +short offsets[MAX_ENTRY_SIZE/2]; unsigned char buf[MAX_ENTRY_SIZE]; namelist = tp->term_names; namelen = strlen(namelist) + 1; + /* + * BOOLWRITE, etc., are less than BOOLCOUNT because we store some + * values internally. + */ boolmax = 0; - for (i = 0; i < BOOLWRITE; i++) - if (tp->Booleans[i]) - boolmax = i+1; + for (i = 0; i < BOOLWRITE; i++) { + if (tp->Booleans[i]) + boolmax = i+1; + } nummax = 0; - for (i = 0; i < NUMWRITE; i++) - if (tp->Numbers[i] != ABSENT_NUMERIC) - nummax = i+1; + for (i = 0; i < NUMWRITE; i++) { + if (tp->Numbers[i] != ABSENT_NUMERIC) + nummax = i+1; + } strmax = 0; - for (i = 0; i < STRWRITE; i++) - if (tp->Strings[i] != ABSENT_STRING) - strmax = i+1; + for (i = 0; i < STRWRITE; i++) { + if (tp->Strings[i] != ABSENT_STRING) + strmax = i+1; + } - nextfree = 0; - for (i = 0; i < strmax; i++) - if (tp->Strings[i] == ABSENT_STRING) - offsets[i] = -1; - else if (tp->Strings[i] == CANCELLED_STRING) - offsets[i] = -2; - else - { - offsets[i] = nextfree; - nextfree += strlen(tp->Strings[i]) + 1; - } + nextfree = compute_offsets(tp->Strings, strmax, offsets); /* fill in the header */ LITTLE_ENDIAN(buf, MAGIC); @@ -371,60 +440,112 @@ unsigned char buf[MAX_ENTRY_SIZE]; LITTLE_ENDIAN(buf+10, nextfree); /* write out the header */ + TRACE_OUT(("Header of %s @%ld", namelist, ftell(fp))); if (fwrite(buf, 12, 1, fp) != 1 - || fwrite(namelist, sizeof(char), (size_t)namelen, fp) != namelen - || fwrite(tp->Booleans, sizeof(char), (size_t)boolmax, fp) != boolmax) - return(ERR); + || fwrite(namelist, sizeof(char), namelen, fp) != namelen + || fwrite(tp->Booleans, sizeof(char), boolmax, fp) != boolmax) + return(ERR); - /* the even-boundary padding byte */ - if ((namelen+boolmax) % 2 != 0 && fwrite(&zero, sizeof(char), 1, fp) != 1) - return(ERR); + if (even_boundary(namelen+boolmax)) + return(ERR); -#ifdef SHOWOFFSET - (void) fprintf(stderr, "Numerics begin at %04lx\n", ftell(fp)); -#endif /* SHOWOFFSET */ + TRACE_OUT(("Numerics begin at %04lx", ftell(fp))); /* the numerics */ - for (i = 0; i < nummax; i++) - { - if (tp->Numbers[i] == -1) /* HI/LO won't work */ - buf[2*i] = buf[2*i + 1] = 0377; - else - LITTLE_ENDIAN(buf + 2*i, tp->Numbers[i]); - } - if (fwrite(buf, 2, (size_t)nummax, fp) != nummax) - return(ERR); + convert_shorts(buf, tp->Numbers, nummax); + if (fwrite(buf, 2, nummax, fp) != nummax) + return(ERR); -#ifdef SHOWOFFSET - (void) fprintf(stderr, "String offets begin at %04lx\n", ftell(fp)); -#endif /* SHOWOFFSET */ + TRACE_OUT(("String offsets begin at %04lx", ftell(fp))); /* the string offsets */ - for (i = 0; i < strmax; i++) - if (offsets[i] == -1) /* HI/LO won't work */ - buf[2*i] = buf[2*i + 1] = 0377; - else if (offsets[i] == -2) /* HI/LO won't work */ - { - buf[2*i] = 0376; - buf[2*i + 1] = 0377; - } - else - LITTLE_ENDIAN(buf + 2*i, offsets[i]); - if (fwrite(buf, 2, (size_t)strmax, fp) != strmax) - return(ERR); + convert_shorts(buf, offsets, strmax); + if (fwrite(buf, 2, strmax, fp) != strmax) + return(ERR); -#ifdef SHOWOFFSET - (void) fprintf(stderr, "String table begins at %04lx\n", ftell(fp)); -#endif /* SHOWOFFSET */ + TRACE_OUT(("String table begins at %04lx", ftell(fp))); /* the strings */ for (i = 0; i < strmax; i++) - if (tp->Strings[i] != ABSENT_STRING && tp->Strings[i] != CANCELLED_STRING) - if (fwrite(tp->Strings[i], sizeof(char), strlen(tp->Strings[i]) + 1, fp) != strlen(tp->Strings[i]) + 1) + if (VALID_STRING(tp->Strings[i])) + if (!WRITE_STRING(tp->Strings[i])) + return(ERR); + +#if NCURSES_XNAMES + if (NUM_EXT_NAMES(tp)) { + unsigned extcnt = NUM_EXT_NAMES(tp); + + if (even_boundary(nextfree)) + return(ERR); + + nextfree = compute_offsets(tp->Strings + STRCOUNT, tp->ext_Strings, offsets); + TRACE_OUT(("after extended string capabilities, nextfree=%d", nextfree)); + nextfree += compute_offsets(tp->ext_Names, extcnt, offsets + tp->ext_Strings); + TRACE_OUT(("after extended capnames, nextfree=%d", nextfree)); + strmax = tp->ext_Strings + extcnt; + + /* + * Write the extended header + */ + LITTLE_ENDIAN(buf+0, tp->ext_Booleans); + LITTLE_ENDIAN(buf+2, tp->ext_Numbers); + LITTLE_ENDIAN(buf+4, tp->ext_Strings); + LITTLE_ENDIAN(buf+6, strmax); + LITTLE_ENDIAN(buf+8, nextfree); + TRACE_OUT(("WRITE extended-header @%ld", ftell(fp))); + if (fwrite(buf, 10, 1, fp) != 1) + return(ERR); + + TRACE_OUT(("WRITE %d booleans @%ld", tp->ext_Booleans, ftell(fp))); + if (tp->ext_Booleans + && fwrite(tp->Booleans + BOOLCOUNT, sizeof(char), tp->ext_Booleans, fp) != tp->ext_Booleans) + return(ERR); + + if (even_boundary(tp->ext_Booleans)) + return(ERR); + + TRACE_OUT(("WRITE %d numbers @%ld", tp->ext_Numbers, ftell(fp))); + if (tp->ext_Numbers) { + convert_shorts(buf, tp->Numbers + NUMCOUNT, tp->ext_Numbers); + if (fwrite(buf, 2, tp->ext_Numbers, fp) != tp->ext_Numbers) return(ERR); + } + + /* + * Convert the offsets for the ext_Strings and ext_Names tables, + * in that order. + */ + convert_shorts(buf, offsets, strmax); + TRACE_OUT(("WRITE offsets @%ld", ftell(fp))); + if (fwrite(buf, 2, strmax, fp) != strmax) + return(ERR); + + /* + * Write the string table after the offset tables so we do not + * have to do anything about alignment. + */ + for (i = 0; i < tp->ext_Strings; i++) { + if (VALID_STRING(tp->Strings[i+STRCOUNT])) { + TRACE_OUT(("WRITE ext_Strings[%d]=%s", i, _nc_visbuf(tp->Strings[i+STRCOUNT]))); + if (!WRITE_STRING(tp->Strings[i+STRCOUNT])) + return(ERR); + } + } + + /* + * Write the extended names + */ + for (i = 0; i < extcnt; i++) { + TRACE_OUT(("WRITE ext_Names[%d]=%s", i, tp->ext_Names[i])); + if (!WRITE_STRING(tp->ext_Names[i])) + return(ERR); + } + + } +#endif /* NCURSES_XNAMES */ total_written++; - return(OK); + return(OK); } /*