home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / mysys / mf_pack.c < prev    next >
C/C++ Source or Header  |  2000-09-29  |  14KB  |  528 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This library is free software; you can redistribute it and/or
  4.    modify it under the terms of the GNU Library General Public
  5.    License as published by the Free Software Foundation; either
  6.    version 2 of the License, or (at your option) any later version.
  7.    
  8.    This library is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.    Library General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU Library General Public
  14.    License along with this library; if not, write to the Free
  15.    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  16.    MA 02111-1307, USA */
  17.  
  18. #include "mysys_priv.h"
  19. #include <m_string.h>
  20. #ifdef HAVE_PWD_H
  21. #include <pwd.h>
  22. #endif
  23. #ifdef VMS
  24. #include <rms.h>
  25. #include <iodef.h>
  26. #include <descrip.h>
  27. #endif /* VMS */
  28.  
  29. static my_string NEAR_F expand_tilde(my_string *path);
  30.  
  31.     /* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
  32.     /* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
  33.     /* to may be == from */
  34.  
  35. void pack_dirname(my_string to, const char *from)
  36. {
  37.   int cwd_err;
  38.   uint d_length,length,buff_length;
  39.   my_string start;
  40.   char buff[FN_REFLEN];
  41.   DBUG_ENTER("pack_dirname");
  42.  
  43.   (void) intern_filename(to,from);        /* Change to intern name */
  44.  
  45. #ifdef FN_DEVCHAR
  46.   if ((start=strrchr(to,FN_DEVCHAR)) != 0)    /* Skipp device part */
  47.     start++;
  48.   else
  49. #endif
  50.     start=to;
  51.  
  52.   LINT_INIT(buff_length);
  53.   if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
  54.   {
  55.     buff_length= (uint) strlen(buff);
  56.     d_length=(uint) (start-to);
  57.     if ((start == to ||
  58.      (buff_length == d_length && !bcmp(buff,start,d_length))) &&
  59.     *start != FN_LIBCHAR && *start)
  60.     {                        /* Put current dir before */
  61.       bchange(to,d_length,buff,buff_length,(uint) strlen(to)+1);
  62.     }
  63.   }
  64.  
  65.   if ((d_length= cleanup_dirname(to,to)) != 0)
  66.   {
  67.     length=0;
  68.     if (home_dir)
  69.     {
  70.       length= (uint) strlen(home_dir);
  71.       if (home_dir[length-1] == FN_LIBCHAR)
  72.     length--;                /* Don't test last '/' */
  73.     }
  74.     if (length > 1 && length < d_length)
  75.     {                        /* test if /xx/yy -> ~/yy */
  76.       if (bcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
  77.       {
  78.     to[0]=FN_HOMELIB;            /* Filename begins with ~ */
  79.     (void) strmov_overlapp(to+1,to+length);
  80.       }
  81.     }
  82.     if (! cwd_err)
  83.     {                        /* Test if cwd is ~/... */
  84.       if (length > 1 && length < buff_length)
  85.       {
  86.     if (bcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
  87.     {
  88.       buff[0]=FN_HOMELIB;
  89.       (void) strmov_overlapp(buff+1,buff+length);
  90.     }
  91.       }
  92.       if (is_prefix(to,buff))
  93.       {
  94.     length= (uint) strlen(buff);
  95.     if (to[length])
  96.       (void) strmov_overlapp(to,to+length);    /* Remove everything before */
  97.     else
  98.     {
  99.       to[0]= FN_CURLIB;            /* Put ./ instead of cwd */
  100.       to[1]= FN_LIBCHAR;
  101.       to[2]= '\0';
  102.     }
  103.       }
  104.     }
  105.   }
  106.   DBUG_PRINT("exit",("to: '%s'",to));
  107.   DBUG_VOID_RETURN;
  108. } /* pack_dirname */
  109.  
  110.  
  111.     /* remove unwanted chars from dirname */
  112.     /* if "/../" removes prev dir; "/~/" removes all before ~ */
  113.     /* "//" is same as "/", except on Win32 at start of a file  */
  114.     /* "/./" is removed */
  115.     /* Unpacks home_dir if "~/.." used */
  116.     /* Unpacks current dir if if "./.." used */
  117.  
  118. uint cleanup_dirname(register my_string to, const char *from)
  119.                         /* to may be == from */
  120.  
  121. {
  122.   reg5 uint length;
  123.   reg2 my_string pos;
  124.   reg3 my_string from_ptr;
  125.   reg4 my_string start;
  126.   char parent[5],                /* for "FN_PARENTDIR" */
  127.        buff[FN_REFLEN+1],*end_parentdir;
  128.   DBUG_ENTER("cleanup_dirname");
  129.   DBUG_PRINT("enter",("from: '%s'",from));
  130.  
  131.   start=buff;
  132.   from_ptr=(my_string) from;
  133. #ifdef FN_DEVCHAR
  134.   if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
  135.   {                        /* Skipp device part */
  136.     length=(uint) (pos-from_ptr)+1;
  137.     start=strnmov(buff,from_ptr,length); from_ptr+=length;
  138.   }
  139. #endif
  140.  
  141.   parent[0]=FN_LIBCHAR;
  142.   length=(uint) (strmov(parent+1,FN_PARENTDIR)-parent);
  143.   for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
  144.   {
  145.     if (*pos == '/')
  146.       *pos = FN_LIBCHAR;
  147.     if (*pos == FN_LIBCHAR)
  148.     {
  149.       if ((uint) (pos-start) > length && bcmp(pos-length,parent,length) == 0)
  150.       {                        /* If .../../; skipp prev */
  151.     pos-=length;
  152.     if (pos != start)
  153.     {                     /* not /../ */
  154.       pos--;
  155.       if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR))
  156.       {
  157.         if (!home_dir)
  158.         {
  159.           pos+=length+1;            /* Don't unpack ~/.. */
  160.           continue;
  161.         }
  162.         pos=strmov(buff,home_dir)-1;    /* Unpacks ~/.. */
  163.         if (*pos == FN_LIBCHAR)
  164.           pos--;                /* home ended with '/' */
  165.       }
  166.       if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR))
  167.       {
  168.         if (my_getwd(curr_dir,FN_REFLEN,MYF(0)))
  169.         {
  170.           pos+=length+1;            /* Don't unpack ./.. */
  171.           continue;
  172.         }
  173.         pos=strmov(buff,curr_dir)-1;    /* Unpacks ./.. */
  174.         if (*pos == FN_LIBCHAR)
  175.           pos--;                /* home ended with '/' */
  176.       }
  177.       end_parentdir=pos;
  178.       while (pos >= start && *pos != FN_LIBCHAR)    /* remove prev dir */
  179.         pos--;
  180.       if (pos[1] == FN_HOMELIB || bcmp(pos,parent,length) == 0)
  181.       {                    /* Don't remove ~user/ */
  182.         pos=strmov(end_parentdir+1,parent);
  183.         *pos=FN_LIBCHAR;
  184.         continue;
  185.       }
  186.     }
  187.       }
  188.       else if ((uint) (pos-start) == length-1 &&
  189.            !bcmp(start,parent+1,length-1))
  190.     start=pos;                /* Starts with "../" */
  191.       else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
  192.       {
  193. #ifdef FN_NETWORK_DRIVES
  194.     if (pos-start != 1)
  195. #endif
  196.       pos--;            /* Remove dupplicate '/' */
  197.       }
  198.       else if (pos-start > 1 && pos[-1] == FN_CURLIB && pos[-2] == FN_LIBCHAR)
  199.     pos-=2;                    /* Skipp /./ */
  200.       else if (pos > buff+1 && pos[-1] == FN_HOMELIB && pos[-2] == FN_LIBCHAR)
  201.       {                    /* Found ..../~/  */
  202.     buff[0]=FN_HOMELIB;
  203.     buff[1]=FN_LIBCHAR;
  204.     start=buff; pos=buff+1;
  205.       }
  206.     }
  207.   }
  208.   (void) strmov(to,buff);
  209.   DBUG_PRINT("exit",("to: '%s'",to));
  210.   DBUG_RETURN((uint) (pos-buff));
  211. } /* cleanup_dirname */
  212.  
  213.  
  214.     /*
  215.       On system where you don't have symbolic links, the following
  216.       code will allow you to create a file: 
  217.       directory-name.lnk that should contain the real path
  218.       to the directory.  This will be used if the directory name
  219.       doesn't exists
  220.     */
  221.       
  222.  
  223. my_bool my_use_symdir=0;    /* Set this if you want to use symdirs */
  224.  
  225. #ifdef USE_SYMDIR
  226. void symdirget(char *dir)
  227. {
  228.   char buff[FN_REFLEN];
  229.   char *pos=strend(dir);
  230.   if (dir[0] && pos[-1] != FN_DEVCHAR && access(dir, F_OK))
  231.   {
  232.     FILE *fp;
  233.     char temp= *(--pos);            /* May be "/" or "\" */
  234.     strmov(pos,".sym");
  235.     fp = my_fopen(dir, O_RDONLY,MYF(0));
  236.     *pos++=temp; *pos=0;      /* Restore old filename */
  237.     if (fp)
  238.     {
  239.       if (fgets(buff, sizeof(buff), fp))
  240.       {
  241.     for (pos=strend(buff);
  242.          pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ;
  243.          pos --);
  244.     strmake(dir,buff, (uint) (pos-buff));
  245.       }
  246.       my_fclose(fp,MYF(0));
  247.     }
  248.   }
  249. }
  250. #endif /* USE_SYMDIR */
  251.  
  252.     /* Unpacks dirname to name that can be used by open... */
  253.     /* Make that last char of to is '/' if from not empty and
  254.        from doesn't end in FN_DEVCHAR */
  255.     /* Uses cleanup_dirname and changes ~/.. to home_dir/.. */
  256.     /* Returns length of new directory */
  257.  
  258. uint unpack_dirname(my_string to, const char *from)
  259.  
  260.                           /* to may be == from */
  261. {
  262.   uint length,h_length;
  263.   char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
  264.   DBUG_ENTER("unpack_dirname");
  265.  
  266.   (void) intern_filename(buff,from);        /* Change to intern name */
  267.   length= (uint) strlen(buff);            /* Fix that '/' is last */
  268.   if (length &&
  269. #ifdef FN_DEVCHAR
  270.       buff[length-1] != FN_DEVCHAR &&
  271. #endif
  272.       buff[length-1] != FN_LIBCHAR && buff[length-1] != '/')
  273.   {
  274.     buff[length]=FN_LIBCHAR;
  275.     buff[length+1]= '\0';
  276.   }
  277.  
  278.   length=cleanup_dirname(buff,buff);
  279.   if (buff[0] == FN_HOMELIB)
  280.   {
  281.     suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
  282.     if (tilde_expansion)
  283.     {
  284.       length-=(uint) (suffix-buff)-1;
  285.       if (length+(h_length= (uint) strlen(tilde_expansion)) <= FN_REFLEN)
  286.       {
  287.     if (tilde_expansion[h_length-1] == FN_LIBCHAR)
  288.       h_length--;
  289.     if (buff+h_length < suffix)
  290.       bmove(buff+h_length,suffix,length);
  291.     else
  292.       bmove_upp(buff+h_length+length,suffix+length,length);
  293.     bmove(buff,tilde_expansion,h_length);
  294.       }
  295.     }
  296.   }
  297. #ifdef USE_SYMDIR
  298.   if (my_use_symdir)
  299.     symdirget(buff);
  300. #endif
  301.   DBUG_RETURN(system_filename(to,buff));    /* Fix for open */
  302. } /* unpack_dirname */
  303.  
  304.  
  305.     /* Expand tilde to home or user-directory */
  306.     /* Path is reset to point at FN_LIBCHAR after ~xxx */
  307.  
  308. static my_string NEAR_F expand_tilde(my_string *path)
  309. {
  310.   if (path[0][0] == FN_LIBCHAR)
  311.     return home_dir;            /* ~/ expanded to home */
  312. #ifdef HAVE_GETPWNAM
  313.   {
  314.     char *str,save;
  315.     struct passwd *user_entry;
  316.  
  317.     if (!(str=strchr(*path,FN_LIBCHAR)))
  318.       str=strend(*path);
  319.     save= *str; *str= '\0';
  320.     user_entry=getpwnam(*path);
  321.     *str=save;
  322.     endpwent();
  323.     if (user_entry)
  324.     {
  325.       *path=str;
  326.       return user_entry->pw_dir;
  327.     }
  328.   }
  329. #endif
  330.   return (my_string) 0;
  331. }
  332.  
  333.     /* fix filename so it can be used by open, create .. */
  334.     /* to may be == from */
  335.     /* Returns to */
  336.  
  337. my_string unpack_filename(my_string to, const char *from)
  338. {
  339.   uint length,n_length;
  340.   char buff[FN_REFLEN];
  341.   DBUG_ENTER("unpack_filename");
  342.  
  343.   length=dirname_part(buff,from);        /* copy & convert dirname */
  344.   n_length=unpack_dirname(buff,buff);
  345.   if (n_length+strlen(from+length) < FN_REFLEN)
  346.   {
  347.     (void) strmov(buff+n_length,from+length);
  348.     (void) system_filename(to,buff);        /* Fix to usably filename */
  349.   }
  350.   else
  351.     (void) system_filename(to,from);        /* Fix to usably filename */
  352.   DBUG_RETURN(to);
  353. } /* unpack_filename */
  354.  
  355.  
  356.     /* Convert filename (unix standard) to system standard */
  357.     /* Used before system command's like open(), create() .. */
  358.     /* Returns to */
  359.  
  360. uint system_filename(my_string to, const char *from)
  361. {
  362. #ifndef FN_C_BEFORE_DIR
  363.   return (uint) (strmake(to,from,FN_REFLEN-1)-to);
  364. #else    /* VMS */
  365.  
  366.     /* change 'dev:lib/xxx' to 'dev:[lib]xxx' */
  367.     /* change 'dev:xxx' to 'dev:xxx' */
  368.     /* change './xxx' to 'xxx' */
  369.     /* change './lib/' or lib/ to '[.lib]' */
  370.     /* change '/x/y/z to '[x.y]x' */
  371.     /* change 'dev:/x' to 'dev:[000000]x' */
  372.  
  373.   int libchar_found,length;
  374.   my_string to_pos,from_pos,pos;
  375.   char buff[FN_REFLEN];
  376.   DBUG_ENTER("system_filename");
  377.  
  378.   libchar_found=0;
  379.   (void) strmov(buff,from);             /* If to == from */
  380.   from_pos= buff;
  381.   if ((pos=strrchr(from_pos,FN_DEVCHAR)))    /* Skipp device part */
  382.   {
  383.     pos++;
  384.     to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
  385.     from_pos=pos;
  386.   }
  387.   else
  388.     to_pos=to;
  389.  
  390.   if (from_pos[0] == FN_CURLIB && from_pos[1] == FN_LIBCHAR)
  391.     from_pos+=2;                /* Skipp './' */
  392.   if (strchr(from_pos,FN_LIBCHAR))
  393.   {
  394.     *(to_pos++) = FN_C_BEFORE_DIR;
  395.     if (strinstr(from_pos,FN_ROOTDIR) == 1)
  396.     {
  397.       from_pos+=strlen(FN_ROOTDIR);        /* Actually +1 but... */
  398.       if (! strchr(from_pos,FN_LIBCHAR))
  399.       {                        /* No dir, use [000000] */
  400.     to_pos=strmov(to_pos,FN_C_ROOT_DIR);
  401.     libchar_found++;
  402.       }
  403.     }
  404.     else
  405.       *(to_pos++)=FN_C_DIR_SEP;            /* '.' gives current dir */
  406.  
  407.     while ((pos=strchr(from_pos,FN_LIBCHAR)))
  408.     {
  409.       if (libchar_found++)
  410.     *(to_pos++)=FN_C_DIR_SEP;        /* Add '.' between dirs */
  411.       if (strinstr(from_pos,FN_PARENTDIR) == 1 &&
  412.       from_pos+strlen(FN_PARENTDIR) == pos)
  413.     to_pos=strmov(to_pos,FN_C_PARENT_DIR);    /* Found '../' */
  414.       else
  415.     to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
  416.       from_pos=pos+1;
  417.     }
  418.     *(to_pos++)=FN_C_AFTER_DIR;
  419.   }
  420.   length=(int) (strmov(to_pos,from_pos)-to);
  421.   DBUG_PRINT("exit",("name: '%s'",to));
  422.   DBUG_RETURN((uint) length);
  423. #endif
  424. } /* system_filename */
  425.  
  426.  
  427.     /* Fix a filename to intern (UNIX format) */
  428.  
  429. my_string intern_filename(my_string to, const char *from)
  430. {
  431. #ifndef VMS
  432.   {
  433.     uint length;
  434.     char buff[FN_REFLEN];
  435.     if (from == to)
  436.     {                        /* Dirname may destroy from */
  437.       strmov(buff,from);
  438.       from=buff;
  439.     }
  440.     length=dirname_part(to,from);            /* Copy dirname & fix chars */
  441.     (void) strcat(to,from+length);
  442.     return (to);
  443.   }
  444. #else    /* VMS */
  445.  
  446.     /* change 'dev:[lib]xxx' to 'dev:lib/xxx' */
  447.     /* change 'dev:xxx' to 'dev:xxx' */
  448.     /* change 'dev:x/y/[.lib]' to 'dev:x/y/lib/ */
  449.     /* change '[.lib]' to './lib/' */
  450.     /* change '[x.y]' or '[x.][y]' or '[x][.y]' to '/x/y/' */
  451.     /* change '[000000.x] or [x.000000]' to '/x/' */
  452.  
  453.   int par_length,root_length;
  454.   my_string pos,from_pos,to_pos,end_pos;
  455.   char buff[FN_REFLEN];
  456.  
  457.   (void) strmov(buff,from);
  458.   convert_dirname(buff);            /* change '<>' to '[]' */
  459.   from_pos=buff;
  460.   if ((pos=strrchr(from_pos,FN_DEVCHAR)))    /* Skipp device part */
  461.   {
  462.     pos++;
  463.     to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
  464.     from_pos=pos;
  465.   }
  466.   else
  467.     to_pos=to;
  468.  
  469.   root_length=strlen(FN_C_ROOT_DIR);
  470.   if ((pos = strchr(from_pos,FN_C_BEFORE_DIR)) &&
  471.       (end_pos = strrchr(pos+1,FN_C_AFTER_DIR)))
  472.   {
  473.     to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
  474.                 /* Copy all between ':' and '[' */
  475.     from_pos=pos+1;
  476.     if (strinstr(from_pos,FN_C_ROOT_DIR) == 1 &&
  477.     (from_pos[root_length] == FN_C_DIR_SEP ||
  478.      from_pos[root_length] == FN_C_AFTER_DIR))
  479.     {
  480.       from_pos+=root_length+1;
  481.     }
  482.     else if (*from_pos == FN_C_DIR_SEP)
  483.       *(to_pos++) = FN_CURLIB;            /* Set ./ first */
  484.     *(to_pos++) = FN_LIBCHAR;
  485.  
  486.     par_length=strlen(FN_C_PARENT_DIR);
  487.     pos=to_pos;
  488.     for (; from_pos <= end_pos ; from_pos++)
  489.     {
  490.       switch (*from_pos) {
  491.       case FN_C_DIR_SEP:
  492.       case FN_C_AFTER_DIR:
  493.     if (pos != to_pos)
  494.     {
  495.       if ((int) (to_pos-pos) == root_length &&
  496.           is_suffix(pos,FN_C_ROOT_DIR))
  497.         to_pos=pos;                /* remove root-pos */
  498.       else
  499.       {
  500.         *(to_pos++)=FN_LIBCHAR;        /* Find lib */
  501.         pos=to_pos;
  502.       }
  503.     }
  504.     break;
  505.       case FN_C_BEFORE_DIR:
  506.     break;
  507.       case '-':                    /* *(FN_C_PARENT_DIR): */
  508.     if (to_pos[-1] == FN_LIBCHAR &&
  509.         strncmp(from_pos,FN_C_PARENT_DIR,par_length) == 0)
  510.     {                    /* Change '-' to '..' */
  511.       to_pos=strmov(to_pos,FN_PARENTDIR);
  512.       *(to_pos++)=FN_LIBCHAR;
  513.       pos=to_pos;
  514.       from_pos+=par_length-1;
  515.       break;
  516.     }
  517.     /* Fall through */
  518.       default:
  519.     *(to_pos++)= *from_pos;
  520.     break;
  521.       }
  522.     }
  523.   }
  524.   (void) strmov(to_pos,from_pos);
  525.   return (to);
  526. #endif /* VMS */
  527. } /* intern_filename */
  528.