Thread: psql \i handling ~ in specified file name

psql \i handling ~ in specified file name

From
Zach Irmen
Date:
refers to following item on TODO
Have psql '\i ~/<tab><tab>' actually load files it displays from home dir

A reviewable patch that could handle tilde expansion for
psql \i ~/filename
or
psql \i ~username/filename

--
Zach Irmen


cvs server: Diffing .
Index: command.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/command.c,v
retrieving revision 1.108
diff -c -r1.108 command.c
*** command.c   1 Dec 2003 22:21:54 -0000       1.108
--- command.c   21 Dec 2003 04:17:24 -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:
   *
***************
*** 522,527 ****
--- 524,530 ----
        /* \i is include file */
        else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
        {
+               char       *expanded_fname;
                char       *fname = scan_option(&string, OT_NORMAL, NULL,
true);

                if (!fname)
***************
*** 531,537 ****
                }
                else
                {
!                       success = (process_file(fname) == EXIT_SUCCESS);
                        free(fname);
                }
        }
--- 534,542 ----
                }
                else
                {
!                       expanded_fname = expand_tilde(fname);
!                       success = (process_file(expanded_fname) ==
EXIT_SUCCESS);
!                       free(expanded_fname);
                        free(fname);
                }
        }
***************
*** 1678,1683 ****
--- 1683,1731 ----
  }


