home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / preproc / files.c < prev    next >
C/C++ Source or Header  |  2002-01-18  |  19KB  |  788 lines

  1. /*
  2.  * This file contains routines for setting up characters sources from
  3.  *  files. It contains code to handle the search for include files.
  4.  */
  5. #include "../preproc/preproc.h"
  6. /*
  7.  * The following code is operating-system dependent [@files.01].
  8.  *  System header files needed for handling paths.
  9.  */
  10.  
  11. #if PORT
  12.    /* something may be needed */
  13. Deliberate Syntax Error
  14. #endif                    /* PORT */
  15.  
  16. #if AMIGA
  17.    /* Amiga paths are not converted.
  18.     *  Absolute paths have the form Volume:dir/dir/.../file
  19.     */
  20. #define IsRelPath(fname) (strchr(fname, ':') == NULL)
  21. #endif                    /* AMIGA */
  22.  
  23. #if MACINTOSH
  24. char *FileNameMacToUnix(char *fn);
  25. char *FileNameUnixToMac(char *fn);
  26. char *FileNameMacConvert(char *(*func)(char *),char *fn);
  27. #define IsRelPath(fname) (fname[0] != '/')
  28. #endif                    /* MACINTOSH */
  29.  
  30. #if MSDOS
  31. #if MICROSOFT || INTEL_386 || HIGHC_386 || ZTC_386 || WATCOM
  32.    /* nothing is needed */
  33. #endif                    /* MICROSOFT || INTEL_386 || ... */
  34. #if TURBO || BORLAND_286 || BORLAND_386
  35. #include <dir.h>
  36. #endif                    /* TURBO || BORLAND_286 ... */
  37. #define IsRelPath(fname) (fname[0] != '/')
  38. #endif                    /* MSDOS */
  39.  
  40. #if UNIX || VMS
  41. #define IsRelPath(fname) (fname[0] != '/')
  42. #endif                    /* UNIX || VMS */
  43.  
  44. /*
  45.  * End of operating-system specific code.
  46.  */
  47.  
  48. #include "../preproc/pproto.h"
  49.  
  50. /*
  51.  * Prototype for static function.
  52.  */
  53. static void file_src (char *fname, FILE *f);
  54.  
  55. static char **incl_search; /* standard locations to search for header files */
  56.  
  57. /*
  58.  * file_src - set up the structures for a characters source from a file,
  59.  *  putting the source on the top of the stack.
  60.  */
  61. static void file_src(fname, f)
  62. char *fname;
  63. FILE *f;
  64.    {
  65.    union src_ref ref;
  66.  
  67. /*
  68.  * The following code is operating-system dependent [@files.02].
  69.  *  Insure that path syntax is in Unix format for internal consistency
  70.  *  (note, this may not work well on all systems).
  71.  *  In particular, relative paths may begin with a / in AmigaDOS, where
  72.  *  /filename is equivalent to the UNIX path ../filename.
  73.  */
  74.  
  75. #if PORT
  76.    /* something may be needed */
  77. Deliberate Syntax Error
  78. #endif                    /* PORT */
  79.  
  80. #if AMIGA
  81.    /* nothing is needed */
  82. #endif                    /* AMIGA */
  83.  
  84. #if MACINTOSH
  85.    fname = FileNameMacConvert(FileNameMacToUnix,fname);
  86. #endif                    /* MACINTOSH */
  87.  
  88. #if MSDOS
  89.    char *s;
  90.  
  91.    /*
  92.     * Convert back slashes to slashes for internal consistency.
  93.     */
  94.    fname = (char *)strdup(fname);
  95.    for (s = fname; *s != '\0'; ++s)
  96.       if (*s == '\\')
  97.          *s = '/';
  98. #endif                    /* MSDOS */
  99.  
  100. #if UNIX || VMS
  101.    /* nothing is needed */
  102. #endif                    /* UNIX || VMS */
  103.  
  104. /*
  105.  * End of operating-system specific code.
  106.  */
  107.  
  108.    ref.cs = new_cs(fname, f, CBufSize);
  109.    push_src(CharSrc, &ref);
  110.    next_char = NULL;
  111.    fill_cbuf();
  112.    }
  113.  
  114. /*
  115.  * source - Open the file named fname or use stdin if fname is "-". fname
  116.  *  is the first file from which to read input (that is, the outermost file).
  117.  */
  118. void source(fname)
  119. char *fname;
  120.    {
  121.    FILE *f;
  122.  
  123.    if (strcmp(fname, "-") == 0)
  124.       file_src("<stdin>", stdin);
  125.    else {
  126.       if ((f = fopen(fname, "r")) == NULL)
  127.          err2("cannot open ", fname);
  128.       file_src(fname, f);
  129.       }
  130.    }
  131.  
  132. /*
  133.  * include - open the file named fname and make it the current input file.
  134.  */
  135. void include(trigger, fname, system)
  136. struct token *trigger;
  137. char *fname;
  138. int system;
  139.    {
  140.    struct str_buf *sbuf;
  141.    char *s;
  142.    char *path;
  143.    char *end_prfx;
  144.    struct src *sp;
  145.    struct char_src *cs;
  146.    char **prefix;
  147.    FILE *f;
  148.  
  149.    /*
  150.     * See if this is an absolute path name.
  151.     */
  152.    if (IsRelPath(fname)) {
  153.       sbuf = get_sbuf();
  154.       f = NULL;
  155.       if (!system) {
  156.          /*
  157.           * This is not a system include file, so search the locations
  158.           *  of the "ancestor files".
  159.           */
  160.          sp = src_stack;
  161.          while (f == NULL && sp != NULL) {
  162.             if (sp->flag == CharSrc) {
  163.                cs = sp->u.cs;
  164.                if (cs->f != NULL) {
  165.                   /*
  166.                    * This character source is a file.
  167.                    */
  168.                   end_prfx = NULL;
  169.                   for (s = cs->fname; *s != '\0'; ++s)
  170.                      if (*s == '/')
  171.                         end_prfx = s;
  172.                   if (end_prfx != NULL)
  173. #if MACINTOSH
  174.              /*
  175.               * For Mac-style names, don't include the file
  176.               * separator character in the prefix.
  177.               */
  178.                      for (s = cs->fname; s < end_prfx; ++s)
  179. #else                    /* MACINTOSH */
  180.                      for (s = cs->fname; s <= end_prfx; ++s)
  181. #endif                    /* MACINTOSH */
  182.                         AppChar(*sbuf, *s);
  183.                   for (s = fname; *s != '\0'; ++s)
  184.                      AppChar(*sbuf, *s);
  185.                   path = str_install(sbuf);
  186. #if MACINTOSH
  187.           /*
  188.            * Convert UNIX-style path to Mac-style.
  189.            */
  190.           path = FileNameMacConvert(FileNameUnixToMac,path);
  191. #endif                    /* MACINTOSH */
  192.                   f = fopen(path, "r");
  193.                   }
  194.                }
  195.             sp = sp->next;
  196.             }
  197.          }
  198.       /*
  199.        * Search in the locations for the system include files.
  200.        */
  201.       prefix = incl_search;
  202.       while (f == NULL && *prefix != NULL) {
  203.          for (s = *prefix; *s != '\0'; ++s)
  204.             AppChar(*sbuf, *s);
  205.          if (s > *prefix && s[-1] != '/')
  206.             AppChar(*sbuf, '/');
  207.          for (s = fname; *s != '\0'; ++s)
  208.             AppChar(*sbuf, *s);
  209.          path = str_install(sbuf);
  210. #if MACINTOSH
  211.      /*
  212.       * Convert UNIX-style path to Mac-style.
  213.       */
  214.      path = FileNameMacConvert(FileNameUnixToMac,path);
  215. #endif                    /* MACINTOSH */
  216.          f = fopen(path, "r");
  217.          prefix = ++prefix;
  218.          }
  219.       rel_sbuf(sbuf);
  220.       }
  221.    else {                               /* The path is absolute. */
  222.       path = fname;
  223.       f = fopen(path, "r");
  224.       }
  225.  
  226.    if (f == NULL)
  227.       errt2(trigger, "cannot open include file ", fname);
  228.    file_src(path, f);
  229.    }
  230.  
  231. /*
  232.  * init_files - Initialize this module, setting up the search path for
  233.  *  system header files.
  234.  */
  235. void init_files(opt_lst, opt_args)
  236. char *opt_lst;
  237. char **opt_args;
  238.    {
  239.    int n_paths = 0;
  240.    int i, j;
  241.    char *s, *s1;
  242.  
  243. /*
  244.  * The following code is operating-system dependent [@files.03].
  245.  *  Determine the number of standard locations to search for
  246.  *  header files and provide any declarations needed for the code
  247.  *  that establishes these search locations.
  248.  */
  249.  
  250. #if PORT
  251.    /* probably needs something */
  252. Deliberate Syntax Error
  253. #endif                    /* PORT */
  254.  
  255. #if VMS
  256.    char **syspaths;
  257.    int  vmsi;
  258.  
  259.    n_paths = vmsi = 0;
  260.    syspaths = alloc(2 * sizeof(char *));
  261.    if (syspaths[n_paths] = getenv("VAXC$INCLUDE")) {
  262.       n_paths++;
  263.       vmsi++;
  264.       }
  265.    if (syspaths[n_paths] = getenv("SYS$LIBRARY")) {
  266.       n_paths++;
  267.       vmsi++;
  268.       }
  269. #endif                    /* VMS */
  270.  
  271. #if AMIGA
  272.    static char *sysdir = "include:";
  273.  
  274.    n_paths = 1;
  275. #endif                    /* AMIGA */
  276.  
  277. #if MACINTOSH && !MPW && !THINK_C
  278.    /* probably needs something */
  279. Deliberate Syntax Error
  280. #endif                    /* MACINTOSH && ... */
  281.  
  282. #if MACINTOSH
  283. #if THINK_C
  284.    char *sysdir = FileNameMacConvert(FileNameMacToUnix, "MacintoshHD:THINK C:THINK C:Standard Libraries:C headers");
  285.    n_paths = 1;
  286. #endif
  287. #if MPW
  288.    /*
  289.     * For MPW, environment variable CIncludes says where to look.
  290.     */
  291.    char *sysdir = FileNameMacConvert(FileNameMacToUnix,getenv("CIncludes"));
  292.    n_paths = 1;
  293. #endif                    /* MPW */
  294. #endif                    /* MACINTOSH */
  295.  
  296. #if MSDOS
  297. #if HIGHC_386 || INTEL_386 || WATCOM
  298.    /* punt for now */
  299.    n_paths = 0;
  300. #endif                    /* HIGHC_386 || INTEL_386 || ... */
  301.  
  302. #if MICROSOFT || NT
  303.    char *syspath;
  304.    char *cl_var;
  305.    char *incl_var;
  306.  
  307.    incl_var = getenv("INCLUDE");
  308.    cl_var = getenv("CL");
  309.    n_paths = 0;
  310.  
  311.    /*
  312.     * Check the CL environment variable for -I and -X options.
  313.     */
  314.    if (cl_var != NULL) {
  315.       s = cl_var;
  316.       while (*s != '\0') {
  317.          if (*s == '/' || *s == '-') {
  318.             ++s;
  319.             if (*s == 'I') {
  320.                ++n_paths;
  321.                ++s;
  322.                while (*s == ' ' || *s == '\t')
  323.                   ++s;
  324.                while (*s != ' ' && *s != '\t' && *s != '\0')
  325.                   ++s;
  326.                }
  327.             else if (*s == 'X')
  328.                incl_var = NULL;        /* ignore INCLUDE environment var */
  329.             }
  330.          if (*s != '\0')
  331.             ++s;
  332.          }
  333.       }
  334.  
  335.    /*
  336.     * Check the INCLUDE environment variable for standard places to
  337.     *  search.
  338.     */
  339.    if (incl_var == NULL)
  340.       syspath = "";
  341.    else {
  342.       syspath = (char *)strdup(incl_var);
  343.       if (*incl_var != '\0')
  344.          ++n_paths;
  345.       while (*incl_var != '\0')
  346.          if (*incl_var++ == ';' && *incl_var != '\0')
  347.             ++n_paths;
  348.       }
  349. #endif                    /* MICROSOFT || NT */
  350.  
  351. #if ZTC_386
  352.    char *syspath;
  353.    char *cl_var;
  354.    char *incl_var;
  355.  
  356.    incl_var = getenv("INCLUDE");
  357.    cl_var = getenv("CFLAGS");
  358.    n_paths = 0;
  359.  
  360.    /*
  361.     * Check the CFLAGS environment variable for -I options.
  362.     */
  363.    if (cl_var != NULL) {
  364.       s = cl_var;
  365.       while (*s != '\0') {
  366.          if (*s == '/' || *s == '-') {
  367.             ++s;
  368.             if (*s == 'I') {
  369.                ++n_paths;
  370.                ++s;
  371.                while (*s == ' ' || *s == '\t')
  372.                   ++s;
  373.                while (*s != ' ' && *s != '\t' && *s != '\0') {
  374.                   if (*s == ';')
  375.                      ++n_paths;
  376.                   ++s;
  377.                   }
  378.                }
  379.             }
  380.          if (*s != '\0')
  381.             ++s;
  382.          }
  383.       }
  384.  
  385.    /*
  386.     * Check the INCLUDE environment variable for standard places to
  387.     *  search.
  388.     */
  389.    if (incl_var == NULL)
  390.       syspath = "";
  391.    else {
  392.       syspath = (char *)strdup(incl_var);
  393.       if (*incl_var != '\0')
  394.          ++n_paths;
  395.       while (*incl_var != '\0')
  396.          if (*incl_var++ == ';' && *incl_var != '\0')
  397.             ++n_paths;
  398.       }
  399. #endif                    /* ZTC_386 */
  400.  
  401. #if TURBO || BORLAND_286 || BORLAND_386
  402.     char *cfg_fname;
  403.     FILE *cfg_file = NULL;
  404.     struct str_buf *sbuf;
  405.     int c;
  406.  
  407.     /*
  408.      * Check the configuration files for -I options.
  409.      */
  410.     n_paths = 0;
  411.     cfg_fname = searchpath("turboc.cfg");
  412.     if (cfg_fname != NULL && (cfg_file = fopen(cfg_fname, "r")) != NULL) {
  413.        c = getc(cfg_file);
  414.        while (c != EOF) {
  415.           if (c == '-') {
  416.              if ((c = getc(cfg_file)) == 'I')
  417.                 ++n_paths;
  418.              }
  419.           else
  420.              c = getc(cfg_file);
  421.           }
  422.        }
  423. #endif                    /* TURBO || BORLAND_286 ... */
  424.  
  425. #if HIGHC_386 || INTEL_386 || WATCOM
  426.    /* something may be needed */
  427. #endif                    /* HIGHC_386 || INTEL_386 || ... */
  428. #endif                    /* MSDOS */
  429.  
  430. #if UNIX
  431.    static char *sysdir = "/usr/include/";
  432.  
  433.    n_paths = 1;
  434. #endif                    /* UNIX */
  435.  
  436. /*
  437.  * End of operating-system specific code.
  438.  */
  439.  
  440.    /*
  441.     * Count the number of -I options to the preprocessor.
  442.     */
  443.    for (i = 0; opt_lst[i] != '\0'; ++i)
  444.       if (opt_lst[i] == 'I')
  445.          ++n_paths;
  446.  
  447.    /*
  448.     * Set up the array of standard locations to search for header files.
  449.     */
  450.    incl_search = alloc((n_paths + 1) * sizeof(char *));
  451.    j = 0;
  452.  
  453. /*
  454.  * The following code is operating-system dependent [@files.04].
  455.  *  Establish the standard locations to search before the -I options
  456.  *  on the preprocessor.
  457.  */
  458.  
  459. #if PORT
  460.    /* something may be needed */
  461. Deliberate Syntax Error
  462. #endif                    /* PORT */
  463.  
  464. #if AMIGA
  465.    /* nothing is needed */
  466. #endif                    /* AMIGA */
  467.  
  468. #if MSDOS
  469. #if MICROSOFT
  470.    /*
  471.     * Get locations from -I options from the CL environment variable.
  472.     */
  473.    if (cl_var != NULL)
  474.       while (*cl_var != '\0') {
  475.          if (*cl_var == '/' || *cl_var == '-') {
  476.             ++cl_var;
  477.             if (*cl_var == 'I') {
  478.                   ++cl_var;
  479.                   while (*cl_var == ' ' || *cl_var == '\t')
  480.                      ++cl_var;
  481.                   i = 0;
  482.                   while (cl_var[i] != ' ' && cl_var[i] != '\t' &&
  483.                     cl_var[i] != '\0')
  484.                      ++i;
  485.                   s1 = alloc(i + 1);
  486.                   strncpy(s1, cl_var, i);
  487.                   s1[i] = '\0';
  488.                   /*
  489.                    * Convert back slashes to slashes for internal consistency.
  490.                    */
  491.                   for (s = s1; *s != '\0'; ++s)
  492.                      if (*s == '\\')
  493.                         *s = '/';
  494.                   incl_search[j++] = s1;
  495.                   cl_var += i;
  496.                }
  497.             }
  498.          if (*cl_var != '\0')
  499.             ++cl_var;
  500.          }
  501. #endif                    /* MICROSOFT */
  502.  
  503. #if ZTC_386
  504.    /*
  505.     * Get locations from -I options from the CL environment variable.
  506.     * Each -I may have multiple options separated by semi-colons.
  507.     */
  508.    if (cl_var != NULL)
  509.       while (*cl_var != '\0') {
  510.          if (*cl_var == '/' || *cl_var == '-') {
  511.             ++cl_var;
  512.             if (*cl_var == 'I') {
  513.                   ++cl_var;
  514.                   while (*cl_var == ' ' || *cl_var == '\t')
  515.                      ++cl_var;
  516.                   i = 0;
  517.                   while (cl_var[i] != ' ' && cl_var[i] != '\t' &&
  518.                     cl_var[i] != '\0') {
  519.                      while (cl_var[i] != ' ' && cl_var[i] != '\t' &&
  520.                        cl_var[i] != ';' && cl_var[i] != '\0')
  521.                         ++i;
  522.                      s1 = alloc(i + 1);
  523.                      strncpy(s1, cl_var, i);
  524.                      s1[i] = '\0';
  525.                      /*
  526.                       * Convert back slashes to slashes for internal consistency.
  527.                       */
  528.                      for (s = s1; *s != '\0'; ++s)
  529.                         if (*s == '\\')
  530.                            *s = '/';
  531.                      incl_search[j++] = s1;
  532.                      if (cl_var[i] == ';') {
  533.                          cl_var += (i + 1);
  534.                          i = 0;
  535.                          }
  536.                      }
  537.                   cl_var += i;
  538.                }
  539.             }
  540.          if (*cl_var != '\0')
  541.             ++cl_var;
  542.          }
  543. #endif                    /* ZTC_386 */
  544.  
  545. #if HIGHC_386 || INTEL_386 || WATCOM
  546.    /* something is needed */
  547. #endif                    /* HIGHC_386 || INTEL_386 || ... */
  548. #endif                    /* MSDOS */
  549.  
  550. #if UNIX || VMS || MACINTOSH
  551.    /* nothing is needed */
  552. #endif                    /* UNIX || VMS || MACINTOSH */
  553.  
  554. /*
  555.  * End of operating-system specific code.
  556.  */
  557.  
  558.    /*
  559.     * Get the locations from the -I options to the preprocessor.
  560.     */
  561.    for (i = 0; opt_lst[i] != '\0'; ++i)
  562.       if (opt_lst[i] == 'I') {
  563.          s = opt_args[i];
  564.          s1 = alloc(strlen(s) + 1);
  565.          strcpy(s1, s);
  566.  
  567. /*
  568.  * The following code is operating-system dependent [@files.05].
  569.  *  Insure that path syntax is in Unix format for internal consistency
  570.  *  (note, this may not work well on all systems).
  571.  *  In particular, Amiga paths are left intact.
  572.  */
  573.  
  574. #if PORT
  575.    /* something might be needed */
  576. Deliberate Syntax Error
  577. #endif                    /* PORT */
  578.  
  579. #if AMIGA
  580.    /* nothing is needed */
  581. #endif                    /* AMIGA */
  582.  
  583. #if MACINTOSH
  584.    s1 = FileNameMacConvert(FileNameMacToUnix,s);
  585. #endif                    /* MACINTOSH */
  586.  
  587. #if MSDOS
  588.          /*
  589.           * Convert back slashes to slashes for internal consistency.
  590.           */
  591.          for (s = s1; *s != '\0'; ++s)
  592.             if (*s == '\\')
  593.                *s = '/';
  594. #endif                    /* MSDOS */
  595.  
  596. #if UNIX || VMS
  597.    /* nothing is needed */
  598. #endif                    /* UNIX || VMS */
  599.  
  600. /*
  601.  * End of operating-system specific code.
  602.  */
  603.  
  604.          incl_search[j++] = s1;
  605.          }
  606.  
  607. /*
  608.  * The following code is operating-system dependent [@files.06].
  609.  *  Establish the standard locations to search after the -I options
  610.  *  on the preprocessor.
  611.  */
  612.  
  613. #if PORT
  614.    /* probably needs something */
  615. Deliberate Syntax Error
  616. #endif                    /* PORT */
  617.  
  618. #if VMS
  619.    for ( ; vmsi; vmsi--)
  620.       incl_search[n_paths - vmsi] = syspaths[vmsi-1];
  621. #endif                    /* VMS */
  622.  
  623. #if AMIGA
  624.    incl_search[n_paths - 1] = sysdir;
  625. #endif                    /* AMIGA */
  626.  
  627. #if MSDOS
  628. #if MICROSOFT
  629.    /*
  630.     * Get the locations from the INCLUDE environment variable.
  631.     */
  632.    s = syspath;
  633.    if (*s != '\0')
  634.       incl_search[j++] = s;
  635.    while (*s != '\0') {
  636.       if (*s == ';') {
  637.          *s = '\0';
  638.          ++s;
  639.          if (*s != '\0')
  640.             incl_search[j++] = s;
  641.          }
  642.       else {
  643.          if (*s == '\\')
  644.             *s = '/';
  645.          ++s;
  646.          }
  647.       }
  648. #endif                    /* MICROSOFT */
  649.  
  650. #if TURBO || BORLAND_286 || BORLAND_386
  651.     /*
  652.      * Get the locations from the -I options in the configuration file.
  653.      */
  654.     if (cfg_file != NULL) {
  655.        rewind(cfg_file);
  656.        sbuf = get_sbuf();
  657.        c = getc(cfg_file);
  658.        while (c != EOF) {
  659.           if (c == '-') {
  660.              if ((c = getc(cfg_file)) == 'I') {
  661.                 c = getc(cfg_file);
  662.                 while (c != ' ' && c != '\t' && c != '\n' && c != EOF) {
  663.                    AppChar(*sbuf, c);
  664.                    c = getc(cfg_file);
  665.                    }
  666.                 incl_search[j++] = str_install(sbuf);
  667.                 }
  668.              }
  669.           else
  670.              c = getc(cfg_file);
  671.           }
  672.        rel_sbuf(sbuf);
  673.        fclose(cfg_file);
  674.        }
  675. #endif                    /* TURBO || BORLAND_286 ... */
  676.  
  677. #if HIGHC_386 || INTEL_386 || WATCOM
  678.   /* something is needed */
  679. #endif                    /* HIGHC_386 || INTEL_386 || ... */
  680. #endif                    /* MSDOS */
  681.  
  682. #if UNIX || MACINTOSH
  683.    incl_search[n_paths - 1] = sysdir;
  684. #endif                    /* UNIX || MACINTOSH */
  685.  
  686. /*
  687.  * End of operating-system specific code.
  688.  */
  689.  
  690.    incl_search[n_paths] = NULL;
  691.    }
  692.  
  693. #if MACINTOSH
  694. #if MPW || THINK_C
  695. /*
  696.  * Extra functions specific to the Macintosh MPW implementation:
  697.  *  functions to convert a UNIX-type file name to Mac-type
  698.  *  and vice versa.
  699.  *
  700.  *  Result is pointer to a static string, or maybe a pointer
  701.  *  to the input string if it is unchanged.
  702.  */
  703.  
  704. static char FileName_newfn[100];
  705.  
  706. char *
  707. FileNameUnixToMac(char *fn) {
  708.   char *q,*e,*r;
  709.   int full;
  710.  
  711.   if (strchr(fn,'/') == NULL) return fn;
  712.   e = fn + strlen(fn);
  713.   r = FileName_newfn;
  714.   if (*fn == '/') {
  715.     full = 1;
  716.     ++fn;
  717.   }
  718.   else full = 0;
  719.   for (;;) {
  720.     (q = strchr(fn,'/')) || (q = e);
  721.     if (fn == q || q - fn == 1 && *fn == '.') {}
  722.     else if (q - fn == 2 && *fn == '.' && *(fn + 1) == '.')
  723.         *r++ = ':';
  724.     else {
  725.       *r++ = ':';
  726.       memcpy(r,fn,q - fn);
  727.       r += q - fn;
  728.     }
  729.     if (q == e) break;
  730.     fn = q + 1;
  731.   }
  732.   if (*(r - 1) == ':') *r++ = ':';
  733.   else if (*(e - 1) == '/') *r++ = ':';
  734.   *r = '\0';
  735.   return full ? FileName_newfn + 1 : FileName_newfn;
  736. }
  737.  
  738. char *
  739. FileNameMacToUnix(char *fn) {
  740.   char *q,*e,*r;
  741.  
  742.   if (strchr(fn,':') == NULL) return fn;
  743.   r = FileName_newfn;
  744.   if (*fn == ':') ++fn;
  745.   else *r++ = '/';
  746.   q = fn;
  747.   e = fn + strlen(fn);
  748.   for (;;) {
  749.     while (*fn == ':') {
  750.       ++fn;
  751.       memcpy(r,"../",3);
  752.       r += 3;
  753.     }
  754.     if (fn == e) break;
  755.     (q = strchr(fn,':')) || (q = e);
  756.     memcpy(r,fn,q - fn);
  757.     r += q - fn;
  758.     *r++ = '/';
  759.     if (q == e) break;
  760.     fn = q + 1;
  761.   }
  762.   *--r = '\0';
  763.   return FileName_newfn;
  764. }
  765.  
  766. /*
  767.  *  Helper function to make filename conversions more convenient.
  768.  *
  769.  *  This function calls either of the two above filename conversion functions
  770.  *  and returns the resulting filename in allocated memory.  Ownership of
  771.  *  the allocated memory is transferred to the caller -- i.e. it is the
  772.  *  caller's responsibility to eventually free it.
  773.  *
  774.  *  Example:  FileNameMacConvert(FileNameMacToUnix,":MyDir:MyFile")
  775.  */
  776. char *
  777. FileNameMacConvert(char *(*func)(char *),char *fn) {
  778.    char *newfp, *newmem;
  779.  
  780.    newfp = (*func)(fn);
  781.    newmem = (char *)malloc(strlen(newfp) + 1);
  782.    if (newmem == NULL) return NULL;
  783.    strcpy(newmem,newfp);
  784.    return newmem;
  785. }
  786. #endif                    /* MPW || THINK_C */
  787. #endif                    /* MACINTOSH */
  788.