home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 3 / Meeting_Pearls_III.iso / Pearls / texmf / source / TeX / gcclib / unx2dos.c < prev   
Encoding:
C/C++ Source or Header  |  1991-11-02  |  16.9 KB  |  713 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <ctype.h>
  4. #include <osbind.h>
  5. #include <device.h>
  6. #include <types.h>
  7. #include <dirent.h>
  8. #include "symdir.h"
  9.  
  10. #if 1    /* ndef NAME_MAX */
  11. #define NAME_MAX 32
  12. #endif
  13.  
  14. #ifndef TRUE
  15. #define TRUE 1
  16. #define FALSE 0
  17. #endif
  18.  
  19. char _lOK;            /* symbolic links are OK            */
  20. char *_lDIR = ".dir";        /* name of symbolic link directory file    */
  21. char _lAUTO;            /* make automatic symbolic links        */
  22. char _lHIDE;            /* hide the _lDIR file from searches        */
  23.  
  24. char _tCASE;            /* translate filenames to lower case       */
  25. char _tSLASH;            /* '/' seperates directories like '\' does */
  26. char _tDOTS;            /* if != 0, translate '.' into this        */
  27. char _tUNLIMITED;        /* filenames are not restricted to 8.3       */
  28. char _tDEV;            /* allow /dev/filename for special files   */
  29. char _tROOT;            /* use this drive as default root directory */
  30.  
  31. /* translations to assume if there is no UNIXMODE environment variable
  32.  * it's assumed that the user will set this via a definition
  33.  *    char *_default_unixmode = whatever
  34.  * if no such definition is present (i.e. _default_unixmode is 0) then
  35.  * "/" is assumed
  36.  */
  37.  
  38. char *_default_unixmode;
  39. int _unixmode = 1;    /* this will go away someday */
  40.  
  41. /*
  42.  * _set_unixmode(mode): set Unix emulation modes. Normally "mode" will come
  43.  * from the environment variable UNIXMODE. These settings should only be
  44.  * changed at the explicit request of the user!
  45.  * The characters in "mode" have the following meanings:
  46.  *     b    Open all files in binary mode (no CR, only LF).
  47.  *    c    Assume case is already significant to the operating system.
  48.  *    d    Allow special file names like /dev/console.
  49.  *    r drv    Filenames starting with '/' are rooted from this drive.
  50.  *    u    Assume the OS allows unlimited length file names already.
  51.  *    /    Allow '/' as a directory seperator.
  52.  *    . char    Translate extra dots in a filename to 'char'.
  53.  *    L    Allow symbolic links.
  54.  *
  55.  * The following characters are meaningful only if 'L' is present.
  56.  *    A    Automatically create symbolic links for files whose names
  57.  *        are changed by the _unx2dos routine (e.g. filenames that
  58.  *        don't match the TOS 8 character + 3 character extension
  59.  *        rule). Such automatic symbolic links are much "tighter"
  60.  *        than normal symbolic links, and are effectively aliases
  61.  *        for the old name.
  62.  *    H    Hide the .dir file from directory searches. Explicit
  63.  *        requests for it (e.g. unlink()) still find it, though.
  64.  */
  65.  
  66. void _set_unixmode(mode)
  67.     char *mode;
  68. {
  69.     char c;
  70.  
  71.     if (!mode && !(mode = _default_unixmode)) {
  72. #if 0
  73. /* this is what we will eventually do */
  74.         mode = "/";
  75. #else
  76. /* compatibility with older versions of the library */
  77.         switch(_unixmode) {
  78.         case 0: mode = ""; break;
  79.         case 1: mode = "/"; break;
  80.         case 2: mode = "/.,"; break;
  81.         default: mode = "/.,LAHd"; break;
  82.         }
  83. #endif
  84.     }
  85.     _tSLASH = _tDOTS = _tUNLIMITED = _tDEV = FALSE;
  86.     _tCASE = TRUE;
  87.     _tROOT = 0;
  88.     _lOK = _lHIDE = _lAUTO = FALSE;
  89.  
  90.     while (c = *mode++) {
  91.         switch(c) {
  92.         case 'b': _binmode(TRUE); break;
  93.         case 'c': _tCASE = FALSE; break;
  94.         case 'd': _tDEV = TRUE; break;
  95.         case 'u': _tUNLIMITED = TRUE; break;
  96.         case '/': _tSLASH = TRUE; break;
  97.         case 'L': _lOK = TRUE; break;
  98.         case 'A': _lAUTO = TRUE; break;
  99.         case 'H': _lHIDE = TRUE; break;
  100.         case '.':
  101.             if (*mode && !isalpha(*mode))
  102.                 _tDOTS = *mode++;
  103.             break;
  104.         case 'r':
  105.             if (*mode && isalpha(*mode))
  106.                 _tROOT = *mode++;
  107.         default:
  108.             break;
  109.         }
  110.     }
  111. }
  112.  
  113. /*
  114.  * Pseudo-device interface stuff. New devices can be hooked into the chain
  115.  * that's rooted at __devices. All unx2dos functions use this chain in
  116.  * determining whether files are devices or disk files, as does stat().
  117.  * The major device number of user-supplied devices must *NOT* be 0 or 0xff,
  118.  * both of which are reserved.
  119.  */
  120.  
  121. static struct _device prn_dev = {
  122. "PRN:", "lp", 0xfffd, NULL, NULL, NULL, NULL, NULL, 0
  123. };
  124.  
  125. static struct _device aux_dev = {
  126. "AUX:", "tty1", 0xfffe, NULL, NULL, NULL, NULL, NULL, &prn_dev
  127. };
  128.  
  129. static struct _device con_dev = {
  130. "CON:", "console", 0xffff, NULL, NULL, NULL, NULL, NULL, &aux_dev
  131. };
  132.  
  133. struct _device *__devices = &con_dev;
  134.  
  135. /*
  136.  * install a new device
  137.  */
  138.  
  139. void
  140. _install_device(d)
  141.     struct _device *d;
  142. {
  143.     d->next = __devices;
  144.     __devices = d;
  145. }
  146.  
  147. /*
  148.  * find a device based on it's file descriptor
  149.  */
  150.  
  151. struct _device *
  152. _dev_fd(fd)
  153.     int fd;
  154. {
  155.     struct _device *d;
  156.  
  157.     for (d = __devices; d; d = d->next)
  158.         if (d->dev == fd) break;
  159.     return d;
  160. }
  161.  
  162. /*
  163.  * find a device based on its DOS or UNIX name.
  164.  */
  165.  
  166. struct _device *
  167. _dev_dosname(dosnm)
  168.     const char *dosnm;
  169. {
  170.     struct _device *d;
  171.  
  172.     for (d = __devices; d; d = d->next) {
  173.         if (!strcmp(dosnm, d->dosnm)) break;
  174.     }
  175.     return d;
  176. }
  177.  
  178. struct _device *
  179. _dev_unxname(unm)
  180.     const char *unm;
  181. {
  182.     struct _device *d;
  183.  
  184.     for (d = __devices; d; d = d->next) {
  185.         if (!strcmp(unm, d->unxnm)) break;
  186.     }
  187.     return d;
  188. }
  189.  
  190. /*
  191.  * _uniquefy(name): change name so that it's not the name of any existing
  192.  * file. If the file already exists, then we try changing the file's
  193.  * extension in the following ways:
  194.  * put '$' as the second character
  195.  * put '0'-'9' as the last character (with '$' still in second place).
  196.  * put 'A'-'Z' as the last character (with '$' still in second place).
  197.  * if all of the above fail, put '$$' in the last two characters and
  198.  * give up.
  199.  */
  200.  
  201. void
  202. _uniquefy(dos)
  203.     char *dos;
  204. {
  205.     char *ext, c;
  206.     struct dirent *_do_stat(char *);
  207.  
  208.     if (!_do_stat(dos))    /* file not found, so "dos" is unique */
  209.         return;
  210.  
  211. /* make 'ext' point to the (last two characters of) the extension */
  212.  
  213.     ext = strrchr(dos, '\\'); if (!ext) ext = dos;
  214.     ext = strrchr(ext, '.');
  215.     if (ext && ext[1]) {
  216.         ext+=2;
  217.         if (!*ext) {
  218.             ext[0] = 0; ext[1] = 0;
  219.         }
  220.     }
  221.     else {
  222.         for(ext=dos; *ext; ext++);
  223.         strcpy(ext, ".$0"); ext++;
  224.     }
  225.  
  226.     *ext = '$';
  227.     if (!_do_stat(dos))
  228.         return;
  229.  
  230.     ext[2] = 0;
  231.     for (c = '0'; c <= '9'; c++) {
  232.         ext[1] = c;
  233.         if (!_do_stat(dos))
  234.             return;
  235.     }
  236.     for (c = 'A'; c <= 'Z'; c++) {
  237.         ext[1] = c;
  238.         if (!_do_stat(dos))
  239.             return;
  240.     }
  241.     /* at this point we're sunk; punt and try '$$' in the extension */
  242.     ext[1] = '$';
  243. }
  244.  
  245. /*
  246.  * adjust(name): adjusts a directory entry to be acceptable to DOS.
  247.  * if _tCASE is on, it is converted to upper case.
  248.  * if _tDOTS is on, '.' is converted to _tDOTS wherever necessary to avoid
  249.  *    conflicts with the DOS 8.3 naming convention.
  250.  * unless _tUNLIMITED is set, only an 8 character base name and 3 character
  251.  *    extension are kept.
  252.  * returns: _NM_CHANGE if the name has been transformed in some irrevocable way
  253.  *    i.e. if dos2unx cannot recover the same name
  254.  *          _NM_OK otherwise
  255.  */
  256.  
  257. static int
  258. _adjust(name, result)
  259.     char *name;
  260.     char *result;
  261. {
  262.     char tmp[NAME_MAX];
  263.     char *n, *eos, *lastdot = 0;
  264.     int count, change;
  265.  
  266. #ifdef DEBUG
  267. printf("_adjust(%s)", name); fflush(stdout);
  268. #endif
  269.     strcpy(tmp, name);
  270.     change = 0;
  271.  
  272. /* first, do case and dot conversion */
  273.     for (n = tmp; *n; n++) {
  274.         if (_tDOTS) {
  275.             if(*n == '.')
  276.                 *n = _tDOTS;
  277.             else if (*n == _tDOTS)
  278.                 change++;
  279.         }
  280.         if (_tCASE) {
  281.             if (islower(*n))
  282.                 *n = toupper(*n);
  283.             else if (isupper(*n))
  284.                 change++;
  285.         }
  286.     }
  287.  
  288.     eos = n;    /* end of the "tmp" string */
  289.  
  290. /* if dots were converted, change the last one possible back into a '.'
  291.  * e.g. if _tDOTS == '_', file.c.Z -> file_c_Z -> file.c_Z
  292.  */
  293.     if (_tDOTS && !_tUNLIMITED) {
  294.         for (n = tmp; *n; n++) {
  295.             if (*n == _tDOTS) {
  296.                 if ( (eos - n) <= 4 ) {
  297.                     *n = '.';
  298.                     goto dot_was_set;
  299.                 }
  300.                 else lastdot = n;
  301.             }
  302.         }
  303. /* if we found no good place, and if the name is too long to fit without
  304.  * an extension, we just put the period in the last possible place
  305.  */
  306.         if (strlen(tmp) >= 8 && lastdot)
  307.             *lastdot = '.' ;
  308.     }
  309.  
  310. dot_was_set:
  311. /*
  312.  * here we enforce the 8 character name + 3 character extension rule
  313.  */
  314.     if (_tUNLIMITED)
  315.         strcpy(result, name);
  316.     else {
  317.         eos = result;
  318.         n = tmp;
  319.         for (count = 0; count < 8; count++) {
  320.             if (!*n || *n == '.') break;
  321.             *eos++ = *n++;
  322.         }
  323.         while (*n && *n != '.') {
  324.             change++; n++;
  325.         }
  326.         if (*n == '.') *eos++ = *n++;
  327.         for (count = 0; count < 3; count++) {
  328.             if (!*n) break;
  329.             *eos++ = *n++;
  330.         }
  331.         *eos++ = 0;
  332.         change += strlen(n);
  333.     }
  334. #ifdef DEBUG
  335.     printf("->(%s)\n", result);
  336. #endif
  337.     return change ? _NM_CHANGE : _NM_OK;
  338. }
  339.  
  340. /*
  341.  * _canon(base, path, result, level):
  342.  * find a canonical form for the given path, based in the directory "base"
  343.  * (e.g. the current directory); the result is copied into "result".
  344.  * "level" is the level of recursion, and is used to prevent infinite
  345.  * loops in symbolic links.
  346.  *
  347.  * "base" must already be in a canonical form; the return value from the
  348.  * GEMDOS Dgetpath() call is almost suitable, but the drive letter must
  349.  * be prefixed to it. No checking of "base" is done.
  350.  * Note that "base" and "result" may be pointers to the same array!
  351.  *
  352.  * returns:
  353.  *    _NM_LINK    if the last component is a symbolic link
  354.  *    _NM_OK    if the name of the last component is recoverable by _dos2unx
  355.  *    _NM_CHANGE otherwise
  356.  *
  357.  * Also, the global variables __link_path and __link_name are set
  358.  * to the path of the last filename component, and the name of
  359.  * the file, respectively (the canonical form of the file name
  360.  * to is returned in result, and will NOT be __link_path\__link_name if
  361.  * __link_name was a symbolic link). If it was a symbolic link, __link_flags
  362.  * is set to the flags associated with the link (e.g. whether it was
  363.  * auto-created), and __link_to is set to the link contents, which were
  364.  * followed in the course of creating the canonical name.
  365.  *
  366.  * All this is done so that functions like "creat" and "rename" that need
  367.  * access to the path and "real" name of the file (if it was a symbolic link)
  368.  * don't have to duplicate work we've already done.
  369.  */
  370.  
  371. #define DIRSEP(p) ((p) == '\\' || (_tSLASH && (p) == '/'))
  372. #define MAXRECURSE 12
  373.  
  374. char __link_path[FILENAME_MAX], __link_name[NAME_MAX], __link_to[NAME_MAX];
  375. int __link_flags = 0;
  376.  
  377. static int
  378. _canon(base, path, result, level)
  379.     char *base, *path;
  380.     char *result;
  381.     int level;
  382. {
  383.     char tmp[NAME_MAX], name[NAME_MAX];
  384.     SYMDIR *dir;
  385.     SYMENTRY *ent;
  386.     char *n, *t;
  387.     int found, change = _NM_OK, needschange = _NM_OK;
  388.  
  389. /* FIX_ME: we really ought to flag an error of some sort here */
  390.     if (level > MAXRECURSE) {
  391.         return _NM_OK;
  392.     }
  393.  
  394. #ifdef DEBUG
  395.     printf("_canon: [%s] + [%s]\n", base, path);
  396. #endif
  397.     if (!*path) {
  398.         if (result != base)
  399.             strcpy(result, base);
  400.         return _NM_OK;
  401.     }
  402.  
  403. /* check for paths relative to root of current drive         */
  404. /* if _tROOT is set, then such paths should start at _tROOT     */
  405.  
  406.     if (DIRSEP(path[0])) {
  407.         if (result != base)
  408.             strcpy(result, base);
  409.         if (_tROOT) {
  410.             if (_tCASE)
  411.                 result[0] = toupper(_tROOT);
  412.             else
  413.                 result[0] = _tROOT;
  414.         }
  415.         result[2] = 0;    /* the drive is already in the first part */
  416.         path++;
  417.     }
  418. /* check for absolute paths with drive letter given */
  419.     else if (path[1] == ':') {
  420.         result[0] = _tCASE ? toupper(path[0]) : path[0];
  421.         result[1] = ':';
  422.         result[2] = 0;
  423.         path += 2;
  424.         if (DIRSEP(path[0])) {
  425.             path++;
  426.         }
  427.     }
  428.     else if (result != base)
  429.         strcpy(result, base);
  430.  
  431. /* now path is relative to what's currently in "result" */
  432.  
  433.     while(*path) {
  434. /* get next name in path */
  435.         n = name;
  436. #if 0
  437.         while (*path && !DIRSEP(*path))
  438.             *n++ = *path++;
  439.         *n++ = 0;
  440. #else /* (br) */
  441.         while (*path && !DIRSEP(*path)) {
  442.             if( n >= &name[NAME_MAX-1] )
  443.                 break;
  444.             *n++ = *path++;
  445.         }
  446.         *n = 0;
  447. #endif
  448.         if (*path) path++;
  449.         change = _NM_OK;    /* assume this is a regular name */
  450.  
  451. /* check for "." and ".." */
  452.         if (!strcmp(name, ".")) continue;
  453.         if (!strcmp(name, "..")) {
  454.             n = strrchr(result, '\\');
  455.             if (n) *n = 0;
  456.             continue;
  457.         }
  458.  
  459. /* see if "name" is a symbolic link */
  460.         found = 0;
  461.         dir = _read_symdir(result);
  462. #ifdef DEBUG
  463. if (!dir) printf("unx2dos: _read_symdir(%s) failed\n", result);
  464. #endif
  465.         ent = dir ? dir->s_dir : 0;
  466.  
  467.         while (ent) {
  468.             if (!strcmp(ent->linkname, name)) {
  469.                 change = _NM_LINK;
  470.                 strcpy(__link_to, ent->linkto);
  471. #ifdef DEBUG
  472. printf("...following link (%s)->(%s)\n", name, ent->linkto);
  473. #endif
  474.  
  475.                 if (level == 0) {
  476.                     strcpy(__link_path, result);
  477.                     __link_flags = ent->flags;
  478.                 }
  479. /*
  480.  * note that _free_symdir caches the directories it frees, so it's OK
  481.  * to use ent->linkto afterwards (otherwise we'd have to strdup() it.
  482.  * Also note that we *do* want to free it before recursively calling
  483.  * ourselves; otherwise it won't be in the cache.
  484.  */
  485.                 found = 1;
  486.                 _free_symdir(dir);
  487. /*
  488.  * We should follow normal symbolic links all the way through, since it's
  489.  * OK to have a link to a link.
  490.  * Auto symbolic links, however, must be linked to a real GEMDOS file.
  491.  */
  492.                 if (ent->flags & SD_AUTO) {
  493.                     strcat(result, "\\");
  494.                     _adjust(ent->linkto, tmp);
  495.                     strcat(result, tmp);
  496.                 }
  497.                 else {
  498.                     _canon(result, ent->linkto, result, level+1);
  499.                 }
  500.  
  501.                 break;    /* out of the search */
  502.             }
  503. /*
  504.  * if the name we're searching for is the target of an automatic link,
  505.  * then we should have been using that name instead. to prevent
  506.  * name conflict problems, flag the name as needing to be changed;
  507.  * _unx2dos can then try to sort out what to do.
  508.  */
  509.             else if (_lAUTO && !strcmp(ent->linkto, name)) {
  510.                 if (ent->flags & SD_AUTO)
  511.                     needschange = _NM_CHANGE;
  512.             }
  513.             ent = ent->next;
  514.         }
  515.  
  516. /* if found == 1, then "result" has already been appropriately updated */
  517. /* otherwise, append "name" to path, adjusting appropriately */
  518.         if (!found) {
  519.             _free_symdir(dir);
  520.             strcat(result, "\\");
  521.             change = _adjust(name, tmp);
  522.             strcat(result, tmp);
  523.             if (needschange) change = needschange;
  524.         }
  525.     }
  526.     if (level == 0)
  527.         strcpy(__link_name, name);
  528.     return change;
  529. }
  530.  
  531. /*
  532.  * translate a Unix style filename to a DOS one 
  533.  * returns:
  534.  * _NM_DEV    if the name was of a device
  535.  * _NM_LINK     if the name is a symbolic link
  536.  * _NM_OK     if the last component can be recovered via _dos2unx
  537.  * _NM_CHANGE    if the last component is irrevocably changed
  538.  */
  539.  
  540. int
  541. _unx2dos(unx, dos)
  542.     const char *unx;
  543.     char *dos;
  544. {
  545.     char path[FILENAME_MAX];
  546.     static char _old_unixmode = 1;
  547.     struct _device *d;
  548.     int change;
  549.  
  550. /* compatibility code: will go away someday soon */
  551.     if (_unixmode != _old_unixmode) {
  552.         _old_unixmode = _unixmode;
  553.         _set_unixmode(NULL);
  554.     }
  555.  
  556. /* check for a TOS device name */
  557.     if (d = _dev_dosname(unx)) {
  558.         strcpy(dos, unx);
  559.         return _NM_DEV;
  560.     }
  561. /* get current directory */
  562.     path[0] = Dgetdrv() + 'A';
  563.     path[1] = ':';
  564.     Dgetpath(path+2, 0);
  565.  
  566.     if (_tDEV && !strncmp(unx, "/dev/", 5)) {
  567.     /* check for a unix device name */
  568.         if (d = _dev_unxname(unx+5)) {
  569.             strcpy(dos, d->dosnm);
  570.             return _NM_DEV;
  571.         }
  572.     /* check for a path like /dev/A/somefile */
  573.         else if (isalpha(unx[5]) && ((unx[6] == '/') || (!unx[6]))) {
  574.             path[0] = unx[5];
  575.             path[2] = 0;
  576.             unx = (unx[6]) ? &unx[7] : &unx[6];
  577.         }
  578.     }
  579.     change = _canon(path, unx, dos, 0);
  580. /*
  581.  * If automatic symbolic links are on, then we should try to remap weird
  582.  * filenames into new, unique ones.
  583.  */
  584.     if (change == _NM_CHANGE && _lOK && _lAUTO) {
  585.         _uniquefy(dos);
  586.     }
  587.     return change;
  588. }
  589.  
  590. /*
  591.  * translate a DOS style filename to Unix. Note that this function does
  592.  * *NOT* look up symbolic links; for that, call _full_dos2unx.
  593.  * The return value may be given a useful purpose someday;
  594.  * for now it's always 0.
  595.  */
  596.  
  597. int
  598. _dos2unx(dos, unx)
  599.     const char *dos;
  600.     char *unx;
  601. {
  602.     char c;
  603. #ifdef DEBUG
  604. char *oldunx = unx;
  605. printf("dos2unx(%s)->", dos); fflush(stdout);
  606. #endif
  607.     while(c = *dos++) {
  608.         if (_tSLASH && c == '\\')
  609.             *unx++ = '/';
  610.         else if (_tDOTS && c == _tDOTS)
  611.             *unx++ = '.';
  612.         else if (_tCASE)
  613.             *unx++ = tolower(c);
  614.         else
  615.             *unx++ = c;
  616.     }
  617.     *unx++ = 0;
  618. #ifdef DEBUG
  619. printf("(%s)\n", oldunx);
  620. #endif
  621.     return 0;
  622. }
  623.  
  624. int
  625. _full_dos2unx(dos, unx)
  626.     char *dos, *unx;
  627. {
  628.     SYMDIR *dir;
  629.     SYMENTRY *ent;
  630.     char *n, *curdir, *lastslash, name[NAME_MAX], tmp[NAME_MAX];
  631.     char slash;
  632.  
  633.     curdir = dos;
  634.     lastslash = 0;
  635.     slash = _tSLASH ? '/' : '\\';
  636.     if (dos[0] && dos[1] == ':') {
  637.         *unx++ = tolower(*dos); dos++;
  638.         *unx++ = *dos++;
  639.     }
  640.     if (*dos == '\\') {
  641.         *unx++ = slash; lastslash = dos; dos++;
  642.     }
  643.     else if (*dos) {    /* something is wrong -- punt */
  644.         return _dos2unx(curdir, unx);
  645.     }
  646.     while (*dos) {
  647.         n = tmp;
  648.         while (*dos && *dos != '\\') {
  649.             *n++ = *dos++;
  650.         }
  651.         *n++ = 0;
  652.         _dos2unx(tmp, name);
  653.         *lastslash = 0;        /* tie off current directory */
  654. /* see if the DOS file has a Unix alias */
  655.         dir = _read_symdir(curdir);
  656.         ent = dir ? dir->s_dir : 0;
  657.         while (ent) {
  658.             if ((ent->flags & SD_AUTO) && 
  659.                 !strcmp(ent->linkto, name)) {
  660.                 strcpy(name, ent->linkname);
  661.                 break;
  662.             }
  663.             ent = ent->next;
  664.         }
  665.         _free_symdir(dir);
  666.         for (n = name; *n; n++)
  667.             *unx++ = *n;
  668.         if (*dos)
  669.             *unx++ = slash;
  670.         *lastslash = '\\';    /* restore path */
  671.         lastslash = dos;
  672.         if (*dos) dos++;
  673.     }
  674.     *unx++ = 0;
  675. }
  676.  
  677. /*
  678.  * the stuff below this line is for compatibility with the old unx2dos, and
  679.  * will go away someday
  680.  */
  681.  
  682. /* system default file name mapping function pointers */
  683. typedef int (*fnmapfunc_t)(const char *, char *);
  684.  
  685. static fnmapfunc_t ux2dos = _unx2dos;
  686. static fnmapfunc_t dos2ux = _dos2unx;
  687.  
  688. /* set user specified filename mapping function
  689.  *    NULL => use system default mapping function
  690.  */
  691. void fnmapfunc(u2dos, dos2u)
  692. fnmapfunc_t u2dos, dos2u;
  693. {
  694.     ux2dos = (u2dos == NULL) ? _unx2dos : u2dos;
  695.     dos2ux = (dos2u == NULL) ? _dos2unx : dos2u;
  696. }
  697.  
  698. /* mapping functions -- call the mapping functions via pointers */
  699.  
  700. int unx2dos(u, d)
  701. const char *u;
  702. char *d;
  703. {
  704.     return (*ux2dos)(u, d);
  705. }
  706.  
  707. int dos2unx(d, u)
  708. const char *d;
  709. char *u;
  710. {
  711.     return (*dos2ux)(d, u);
  712. }
  713.