zsh-workers
 help / color / mirror / code / Atom feed
From: "Jun. T" <takimoto-j@kba.biglobe.ne.jp>
To: zsh-workers@zsh.org
Subject: Re: ksh compatibility: initial value of $_
Date: Mon, 3 Apr 2023 20:16:22 +0900	[thread overview]
Message-ID: <20B96AB1-75EB-4DAD-93C5-B56A84CCA045@kba.biglobe.ne.jp> (raw)
In-Reply-To: <CAH+w=7Z-uZxniq5HB7Wqbtx706=q1q35kjdN+WfDVYGE7Q5erQ@mail.gmail.com>


> 2023/04/01 2:45, Bart Schaefer <schaefer@brasslantern.com> wrote:
> 
> With your patch:
> 
> % /bin/sh
> $ Src/zsh -fc 'print $_'
> /bin/sh
> $ Src/zsh -fc 'echo $_'
> print $_
> $
> 
> Similar behavior from ksh, so it really is whatever happens to be in
> the environment for '_' rather than an actual pathname.  This means
> you only get the documented behavior when a new shell or script was
> invoked via a previous shell that exports $_

Well, I think this is _the_ behavior ksh document specifies. If what
we want to achieve is just the ksh compatibility then this is enough?

But of course we can do better. The patch below ignores the $_ in
environment and tries to guess the executable/script pathname.
(this is just a draft; it would be better to set PROC_SELF_EXE in
configure if we are going to use this).

Or we can use this only if $_ is not in environment (I guess bash
behaves this way).


diff --git a/Src/init.c b/Src/init.c
index 68621a0ad..5fa8985e0 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -246,6 +246,9 @@ loop(int toplevel, int justonce)
 
 static int restricted;
 
+/* save original argv[0] for initialization of $_ */
+static char *argv0;
+
 /**/
 static void
 parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr,
@@ -258,6 +261,7 @@ parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr,
 	flags |= PARSEARGS_LOGIN;
 
     argzero = posixzero = *argv++;
+    argv0 = unmetafy(ztrdup(argzero), NULL);
     SHIN = 0;
 
     /*
@@ -893,6 +897,109 @@ init_term(void)
     return 1;
 }
 
+/*
+ * Get (or guess) the full pathname of myself.  If runscript is non-NULL,
+ * use it as a script file name, and guess its full pathname.
+ * Otherwize, get the full pathname of the current zsh executable by
+ * OS-specific method, and if it fails, guess the full pathname of argv0.
+ * argv0, runscript and cwd are all unmetafied.
+ * Returns a zalloc()ed string, or NULL if failed.
+ */
+#if defined(__APPLE__)
+#include <mach-o/dyld.h>
+#elif defined(__linux)
+#define PROC_SELF_EXE "/proc/self/exe"
+#endif
+
+/**/
+static char *
+getmypath(const char *argv0, const char *runscript, const char *cwd)
+{
+    char *buf;
+    const char *name;
+    int isscript, namelen;
+
+    if (!runscript) {
+	isscript = 0;
+	name = argv0;
+	if (name && *name == '-')
+	    ++name;
+#if defined(__APPLE__)
+	unsigned int n;
+	int ret;
+	buf = (char *)zalloc(PATH_MAX);
+	n = PATH_MAX;
+	if ((ret = _NSGetExecutablePath(buf, &n)) < 0) {
+	    /* try again with increased buffer size */
+	    free(buf);
+	    buf = (char *)zalloc(n);
+	    ret = _NSGetExecutablePath(buf, &n);
+	}
+	if (ret == 0 && strlen(buf) > 0)
+	    return buf;
+#elif defined(PROC_SELF_EXE)
+	int n;
+	buf = (char *)zalloc(PATH_MAX);
+	n = readlink(PROC_SELF_EXE, buf, PATH_MAX);
+	if (n > 0 && n < PATH_MAX) {
+	    buf[n] = '\0';
+	    return buf;
+	}
+#endif
+	free(buf);
+    }
+    else {
+	isscript = 1;
+	name = runscript;
+    }
+
+    /* guess the full pathname of 'name' */
+    namelen = strlen(name);
+    if (namelen == 0)
+	return NULL;
+    else if (name[namelen-1] == '/')    /* name should not end with '/' */
+	return NULL;
+    else if (name[0] == '/') {
+	/* name is already a fullpath */
+	buf = (char *)zalloc(namelen + 1);
+	strcpy(buf, name);
+	return buf;
+    }
+    else if (isscript || strchr(name, '/')) {
+	/* realative path */
+	if (!cwd)
+	    return NULL;
+	buf = (char *)zalloc(strlen(cwd) + namelen + 2);
+	strcpy(buf, cwd);
+	strcat(buf, "/");
+	strcat(buf, name);
+	return buf;
+    }
+    else {
+	/* search each dir in PARH */
+	const char *path, *sep;
+	char *real;
+	int pathlen, dirlen;
+	path = getenv("PATH");
+	if (!path || (pathlen = strlen(path)) == 0)
+	    return NULL;
+	buf = (char *)zalloc(pathlen + namelen + 2);
+	do {
+	    sep = strchr(path, ':');
+	    dirlen = sep ? sep - path : strlen(path);
+	    strncpy(buf, path, dirlen);
+	    buf[dirlen] = '/';
+	    buf[dirlen+1] = '\0';
+	    strcat(buf, name);
+	    real = realpath(buf, NULL);
+	    if (sep)
+		path = sep + 1;
+	} while (!real && sep);
+	free(buf);
+	return real;	/* this may be NULL */
+    }
+}
+
 /* Initialize lots of global variables and hash tables */
 
 /**/