+ /* expand_tilde
+  *
+  * substitute '~' with HOME or '~username' with username's home dir
+  *
+  */
+ static char *
+ expand_tilde(char *filename)
+ {
+       char       *home;
+       char       oldp, *p;
+       struct passwd *pw;
+
+       filename = xstrdup(filename);
+
+       /* try tilde expansion */
+       if (*filename == '~')
+       {
+               home = NULL;
+
+               p = filename+1;
+               while (*p != '/' && *p != '\0')
+                       p++;
+
+               oldp = *p;
+               *p = '\0';
+
+               if (*(filename+1) == '\0')
+                       home = xstrdup(getenv("HOME"));
+               else if ((pw = getpwnam(filename+1)) != NULL)
+                       home = xstrdup(pw->pw_dir);
+
+               *p = oldp;
+               if (home)
+               {
+                       home = realloc(home, strlen(home) + strlen(p) + 1);
+                       strcat(home,p);
+                       free(filename);
+                       filename = home;
+               }
+       }
+
+       return filename;
+ }

  /*
   * process_file



Re: psql \i handling ~ in specified file name

From
Tom Lane
Date:
Zach Irmen <zirmen@shaw.ca> writes:
> A reviewable patch that could handle tilde expansion for
> psql \i ~/filename

Needs a bit of work.  What happens if getenv("HOME") returns NULL?
You also need to think about Windows (dunno if the whole thing is
even meaningful there, but if it is then you need to allow for
backslash path separators).  Finally, couldn't we reduce the number
of times strings are strdup'd only to be freed again?  I don't think
doing it this way makes the code simpler --- it took me a fair while
to convince myself there was no memory leak.

            regards, tom lane

Re: psql \i handling ~ in specified file name

From
Zach Irmen
Date:
"Tom Lane" <tgl@sss.pgh.pa.us> writes:
> What happens if getenv("HOME") returns NULL?

Yeah, the strdup fails. I'll take it out to fix that.

> You also need to think about Windows

Can I just ifndef WIN32 and not think about it? I'm not sure how that would
work either.

> Finally, couldn't we reduce the number
> of times strings are strdup'd only to be freed again?  I don't think
> doing it this way makes the code simpler --- it took me a fair while
> to convince myself there was no memory leak.

Ok. I cut it down to one dup within the function. Attempt 2 is below.
--
Zach Irmen


Index: command.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/command.c,v
retrieving revision 1.108
diff -c -r1.108 command.c
*** command.c   1 Dec 2003 22:21:54 -0000       1.108
--- command.c   21 Dec 2003 08:10:50 -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:
   *
***************
*** 531,536 ****
--- 533,539 ----
                }
                else
                {
+                       expand_tilde(&fname);
                        success = (process_file(fname) == EXIT_SUCCESS);
                        free(fname);
                }
***************
*** 1678,1683 ****
--- 1681,1740 ----
  }


+ /* expand_tilde
+  *
+  * substitute '~' with HOME or '~username' with username's home dir
+  *
+  */
+ static char *
+ expand_tilde(char **filename)
+ {
+       if (!filename || !(*filename))
+               return NULL;
+
+ #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);
+                       strcpy(newfn,home);
+                       strcat(newfn,p);
+
+                       free(fn);
+                       *filename = newfn;
+               }
+       }
+
+ #endif
+
+       return *filename;
+ }

  /*
   * process_file


Re: psql \i handling ~ in specified file name

From
"Andrew Dunstan"
Date:
Zach Irmen said:
> "Tom Lane" <tgl@sss.pgh.pa.us> writes:
>> What happens if getenv("HOME") returns NULL?
>
> Yeah, the strdup fails. I'll take it out to fix that.
>
>> You also need to think about Windows
>
> Can I just ifndef WIN32 and not think about it? I'm not sure how that
> would work either.
>

If we are going to have a Windows port I don't think we should treat it as
a poor cousin.

This information is easily discoverable on MSDN in 5 minutes. The answer
is that you need to call NetUserGetInfo at level 11 to get a user's home
directory. See
http://msdn.microsoft.com/library/en-us/dnucmg/html/ucmgch09.asp and
http://msdn.microsoft.com/library/en-us/netmgmt/netmgmt/netusergetinfo.asp

(Thinks: using this requires linking with NetAPI32.dll - is that a legal
or practical problem for us?)

Also, I strongly recommend that the name be canonicalised - see initdb.c
for an example. Doing this reduces platform-specific code a lot. Windows
is quite able to handle filenames with a forward slash.

(Thinks again: when we have WIN32 done we need to trawl through the code
to try to abstract out as much as possible, so that people who
don't/won't/can't do Windows specific code won't have to bother.)

cheers

andrew



Re: psql \i handling ~ in specified file name

From
"Magnus Hagander"
Date:
>Zach Irmen said:
>> "Tom Lane" <tgl@sss.pgh.pa.us> writes:
>>> What happens if getenv("HOME") returns NULL?
>>
>> Yeah, the strdup fails. I'll take it out to fix that.
>>
>>> You also need to think about Windows
>>
>> Can I just ifndef WIN32 and not think about it? I'm not sure how that
>> would work either.
>>
>
>If we are going to have a Windows port I don't think we should
>treat it as
>a poor cousin.
>
>This information is easily discoverable on MSDN in 5 minutes.
>The answer
>is that you need to call NetUserGetInfo at level 11 to get a
>user's home
>directory. See
>http://msdn.microsoft.com/library/en-us/dnucmg/html/ucmgch09.asp and
>http://msdn.microsoft.com/library/en-us/netmgmt/netmgmt/netuser
getinfo.asp

> (Thinks: using this requires linking with NetAPI32.dll - is that a
legal
> or practical problem for us?)

This is already done by libpq if compiled on Win32. Which means also
psql.exe is linked against it on Win32. (see win32.mak in
interfaces/libpq).

So it shuoldn't be a problem, I think.


//Magnus

Re: psql \i handling ~ in specified file name

From
Zach Irmen
Date:
"Andrew Dunstan" <andrew@dunslane.net> writes:
> Zach Irmen said:
> > Can I just ifndef WIN32 and not think about it? I'm not sure how that
> > would work either.
> >
>
> If we are going to have a Windows port I don't think we should treat it as
> a poor cousin.

I guess I was thinking more about if it should be done as opposed to how it
would be done. On the one hand, I think '~' by itself has no meaning in a
normal Windows environment, so why should psql on Windows give it one? The
readline library on unix, which can be used by psql, interprets the tilde
and is the big reason why psql on unix should interpret the tilde as well.
On the other hand however, I can see consistency being important in that
giving '~' a meaning in psql should give it the same meaning regardless of
platform.

--
Zach Irmen


Re: psql \i handling ~ in specified file name

From
Peter Eisentraut
Date:
Zach Irmen wrote:
> refers to following item on TODO
> Have psql '\i ~/<tab><tab>' actually load files it displays from home
> dir

This expansion should also apply to all other commands that take file
names.


Re: psql \i handling ~ in specified file name

From
Bruce Momjian
Date:
Peter Eisentraut wrote:
> Zach Irmen wrote:
> > refers to following item on TODO
> > Have psql '\i ~/<tab><tab>' actually load files it displays from home
> > dir
>
> This expansion should also apply to all other commands that take file
> names.

Here is a patch that handles "~" in all the file cases.  Thanks for the
initial patch.

--
  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 05:17:35 -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,1747 ----
  }


+ /* expand_tilde
+  *
+  * substitute '~' with HOME or '~username' with username's home dir
+  *
+  */
+ static char *
+ expand_tilde(char **filename)
+ {
+       if (!filename || !(*filename))
+               return NULL;
+
+ #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);
+                       strcpy(newfn,home);
+                       strcat(newfn,p);
+
+                       free(fn);
+                       *filename = newfn;
+               }
+       }
+
+ #endif
+
+       return *filename;
+ }

  /*
   * process_file

Re: psql \i handling ~ in specified file name

From
Zach Irmen
Date:
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
askthem 
here.

First off, there should be a check after the malloc to make sure NULL wasn't returned in the expand_tilde function. I
missedthat 
one.

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
thatthe 
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).

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

Zach Irmen


Re: psql \i handling ~ in specified file name

From
Bruce Momjian
Date:
Zach Irmen wrote:
> "Andrew Dunstan" <andrew@dunslane.net> writes:
> > Zach Irmen said:
> > > Can I just ifndef WIN32 and not think about it? I'm not sure how that
> > > would work either.
> > >
> >
> > If we are going to have a Windows port I don't think we should treat it as
> > a poor cousin.
>
> I guess I was thinking more about if it should be done as opposed to how it
> would be done. On the one hand, I think '~' by itself has no meaning in a
> normal Windows environment, so why should psql on Windows give it one? The
> readline library on unix, which can be used by psql, interprets the tilde
> and is the big reason why psql on unix should interpret the tilde as well.
> On the other hand however, I can see consistency being important in that
> giving '~' a meaning in psql should give it the same meaning regardless of
> platform.

As I remember, MSDOS uses the "~" to specify short versions of long file
names.  I think that is enough for us to say that we are best leaving
'~' expansion only for Unix.  We already dump COPY in a native Win32
format, so it seems we should handle special characters in a similar
native way.

I will add a comment to this affect in the source code.

--
  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

Re: psql \i handling ~ in specified file name

From
"Joshua D. Drake"
Date:

As I remember, MSDOS uses the "~" to specify short versions of long file
names.
I is not just msdos, it is cmd.exe which exists on (to my knowledge) all versions of windows. For example:
Program Files == progra~1




  I think that is enough for us to say that we are best leaving
'~' expansion only for Unix.  We already dump COPY in a native Win32
format, so it seems we should handle special characters in a similar
native way.

I will add a comment to this affect in the source code.
 


-- 
Command Prompt, Inc., home of Mammoth PostgreSQL - S/ODBC and S/JDBC
Postgresql support, programming shared hosting and dedicated hosting.
+1-503-222-2783 - jd@commandprompt.com - http://www.commandprompt.com

Re: psql \i handling ~ in specified file name

From
Bruce Momjian
Date:
Joshua D. Drake wrote:
>
> >
> >As I remember, MSDOS uses the "~" to specify short versions of long file
> >names.
> >
> I is not just msdos, it is cmd.exe which exists on (to my knowledge) all
> versions of windows. For example:
> Program Files == progra~1

Yes, I meant it is a hold-over from dealing with MS-DOS style 8.3 file
names.

--
  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

Re: psql \i handling ~ in specified file name

From
Bruce Momjian
Date:
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

Re: psql \i handling ~ in specified file name

From
Andrew Dunstan
Date:

Bruce Momjian wrote:

>Joshua D. Drake wrote:
>
>
>>>As I remember, MSDOS uses the "~" to specify short versions of long file
>>>names.
>>>
>>>
>>>
>>I is not just msdos, it is cmd.exe which exists on (to my knowledge) all
>>versions of windows. For example:
>>Program Files == progra~1
>>
>>
>
>Yes, I meant it is a hold-over from dealing with MS-DOS style 8.3 file
>names.
>
>

This pattern should not cause tilde expansion on any platform, I
believe.  Only a *leading* ~/ or ~username/ should be expanded.

The normal "home" directory on a (modern) Windows machine is usually
"C:\Documents and Settings\username", IIRC.

cheers

andrew


Re: psql \i handling ~ in specified file name

From
Bruce Momjian
Date:
Andrew Dunstan wrote:
> >>>As I remember, MSDOS uses the "~" to specify short versions of long file
> >>>names.
> >>>
> >>>
> >>>
> >>I is not just msdos, it is cmd.exe which exists on (to my knowledge) all
> >>versions of windows. For example:
> >>Program Files == progra~1
> >>
> >>
> >
> >Yes, I meant it is a hold-over from dealing with MS-DOS style 8.3 file
> >names.
> >
> >
>
> This pattern should not cause tilde expansion on any platform, I
> believe.  Only a *leading* ~/ or ~username/ should be expanded.
>
> The normal "home" directory on a (modern) Windows machine is usually
> "C:\Documents and Settings\username", IIRC.

Yes, I understand, but on an OS that uses tilde so much inside the file
name, do we want special meaning when it is leading the file name?

--
  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

Re: psql \i handling ~ in specified file name

From
Zach Irmen
Date:
Bruce Momjian wrote:
> Yes, seems like that will be required.  Please use my attached version
> to make the adjustments.

Ok. Adjustments made.  All psql commands should be handled.

> Zach Irmen wrote:
> > And finally, I was wondering if arguments with leading pipes
> > (e.g. "|~/file") should  also get substituted.
>
> Yep, that too.

Actually, I found out that popen calls seem to handle the tilde fine as
this was already working on my FreeBSD box without
substitution. I'm not sure if this is true for all Unix systems in
general, but I won't bother putting that in unless it turns out
to be needed.

Index: command.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/command.c,v
retrieving revision 1.108
diff -c -r1.108 command.c
*** command.c    1 Dec 2003 22:21:54 -0000    1.108
--- command.c    9 Jan 2004 06:51:55 -0000
***************
*** 413,418 ****
--- 413,419 ----
          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 ****
--- 495,504 ----
          if (!fname)
              pset.gfname = NULL;
          else
+         {
+             expand_tilde(&fname);
              pset.gfname = xstrdup(fname);
+         }
          free(fname);
          status = CMD_SEND;
      }
***************
*** 531,536 ****
--- 535,541 ----
          }
          else
          {
+             expand_tilde(&fname);
              success = (process_file(fname) == EXIT_SUCCESS);
              free(fname);
          }
***************
*** 561,567 ****
--- 566,575 ----
                  success = false;
              }
              else
+             {
+                 expand_tilde(&opt2);
                  success = do_lo_export(opt1, opt2);
+             }
          }

          else if (strcmp(cmd + 3, "import") == 0)
***************
*** 572,578 ****
--- 580,589 ----
                  success = false;
              }
              else
+             {
+                 expand_tilde(&opt1);
                  success = do_lo_import(opt1, opt2);
+             }
          }

          else if (strcmp(cmd + 3, "list") == 0)
***************
*** 602,607 ****
--- 613,619 ----
      {
          char       *fname = scan_option(&string, OT_FILEPIPE, NULL, true);

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

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

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

              if (!fname)
              {
Index: common.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/common.c,v
retrieving revision 1.78
diff -c -r1.78 common.c
*** common.c    29 Nov 2003 19:52:06 -0000    1.78
--- common.c    9 Jan 2004 06:51:56 -0000
***************
*** 814,816 ****
--- 814,878 ----
      else
          return PQuser(pset.db);
  }
+
+
+ /* expand_tilde
+  *
+  * substitute '~' with HOME or '~username' with username's home dir
+  *
+  */
+ 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;
+ }
Index: common.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/common.h,v
retrieving revision 1.31
diff -c -r1.31 common.h
*** common.h    1 Dec 2003 22:14:40 -0000    1.31
--- common.h    9 Jan 2004 06:51:56 -0000
***************
*** 58,61 ****
--- 58,63 ----
  #define pclose(x) _pclose(x)
  #endif

