Index: /trunk/src/kash/eval.c
===================================================================
--- /trunk/src/kash/eval.c	(revision 3474)
+++ /trunk/src/kash/eval.c	(revision 3475)
@@ -1012,5 +1012,5 @@
 					exitshell(psh, psh->exitstatus);
 			}
-			if (savecmdnamemalloc)
+			else if (savecmdnamemalloc)
 				sh_free(psh, savecmdname);
 			if (e != -1) {
@@ -1041,5 +1041,6 @@
                                 setvareq(psh, sp->text, VEXPORT|VSTACK);
 			envp = environment(psh);
-			shellexec(psh, args->argv, envp, args->path, args->cmdentry.u.index);
+			shellexec(psh, args->argv, envp, args->path,
+			          args->cmdentry.u.n.index, args->cmdentry.u.n.suffix);
 			break;
 		}
@@ -1421,5 +1422,5 @@
 		for (sp = psh->cmdenviron; sp; sp = sp->next)
 			setvareq(psh, sp->text, VEXPORT|VSTACK);
-		shellexec(psh, argv + 1, environment(psh), pathval(psh), 0);
+		shellexec(psh, argv + 1, environment(psh), pathval(psh), 0, -1);
 	}
 	return 0;
Index: /trunk/src/kash/exec.c
===================================================================
--- /trunk/src/kash/exec.c	(revision 3474)
+++ /trunk/src/kash/exec.c	(revision 3475)
@@ -46,4 +46,5 @@
 #include <stdlib.h>
 #include <stddef.h>
+#include <assert.h>
 
 /*
@@ -98,4 +99,7 @@
 //STATIC int builtinloc = -1;		/* index in path of %builtin, or -1 */
 //int exerrno = 0;			/* Last exec error */
+#ifdef PC_EXE_EXTS
+STATIC const char * const g_exe_suffixes[] = { "", ".exe", ".cmd", ".btm", ".com" };
+#endif
 
 
@@ -107,5 +111,5 @@
 STATIC void delete_cmd_entry(shinstance *);
 #ifdef PC_EXE_EXTS
-STATIC int stat_pc_exec_exts(shinstance *, char *fullname, struct stat *st, int has_ext);
+STATIC int stat_pc_exec_exts(shinstance *, char *fullname, int has_ext, int *suffixp);
 #endif
 
@@ -136,5 +140,6 @@
 		case CMDUNKNOWN:
 		case CMDNORMAL:
-		    dst->param.index = csrc->param.index;
+		    dst->param.n.index = csrc->param.n.index;
+		    dst->param.n.suffix = csrc->param.n.suffix;
 		    break;
 		case CMDFUNCTION:
