/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */ /* 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 char * __getcwd(char *buf, size_t size) { char *bp; __dpmi_regs r; size_t needed_length, buf_off; int c; unsigned use_lfn = _USE_LFN; int preserve_case = _preserve_fncase(); char *name_start; if (!size) { errno = EINVAL; return 0; } if (!buf) { buf = (char *)malloc(size); if (!buf) { errno = ENOMEM; return 0; } } /* make sure we don't overrun the TB */ if (size > _go32_info_block.size_of_transfer_buffer) 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; r.h.dl = 0; r.x.si = __tb_offset; r.x.ds = __tb_segment; __dpmi_int(0x21, &r); /* current drive may be invalid (it happens) */ if (r.x.flags & 1) { errno = __doserr_to_errno(r.x.ax); return 0; } /* path is ASCIIZ. Scan it, filling in buf, watching for end of buffer. */ _farsetsel(_dos_ds); needed_length = 0; buf_off = 3; if(use_lfn && _farnspeekb(__tb) == 0 && _get_dos_version(1) == 0x532) { /* Root path under WinNT/2K/XP with lfn (may be silent failure). If the short name equivalent of the current path is greater than 64 characters, Windows 2000 and XP do not return the correct long path name - they return the root directory instead without any failure code. We check for this bug and try and fix the path. */ r.x.ax = 0x7160; r.x.cx = 0x8002; /* Get Long Path Name, using subst drive basis */ r.x.es = __tb_segment; r.x.si = __tb_offset + FILENAME_MAX; r.x.di = __tb_offset; _farnspokew(__tb + FILENAME_MAX, '.'); /* Null terminated */ __dpmi_int(0x21, &r); if (r.x.flags & 1) _farnspokeb(__tb, 0); /* Put back as root if failure */ else buf_off = 0; } while ((c = _farnspeekb(__tb+needed_length))) { if (needed_length + buf_off >= size) { errno = ERANGE; return 0; } buf[buf_off + needed_length] = c; needed_length++; } buf[needed_length + buf_off] = 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(int argc, char** argv) { if(argc > 1) { if(chdir(argv[1]) == -1) perror("Change dir failed"); else printf("Change dir to %s\n",argv[1]); } printf (getcwd ((char *)0, FILENAME_MAX + 10)); return 0; } #endif