+ extern char *expand_tilde(char **filename);
+
  #endif   /* COMMON_H */
Index: copy.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/copy.c,v
retrieving revision 1.35
diff -c -r1.35 copy.c
*** copy.c    1 Dec 2003 22:14:40 -0000    1.35
--- copy.c    9 Jan 2004 06:51:56 -0000
***************
*** 221,226 ****
--- 221,227 ----
          result->file = NULL;
      else
          result->file = xstrdup(token);
+     expand_tilde(&result->file);

      token = strtokx(NULL, whitespace, NULL, NULL,
                      0, false, pset.encoding);


Re: psql \i handling ~ in specified file name

From
Bruce Momjian
Date:
Zach Irmen wrote:
>
> Bruce Momjian wrote:
> > Yes, seems like that will be required.  Please use my attached version
> > to make the adjustments.
>
> Ok. Adjustments made.  All psql commands should be handled.
>
> > Zach Irmen wrote:
> > > And finally, I was wondering if arguments with leading pipes
> > > (e.g. "|~/file") should  also get substituted.
> >
> > Yep, that too.
>
> Actually, I found out that popen calls seem to handle the tilde fine as
> this was already working on my FreeBSD box without
> substitution. I'm not sure if this is true for all Unix systems in
> general, but I won't bother putting that in unless it turns out
> to be needed.