@@ -162,4 +167,38 @@
 
 /*
+ * Check if 'path' is an absolute (starts with root) path or not.
+ */
+K_INLINE isabspath(const char *path)
+{
+#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
+	if (path[0] == '/' || path[0] == '\\') {
+		if (   (path[1] == '/' || path[1] == '\\')
+		    && (path[2] != '/' && path[2] != '\\' && path[2]))
+			return 1;
+	} else if (path[0] && path[1] == ':' && (path[2] == '\\' || path[2] == '/') && isalpha(path[0])) {
+		return 1;
+	}
+	return 0;
+#else
+	return path[0] == '/';
+#endif
+}
+
+/*
+ * Checks if the filename include a path or not.
+ */
+K_INLINE haspath(const char *name)
+{
+#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
+    return strchr(name, '/') != NULL
+	|| strchr(name, '\\') != NULL
+	|| (name[0] && name[1] == ':');
+#else
+    return strchr(name, '/') != NULL;
+#endif
+}
+
+
+/*
  * Exec a program.  Never returns.  If you change this routine, you may
  * have to change the find_command routine as well.
@@ -167,5 +206,5 @@
 
 SH_NORETURN_1 void
-shellexec(shinstance *psh, char **argv, char **envp, const char *path, int idx)
+shellexec(shinstance *psh, char **argv, char **envp, const char *path, int idx, int suffix)
 {
 	char *cmdname;
@@ -189,8 +228,18 @@
 	const int has_ext = 1;
 #endif
-	TRACE((psh, "shellexec: argv[0]=%s idx=%d\n", argv0, idx));
-	if (strchr(argv0, '/') != NULL) {
-		cmdname = stalloc(psh, argv0len + 5);
-		strcpy(cmdname, argv0);
+	TRACE((psh, "shellexec: argv[0]=%s idx=%d suffix=%d\n", argv0, idx, suffix));
+	if (haspath(argv0)) {
+#ifdef PC_EXE_EXTS
+		if (!has_ext && suffix && (unsigned)suffix < K_ELEMENTS(g_exe_suffixes)) {
+			size_t sufflen = strlen(g_exe_suffixes[suffix]);
+			cmdname = stalloc(psh, argv0len + sufflen + 1);
+			memcpy(cmdname, argv0, argv0len);
+			memcpy(cmdname + argv0len, g_exe_suffixes[suffix], sufflen + 1);
+		} else
+#endif
+		{
+			cmdname = stalloc(psh, argv0len + 5);
+			memcpy(cmdname, argv0, argv0len + 1);
+		}
 		tryexec(psh, cmdname, argv, envp, has_ext);
 		TRACE((psh, "shellexec: cmdname=%s\n", cmdname));
@@ -214,4 +263,8 @@
 		while ((cmdname = padvance(psh, &path, argv0)) != NULL) {
 			if (--idx < 0 && psh->pathopt == NULL) {
+#ifdef PC_EXE_EXTS
+				if (!has_ext && idx == -1 && suffix && (unsigned)suffix < K_ELEMENTS(g_exe_suffixes))
+					strcat(cmdname, g_exe_suffixes[suffix]);
+#endif
 				tryexec(psh, cmdname, argv, envp, has_ext);
 				if (errno != ENOENT && errno != ENOTDIR)
@@ -250,9 +303,10 @@
 #ifdef PC_EXE_EXTS
         /* exploit the effect of stat_pc_exec_exts which adds the
-         * correct extentions to the file.
-         */
-        struct stat st;
-        if (!has_ext)
-            stat_pc_exec_exts(psh, cmd, &st, 0);
+         * correct extentions to the file. */
+        if (!has_ext) {
+		int suffix;
+		int isreg = stat_pc_exec_exts(psh, cmd, 0, &suffix);
+		assert(isreg > 0);
+	}
 #endif
 #if defined(__INNOTEK_LIBC__) && defined(EXEC_HASH_BANG_SCRIPT)
@@ -396,5 +450,5 @@
 	    /* nothing*/;
 	TRACE((psh, "hash bang '%s'\n", new[0]));
-	shellexec(psh, new, envp, pathval(psh), 0);
+	shellexec(psh, new, envp, pathval(psh), 0, -1);
 	/* NOTREACHED */
 }
@@ -466,42 +520,30 @@
 
 #ifdef PC_EXE_EXTS
