Re: [AD] No more END_OF_MAIN on *nix!

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


> There's no need to use uzsprintf to produce the command line and then 
> convert to ASCII.  I guess you don't want to depend on snprintf, but 
> sprintf is fine in this case.

Ok.

> Also, if the ps output is not an absolute path it should search the 
> PATH, like with argv[0].

Of course.
Revised patch attached. If procfs is not available or does not follow the 
layout of Linux, this uses ps -f to get the filename. This lists a load of 
junk we don't need, but the filename is always in the last column. 
Unfortunately, the number and layout of the columns seems to vary between 
platforms, so I parse the output from the right until I reach a blank 
character. This is theoretically unsound as the filename could contain a 
space character. If desired, I'll think of something clever to work around 
that one too. In practice, it'll probably be ok as it is.
I have also fixed the bug Elias commented on, if a program is started as 
subdir/exefile, then the old code would not correctly prepend the current 
path to the output. This has been fixed.
I've tested the code on Linux and two flavours of UNIX and it behaves as 
expected on all of them.

I have yet to update the documentation.

If this is all in order, then the need for END_OF_MAIN() can be removed 
from the UNIX port.

Evert
--- allegro/src/unix/usystem.c	2004-07-28 19:56:56.000000000 +0200
+++ alleg_no_magic_main/src/unix/usystem.c	2004-08-02 00:40:46.000000000 +0200
@@ -16,6 +16,7 @@
  */
 
 
+#include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
@@ -240,45 +241,111 @@
 #ifndef ALLEGRO_MACOSX
 
 /* _unix_get_executable_name:
- *  Return full path to the current executable.
+ *  Return full path to the current executable, use proc fs if available.
  */
 void _unix_get_executable_name(char *output, int size)
 {
+   FILE *pipe;
+   char linkname[1024];
+   char filename[1024];
+   struct stat buf;
    char *path;
-
-   /* If argv[0] has no explicit path, but we do have $PATH, search there */
-   if (!strchr (__crt0_argv[0], '/') && (path = getenv("PATH"))) {
-      char *start = path, *end = path, *buffer = NULL, *temp;
-      struct stat finfo;
-
-      while (*end) {
-	 end = strchr (start, ':');
-	 if (!end) end = strchr (start, '\0');
-
-	 /* Resize `buffer' for path component, slash, argv[0] and a '\0' */
-	 temp = realloc (buffer, end - start + 1 + strlen (__crt0_argv[0]) + 1);
-	 if (temp) {
-	    buffer = temp;
-
-	    _al_sane_strncpy (buffer, start, end - start);
-	    *(buffer + (end - start)) = '/';
-	    _al_sane_strncpy (buffer + (end - start) + 1, __crt0_argv[0], end - start + 1 + strlen (__crt0_argv[0]) + 1);
-
-	    if ((stat(buffer, &finfo)==0) && (!S_ISDIR (finfo.st_mode))) {
-	       do_uconvert (buffer, U_ASCII, output, U_CURRENT, size);
-	       free (buffer);
-	       return;
-	    }
-	 } /* else... ignore the failure; `buffer' is still valid anyway. */
-
-	 start = end + 1;
+   pid_t pid;
+   int len;
+   
+   /* get symolic link to executable from proc fs */
+   pid = getpid();
+   sprintf (linkname, "/proc/%d/exe", pid);
+   
+   if (stat (linkname, &buf) == 0) {
+      len = readlink (linkname, filename, sizeof(filename)-1);
+      if (len>-1) {
+	 filename[len] = '\0';
+         
+	 do_uconvert (filename, U_ASCII, output, U_CURRENT, size);
+	 return;
       }
-      /* Path search failed */
-      free (buffer);
    }
-
-   /* If argv[0] had a slash, or the path search failed, just return argv[0] */
-   do_uconvert (__crt0_argv[0], U_ASCII, output, U_CURRENT, size);
+   
+   /* Cannot stat /proc/pid/exe, or cannot resolve symlink */
+   /* Try using the output of the ps command to at least find the name of */
+   /* the file if not the full path */
+   uszprintf (linkname, sizeof(linkname), "ps -f -p %d", pid);
+   do_uconvert (linkname, U_CURRENT, filename, U_ASCII, size);
+   pipe = popen(filename, "r");
+   if (pipe) {
+      /* First line of output is junk, second line contains the info we want */
+      fgets(linkname, sizeof(linkname), pipe);
+      fgets(linkname, sizeof(linkname), pipe);
+      pclose(pipe);
+      
+      /* Now, our filename should be in the last column */
+      len = strlen(linkname);
+      while (linkname[len] != ' ' && linkname[len] != '\t')
+         len--;
+      _al_sane_strncpy (filename, linkname+len+1, strlen(linkname)-len+1);
+            
+      do_uconvert (filename, U_ASCII, output, U_CURRENT, size);
+
+      /* If filename has an explicit path, search current directory */
+      if (strchr (filename, '/')) {
+         if (filename[0] == '/') {
+            /* Full path; done */
+            do_uconvert (filename, U_ASCII, output, U_CURRENT, size);
+            return;
+         }
+         else {
+            struct stat finfo;
+            
+            /* Prepend current directory */
+            getcwd(linkname, sizeof(linkname));
+            len = strlen(linkname);
+            linkname[len] = '/';
+            _al_sane_strncpy (linkname+len+1, filename, strlen(filename));
+            
+            if ((stat(linkname, &finfo)==0) && (!S_ISDIR (finfo.st_mode))) {
+               do_uconvert (linkname, U_ASCII, output, U_CURRENT, size);
+               return;
+            }
+         }
+      }
+      /* If filename has no explicit path, but we do have $PATH, search there */
+      else if ((path = getenv("PATH"))) {
+         char *start = path, *end = path, *buffer = NULL, *temp;
+         struct stat finfo;
+
+         while (*end) {
+	    end = strchr (start, ':');
+	    if (!end) end = strchr (start, '\0');
+
+	    /* Resize `buffer' for path component, slash, filename and a '\0' */
+	    temp = realloc (buffer, end - start + 1 + strlen (filename) + 1);
+	    if (temp) {
+	       buffer = temp;
+
+	       _al_sane_strncpy (buffer, start, end - start);
+	       *(buffer + (end - start)) = '/';
+	       _al_sane_strncpy (buffer + (end - start) + 1, filename, end - start + 1 + strlen (filename) + 1);
+
+	       if ((stat(buffer, &finfo)==0) && (!S_ISDIR (finfo.st_mode))) {
+	          do_uconvert (buffer, U_ASCII, output, U_CURRENT, size);
+	          free (buffer);
+	          return;
+	       }
+	    } /* else... ignore the failure; `buffer' is still valid anyway. */
+
+	    start = end + 1;
+         }
+         /* Path search failed */
+         free (buffer);
+      }
+      
+      do_uconvert (filename, U_ASCII, output, U_CURRENT, size);
+      return;
+   }
+   
+   /* Give up; return empty string */
+   do_uconvert ("", U_ASCII, output, U_CURRENT, size);
 }
 
 #endif


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/