Oh, yea, "|" should work fine because it uses the shell.  pipe manual
page says:

     The popen() function ``opens'' a process by creating an IPC connection,
     forking, and invoking the shell.

and

     The command argument is a pointer to a null-terminated string containing
     a shell command line.  This command is passed to /bin/sh using the -c
     flag; interpretation, if any, is performed by the shell.

so we are find with pipe already.

--
  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

Re: psql \i handling ~ in specified file name

From
Bruce Momjian
Date:
Patch applied.  Thanks.

---------------------------------------------------------------------------

Zach Irmen wrote:
>
> Bruce Momjian wrote:
> > Yes, seems like that will be required.  Please use my attached version
> > to make the adjustments.
>
> Ok. Adjustments made.  All psql commands should be handled.
>
> > Zach Irmen wrote:
> > > And finally, I was wondering if arguments with leading pipes
> > > (e.g. "|~/file") should  also get substituted.
> >
> > Yep, that too.
>
> Actually, I found out that popen calls seem to handle the tilde fine as
> this was already working on my FreeBSD box without
> substitution. I'm not sure if this is true for all Unix systems in
> general, but I won't bother putting that in unless it turns out
> to be needed.
>
> Index: command.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/command.c,v
> retrieving revision 1.108
> diff -c -r1.108 command.c
> *** command.c    1 Dec 2003 22:21:54 -0000    1.108
> --- command.c    9 Jan 2004 06:51:55 -0000
> ***************
> *** 413,418 ****
> --- 413,419 ----
>           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 ****
> --- 495,504 ----
>           if (!fname)
>               pset.gfname = NULL;
>           else
> +         {
> +             expand_tilde(&fname);
>               pset.gfname = xstrdup(fname);
> +         }
>           free(fname);
>           status = CMD_SEND;
>       }
> ***************
> *** 531,536 ****
> --- 535,541 ----
>           }
>           else
>           {
> +             expand_tilde(&fname);
>               success = (process_file(fname) == EXIT_SUCCESS);
>               free(fname);
>           }
> ***************
> *** 561,567 ****
> --- 566,575 ----
>                   success = false;
>               }
>               else
> +             {
> +                 expand_tilde(&opt2);
>                   success = do_lo_export(opt1, opt2);
> +             }
>           }
>
>           else if (strcmp(cmd + 3, "import") == 0)
> ***************
> *** 572,578 ****
> --- 580,589 ----
>                   success = false;
>               }
>               else
> +             {
> +                 expand_tilde(&opt1);
>                   success = do_lo_import(opt1, opt2);
> +             }
>           }
>
>           else if (strcmp(cmd + 3, "list") == 0)
> ***************
> *** 602,607 ****
> --- 613,619 ----
>       {
>           char       *fname = scan_option(&string, OT_FILEPIPE, NULL, true);
>
> +         expand_tilde(&fname);
>           success = setQFout(fname);
>           free(fname);
>       }
> ***************
> *** 653,658 ****
> --- 665,671 ----
>       {
>           char       *fname = scan_option(&string, OT_NORMAL, NULL, true);
>
> +         expand_tilde(&fname);
>           success = saveHistory(fname ? fname : "/dev/tty");
>
>           if (success && !quiet && fname)
> ***************
> *** 771,776 ****
> --- 784,790 ----
>           else
>           {
>               fname = scan_option(&string, OT_FILEPIPE, NULL, true);
> +             expand_tilde(&fname);
>
>               if (!fname)
>               {
> Index: common.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/common.c,v
> retrieving revision 1.78
> diff -c -r1.78 common.c
> *** common.c    29 Nov 2003 19:52:06 -0000    1.78
> --- common.c    9 Jan 2004 06:51:56 -0000
> ***************
> *** 814,816 ****
> --- 814,878 ----
>       else
>           return PQuser(pset.db);
>   }
> +
> +
> + /* expand_tilde
> +  *
> +  * substitute '~' with HOME or '~username' with username's home dir
> +  *
> +  */
> + 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;
> + }
> Index: common.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/common.h,v
> retrieving revision 1.31
> diff -c -r1.31 common.h
> *** common.h    1 Dec 2003 22:14:40 -0000    1.31
> --- common.h    9 Jan 2004 06:51:56 -0000
> ***************
> *** 58,61 ****
> --- 58,63 ----
>   #define pclose(x) _pclose(x)
>   #endif
>
> + extern char *expand_tilde(char **filename);
> +
>   #endif   /* COMMON_H */
> Index: copy.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/copy.c,v
> retrieving revision 1.35
> diff -c -r1.35 copy.c
> *** copy.c    1 Dec 2003 22:14:40 -0000    1.35
> --- copy.c    9 Jan 2004 06:51:56 -0000
> ***************
> *** 221,226 ****
> --- 221,227 ----
>           result->file = NULL;
>       else
>           result->file = xstrdup(token);
> +     expand_tilde(&result->file);
>
>       token = strtokx(NULL, whitespace, NULL, NULL,
>                       0, false, pset.encoding);
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
>

--
  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