Re: psql \i handling ~ in specified file name - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: psql \i handling ~ in specified file name
Date
Msg-id 200401081804.i08I4Ce11805@candle.pha.pa.us
Whole thread Raw
In response to Re: psql \i handling ~ in specified file name  (Zach Irmen <zirmen@shaw.ca>)
List pgsql-patches
Zach Irmen wrote:
> Bruce Momjian wrote:
> > Here is a patch that handles "~" in all the file cases.
>
> Beat me to it. :)
>
> I do have a few issues that I was trying to sort out myself
> regarding this, but I guess now is as good a time as any to ask
> them here.
>
> First off, there should be a check after the malloc to make sure
> NULL wasn't returned in the expand_tilde function. I missed that
> one.

OK, test added.  I see no way to recover from a malloc failure in this
case because we can't honor their specification of file name, so we have
to exit.

> Secondly, there are a couple of SQL commands (like COPY and
> LOAD) and psql commands handled outside command.c (like \copy)
> which also take filenames. I'm guessing that eventually you'll
> want substitution in those cases as well. So does this mean that
> the expand_tilde function probably should not be in command.c?
> Placing it in common.c seems the logical place to make it at
> least available to all the psql commands (\copy included).

Yes, seems like that will be required.  Please use my attached version
to make the adjustments.

> And finally, I was wondering if arguments with leading pipes
> (e.g. "|~/file") should  also get substituted.

Yep, that too.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: src/bin/psql/command.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/bin/psql/command.c,v
retrieving revision 1.108
diff -c -c -r1.108 command.c
*** src/bin/psql/command.c    1 Dec 2003 22:21:54 -0000    1.108
--- src/bin/psql/command.c    8 Jan 2004 18:01:55 -0000
***************
*** 65,70 ****
--- 65,72 ----
  static bool do_connect(const char *new_dbname, const char *new_user);
  static bool do_shell(const char *command);

+ static char *expand_tilde(char **filename);
+
  /*----------
   * HandleSlashCmds:
   *
***************
*** 413,418 ****
--- 415,421 ----
          else
          {
              fname = scan_option(&string, OT_NORMAL, NULL, true);
+             expand_tilde(&fname);
              status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
              free(fname);
          }
***************
*** 494,500 ****
--- 497,506 ----
          if (!fname)
              pset.gfname = NULL;
          else
+         {
+             expand_tilde(&fname);
              pset.gfname = xstrdup(fname);
+         }
          free(fname);
          status = CMD_SEND;
      }
***************
*** 531,536 ****
--- 537,543 ----
          }
          else
          {
+             expand_tilde(&fname);
              success = (process_file(fname) == EXIT_SUCCESS);
              free(fname);
          }
***************
*** 602,607 ****
--- 609,615 ----
      {
          char       *fname = scan_option(&string, OT_FILEPIPE, NULL, true);

+         expand_tilde(&fname);
          success = setQFout(fname);
          free(fname);
      }
***************
*** 653,658 ****
--- 661,667 ----
      {
          char       *fname = scan_option(&string, OT_NORMAL, NULL, true);

+         expand_tilde(&fname);
          success = saveHistory(fname ? fname : "/dev/tty");

          if (success && !quiet && fname)
***************
*** 771,776 ****
--- 780,786 ----
          else
          {
              fname = scan_option(&string, OT_FILEPIPE, NULL, true);
+             expand_tilde(&fname);

              if (!fname)
              {
***************
*** 1678,1683 ****
--- 1688,1753 ----
  }


+ /* expand_tilde
+  *
+  * substitute '~' with HOME or '~username' with username's home dir
+  *
+  */
+ static char *
+ expand_tilde(char **filename)
+ {
+     if (!filename || !(*filename))
+         return NULL;
+
+     /* MSDOS uses tilde for short versions of long file names, so skip it. */
+ #ifndef WIN32
+
+     /* try tilde expansion */
+     if (**filename == '~')
+     {
+         char       *fn;
+         char       *home;
+         char        oldp,
+                    *p;
+         struct passwd *pw;
+
+         fn = *filename;
+         home = NULL;
+
+         p = fn + 1;
+         while (*p != '/' && *p != '\0')
+             p++;
+
+         oldp = *p;
+         *p = '\0';
+
+         if (*(fn + 1) == '\0')
+             home = getenv("HOME");
+         else if ((pw = getpwnam(fn + 1)) != NULL)
+             home = pw->pw_dir;
+
+         *p = oldp;
+         if (home)
+         {
+             char       *newfn;
+
+             newfn = malloc(strlen(home) + strlen(p) + 1);
+             if (!newfn)
+             {
+                 psql_error("out of memory\n");
+                 exit(EXIT_FAILURE);
+             }
+             strcpy(newfn, home);
+             strcat(newfn, p);
+
+             free(fn);
+             *filename = newfn;
+         }
+     }
+ #endif
+
+     return *filename;
+ }

  /*
   * process_file

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: psql \i handling ~ in specified file name
Next
From: Andrew Dunstan
Date:
Subject: Re: psql \i handling ~ in specified file name