-STATIC int stat_pc_exec_exts(shinstance *psh, char *fullname, struct stat *st, int has_ext)
-{
+STATIC int stat_pc_exec_exts(shinstance *psh, char *fullname, int has_ext, int *suffixp)
+{
+    int isreg;
+
     /* skip the SYSV crap */
-    if (shfile_stat(&psh->fdtab, fullname, st) >= 0)
-        return 0;
+    if ((isreg = shfile_stat_isreg(&psh->fdtab, fullname)) >= 1) {
+	*suffixp = 0;
+        return isreg;
+    }
     if (!has_ext && errno == ENOENT)
     {
+	/* Ignore non-regular files here. */
         char *psz = strchr(fullname, '\0');
-        memcpy(psz, ".exe", 5);
-        if (shfile_stat(&psh->fdtab, fullname, st) >= 0)
-            return 0;
-        if (errno != ENOENT && errno != ENOTDIR)
-            return -1;
-
-        memcpy(psz, ".cmd", 5);
-        if (shfile_stat(&psh->fdtab, fullname, st) >= 0)
-            return 0;
-        if (errno != ENOENT && errno != ENOTDIR)
-            return -1;
-
-        memcpy(psz, ".bat", 5);
-        if (shfile_stat(&psh->fdtab, fullname, st) >= 0)
-            return 0;
-        if (errno != ENOENT && errno != ENOTDIR)
-            return -1;
-
-        memcpy(psz, ".com", 5);
-        if (shfile_stat(&psh->fdtab, fullname, st) >= 0)
-            return 0;
-        if (errno != ENOENT && errno != ENOTDIR)
-            return -1;
-
-        memcpy(psz, ".btm", 5);
-        if (shfile_stat(&psh->fdtab, fullname, st) >= 0)
-            return 0;
-        *psz = '\0';
+	int i;
+	for (i = 1 /*first entry is empty*/; i < K_ELEMENTS(g_exe_suffixes); i++) {
+	    strcpy(psz, g_exe_suffixes[i]);
+	    if ((isreg = shfile_stat_isreg(&psh->fdtab, fullname)) >= 1) {
+		*suffixp = i;
+		return isreg;
+	    }
+	    if (isreg < 0 && errno != ENOENT && errno != ENOTDIR)
+		break;
+	}
     }
-    return -1;
+    *suffixp = -1;
+    return isreg;
 }
 #endif /* PC_EXE_EXTS */
@@ -567,5 +609,5 @@
 	switch (cmdp->cmdtype) {
 	case CMDNORMAL:
-		idx = cmdp->param.index;
+		idx = cmdp->param.n.index;
 		path = pathval(psh);
 		do {
@@ -574,4 +616,8 @@
 		} while (--idx >= 0);
 		out1str(psh, name);
+#ifdef PC_EXE_EXTS
+		if ((unsigned)cmdp->param.n.suffix < K_ELEMENTS(g_exe_suffixes))
+			out1str(psh, g_exe_suffixes[cmdp->param.n.suffix]);
+#endif
 		break;
 	case CMDSPLBLTIN:
@@ -614,6 +660,6 @@
 	int idx;
 	int prev;
+	int norehashoncd = 1;
 	char *fullname;
-	struct stat statb;
 	int e;
 	int (*bltin)(shinstance*,int,char **);
@@ -635,7 +681,7 @@
 
 	/* If name contains a slash, don't use PATH or hash table */
-	if (strchr(name, '/') != NULL) {
+	if (haspath(name)) {
 		if (act & DO_ABS) {
-			while (shfile_stat(&psh->fdtab, name, &statb) < 0) {
+			while (shfile_stat_exists(&psh->fdtab, name) < 0) {
 #ifdef SYSV
 				if (errno == EINTR)
@@ -645,13 +691,16 @@
 					e = errno;
 				entry->cmdtype = CMDUNKNOWN;
-				entry->u.index = -1;
+				entry->u.n.index = -1;
+				entry->u.n.suffix = -1;
 				return;
 			}
 			entry->cmdtype = CMDNORMAL;
-			entry->u.index = -1;
+			entry->u.n.index = -1;
+			entry->u.n.suffix = -1;
 			return;
 		}
 		entry->cmdtype = CMDNORMAL;
-		entry->u.index = 0;
+		entry->u.n.index = 0;
+		entry->u.n.suffix = 0;
 		return;
 	}
@@ -703,5 +752,5 @@
 			prev = psh->builtinloc;
 		else
-			prev = cmdp->param.index;
+			prev = cmdp->param.n.index;
 	}
 
@@ -723,4 +772,8 @@
 loop:
 	while ((fullname = padvance(psh, &path, name)) != NULL) {
+#ifdef PC_EXE_EXTS
+		int suffix;
+#endif
+		int isreg;
 		stunalloc(psh, fullname);
 		idx++;
@@ -738,5 +791,5 @@
 		}
 		/* if rehash, don't redo absolute path names */
-		if (fullname[0] == '/' && idx <= prev) {
+		if (idx <= prev && isabspath(fullname)) {
 			if (idx < prev)
 				goto loop;
@@ -745,7 +798,7 @@
 		}
 #ifdef PC_EXE_EXTS
-		while (stat_pc_exec_exts(psh, fullname, &statb, has_ext) < 0) {
+		while ((isreg = stat_pc_exec_exts(psh, fullname, has_ext, &suffix)) < 0) {
 #else
-		while (shfile_stat(&psh->fdtab, fullname, &statb) < 0) {
+		while ((isreg = shfile_stat_isreg(&psh->fdtab, fullname)) < 0) {
 #endif
 #ifdef SYSV
@@ -759,5 +812,5 @@
 		}
 		e = EACCES;	/* if we fail, this will be the error */
-		if (!S_ISREG(statb.st_mode))
+		if (isreg < 1)
 			goto loop;
 		if (psh->pathopt) {		/* this is a %func directory */
@@ -794,5 +847,6 @@
 			cmdp = cmdlookup(psh, name, 1);
 		cmdp->cmdtype = CMDNORMAL;
-		cmdp->param.index = idx;
+		cmdp->param.n.index = idx;
+		cmdp->param.n.suffix = suffix;
 		INTON;
 		goto success;
@@ -971,5 +1025,5 @@
 		while ((cmdp = *pp) != NULL) {
 			if ((cmdp->cmdtype == CMDNORMAL &&
-			     cmdp->param.index >= firstchange)
+			     cmdp->param.n.index >= firstchange)
 			 || (cmdp->cmdtype == CMDBUILTIN &&
 			     psh->builtinloc >= firstchange)) {
@@ -1064,4 +1118,6 @@
 		cmdp->cmdtype = CMDUNKNOWN;
 		cmdp->rehash = 0;
+		cmdp->param.n.index = 0;
+		cmdp->param.n.suffix = 0;
 		strcpy(cmdp->cmdname, name);
 		INTON;
@@ -1229,8 +1285,8 @@
 		switch (entry.cmdtype) {
 		case CMDNORMAL: {
-			if (strchr(arg, '/') == NULL) {
+			if (!haspath(arg)) {
 				const char *path = pathval(psh);
 				char *name;
-				int j = entry.u.index;
+				int j = entry.u.n.index;
 				do {
 					name = padvance(psh, &path, arg);
@@ -1240,5 +1296,10 @@
 					out1fmt(psh, " is%s ",
 					    cmdp ? " a tracked alias for" : "");
-				out1fmt(psh, "%s\n", name);
+#ifdef PC_EXE_EXTS
+				if ((unsigned)entry.u.n.suffix < K_ELEMENTS(g_exe_suffixes))
+					out1fmt(psh, "%s%s\n", name, g_exe_suffixes[entry.u.n.suffix]);
+				else
+#endif
+					out1fmt(psh, "%s\n", name);
 			} else {
 				if (shfile_access(&psh->fdtab, arg, X_OK) == 0) {
Index: /trunk/src/kash/exec.h
===================================================================
--- /trunk/src/kash/exec.h	(revision 3474)
+++ /trunk/src/kash/exec.h	(revision 3475)
@@ -47,5 +47,9 @@
 
 union param {
-        int index;
+        struct
+        {
+            int index;
+            int suffix; /* PC suffix index */
+        } n;
         int (*bltin)(struct shinstance*, int, char**);
         union node *func;
@@ -74,5 +78,5 @@
 void subshellinitexec(shinstance *, shinstance *);
 #endif
-SH_NORETURN_1 void shellexec(struct shinstance *, char **, char **, const char *, int) SH_NORETURN_2;
+SH_NORETURN_1 void shellexec(struct shinstance *, char **, char **, const char *, int, int) SH_NORETURN_2;
 char *padvance(struct shinstance *, const char **, const char *);
 int hashcmd(struct shinstance *, int, char **);