@@ -903,7 +1010,7 @@ setupvals(char *cmd, char *runscript, char *zsh_name)
     struct passwd *pswd;
 #endif
     struct timezone dummy_tz;
-    char *ptr;
+    char *ptr, *mypath;
     int i, j;
 #if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined (ADDITIONAL_FPATH) || defined(FIXED_FPATH_DIR)
 # define FPATH_NEEDS_INIT 1
@@ -1084,9 +1191,6 @@ setupvals(char *cmd, char *runscript, char *zsh_name)
 	ztrdup(DEFAULT_IFS_SH) : ztrdup(DEFAULT_IFS);
     wordchars   = ztrdup(DEFAULT_WORDCHARS);
     postedit    = ztrdup("");
-    zunderscore  = (char *) zalloc(underscorelen = 32);
-    underscoreused = 1;
-    *zunderscore = '\0';
 
     zoptarg = ztrdup("");
     zoptind = 1;
@@ -1138,6 +1242,34 @@ setupvals(char *cmd, char *runscript, char *zsh_name)
 
     oldpwd = ztrdup(pwd);  /* initialize `OLDPWD' = `PWD' */
 
+    /* initialize $_ */
+    {
+	char *exename = argv0, *scriptname = runscript, *cwd = pwd;
+	if (exename)
+	    exename = unmetafy(ztrdup(exename), NULL);
+	if (scriptname)
+	    scriptname = unmetafy(ztrdup(scriptname), NULL);
+	if (cwd)
+	    cwd = unmetafy(ztrdup(cwd), NULL);
+	zunderscore = getmypath(exename, scriptname, cwd);
+	free(exename);
+	free(scriptname);
+	free(cwd);
+    }
+    if (zunderscore) {
+	zunderscore = metafy(zunderscore, -1, META_REALLOC);
+	underscoreused = strlen(zunderscore) + 1;
+	underscorelen = (underscoreused + 31) & ~31;
+	zunderscore = (char *)zrealloc(zunderscore, underscorelen);
+    }
+    else {
+	zunderscore  = (char *) zalloc(underscorelen = 32);
+	underscoreused = 1;
+	*zunderscore = '\0';
+    }
+
+
+
     inittyptab();     /* initialize the ztypes table */
     initlextabs();    /* initialize lexing tables    */
 




  reply	other threads:[~2023-04-03 11:17 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-28  1:52 Bart Schaefer
2023-03-23 10:40 ` Jun T
2023-03-31  8:18   ` Jun T
2023-03-31 14:31     ` Jun. T
2023-03-31 17:45       ` Bart Schaefer
2023-04-03 11:16         ` Jun. T [this message]
2023-04-03 16:48           ` Bart Schaefer
2023-03-31 19:02       ` Bart Schaefer
2023-03-31 19:03         ` Bart Schaefer
2023-04-03 12:13     ` Jun. T
2023-04-03 16:50       ` Bart Schaefer
2023-04-04 16:24         ` Jun. T
2023-04-05  1:03           ` Oliver Kiddle
2023-04-05  8:15             ` zeurkous
2023-04-05  9:00               ` Oliver Kiddle
2023-04-05 16:24             ` Jun. T
2023-04-05  8:14           ` dana
2023-04-05 18:16             ` Jun. T
2023-04-08  4:03               ` dana
2023-04-08 16:22                 ` Oliver Kiddle
2023-04-09 13:30                   ` Jun. T
2023-04-10  0:51                     ` Jun T
2023-04-15  5:02                   ` Felipe Contreras
2023-04-15 22:24               ` Bart Schaefer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20B96AB1-75EB-4DAD-93C5-B56A84CCA045@kba.biglobe.ne.jp \
    --to=takimoto-j@kba.biglobe.ne.jp \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).