Date: Sun, 18 Aug 1996 12:59:32 +0200 (IST) From: Eli Zaretskii To: DJ Delorie Cc: djgpp-workers AT delorie DOT com Subject: Re: LFN woes (again) In-Reply-To: <199608131307.JAA07660@delorie.com> Message-Id: Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII OK, here are the patches required for better LFN support in libc. Part of the changes are intertwined with the changes in spawning child programs (see my other message) and were tested together with them, so I suggest installing them together. There is a new environment variable $FNCASE: if you set it to `y', the filenames are reported exactly as they are found in directory entries. There is also a new bit in `_crt0_startup_flags' that does the same; see the docs changes (and the code) for more details. If neither of these is set, DOS 8+3 names are downcased and long filenames are left intact. (`glob' has a slightly different logic, to make it compatible with the current behavior, see the docs for `glob' below.) I also changed the command-line expansion code to allow for wilcards like "Program Files"/* to be expanded even though there are quoting characters in it; this is required on Windows 95 where filenames can include whitespace. ---------------------------- cut here --------------------------------- *** src/libc/ansi/stdio/_rename.c~0 Mon Aug 28 00:15:38 1995 --- src/libc/ansi/stdio/_rename.c Fri Aug 16 14:38:16 1996 *************** *** 2,7 **** --- 2,8 ---- #include #include #include + #include #include #include #include *************** *** 11,16 **** --- 12,18 ---- __dpmi_regs r; int olen = strlen(old) + 1; int i; + int use_lfn = _USE_LFN; r.x.dx = __tb_offset; r.x.di = __tb_offset + olen; *************** *** 18,24 **** for (i=0; i<2; i++) { ! if(_USE_LFN) r.x.ax = 0x7156; else r.h.ah = 0x56; --- 20,26 ---- for (i=0; i<2; i++) { ! if(use_lfn) r.x.ax = 0x7156; else r.h.ah = 0x56; *************** *** 41,43 **** --- 43,63 ---- return 0; } + #ifdef TEST + + #include + + int main(int argc, char *argv[]) + { + if (argc > 2) + { + printf ("%s -> %s: ", argv[1], argv[2]); + if (_rename (argv[1], argv[2])) + printf ("%s\n", strerror (errno)); + else + printf ("Done\n"); + } + return 0; + } + + #endif *** src/libc/ansi/stdio/rename.c~1 Wed Jan 24 03:30:16 1996 --- src/libc/ansi/stdio/rename.c Fri Aug 16 13:32:48 1996 *************** *** 188,194 **** static int is_parent(const char *dir1, const char *dir2) { ! return dir1 != 0 && dir2 != 0 && *dir1 != 0 && strstr(dir2, dir1) == dir2; } /* --- 188,202 ---- static int is_parent(const char *dir1, const char *dir2) { ! if (dir1 == 0 || dir2 == 0 || *dir1 == 0) ! return 0; ! while (*dir1 && *dir2 && tolower(*dir1) == tolower(*dir2)) ! { ! dir1++; ! dir2++; ! } ! ! return *dir1 == '\0' && (*dir2 == '/' || *dir2 == '\\'); } /* *************** *** 352,358 **** } /* On to some REAL work for a change. Let DOS do the simple job: ! moving a regular file, or renaming a directory. */ if ((status = _rename(old, new)) == 0) { errno = e; /* restore errno we inherited */ --- 360,368 ---- } /* On to some REAL work for a change. Let DOS do the simple job: ! moving a regular file, or renaming a directory. Note that on ! Windows 95 this will also move a directory to a subtree of ! another parent directory. */ if ((status = _rename(old, new)) == 0) { errno = e; /* restore errno we inherited */ *** src/libc/ansi/stdio/rename.t~0 Mon Jul 10 05:39:38 1995 --- src/libc/ansi/stdio/rename.txh Fri Aug 16 14:33:44 1996 *************** *** 41,43 **** --- 41,81 ---- rename("c:/path1/mydir", "c:/path2"); @end example + @c ------------------------------------------------------------------------- + + @node _rename, file system + @subheading Syntax + + @example + #include + + int _rename(const char *oldname, const char *newname); + @end example + + @subheading Description + + This function renames an existing file or directory @var{oldname} to + @var{newname}. It is much smaller that @code{rename} (@pxref{rename}), + but it can only rename a directory so it stays under the same perent, it + cannot move directories between different branches of the directory + tree. This means that in the following example, the first call will + succeed, while the second will fail: + + @example + _rename("c:/path1/mydir", "c:/path1/yourdir"); + _rename("c:/path1/mydir", "c:/path2"); + @end example + + On systems that support long filenames (@pxref{_use_lfn}), + @code{_rename} can also move directories (so that both calls in the + above example succeed there), unless the @samp{LFN} environment variable + is set to @kbd{n}, or the @code{_CRT0_FLAG_NO_LFN} is set in the + @code{_crt0_startup_flags} variable, @xref{_crt0_startup_flags}. + + If you don't need the extra functionality offered by @code{rename} + (which usually is only expected by Unix-born programs), you can use + @code{_rename} instead and thus make your program a lot smaller. + + @subheading Return Value + + Zero on success, nonzero on failure. *** src/libc/ansi/stdio/remove.c~0 Thu Aug 31 07:34:56 1995 --- src/libc/ansi/stdio/remove.c Sat Aug 10 23:35:42 1996 *************** *** 2,7 **** --- 2,8 ---- #include #include #include + #include #include #include #include *************** *** 13,18 **** --- 14,20 ---- __dpmi_regs r; unsigned attr; int directory_p; + int use_lfn = _USE_LFN; /* Get the file attribute byte. */ attr = _chmod(fn, 0); *************** *** 22,33 **** in addition to the Read-Only bit, or else 214301 will fail. */ _chmod(fn, 1, attr & 0xffe0); ! /* Now delete it. Note, _chmod leave dir name in tranfer buffer. */ if (directory_p) r.h.ah = 0x3a; /* DOS Remove Directory function */ else r.h.ah = 0x41; /* DOS Remove File function */ ! if(_USE_LFN) { r.h.al = r.h.ah; r.h.ah = 0x71; r.x.si = 0; /* No Wildcards */ --- 24,35 ---- in addition to the Read-Only bit, or else 214301 will fail. */ _chmod(fn, 1, attr & 0xffe0); ! /* Now delete it. Note, _chmod leaves dir name in tranfer buffer. */ if (directory_p) r.h.ah = 0x3a; /* DOS Remove Directory function */ else r.h.ah = 0x41; /* DOS Remove File function */ ! if(use_lfn) { r.h.al = r.h.ah; r.h.ah = 0x71; r.x.si = 0; /* No Wildcards */ *** src/libc/compat/stdlib/putenv.c~0 Sun Oct 1 04:41:00 1995 --- src/libc/compat/stdlib/putenv.c Sat Aug 10 16:08:36 1996 *************** *** 1,7 **** --- 1,10 ---- + /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include #include + #include + #include /* *************** *** 14,19 **** --- 17,36 ---- extern char **environ; static int ecount = -1; static int emax = -1; + static int putenv_bss_count = -1; + + + /* This gets incremented every time some variable in the + environment is added, deleted, or changes its value. + It is meant to be used by functions that depend on values + of environment variables, but don't want to call `getenv' + unnecessarily (example: `__use_lfn'). + + Users should compare this variable with their static + variable whose value is initialized to zero; thus this + variable begins with 1 so first time users look they will + call `getenv'. */ + unsigned __environ_changed = 1; int putenv(const char *val) *************** *** 23,37 **** int nlen = epos - val + 1; int eindex; ! if (epos == 0) ! return -1; ! ! if (ecount == -1) { for (ecount=0; environ[ecount]; ecount++); emax = ecount; } for (eindex=0; environ[eindex]; eindex++) if (strncmp(environ[eindex], val, nlen) == 0) { --- 40,58 ---- int nlen = epos - val + 1; int eindex; ! if (putenv_bss_count != __bss_count) { + putenv_bss_count = __bss_count; for (ecount=0; environ[ecount]; ecount++); emax = ecount; + /* Bump the count to a value no function has yet seen, + even if they were dumped with us. */ + __environ_changed++; } + if (epos == 0) + return -1; + for (eindex=0; environ[eindex]; eindex++) if (strncmp(environ[eindex], val, nlen) == 0) { *************** *** 43,48 **** --- 64,70 ---- environ[eindex] = environ[ecount-1]; environ[ecount-1] = 0; ecount--; + __environ_changed++; return 0; } *************** *** 57,62 **** --- 79,85 ---- } free(oval); strcpy(environ[eindex], val); + __environ_changed++; return 0; } *************** *** 84,89 **** --- 107,114 ---- ecount++; environ[ecount] = 0; + + __environ_changed++; return 0; } *** src/libc/crt0/crt0.t~1 Thu Jul 25 17:41:18 1996 --- src/libc/crt0/crt0.txh Tue Aug 13 19:20:38 1996 *************** *** 31,37 **** @subheading Syntax @example ! #include void *sbrk(int delta) @end example --- 31,37 ---- @subheading Syntax @example ! #include void *sbrk(int delta) @end example *** src/libc/crt0/crt1.c~0 Wed Jan 24 02:49:26 1996 --- src/libc/crt0/crt1.c Sat Aug 17 15:27:08 1996 *************** *** 11,21 **** --- 11,29 ---- #include #include #include + #include + #include /* Global variables */ #define ds _my_ds() + /* This gets incremented each time the program is started. + Programs (such as Emacs) which dump their code to create + a new executable, cause this to be larger than 2. Library + functions that cache info in static variables should check + the value of `__bss_count' if they need to reinitialize + the static storage. */ int __bss_count = 1; char **environ; *************** *** 124,129 **** --- 132,140 ---- extern int main(int, char **, char **); extern void _crt0_init_mcount(void); /* For profiling */ + char __PROXY[] = " !proxy"; + size_t __PROXY_LEN = sizeof(__PROXY)-1; + void __crt1_startup(void) { *************** *** 135,143 **** --- 146,158 ---- setup_go32_info_block(); __djgpp_exception_setup(); setup_environment(); + __environ_changed++; + /* Make so rest of startup could use LFN. */ + (void)_USE_LFN; __crt0_setup_arguments(); pn = __crt0_argv ? __crt0_argv[0] : __dos_argv0; __crt0_load_environment_file(pn); + (void)_USE_LFN; /* DJGPP.ENV might have set $LFN */ _npxsetup(pn); _crt0_init_mcount(); __main(); *** src/libc/crt0/c1args.c~1 Fri Aug 2 14:17:30 1996 --- src/libc/crt0/c1args.c Sat Aug 17 15:26:48 1996 *************** *** 111,163 **** free(al); } static ArgList * parse_bytes(char *bytes, int length) { ! int largc, quote=0, i; Arg *a, **anext, *afirst; ArgList *al; ! char *bp=bytes, *ep, *epp, *last=bytes+length; anext = &afirst; largc = 0; while (bpwas_quoted = 1; ! } ! else if (*ep == '\\' && strchr("'\"", ep[1]) && ep < last-1) ! { ! ep++; ! *epp++ = *ep++; ! /* a->was_quoted = 1; - This makes no sense. */ ! } ! else ! { ! *epp++ = *ep++; ! } ! } anext = &(a->next); largc++; ! a->arg = (char *)c1xmalloc(epp-bp+1); ! memcpy(a->arg, bp, epp-bp); ! a->arg[epp-bp] = 0; bp = ep+1; } al = new_arglist(largc); --- 111,176 ---- free(al); } + static char * + parse_arg(char *bp, char *last, size_t *len, int *was_quoted) + { + char *ep = bp, *epp = bp; + int quote=0; + + while ((quote || !isspace(*ep)) && ep < last) + { + if (quote && *ep == quote) + { + quote = 0; + ep++; + } + else if (!quote && (*ep == '\'' || *ep == '"')) + { + quote = *ep; + ep++; + } + else if (*ep == '\\' && strchr("'\"", ep[1]) && ep < last-1) + { + ep++; + *epp++ = *ep++; + /* *was_quoted = 1; - This makes no sense. */ + } + else + { + if (quote && (strchr("[?*", *ep) || strncmp(ep, "...", 3) == 0)) + *was_quoted = 1; + *epp++ = *ep++; + } + } + + *len = epp - bp; + return ep; + } + static ArgList * parse_bytes(char *bytes, int length) { ! int largc, i; Arg *a, **anext, *afirst; ArgList *al; ! char *bp=bytes, *ep, *last=bytes+length; anext = &afirst; largc = 0; while (bpwas_quoted)); anext = &(a->next); largc++; ! a->arg = (char *)c1xmalloc(arg_len+1); ! memcpy(a->arg, bp, arg_len); ! a->arg[arg_len] = 0; bp = ep+1; } al = new_arglist(largc); *************** *** 255,260 **** --- 268,276 ---- } } + extern char __PROXY[]; /* defined on crt0/crt1.c */ + extern size_t __PROXY_LEN; + void __crt0_setup_arguments(void) { *************** *** 262,267 **** --- 278,284 ---- char *argv0; int prepend_argv0 = 1; int should_expand_wildcards = 1; + char *proxy_v = 0; /* ** first, figure out what to pass for argv[0] *************** *** 270,276 **** int i; char *ap, *ls, *fc; /* char newbase[14]; */ ! if (_crt0_startup_flags & _CRT0_FLAG_DROP_DRIVE_SPECIFIER) if (__dos_argv0[1] == ':') __dos_argv0 += 2; --- 287,293 ---- int i; char *ap, *ls, *fc; /* char newbase[14]; */ ! if (_crt0_startup_flags & _CRT0_FLAG_DROP_DRIVE_SPECIFIER) if (__dos_argv0[1] == ':') __dos_argv0 += 2; *************** *** 336,344 **** } /* ! ** Check for !proxy */ ! if (arglist->argc > 3 && strcmp(arglist->argv[0]->arg, "!proxy") == 0) { int argv_seg, argv_ofs, i; unsigned short *rm_argv; --- 353,376 ---- } /* ! ** Check for !proxy. ! ** ! ** If there is " !proxy" (note the leading blank!) in the environ, ! ** use it instead of what DOS command line tells. This is the method ! ** v2.01 and later uses to pass long command lines from `system'; ! ** these should be passed through wildcard expansion unless quoted. */ ! if ((proxy_v = getenv(__PROXY))) ! { ! char proxy_line[50]; /* need only 34 */ ! size_t plen = strlen(proxy_v); ! strncpy(proxy_line, __PROXY, __PROXY_LEN + 1); /* copy " !proxy" */ ! proxy_line[__PROXY_LEN] = ' '; ! strncpy(proxy_line + __PROXY_LEN+1, proxy_v, plen+1); /* copy value */ ! delete_arglist(arglist); ! arglist = parse_bytes(proxy_line, plen+__PROXY_LEN+1); ! } ! if (arglist->argc > 3 && strcmp(arglist->argv[0]->arg, __PROXY+1) == 0) { int argv_seg, argv_ofs, i; unsigned short *rm_argv; *************** *** 351,356 **** --- 383,393 ---- movedata(_dos_ds, argv_seg*16+argv_ofs, ds, (int)rm_argv, __crt0_argc*sizeof(unsigned short)); arglist = new_arglist(__crt0_argc); + if (proxy_v) + should_expand_wildcards = 1; + else + should_expand_wildcards = 0; + for (i=0; i<__crt0_argc; i++) { *************** *** 358,367 **** arglist->argv[i] = new_arg(); arglist->argv[i]->arg = (char *)c1xmalloc(al+1); movedata(_dos_ds, argv_seg*16 + rm_argv[i], ds, (int)(arglist->argv[i]->arg), al+1); } prepend_argv0 = 0; - should_expand_wildcards = 0; } else if (arglist->argc > 3 && strcmp(arglist->argv[0]->arg, "!proxy2") == 0) { int argv_sel, argv_ofs, i; --- 395,414 ---- arglist->argv[i] = new_arg(); arglist->argv[i]->arg = (char *)c1xmalloc(al+1); movedata(_dos_ds, argv_seg*16 + rm_argv[i], ds, (int)(arglist->argv[i]->arg), al+1); + if (proxy_v) + { + size_t ln; + char *lastc = arglist->argv[i]->arg + al; + parse_arg(arglist->argv[i]->arg, lastc, + &ln, &(arglist->argv[i]->was_quoted)); + arglist->argv[i]->arg[ln] = '\0'; + } } prepend_argv0 = 0; } + #if 0 + /* This method will break under DPMI 1.0, because descriptor + tables are private to a process there. Disabled. */ else if (arglist->argc > 3 && strcmp(arglist->argv[0]->arg, "!proxy2") == 0) { int argv_sel, argv_ofs, i; *************** *** 386,391 **** --- 433,439 ---- prepend_argv0 = 0; should_expand_wildcards = 0; } + #endif /* ** Now, expand response files *************** *** 396,401 **** --- 444,450 ---- /* ** Now, expand wildcards */ + if (should_expand_wildcards) expand_wildcards(arglist); *** src/libc/crt0/crt1.t~0 Fri Dec 15 16:31:24 1995 --- src/libc/crt0/crt1.txh Fri Aug 16 14:07:44 1996 *************** *** 10,21 **** @subheading Description If the application wishes to provide a wildcard expansion function, it ! should define a __crt0_glob_function function. It should return a ! list of the expanded values, or 0 if no expansion will occur. The startup code will free the returned pointer if it is nonzero. If no expander function is provided, wildcards will be expanded in the ! POSIX.1 style. To disable expansion, provide a __crt0_glob_function that always returns 0. @c ---------------------------------------------------------------------- --- 10,22 ---- @subheading Description If the application wishes to provide a wildcard expansion function, it ! should define a @code{__crt0_glob_function} function. It should return ! a list of the expanded values, or 0 if no expansion will occur. The startup code will free the returned pointer if it is nonzero. If no expander function is provided, wildcards will be expanded in the ! POSIX.1 style by the default @code{__crt0_glob_function} from the C ! library. To disable expansion, provide a @code{__crt0_glob_function} that always returns 0. @c ---------------------------------------------------------------------- *************** *** 36,41 **** --- 37,48 ---- can reduce the size of the program image by providing a version of this function that does nothing. + Note that since the default @code{__crt0_setup_arguments_function} will + @emph{not} expand wildcards inside quotes (@kbd{"} or @kbd{'}), but you + can quote a part of the argument that doesn't include wildcards and + still have them expanded. This is so you could use wildcard expansion + with filenames which have embedded whitespace (on LFN filesystems). + @xref{__crt0_load_environment_file}. @c ---------------------------------------------------------------------- *************** *** 136,142 **** If set, disable usage of long file name functions even on systems (such as Win95) which support them. This might be needed to work around program assumptions on file name format on programs written ! specifically for DOS. @item _CRT0_FLAG_NONMOVE_SBRK --- 143,150 ---- If set, disable usage of long file name functions even on systems (such as Win95) which support them. This might be needed to work around program assumptions on file name format on programs written ! specifically for DOS. Note that this flag overrides the value of the ! environment variable @samp{LFN}. @item _CRT0_FLAG_NONMOVE_SBRK *************** *** 165,169 **** --- 173,192 ---- during execution. When sbrk() uses multiple memory zones, it can be difficult to lock all memory since the memory block size and location is impossible to determine. + + @item _CRT0_FLAG_PRESERVE_FILENAME_CASE + + If set, disables all filename letter-case conversions in functions that + traverse directories (except findfirst/findnext which always return the + filenames exactly as found in the directory entry). When reset, all + filenames on 8+3 MSDOS filesystems and DOS-style 8+3 filenames on LFN + systems are converted to lower-case by functions such as `readdir', + @code{getcwd}, @code{_fixpath} and others. Note that when this flag is + set, ALL filenames on MSDOS systems will appear in upper-case, which is + both ugly and will break many Unix-born programs. Use only if you know + exactly what you are doing! + + This flag overrides the value of the environment variable @samp{FNCASE}, + @xref{_preserve_fncase}. @end table *** src/libc/dos/dir/findfirs.c~0 Sun Oct 29 01:15:10 1995 --- src/libc/dos/dir/findfirs.c Sat Aug 10 23:40:16 1996 *************** *** 3,8 **** --- 3,9 ---- #include #include #include + #include #include #include #include *************** *** 13,18 **** --- 14,20 ---- { __dpmi_regs r; int pathlen; + int use_lfn = _USE_LFN; if (pathname == 0 || ffblk == 0) { *************** *** 23,29 **** pathlen = strlen(pathname) + 1; _put_path(pathname); ! if(_USE_LFN) { /* si = 1 indicates DOS style dates, 0 means Win32 type dates. DOS style dates are broken in some Win95 betas, build for either. --- 25,31 ---- pathlen = strlen(pathname) + 1; _put_path(pathname); ! if(use_lfn) { /* si = 1 indicates DOS style dates, 0 means Win32 type dates. DOS style dates are broken in some Win95 betas, build for either. *** src/libc/dos/dir/findnext.c~0 Sun Oct 29 01:14:38 1995 --- src/libc/dos/dir/findnext.c Fri Aug 16 14:09:08 1996 *************** *** 6,11 **** --- 6,12 ---- #include #include #include + #include #include int *** src/libc/dos/dir/ftreewlk.c~0 Tue Jun 13 06:04:02 1995 --- src/libc/dos/dir/ftreewlk.c Sat Aug 17 12:03:24 1996 *************** *** 8,14 **** * is closely modeled on ftw(), but uses DOS directory search * functions and structures instead of opendir()/readdir()/stat(). * ! * Copyright (c) 1995 Eli Zaretskii * * This software may be used freely as long as this copyright notice is * left intact. There is no warranty on this software. --- 8,14 ---- * is closely modeled on ftw(), but uses DOS directory search * functions and structures instead of opendir()/readdir()/stat(). * ! * Copyright (c) 1995, 1996 Eli Zaretskii * * This software may be used freely as long as this copyright notice is * left intact. There is no warranty on this software. *************** *** 83,89 **** do { int func_result; - unsigned char *p = dir_end; /* Skip `.' and `..' entries. */ if (ff.ff_name[0] == '.' && --- 83,88 ---- *************** *** 92,102 **** /* Construct full pathname in FOUND[]. */ strcpy(dir_end, ff.ff_name); - - /* Convert name of found file to lower-case. Cannot use - strlwr() because it's non-ANSI. Sigh... */ - while (*p) - *p++ = tolower(*p); /* Invoke FUNC() on this file. */ if ((func_result = (*func)(found, &ff)) != 0) --- 91,96 ---- *** src/libc/dos/dir/srchpath.c~0 Sun Jun 18 07:43:28 1995 --- src/libc/dos/dir/srchpath.c Fri Aug 16 13:28:32 1996 *************** *** 2,11 **** --- 2,19 ---- #include #include #include + #include #include #include #include #include + #include + #include + #include + #include + + static int env_changed = 0; + static int srchpath_bss_count = -1; /* Search PATH for FILE. If successful, store the full pathname in static buffer and return a *************** *** 22,54 **** memset(found, 0, sizeof(found)); ! /* Get the PATH and store it for reuse. */ ! if (path == 0) { char *p = getenv("PATH"); ! path = (char *)calloc(p ? strlen(p) + 3 : 2, sizeof(char)); if (path == (char *)0) return (char *)0; /* Prepend `.' to the PATH, so current directory ! is always searched. */ path[0] = '.'; if (p) { ! register char *s; path[1] = ';'; strcpy(path+2, p); ! ! /* Convert to more plausible form. */ ! for (s = path; *s; ++s) { if (*s == '\\') *s = '/'; ! if (isupper(*s)) ! *s = tolower(*s); } } else --- 30,90 ---- memset(found, 0, sizeof(found)); ! /* Get $PATH and store it for reuse. */ ! if (path == 0 ! || srchpath_bss_count != __bss_count ! || env_changed != __environ_changed) { char *p = getenv("PATH"); ! ! if (path && srchpath_bss_count == __bss_count) ! free(path); path = (char *)calloc(p ? strlen(p) + 3 : 2, sizeof(char)); if (path == (char *)0) return (char *)0; /* Prepend `.' to the PATH, so current directory ! is always searched first. */ path[0] = '.'; if (p) { ! register char *s, *name_start = 0; ! int preserve_case = _preserve_fncase(); path[1] = ';'; strcpy(path+2, p); ! ! /* switch FOO\BAR to foo/bar, downcase where appropriate */ ! for (s = path + 2, name_start = s; *name_start; s++) { + char lname[FILENAME_MAX], sname[13]; + if (*s == '\\') *s = '/'; ! if (s == name_start) ! continue; ! if (*s == ':') ! name_start = s + 1; ! else if (!preserve_case && (*s == '/' || *s == ';' || *s == '\0')) ! { ! memcpy(lname, name_start+1, s - name_start - 1); ! lname[s - name_start - 1] = '\0'; ! if (!strcmp(_lfn_gen_short_fname(lname, sname), lname)) ! { ! name_start++; ! while (name_start < s) ! { ! if (*name_start >= 'A' && *name_start <= 'Z') ! *name_start += 'a' - 'A'; ! name_start++; ! } ! } ! else ! name_start = s; ! } ! else if (*s == '\0') ! break; } } else *************** *** 90,92 **** --- 126,143 ---- return NULL; } + + #ifdef TEST + + int main(int argc, char *argv[]) + { + if (argc > 1) + { + char *found = searchpath (argv[1]); + printf ("%s: %s%s\n", + argv[1], found ? "found as " : "not found", found ? found : " "); + } + return 0; + } + + #endif *** src/libc/dos/dos/truename.c~0 Sun Aug 27 23:49:44 1995 --- src/libc/dos/dos/truename.c Fri Aug 16 14:49:24 1996 *************** *** 16,21 **** --- 16,22 ---- #include #include #include + #include #include #include #include *************** *** 47,56 **** char * _truename(const char *file, char *buf) { ! __dpmi_regs regs; ! unsigned short dos_mem_selector = _dos_ds; ! unsigned short our_mem_selector = _my_ds(); ! int e = errno; char true_name[MAX_TRUE_NAME]; char file_name[MAX_TRUE_NAME], *name_start = file_name, *name_end; --- 48,58 ---- char * _truename(const char *file, char *buf) { ! __dpmi_regs regs; ! unsigned short dos_mem_selector = _dos_ds; ! unsigned short our_mem_selector = _my_ds(); ! int e = errno; ! unsigned use_lfn = _USE_LFN; char true_name[MAX_TRUE_NAME]; char file_name[MAX_TRUE_NAME], *name_start = file_name, *name_end; *************** *** 101,109 **** dos_mem_selector, __tb, strlen(name_start) + 1); /* Call DOS INT 21H undocumented function 60h. */ ! if(_USE_LFN) { regs.x.ax = 0x7160; ! regs.x.cx = 2; /* Get Long Path Name */ } else regs.x.ax = 0x6000; --- 103,111 ---- dos_mem_selector, __tb, strlen(name_start) + 1); /* Call DOS INT 21H undocumented function 60h. */ ! if(use_lfn) { regs.x.ax = 0x7160; ! regs.x.cx = 2; /* Get Long Path Name (if there is one) */ } else regs.x.ax = 0x6000; *** src/libc/dos/io/_open.c~0 Sat Nov 25 22:47:48 1995 --- src/libc/dos/io/_open.c Fri Aug 16 14:51:30 1996 *************** *** 14,19 **** --- 14,20 ---- { __dpmi_regs r; int rv; + int use_lfn = _USE_LFN; if (filename == 0) { *************** *** 25,31 **** return rv; _put_path(filename); ! if(_USE_LFN) { r.x.ax = 0x716c; r.x.bx = oflag; r.x.dx = 1; /* Open existing file */ --- 26,32 ---- return rv; _put_path(filename); ! if(use_lfn) { r.x.ax = 0x716c; r.x.bx = oflag; r.x.dx = 1; /* Open existing file */ *** src/libc/dos/io/_creat.c~0 Sat Nov 25 21:02:48 1995 --- src/libc/dos/io/_creat.c Sat Aug 10 23:45:54 1996 *************** *** 13,18 **** --- 13,19 ---- { __dpmi_regs r; int rv; + unsigned use_lfn = _USE_LFN; if (filename == 0) { *************** *** 24,30 **** return rv; _put_path(filename); ! if(_USE_LFN) { r.x.ax = 0x716c; r.x.bx = 0x0002; /* open r/w */ r.x.dx = 0x0012; /* Create, truncate if exists */ --- 25,31 ---- return rv; _put_path(filename); ! if(use_lfn) { r.x.ax = 0x716c; r.x.bx = 0x0002; /* open r/w */ r.x.dx = 0x0012; /* Create, truncate if exists */ *** src/libc/dos/io/_chmod.c~0 Thu Aug 10 06:19:38 1995 --- src/libc/dos/io/_chmod.c Fri Aug 16 14:50:20 1996 *************** *** 4,9 **** --- 4,10 ---- #include #include #include + #include #include int *** src/libc/dos/lfn/_use_lfn.c~0 Wed Jan 24 03:25:04 1996 --- src/libc/dos/lfn/_use_lfn.c Fri Aug 16 13:21:26 1996 *************** *** 1,52 **** /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include #include #include #include #include ! #include #include ! static int use_lfn_bss_count = -1; ! static char use_lfn = 2; /* 0 = no, 1 = yes, 2 = find out */ ! char _use_lfn(void) { ! if (use_lfn_bss_count != __bss_count) { ! __dpmi_regs r; ! char *lfnenv; ! use_lfn_bss_count = __bss_count; ! if(_crt0_startup_flags & _CRT0_FLAG_NO_LFN) { ! use_lfn = 0; ! return 0; } ! lfnenv = getenv("LFN"); ! if(lfnenv && (tolower(lfnenv[0]) == 'n')) { ! _crt0_startup_flags |= _CRT0_FLAG_NO_LFN; ! use_lfn = 0; return 0; } - - r.x.ax = 0x7147; - r.x.dx = 0; /* Current drive */ - r.x.si = __tb_offset + _go32_info_block.size_of_transfer_buffer - FILENAME_MAX; /* end */ - r.x.ds = __tb_segment; - r.x.ss = r.x.sp = 0; - r.x.flags = 1; /* Set the carry */ - __dpmi_simulate_real_mode_interrupt(0x21, &r); - if(r.x.ax == 0x7100 || r.x.flags & 1) - { - _crt0_startup_flags |= _CRT0_FLAG_NO_LFN; - use_lfn = 0; - } else - use_lfn = 1; } ! return use_lfn; } --- 1,193 ---- /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ + #include #include #include #include + #include + #include + #include #include #include #include ! #include #include + #include + #include ! static int use_lfn_bss_count = -1; /* if we are restarted (emacs) */ ! static unsigned filesystem_flags = _FILESYS_UNKNOWN; ! static unsigned last_env_changed = 0; ! static int last_drive; /* drive *letter*, not *number*! */ ! /* Return the parameters of the filesystem where PATH resides. */ ! unsigned ! _get_volume_info (const char *path, int *maxfile, int *maxpath, char *fsystype) { ! __dpmi_regs r; ! unsigned long tbuf_la = __tb & 0xfffff; ! unsigned long tbuf_seg = tbuf_la >> 4; ! unsigned retval; ! ! if (path && *path) { ! if (path[1] == ':') ! { ! dosmemput (path, 3, tbuf_la); ! tbuf_la += 3; ! if (path[2] != '\\') ! _farpokeb(_dos_ds, tbuf_la - 1, '\\'); ! _farpokeb(_dos_ds, tbuf_la++, '\0'); ! } ! else if (*path == '\\' && path[1] == '\\') ! { ! int plen = strlen (path) + 1; ! /* FIXME: what should we do with the UNC pathnames like ! "\\machine\vol\path"? We need to know either their ! DOS drive letter or where does the root directory path ! ends. For now, we assume the entire path is the root path. */ ! dosmemput (path, plen, tbuf_la); ! tbuf_la += plen + 1; ! } ! } ! /* No explicit drive, use default drive. */ ! if (tbuf_la == __tb) ! { ! unsigned drv_no; ! ! /* FIXME: can `_dos_getdrive' fail (e.g. no floppy in drive)? */ ! _dos_getdrive(&drv_no); ! _farpokeb(_dos_ds, tbuf_la++, 'A' + drv_no - 1); ! _farpokeb(_dos_ds, tbuf_la++, ':'); ! _farpokeb(_dos_ds, tbuf_la++, '\\'); ! _farpokeb(_dos_ds, tbuf_la++, '\0'); ! } ! ! r.x.ax = 0x71a0; /* Get Volume Information function */ ! r.x.ds = tbuf_seg; /* DS:DX points to root directory name */ ! r.x.dx = 0; ! r.x.es = tbuf_seg; /* ES:DI points to a buffer for filesys name */ ! r.x.di = (tbuf_la - __tb) & 0xffff; ! r.x.cx = 32; /* max size of filesystem name (Interrupt List) */ ! __dpmi_int(0x21, &r); ! ! if ((r.x.flags & 1) == 0 && r.x.ax != 0x7100) ! { ! char *p = fsystype, c; ! ! retval = r.x.bx; ! if (maxfile) ! *maxfile = r.x.cx; ! if (maxpath) ! *maxpath = r.x.dx; ! ! if (fsystype) ! { ! /* Only copy as much as required, in case the ! buffer isn't large enough for 32 bytes. */ ! _farsetsel (_dos_ds); ! while ((c = _farnspeekb (tbuf_la++))) ! *p++ = c; ! *p = '\0'; ! } ! } ! else ! { ! errno = ENOSYS; ! retval = 0; /* meaning none of the features supported */ ! if (maxfile) ! *maxfile = 13; ! if (maxpath) ! *maxpath = 80; ! if (fsystype) ! *fsystype = '\0'; ! } ! ! return retval; ! } ! ! char ! _use_lfn (const char *path) ! { ! int same_drive_as_last_time; ! ! if (_crt0_startup_flags & _CRT0_FLAG_NO_LFN) ! { ! /* Don't update the static counters, so the first time ! after NO_LFN flag is reset, the environment and the ! filesystem will be queried. */ ! return 0; ! } ! ! same_drive_as_last_time = 1; ! if (path) ! { ! /* FIXME: a UNC PATH will always force a call to `_get_volume_info'. */ ! if ((path[1] == ':' && toupper (*path) != last_drive) ! || (*path == '\\' && path[1] == '\\')) ! same_drive_as_last_time = 0; ! else ! { ! unsigned drv_no; ! ! _dos_getdrive(&drv_no); ! if (drv_no - 1 + 'A' != last_drive) ! same_drive_as_last_time = 0; } + } + + if (same_drive_as_last_time + && last_env_changed == __environ_changed + && use_lfn_bss_count == __bss_count + && filesystem_flags != _FILESYS_UNKNOWN) /* paranoia */ + return (filesystem_flags & _FILESYS_LFN_SUPPORTED) != 0; + else + { + char *lfnenv; + + use_lfn_bss_count = __bss_count; + last_env_changed = __environ_changed; ! lfnenv = getenv ("LFN"); ! if(lfnenv && (tolower (lfnenv[0]) == 'n')) { ! filesystem_flags &= ~_FILESYS_LFN_SUPPORTED; ! last_drive = 0; return 0; } } ! ! if (!same_drive_as_last_time || filesystem_flags == _FILESYS_UNKNOWN) ! filesystem_flags = _get_volume_info (path, 0, 0, 0); ! ! return (filesystem_flags & _FILESYS_LFN_SUPPORTED) != 0; } + + #ifdef TEST + + int main (int argc, char *argv[]) + { + char *path = "."; + unsigned flags; + char fsname[32]; + int maxfile, maxpath; + + printf ("_USE_LFN reports %d at startup\n", _USE_LFN); + if (argc > 1) + path = argv[1]; + flags = _get_volume_info (path, &maxfile, &maxpath, fsname); + printf ("Flags: %x, MaxFile: %d, MaxPath: %d, FSName: %s\n", + flags, maxfile, maxpath, fsname); + _crt0_startup_flags |= _CRT0_FLAG_NO_LFN; + printf ("_USE_LFN reports %d when _CRT0_FLAG_NO_LFN is set\n", _USE_LFN); + _crt0_startup_flags &= ~_CRT0_FLAG_NO_LFN; + putenv ("LFN=y"); + printf ("_USE_LFN reports %d when LFN is set to Y\n", _USE_LFN); + putenv ("LFN=n"); + printf ("_USE_LFN reports %d when LFN is set to N\n", _USE_LFN); + return 0; + } + + #endif *** src/libc/dos/lfn/_use_lfn.t~0 Thu Nov 9 02:08:20 1995 --- src/libc/dos/lfn/_use_lfn.txh Sat Aug 17 13:00:20 1996 *************** *** 2,35 **** @subheading Syntax @example ! #include ! int _use_lfn(void); @end example @subheading Description ! This function returns a nonzero value if the low level libc routines should ! try to use the Long File Name (LFN) functions provided with Windows 95. This ! routine can be replaced with one always returning 0 to disable using long ! file names. ! ! Long file names can also be disabled by setting the flag _CRT0_FLAG_NO_LFN in ! _crt0_startup_flags for an image which should not allow use of long file names. ! Long names can be suppressed at runtime on a global basis by setting the ! environment variable LFN to N, i.e. SET LFN=N. This might be needed if a ! distribution expected the truncation of long file names to 8.3 format to ! work. For example, if a C source routine included the file exception.h ! (9 letters) and the file was unzipped as exceptio.h, then GCC would not find ! the file unless the environment variable was set. The environment variable ! can be set in the djgpp.env file to always disable LFN support on any ! system, or can be set in the DOS environment for a short term (single project) ! basis. If you dual boot a system between Windows 95 and DOS, you probably ! should set LFN=n in your djgpp.env file, since long file names would not ! be visable under DOS, and working with the short names under DOS will damage ! the long names when returning to Windows 95. ! @subheading Return Value If LFN APIs are supported and should be used, it returns 1, else 0. --- 2,230 ---- @subheading Syntax @example ! #include ! char _use_lfn(const char *path); @end example @subheading Description ! The @code{_use_lfn} function returns a nonzero value if the low level ! libc routines will use the @dfn{Long File Name} (LFN) functions provided ! with Windows 9x (and other advanced filesystems), when accessing files ! and directories on the same filesystem as @var{path}. @var{path} may be ! any legal pathname; however, the function only needs the name of the ! root directory on the particular drive in question. If @var{path} is a ! @code{NULL} pointer, the function assumes that all the filesystems ! support (or do not support) LFN in the same manner, and returns the info ! pertinent to the last filesystem that was queried; this usually makes ! the call faster. Note that on Windows 95 you don't need to distinguish ! between different drives: they all support LFN API. If @var{path} does ! not specify the drive explicitly, the current drive is used. ! ! The header @file{fcntl.h} defines a macro @code{_USE_LFN}; applications ! should use this macro instead of calling @code{_use_lfn} directly. That ! is so this routine could be replaced with one which always returns 0 to ! disable using long file names. Calling @code{_USE_LFN} also makes the ! code more portable to other operating systems, where the macro can be ! redefined to whatever is appropriate for that environment (e.g., it ! should be a constant 1 on Unix systems and constant 0 for environments ! that don't support LFN API, like some other MSDOS compilers). ! Currently, @code{_USE_LFN} assumes that LFN API does @emph{not} depend ! on a drive. ! ! Long file names can also be disabled by setting the flag ! @code{_CRT0_FLAG_NO_LFN} in @code{_crt0_startup_flags} for an image ! which should not allow use of long file names. Long names can be ! suppressed at runtime on a global basis by setting the environment ! variable @code{LFN} to @code{N}, i.e. @samp{SET LFN=N}. This might be ! needed if a distribution expected the truncation of long file names to ! 8.3 format to work. For example, if a C source routine included the ! file exception.h (9 letters) and the file was unzipped as exceptio.h, ! then GCC would not find the file unless you set @samp{LFN=n}. The ! environment variable can be set in the @file{DJGPP.ENV} file to always ! disable LFN support on any system, or can be set in the DOS environment ! for a short term (single project) basis. If you dual boot a system ! between Windows 95 and DOS, you probably should set @samp{LFN=n} in your ! @file{DJGPP.ENV} file, since long file names would not be visible under ! DOS, and working with the short names under DOS will damage the long ! names when returning to Windows 95. ! @subheading Return Value If LFN APIs are supported and should be used, it returns 1, else 0. + Note that if the @code{_CRT0_FLAG_NO_LFN} bit is set, or @code{LFN} is + set to @code{N} or @code{n} in the environment, both @code{_use_lfn} and + @code{_USE_LFN} will always return 0 without querying the filesystem. + You can reset the @code{_CRT0_FLAG_NO_LFN} bit at runtime to force + filesystem to be queried. + + @subheading Example + + @example + + #include + #include + + int fd = creat (_USE_LFN ? "MyCurrentJobFile.Text" : "currjob.txt", + S_IRUSR | S_IWUSR); + + @end example + + @c -------------------------------------------------------------------- + + @node _get_volume_info, file system + @subheading Syntax + + @example + #include + + unsigned _get_volume_info (const char *path, + int *max_file_len, int *max_path_len, + char *fsystype); + @end example + + @subheading Description + + This function returns filesystem information about the volume where + @var{path} resides. Only the root directory name part is actually used; + if @var{path} does not specify the drive explicitly, or is a @code{NULL} + pointer, the current drive is used. Upon return, the variable pointed + to by @var{*max_file_len} contains the maximum length of a filename + (including the terminating zero), the variable pointed to by + @var{*max_path_len} contains the maximum length of a pathname (including + the terminating zero), and a string that identifies the filesystem type + (e.g., ``FAT'', ``NTFS'' etc.) is placed into the buffer pointed to by + @var{*fsystype}, which should be long enough (32 bytes are usually + enough). If any of these pointers is a @code{NULL} pointer, it will be + ignored. The function returns various flags that describe features + supported by the given filesystem as a bit-mapped number. The following + bits are currently defined: + + @table @code + @item _FILESYS_CASE_SENSITIVE + Specifies that file searches are case-sensitive. + + @item _FILESYS_CASE_PRESERVED + Filename letter-case is preserved in directory entries. + + @item _FILESYS_UNICODE + Filesystem uses Unicode characters in file and directory names. + + @item _FILESYS_LFN_SUPPORTED + Filesystem supports the @dfn{Long File Name} (LFN) API. + + @item _FILESYS_VOL_COMPRESSED + This volume is compressed. + @end table + + + @subheading Return value + + A combination of the above bits. + + @c ----------------------------------------------------------------------- + + @node _preserve_fncase, file system + @subheading Syntax + + @example + #include + + char _preserve_fncase (void); + @end example + + @subheading Description + + This function returns a non-zero value if letter-case in filenames + should be preserved. It is used by library functions that get filenames + from the operating system (like @code{readdir}, @code{_fixpath} and + others). The usual behavior of these functions (when + @code{_preserve_fncase} returns zero) is to down-case 8+3 DOS-style + filenames, but leave alone the letter-case in long filenames when these + are supported (@pxref{_use_lfn}). This can be changed by either setting + @code{_CRT0_FLAG_PRESERVE_FILENAME_CASE} bit in the + @code{_crt0_startup_flags} variable (@pxref{_crt0_startup_flags}), or by + setting the @code{FNCASE} environment variable to @kbd{Y} at run time. + You might need such a setup e.g. on Windows 95 if you want to see files + with names like @file{README} and @file{FAQ} listed in upper-case (for + this to work, you will have to manually rename all the other files with + 8+3 DOS-style names to lower-case names). When the case in filenames is + preserved, all filenames will be returned in upper case on MSDOS (and + other systems that don't support long filenames), or if the environment + variable @code{LFN} is set to @kbd{N} on systems that support LFN. That + is because this is how filenames are stored in the DOS directory entries. + + @subheading Return value + + Zero when 8+3 filenames should be converted to lower-case, non-zero + otherwise. + + @c ----------------------------------------------------------------------- + + @node _lfn_gen_short_fname, file system + @subheading Syntax + + @example + #include + + char _lfn_gen_short_fname (const char *long_fname, char *short_fname); + @end example + + @subheading Description + + This function generates a short (8+3) filename alias for the long + filename pointed to by @var{long_fname} and puts it into the buffer + pointed to by @var{short_fname}. It uses the same algorithm that + Windows 9x uses, with the exception that the returned short name will + never have a numeric tail, because this function doesn't check the + directory to see whether the generated short name will collide with + any other file in the directory. Note that @var{long_fname} must + contain only the name part of a file; elements of a full pathname + (like @kbd{:} or @kbd{/} are not allowed (they will cause the + function to fail). @var{short_fname} will be returned upper-cased, + since that is how 8+3 filenames are stored in directory entries. + + When the LFN API is not supported (@pxref{_use_lfn}), the function + simply converts up to 12 characters of @var{long_fname} to upper-case + and returns that. It will do the same if @var{long_fname} includes any + characters illegal in a filename. + + You might need to call this function if you want to know whether a given + filename is valid on MSDOS: if a case-sensitive string comparison + function such as @code{strcmp} (@pxref{strcmp}) returns a 0 when it + compares the original long filename with the short one returned by + @code{_lfn_gen_short_fname}, then the filename is a valid DOS name. + (Note that if @var{long_fname} is in lower case, it might not compare + equal with @var{short_fname} because of the case difference.) + + @subheading Return value + + The function returns a pointer to @var{short_fname}. + + @subheading Example + + @example + #include + #include + #include + + int dos_check (char *fname) + @{ + char fshort[13]; + int retval; + + if (stricmp (_lfn_gen_short_fname (fname, fshort), fname) == 0) + @{ + printf ("%s is a valid MSDOS 8+3 filename\n", fname); + retval = 1; + @} + else + @{ + printf ("%s will have to be changed for MSDOS\n", fname); + retval = 0; + @} + return retval; + @} + @end example *** src/libc/dos/lfn/lfnshort.c~0 Sat Aug 17 12:23:04 1996 --- src/libc/dos/lfn/lfnshort.c Wed Aug 14 10:25:20 1996 *************** *** 0 **** --- 1,81 ---- + #include + #include + #include + #include + #include + #include + + static int + msdos_toupper_fname (int c) + { + return (c >= 'a' && c <= 'z') ? toupper (c) : c; + } + + char * + _lfn_gen_short_fname (const char *long_fname, char *short_fname) + { + __dpmi_regs r; + unsigned long tbuf = __tb & 0xfffff; + + r.x.ax = 0x7100; + if (_USE_LFN) + { + dosmemput (long_fname, strlen (long_fname) + 1, tbuf); + r.x.ax = 0x71a8; + r.x.ds = tbuf >> 4; + r.x.si = 0; + r.x.es = r.x.ds; + r.x.di = 260; + r.x.dx = 0x0011; /* DH=01 would be better, but it's buggy */ + __dpmi_int (0x21, &r); + } + + if ((r.x.flags & 1) == 0 && r.x.ax != 0x7100) + { + char buf[13], *s = buf, *d = short_fname; + + dosmemget (tbuf + 260, sizeof buf, buf); + + /* The short name in BUF is ASCIZ in the FCB format. + Convert to 8.3 filename. */ + while (s - buf < 8 && *s && *s != ' ') + *d++ = *s++; + while (*s && *s == ' ') + s++; + if (*s) + { + *d++ = '.'; + while (*s && *s != ' ') + *d++ = *s++; + } + *d = '\0'; + } + else + { + const char *s = long_fname; + char *d = short_fname; + + while ((*d++ = msdos_toupper_fname (*s++))) + if (d - short_fname >= 12) + { + *d = '\0'; + break; + } + } + return short_fname; + } + + #ifdef TEST + + #include + + int main (int argc, char *argv[]) + { + char sh[13]; + if (argc > 1) + printf ("Orig: %s\nShort: %s\n", + argv[1], _lfn_gen_short_fname(argv[1], sh)); + return 0; + } + + #endif *** src/libc/dos/lfn/fncase.c~0 Sat Aug 17 12:23:14 1996 --- src/libc/dos/lfn/fncase.c Fri Aug 16 13:20:08 1996 *************** *** 0 **** --- 1,15 ---- + /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ + #include + #include + #include + #include + #include + + char + _preserve_fncase (void) + { + char *ep; + + return ((_crt0_startup_flags & _CRT0_FLAG_PRESERVE_FILENAME_CASE) + || ((ep = getenv ("FNCASE")) && tolower (*ep) == 'y')); + } *** src/libc/posix/dirent/opendir.c~0 Tue Jan 16 02:38:34 1996 --- src/libc/posix/dirent/opendir.c Fri Aug 16 13:43:44 1996 *************** *** 3,13 **** --- 3,15 ---- #include #include #include + #include #include #include #include #include #include + #include #include "dirstruc.h" DIR * *************** *** 26,40 **** } dir->flags = __opendir_flags; /* Make absolute path */ ! _fixpath (name, dir->name); /* Ensure that directory to be accessed exists */ if (access(dir->name, D_OK)) { ! free (dir->name); ! free (dir); return 0; } --- 28,44 ---- } dir->flags = __opendir_flags; + if (!(__opendir_flags & __OPENDIR_PRESERVE_CASE) && _preserve_fncase()) + dir->flags |= __OPENDIR_PRESERVE_CASE; /* Make absolute path */ ! _fixpath(name, dir->name); /* Ensure that directory to be accessed exists */ if (access(dir->name, D_OK)) { ! free(dir->name); ! free(dir); return 0; } *** src/libc/posix/dirent/readdir.c~0 Thu May 25 06:19:46 1995 --- src/libc/posix/dirent/readdir.c Tue Aug 13 21:22:06 1996 *************** *** 2,7 **** --- 2,8 ---- #include #include #include + #include #include #include #include "dirstruc.h" *************** *** 29,41 **** return 0; } dir->num_read ++; - strcpy(dir->de.d_name, dir->ff.ff_name); - dir->de.d_namlen = strlen(dir->de.d_name); if (!(dir->flags & __OPENDIR_PRESERVE_CASE)) { ! char *cp; ! for (cp=dir->de.d_name; *cp; cp++) ! *cp = tolower(*cp); } return &dir->de; } --- 30,45 ---- return 0; } dir->num_read ++; if (!(dir->flags & __OPENDIR_PRESERVE_CASE)) { ! char *cp, fsh[13]; ! ! if (!strcmp(_lfn_gen_short_fname(dir->ff.ff_name, fsh), dir->ff.ff_name)) ! for (cp=dir->ff.ff_name; *cp; cp++) ! if (*cp >= 'A' && *cp <= 'Z') ! *cp += 'a' - 'A'; } + strcpy(dir->de.d_name, dir->ff.ff_name); + dir->de.d_namlen = strlen(dir->de.d_name); return &dir->de; } *** src/libc/posix/glob/glob.c~1 Sun Jun 18 05:51:58 1995 --- src/libc/posix/glob/glob.c Sat Aug 17 13:11:22 1996 *************** *** 5,13 **** --- 5,15 ---- #include #include #include + #include #include #include #include + #include typedef struct Save { struct Save *prev; *************** *** 20,38 **** static int (*errfunc)(const char *epath, int eerno); static char *pathbuf; static int wildcard_nesting; ! static char use_lower_case; static char slash; ! static int glob2(const char *pattern, char *epathbuf); static int add(const char *path); static int str_compare(const void *va, const void *vb); static int add(const char *path) { Save *sp; for (sp=save_list; sp; sp=sp->prev) ! if (strcmp(sp->entry, path) == 0) return 0; sp = (Save *)malloc(sizeof(Save)); if (sp == 0) --- 22,49 ---- static int (*errfunc)(const char *epath, int eerno); static char *pathbuf; static int wildcard_nesting; ! static char use_lfn; ! static char preserve_case; static char slash; ! static int glob2(const char *pattern, char *epathbuf, int lower, int caseless); ! static int glob_dirs(const char *rest, char *epathbuf, int first, int lower, int caseless); static int add(const char *path); static int str_compare(const void *va, const void *vb); + /* `tolower' might depend on the locale. We don't want to. */ + static int + msdos_tolower_fname (int c) + { + return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c; + } + static int add(const char *path) { Save *sp; for (sp=save_list; sp; sp=sp->prev) ! if (stricmp(sp->entry, path) == 0) return 0; sp = (Save *)malloc(sizeof(Save)); if (sp == 0) *************** *** 52,58 **** } static int ! glob_dirs(const char *rest, char *epathbuf, int first) /* rest is ptr to null or ptr after slash, bp after slash */ { struct ffblk ff; int done; --- 63,70 ---- } static int ! glob_dirs(const char *rest, char *epathbuf, int first, /* rest is ptr to null or ptr after slash, bp after slash */ ! int lower, int caseless) { struct ffblk ff; int done; *************** *** 64,70 **** { if (*rest) { ! glob2(rest, epathbuf); } else { --- 76,83 ---- { if (*rest) { ! if (glob2(rest, epathbuf, lower, caseless) == GLOB_NOSPACE) ! return GLOB_NOSPACE; } else { *************** *** 79,85 **** else epathbuf[-1] = 0; if (__file_exists(pathbuf)) ! add(pathbuf); epathbuf[-1] = sl; } } --- 92,99 ---- else epathbuf[-1] = 0; if (__file_exists(pathbuf)) ! if (add(pathbuf)) ! return GLOB_NOSPACE; epathbuf[-1] = sl; } } *************** *** 88,102 **** done = findfirst(pathbuf, &ff, FA_DIREC); while (!done) { if ((ff.ff_name[0] != '.') && (ff.ff_attrib & FA_DIREC)) { int i; char *tp; ! if (use_lower_case) for (i=0; ff.ff_name[i] && i<13; i++) ! ff.ff_name[i] = tolower(ff.ff_name[i]); ! /* printf("found `%s' `%s'\n", pathbuf, ff.ff_name); */ strcpy(epathbuf, ff.ff_name); tp = epathbuf + strlen(epathbuf); --- 102,120 ---- done = findfirst(pathbuf, &ff, FA_DIREC); while (!done) { + char short_name[13]; + if ((ff.ff_name[0] != '.') && (ff.ff_attrib & FA_DIREC)) { int i; char *tp; ! /* Long directory names are never lower-cased! */ ! if (lower ! && !strcmp(ff.ff_name, _lfn_gen_short_fname(ff.ff_name, short_name))) for (i=0; ff.ff_name[i] && i<13; i++) ! ff.ff_name[i] = msdos_tolower_fname(ff.ff_name[i]); ! /* printf("found `%s' `%s'\n", pathbuf, ff.ff_name); */ strcpy(epathbuf, ff.ff_name); tp = epathbuf + strlen(epathbuf); *************** *** 106,122 **** wildcard_nesting++; if (*rest) { ! glob2(rest, tp); } else { if (!(flags & GLOB_MARK)) tp[-1] = 0; ! add(pathbuf); tp[-1] = slash; } *tp = 0; ! glob_dirs(rest, tp, 0); wildcard_nesting--; } done = findnext(&ff); --- 124,143 ---- wildcard_nesting++; if (*rest) { ! if (glob2(rest, tp, lower, caseless) == GLOB_NOSPACE) ! return GLOB_NOSPACE; } else { if (!(flags & GLOB_MARK)) tp[-1] = 0; ! if (add(pathbuf)) ! return GLOB_NOSPACE; tp[-1] = slash; } *tp = 0; ! if (glob_dirs(rest, tp, 0, lower, caseless) == GLOB_NOSPACE) ! return GLOB_NOSPACE; wildcard_nesting--; } done = findnext(&ff); *************** *** 125,131 **** } static int ! glob2(const char *pattern, char *epathbuf) /* both point *after* the slash */ { const char *pp, *pslash; char *bp; --- 146,153 ---- } static int ! glob2(const char *pattern, char *epathbuf, /* both point *after* the slash */ ! int lower, int caseless) { const char *pp, *pslash; char *bp; *************** *** 135,146 **** if (strcmp(pattern, "...") == 0) { ! return glob_dirs(pattern+3, epathbuf, 1); } if (strncmp(pattern, "...", 3) == 0 && (pattern[3] == '\\' || pattern[3] == '/')) { slash = pattern[3]; ! return glob_dirs(pattern+4, epathbuf, 1); } *epathbuf = 0; --- 157,168 ---- if (strcmp(pattern, "...") == 0) { ! return glob_dirs(pattern+3, epathbuf, 1, lower, caseless); } if (strncmp(pattern, "...", 3) == 0 && (pattern[3] == '\\' || pattern[3] == '/')) { slash = pattern[3]; ! return glob_dirs(pattern+4, epathbuf, 1, lower, caseless); } *epathbuf = 0; *************** *** 178,187 **** break; } ! else if (islower(*pp)) ! use_lower_case = 1; ! else if (isupper(*pp)) ! use_lower_case = 0; *bp++ = *pp++; } --- 200,219 ---- break; } ! /* Upper-case or mixed-case patterns force case-sensitive ! matches in `fnmatch' for LFN filesystems. They also ! suppress downcasing 8+3 filenames (on all filesystems). */ ! else if (!preserve_case) ! { ! if (*pp >= 'A' && *pp <= 'Z') ! { ! if (use_lfn) ! caseless = 0; ! lower = 0; ! } ! else if (*pp >= 'a' && *pp <= 'z') ! lower = 1; ! } *bp++ = *pp++; } *************** *** 190,196 **** if (*pp == 0) /* end of pattern? */ { if (wildcard_nesting==0 || __file_exists(pathbuf)) ! add(pathbuf); return 0; } /* printf("glob2: initial segment is `%s'\n", pathbuf); */ --- 222,229 ---- if (*pp == 0) /* end of pattern? */ { if (wildcard_nesting==0 || __file_exists(pathbuf)) ! if (add(pathbuf)) ! return GLOB_NOSPACE; return 0; } /* printf("glob2: initial segment is `%s'\n", pathbuf); */ *************** *** 204,220 **** } for (pslash = pp; *pslash && *pslash != '\\' && *pslash != '/'; pslash++) ! { ! if (islower(*pslash)) ! use_lower_case = 1; ! else if (isupper(*pslash)) ! use_lower_case = 0; ! } if (*pslash) slash = *pslash; my_pattern = (char *)alloca(pslash - pp + 1); if (my_pattern == 0) ! return 0; strncpy(my_pattern, pp, pslash - pp); my_pattern[pslash-pp] = 0; --- 237,259 ---- } for (pslash = pp; *pslash && *pslash != '\\' && *pslash != '/'; pslash++) ! if (!preserve_case) ! { ! if (*pslash >= 'A' && *pslash <= 'Z') ! { ! if (use_lfn) ! caseless = 0; ! lower = 0; ! } ! else if (*pslash >= 'a' && *pslash <= 'z') ! lower = 1; ! } ! if (*pslash) slash = *pslash; my_pattern = (char *)alloca(pslash - pp + 1); if (my_pattern == 0) ! return GLOB_NOSPACE; strncpy(my_pattern, pp, pslash - pp); my_pattern[pslash-pp] = 0; *************** *** 222,228 **** if (strcmp(my_pattern, "...") == 0) { ! glob_dirs(*pslash ? pslash+1 : pslash, bp, 1); return 0; } --- 261,268 ---- if (strcmp(my_pattern, "...") == 0) { ! if (glob_dirs(*pslash ? pslash+1 : pslash, bp, 1, lower, caseless) == GLOB_NOSPACE) ! return GLOB_NOSPACE; return 0; } *************** *** 232,243 **** while (!done) { int i; if (ff.ff_name[0] != '.') { ! if (use_lower_case) for (i=0; ff.ff_name[i] && i<13; i++) ! ff.ff_name[i] = tolower(ff.ff_name[i]); ! if (fnmatch(my_pattern, ff.ff_name, FNM_NOESCAPE|FNM_PATHNAME|FNM_NOCASE) == 0) { strcpy(bp, ff.ff_name); if (*pslash) --- 272,288 ---- while (!done) { int i; + char fshort[13]; if (ff.ff_name[0] != '.') { ! /* Long filenames are never lower-cased! */ ! if (lower ! && !strcmp(ff.ff_name, _lfn_gen_short_fname(ff.ff_name, fshort))) for (i=0; ff.ff_name[i] && i<13; i++) ! ff.ff_name[i] = msdos_tolower_fname(ff.ff_name[i]); ! ! if (fnmatch(my_pattern, ff.ff_name, ! FNM_NOESCAPE|FNM_PATHNAME|(caseless ? FNM_NOCASE : 0)) == 0) { strcpy(bp, ff.ff_name); if (*pslash) *************** *** 247,253 **** *tp = 0; /* printf("nest: `%s' `%s'\n", pslash+1, pathbuf); */ wildcard_nesting++; ! glob2(pslash+1, tp); wildcard_nesting--; } else --- 292,299 ---- *tp = 0; /* printf("nest: `%s' `%s'\n", pslash+1, pathbuf); */ wildcard_nesting++; ! if (glob2(pslash+1, tp, lower, caseless) == GLOB_NOSPACE) ! return GLOB_NOSPACE; wildcard_nesting--; } else *************** *** 259,265 **** bp[strlen(bp)] = slash; bp[strlen(bp)+1] = 0; } ! add(pathbuf); } } } --- 305,312 ---- bp[strlen(bp)] = slash; bp[strlen(bp)+1] = 0; } ! if (add(pathbuf)) ! return GLOB_NOSPACE; } } } *************** *** 287,301 **** wildcard_nesting = 0; save_count = 0; save_list = 0; ! use_lower_case = 1; slash = '/'; ! glob2(_pattern, pathbuf); if (save_count == 0) { if (flags & GLOB_NOCHECK) ! add(_pattern); else return GLOB_NOMATCH; } --- 334,355 ---- wildcard_nesting = 0; save_count = 0; save_list = 0; ! use_lfn = _USE_LFN; ! preserve_case = _preserve_fncase(); slash = '/'; ! if (glob2(_pattern, pathbuf, preserve_case ? 0 : 1, preserve_case ? 0 : 1) == GLOB_NOSPACE) ! { ! return GLOB_NOSPACE; ! } if (save_count == 0) { if (flags & GLOB_NOCHECK) ! { ! if (add(_pattern)) ! return GLOB_NOSPACE; ! } else return GLOB_NOMATCH; } *************** *** 309,322 **** { _pglob->gl_pathv = (char **)realloc(_pglob->gl_pathv, (l_ofs + _pglob->gl_pathc + save_count + 1) * sizeof(char *)); if (_pglob->gl_pathv == 0) ! return GLOB_ERR; l_ptr = l_ofs + _pglob->gl_pathc; } else { _pglob->gl_pathv = (char* *)malloc((l_ofs + save_count + 1) * sizeof(char *)); if (_pglob->gl_pathv == 0) ! return GLOB_ERR; l_ptr = l_ofs; if (l_ofs) memset(_pglob->gl_pathv, 0, l_ofs * sizeof(char *)); --- 363,376 ---- { _pglob->gl_pathv = (char **)realloc(_pglob->gl_pathv, (l_ofs + _pglob->gl_pathc + save_count + 1) * sizeof(char *)); if (_pglob->gl_pathv == 0) ! return GLOB_NOSPACE; l_ptr = l_ofs + _pglob->gl_pathc; } else { _pglob->gl_pathv = (char* *)malloc((l_ofs + save_count + 1) * sizeof(char *)); if (_pglob->gl_pathv == 0) ! return GLOB_NOSPACE; l_ptr = l_ofs; if (l_ofs) memset(_pglob->gl_pathv, 0, l_ofs * sizeof(char *)); *** src/libc/posix/glob/glob.t~1 Sat Mar 9 15:09:30 1996 --- src/libc/posix/glob/glob.txh Fri Aug 16 13:59:28 1996 *************** *** 137,145 **** @item GLOB_NOSPACE @item GLOB_ERR ! Not enough memory to accomodate expanded filenames. @end table --- 137,147 ---- @item GLOB_NOSPACE + Not enough memory to accomodate expanded filenames. + @item GLOB_ERR ! Never happens on MSDOS, see above. @end table *************** *** 147,156 **** @code{glob} will not match names of volume labels. ! Filenames are matched case-insensitively. The list of expanded ! filenames will be returned in lower case, if all the characters of the ! pattern (except those between brackets [...]) are lower-case; if they ! are upper-case, the expanded filenames will be also in upper case. @subheading Example --- 149,176 ---- @code{glob} will not match names of volume labels. ! On MSDOS, filenames are always matched case-insensitively. On ! filesystems that preserve letter-case in filenames (such as Windows 9x), ! matches are case-insensitive unless the pattern includes uppercase ! characters. ! ! On MSDOS, the list of expanded filenames will be returned in lower case, ! if all the characters of the pattern (except those between brackets ! [...]) are lower-case; if some of them are upper-case, the expanded ! filenames will be also in upper case. On filesystems that preserve ! letter-case in filenames, long filenames are returned as they are found ! in the directory entry; DOS-style 8+3 filenames are returned as on MSDOS ! (in lower case if the pattern doesn't include any upper-case letters, in ! upper case otherwise). ! ! When the environment variable @samp{LFN} is set to @kbd{n}, @code{glob} ! behaves on Windows 9x exactly as it does on MSDOS. ! ! Setting the environment variable @samp{FNCASE} to @kbd{y}, or setting ! the @code{_CRT0_FLAG_PRESERVE_FILENAME_CASE} bit in the ! @code{_crt0_startup_flags} variable (@pxref{_crt0_startup_flags}) ! suppresses any letter-case conversions in filenames and forces ! case-sensitive filename matching. @xref{_preserve_fncase}. @subheading Example *** src/libc/posix/sys/stat/mkdir.c~0 Sun Oct 29 00:55:42 1995 --- src/libc/posix/sys/stat/mkdir.c Fri Aug 16 14:54:08 1996 *************** *** 5,20 **** #include #include #include #include int mkdir(const char *dirname, mode_t mode) { __dpmi_regs r; _put_path(dirname); ! if(_USE_LFN) r.x.ax = 0x7139; else r.h.ah = 0x39; --- 5,22 ---- #include #include #include + #include #include int mkdir(const char *dirname, mode_t mode) { __dpmi_regs r; + int use_lfn = _USE_LFN; _put_path(dirname); ! if(use_lfn) r.x.ax = 0x7139; else r.h.ah = 0x39; *** src/libc/posix/sys/stat/stat.c~6 Sun Aug 11 18:04:52 1996 --- src/libc/posix/sys/stat/stat.c Fri Aug 16 12:33:24 1996 *************** *** 778,783 **** --- 778,785 ---- char lastc = dos_path[pathlen - 1]; char *search_spec = (char *)alloca(pathlen + 10); /* need only +5 */ int nfiles = 0, nsubdirs = 0, done; + size_t extra = 0; + int add_extra = 0; strcpy(search_spec, dos_path); if (lastc == '/' || lastc == '\\' || lastc == ':') *************** *** 785,811 **** else strcat(search_spec, "\\*.*"); /* Count files and subdirectories. */ for (done = __findfirst(search_spec, &ff_blk, ALL_FILES); !done; done = __findnext(&ff_blk)) { /* Don't count "." and ".." entries. This will show empty directories as size 0. */ ! if (! (ff_blk.ff_name[0] == '.' ! && (ff_blk.ff_name[1] == '\0' ! || (ff_blk.ff_name[1] == '.' ! && ff_blk.ff_name[2] == '\0')))) { nfiles++; if (ff_blk.ff_attrib & 0x10) nsubdirs++; } } statbuf->st_nlink = nsubdirs + 2; if (statbuf->st_size == 0) ! statbuf->st_size = nfiles * sizeof(struct full_dirent); } return 0; --- 787,832 ---- else strcat(search_spec, "\\*.*"); + if (statbuf->st_size == 0 && _USE_LFN) + { + /* VFAT filesystems use additional directory entries to + store the long filenames. */ + char fstype[40]; + + if ((_get_volume_info(dos_path,0,0,fstype) & _FILESYS_LFN_SUPPORTED) + && strncmp(fstype, "FAT", 4) == 0) + add_extra = 1; + } + /* Count files and subdirectories. */ for (done = __findfirst(search_spec, &ff_blk, ALL_FILES); !done; done = __findnext(&ff_blk)) { + register char *fname = ff_blk.ff_name; + /* Don't count "." and ".." entries. This will show empty directories as size 0. */ ! if (! (fname[0] == '.' ! && (fname[1] == '\0' ! || (fname[1] == '.' ! && fname[2] == '\0')))) { + char fn[13]; + nfiles++; if (ff_blk.ff_attrib & 0x10) nsubdirs++; + /* For each 13 characters of the long filename, a + 32-byte directory entry is used. */ + if (add_extra && strcmp(_lfn_gen_short_fname(fname, fn), fname)) + extra += (strlen(fname) + 12) / 13; } } statbuf->st_nlink = nsubdirs + 2; if (statbuf->st_size == 0) ! statbuf->st_size = (nfiles + extra) * sizeof(struct full_dirent); } return 0; *** src/libc/posix/sys/stat/stat.t~1 Sat Apr 27 11:13:40 1996 --- src/libc/posix/sys/stat/stat.txh Sat Aug 17 13:21:08 1996 *************** *** 66,72 **** executables) or run by go32 extender. 4. Size of directories is reported as the number of its files (sans `.' and ! `..' entries) multiplied by 32 bytes (the size of directory entry). 5. Time stamp for root directories is taken from the volume label entry, if that's available; otherwise, it is reported as 1-Jan-1980. --- 66,75 ---- executables) or run by go32 extender. 4. Size of directories is reported as the number of its files (sans `.' and ! `..' entries) multiplied by 32 bytes (the size of directory entry). On FAT ! filesystems that support the LFN API (such as Windows 9x), the reported ! size of the directory accounts for additional space used to store the long ! filenames. 5. Time stamp for root directories is taken from the volume label entry, if that's available; otherwise, it is reported as 1-Jan-1980. *** src/libc/posix/sys/stat/fixpath.c~0 Sun Jan 14 02:04:36 1996 --- src/libc/posix/sys/stat/fixpath.c Fri Aug 16 13:35:10 1996 *************** *** 2,14 **** /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include /* For FILENAME_MAX */ #include /* For errno */ #include /* For strlen() */ #include ! #include /* FOR dpmisim */ #include #include static char *__get_current_directory(char *out, int drive_number); static char * --- 2,20 ---- /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include /* For FILENAME_MAX */ + #include #include /* For errno */ + #include /* For tolower */ #include /* For strlen() */ + #include /* For LFN stuff */ #include ! #include /* For dpmisim */ ! #include /* For crt0 flags */ #include #include + static unsigned use_lfn; + static char *__get_current_directory(char *out, int drive_number); static char * *************** *** 18,24 **** char tmpbuf[FILENAME_MAX]; memset(&r, 0, sizeof(r)); ! if(_USE_LFN) r.x.ax = 0x7147; else r.h.ah = 0x47; --- 24,30 ---- char tmpbuf[FILENAME_MAX]; memset(&r, 0, sizeof(r)); ! if(use_lfn) r.x.ax = 0x7147; else r.h.ah = 0x47; *************** *** 72,78 **** { int drive_number; const char *ip = in; ! char *op = out; /* Add drive specification to output string */ if (((*ip >= 'a' && *ip <= 'z') || --- 78,88 ---- { int drive_number; const char *ip = in; ! char *op = out; ! int preserve_case = _preserve_fncase(); ! char *name_start; ! ! use_lfn = _USE_LFN; /* Add drive specification to output string */ if (((*ip >= 'a' && *ip <= 'z') || *************** *** 92,98 **** r.h.ah = 0x19; __dpmi_int(0x21, &r); drive_number = r.h.al; ! *op++ = drive_number + 'a'; *op++ = ':'; } --- 102,108 ---- r.h.ah = 0x19; __dpmi_int(0x21, &r); drive_number = r.h.al; ! *op++ = drive_number + (drive_number < 26 ? 'a' : 'A'); *op++ = ':'; } *************** *** 139,146 **** /* Null terminate the output */ *op = '\0'; ! /* convert slashes (else we miss some) */ ! for (op=out; *op; op++) if (*op == '\\') *op = '/'; } --- 149,190 ---- /* Null terminate the output */ *op = '\0'; ! /* switch FOO\BAR to foo/bar, downcase where appropriate */ ! for (op = out + 3, name_start = op - 1; *name_start; op++) ! { ! char long_name[FILENAME_MAX], short_name[13]; ! if (*op == '\\') *op = '/'; + if (!preserve_case && (*op == '/' || *op == '\0')) + { + memcpy(long_name, name_start+1, op - name_start - 1); + long_name[op - name_start - 1] = '\0'; + if (!strcmp(_lfn_gen_short_fname(long_name, short_name), long_name)) + { + while (++name_start < op) + if (*name_start >= 'A' && *name_start <= 'Z') + *name_start += 'a' - 'A'; + } + else + name_start = op; + } + else if (*op == '\0') + break; + } } + + #ifdef TEST + + int main (int argc, char *argv[]) + { + char fixed[FILENAME_MAX]; + if (argc > 1) + { + _fixpath (argv[1], fixed); + printf ("You mean %s?\n", fixed); + } + return 0; + } + + #endif *** src/libc/posix/sys/stat/fixpath.t~0 Mon Jul 10 05:40:50 1995 --- src/libc/posix/sys/stat/fixpath.txh Sat Aug 17 13:33:52 1996 *************** *** 9,21 **** @subheading Description ! This function canonacalizes the input path @var{in_path} and stores the result in the buffer pointed to by @var{out_path}. The path is fixed by removing consecutive and trailing slashes, making the path absolute if it's relative, removing "." components, collapsing ".." components, adding a drive specifier if needed, and converting all ! slashes to '/'. @subheading Return Value --- 9,25 ---- @subheading Description ! This function canonicalizes the input path @var{in_path} and stores the result in the buffer pointed to by @var{out_path}. The path is fixed by removing consecutive and trailing slashes, making the path absolute if it's relative, removing "." components, collapsing ".." components, adding a drive specifier if needed, and converting all ! slashes to '/'. DOS-style 8+3 names of directories which are part of ! the pathname, as well as its final filename part, are returned ! lower-cased in @var{out_path}, but long filenames are left intact. ! @xref{_preserve_fncase}, for more details on letter-case conversions in ! filenames. @subheading Return Value *** src/libc/posix/unistd/chdir.c~0 Wed Nov 15 03:07:44 1995 --- src/libc/posix/unistd/chdir.c Sun Aug 11 00:44:28 1996 *************** *** 2,14 **** #include #include #include #include #include #include #include int ! chdir (const char *dirname) { __dpmi_regs r; --- 2,15 ---- #include #include #include + #include #include #include #include #include int ! __chdir (const char *dirname) { __dpmi_regs r; *** src/libc/posix/unistd/getcwd.c~0 Sat Nov 25 02:21:24 1995 --- src/libc/posix/unistd/getcwd.c Fri Aug 16 13:38:36 1996 *************** *** 2,19 **** #include #include #include #include #include #include #include #include char * ! getcwd(char *buf, size_t size) { char *bp; __dpmi_regs r; int needed_length, c; if (!size) { --- 2,27 ---- #include #include #include + #include + #include + #include + #include #include #include #include + #include #include #include char * ! __getcwd(char *buf, size_t size) { char *bp; __dpmi_regs r; int needed_length, c; + unsigned use_lfn = _USE_LFN; + int preserve_case = _preserve_fncase(); + char *name_start; if (!size) { *************** *** 35,41 **** size = _go32_info_block.size_of_transfer_buffer; /* get the path into the transfer buffer at least */ ! if(_USE_LFN) r.x.ax = 0x7147; else r.h.ah = 0x47; --- 43,49 ---- size = _go32_info_block.size_of_transfer_buffer; /* get the path into the transfer buffer at least */ ! if(use_lfn) r.x.ax = 0x7147; else r.h.ah = 0x47; *************** *** 67,88 **** } buf[needed_length+3] = 0; ! /* switch FOO\BAR to foo/bar */ ! for (bp = buf+3; *bp; bp++) { if (*bp == '\\') *bp = '/'; ! if (*bp >= 'A' && *bp <= 'Z') ! *bp += 'a' - 'A'; } /* get current drive */ r.h.ah = 0x19; __dpmi_int(0x21, &r); ! buf[0] = r.h.al + 'a'; ! buf[1] = ':'; ! buf[2] = '/'; return buf; } --- 75,121 ---- } buf[needed_length+3] = 0; ! /* switch FOO\BAR to foo/bar, downcase where appropriate */ ! buf[1] = ':'; ! buf[2] = '/'; ! for (bp = buf+3, name_start = bp - 1; *name_start; bp++) { + char long_name[FILENAME_MAX], short_name[13]; + if (*bp == '\\') *bp = '/'; ! if (!preserve_case && (*bp == '/' || *bp == '\0')) ! { ! memcpy(long_name, name_start+1, bp - name_start - 1); ! long_name[bp - name_start - 1] = '\0'; ! if (!strcmp(_lfn_gen_short_fname(long_name, short_name), long_name)) ! { ! while (++name_start < bp) ! if (*name_start >= 'A' && *name_start <= 'Z') ! *name_start += 'a' - 'A'; ! } ! else ! name_start = bp; ! } ! else if (*bp == '\0') ! break; } /* get current drive */ r.h.ah = 0x19; __dpmi_int(0x21, &r); ! buf[0] = r.h.al + (r.h.al < 26 ? 'a' : 'A'); return buf; } + + #ifdef TEST + + int main(void) + { + printf (getcwd ((char *)0, FILENAME_MAX + 10)); + return 0; + } + + #endif *** src/libc/posix/unistd/rmdir.c~0 Thu Aug 10 06:47:24 1995 --- src/libc/posix/unistd/rmdir.c Sun Aug 11 00:49:48 1996 *************** *** 2,7 **** --- 2,8 ---- #include #include #include + #include #include #include #include *** include/libc/stubs.h~0 Sun Jan 14 01:39:40 1996 --- include/libc/stubs.h Sat Jul 27 15:21:44 1996 *************** *** 15,24 **** --- 15,26 ---- /* POSIX functions (for when compiling an ANSI function) */ #define access __access + #define chdir __chdir #define close __close #define dup __dup #define dup2 __dup2 #define fnmatch __fnmatch + #define getcwd __getcwd #define glob __glob #define isatty __isatty #define lseek __lseek *** include/libc/environ.h~0 Sun Jul 28 19:21:44 1996 --- include/libc/environ.h Sun Jul 28 19:57:48 1996 *************** *** 0 **** --- 1,38 ---- + /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ + #ifndef __dj_include_libc_environ_h_ + #define __dj_include_libc_environ_h_ + + #ifdef __cplusplus + extern "C" { + #endif + + #ifndef __dj_ENFORCE_ANSI_FREESTANDING + + #ifndef __STRICT_ANSI__ + + #ifndef _POSIX_SOURCE + + /* This starts at 1 and gets incremented every time some + variable in the environment is added, deleted, or changes + its value. It is meant to be used by functions that depend + on values of environment variables, but don't want to call + `getenv' unnecessarily (example: `__use_lfn'). + + To use this feature, define a static variable that is + initialized to zero, and compare its value with the value of + `__environ_changed': if they differ, you should call `getenv' + (and record the last value of `__environ_changed' you've seen). */ + extern unsigned __environ_changed; + + #endif /* !_POSIX_SOURCE */ + #endif /* !__STRICT_ANSI__ */ + #endif /* !__dj_ENFORCE_ANSI_FREESTANDING */ + + #ifndef __dj_ENFORCE_FUNCTION_CALLS + #endif /* !__dj_ENFORCE_FUNCTION_CALLS */ + + #ifdef __cplusplus + } + #endif + + #endif /* !__dj_include_environ_h_ */ *** include/libc/dosio.h~0 Thu Aug 10 06:18:12 1995 --- include/libc/dosio.h Sat Aug 10 11:59:02 1996 *************** *** 23,32 **** void _put_path(const char *_path); void _put_path2(const char *_path, int _offset); - /* Long file name support (Win95). May make _USE_LFN a variable or disable */ - extern char _use_lfn(void); - #define _USE_LFN _use_lfn() - /* Convenience functions for setting up transfers */ #define __tb_offset 0 /* (__tb & 15) Always paragraph aligned */ --- 23,28 ---- *** include/fcntl.h~0 Sun Aug 27 06:47:24 1995 --- include/fcntl.h Fri Aug 16 13:07:32 1996 *************** *** 90,95 **** --- 90,112 ---- #define _O_BINARY O_BINARY #define _O_NOINHERIT O_NOINHERIT + /* + * Support for advanced filesystems (Windows 9x VFAT, NTFS, LFN etc.) + */ + + #define _FILESYS_UNKNOWN 0x80000000U + #define _FILESYS_CASE_SENSITIVE 0x0001 + #define _FILESYS_CASE_PRESERVED 0x0002 + #define _FILESYS_UNICODE 0x0004 + #define _FILESYS_LFN_SUPPORTED 0x4000 + #define _FILESYS_VOL_COMPRESSED 0x8000 + + unsigned _get_volume_info (const char *_path, int *_max_file_len, int *_max_path_len, char *_filesystype); + char _use_lfn (const char *_path); + char *_lfn_gen_short_fname (const char *_long_fname, char *_short_fname); + char _preserve_fncase (void); + #define _USE_LFN _use_lfn(0) /* assume it's the same on ALL drives */ + #endif /* !_POSIX_SOURCE */ #endif /* !__STRICT_ANSI__ */ #endif /* !__dj_ENFORCE_ANSI_FREESTANDING */ *** include/crt0.h~0 Fri Dec 15 16:19:44 1995 --- include/crt0.h Tue Aug 13 18:37:40 1996 *************** *** 140,145 **** --- 140,158 ---- #define _CRT0_FLAG_LOCK_MEMORY 0x1000 + /* If set, disables all filename letter-case conversion in functions that + ** traverse directories (except findfirst/findnext which always return the + ** filenames exactly as found in the directory entry). When reset, all + ** filenames on 8+3 MSDOS filesystems and DOS-style 8+3 filenames on LFN + ** systems are converted to lower-case by functions such as `readdir', + ** `getcwd', `_fixpath' and `srchpath'. Note that when this flag is set, + ** ALL filenames on MSDOS systems will appear in upper-case, which is + ** both ugly and will break many Unix-born programs. Use only if you know + ** exactly what you are doing! + */ + + #define _CRT0_FLAG_PRESERVE_FILENAME_CASE 0x2000 + /*****************************************************************************\ * Access to the memory handles used by the non-move sbrk algorithm. * The handle is the SI:DI DPMI handle; the address is the offset relative