gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master bfc00b75: Library (checkset.h): general functi


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master bfc00b75: Library (checkset.h): general function to easily replace system()
Date: Sat, 18 May 2024 17:39:31 -0400 (EDT)

branch: master
commit bfc00b757b3be6a1c91c366c71c9648bd888298f
Author: Mohammad Akhlaghi <mohammad@akhlaghi.org>
Commit: Mohammad Akhlaghi <mohammad@akhlaghi.org>

    Library (checkset.h): general function to easily replace system()
    
    Until now, Gnuastro's PDF library had its own low-level call to the
    'fork+execl' functions. But we do not want each Gnuastro component that
    needs to run commands to have to do this low-level operation. Furthermore,
    the 'execl' function took arguments on the shell as a variable length
    argument list; again, making it hard to generalize.
    
    With this commit, a new internal Gnuastro library function
    ('gal_checkset_exec') has been added for this job: it will take a simple
    linked list of arguments that should be executed, internally build an
    array, then run 'execv' after forking a new process.
---
 bootstrap.conf                   |  1 +
 lib/checkset.c                   | 55 ++++++++++++++++++++++++++++++++++++++++
 lib/gnuastro-internal/checkset.h |  6 +++++
 lib/pdf.c                        | 45 +++++++++++++++-----------------
 lib/pointer.c                    |  3 ++-
 lib/type.c                       | 22 ++++++++--------
 6 files changed, 95 insertions(+), 37 deletions(-)

diff --git a/bootstrap.conf b/bootstrap.conf
index 540ddb77..0bb79236 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -203,6 +203,7 @@ gnulib_modules="
     error
     nproc
     stdio
+    execv
     select
     stdint
     strtod
diff --git a/lib/checkset.c b/lib/checkset.c
index 567aaa9f..7af8fb82 100644
--- a/lib/checkset.c
+++ b/lib/checkset.c
@@ -29,10 +29,12 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/fcntl.h>
 
 #include <gnuastro/data.h>
+#include <gnuastro/pointer.h>
 
 #include <gnuastro-internal/timing.h>
 #include <gnuastro-internal/checkset.h>
@@ -507,6 +509,59 @@ gal_checkset_noprefix_isequal(char *string, char *prefix,
 
 
 
+
+/**************************************************************/
+/**********               Run commands             ************/
+/**************************************************************/
+/* We are not using the 'system()' command because that call '/bin/sh',
+   which may not always be usable within the running environment; see
+   https://savannah.nongnu.org/bugs/?65677. */
+int
+gal_checkset_exec(char *executable_abs_address, gal_list_str_t *args)
+{
+  pid_t pid;
+  char **argv;
+  int childstat=0;
+  gal_list_str_t *tmp;
+  size_t i, numargs=gal_list_str_number(args);
+
+  /* Allocate the array  */
+  argv=gal_pointer_allocate(GAL_TYPE_STRING, numargs+1, 0,
+                            __func__, "argv");
+
+  /* Fill the argument list array. */
+  tmp=args;
+  for(i=0;i<numargs;++i){ argv[i]=tmp->v; tmp=tmp->next; }
+  argv[numargs]=NULL;
+
+  /* Fork a new process to run 'exec'. */
+  pid=fork();
+  if(pid<0) error(EXIT_FAILURE, 0, "%s: could not build fork", __func__);
+  if(pid==0) execv(executable_abs_address, argv);   /* Child.  */
+  else       waitpid(pid, &childstat, 0);           /* Parent. */
+
+  /* Return the status of the child. */
+  free(argv);
+  return childstat;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 /**************************************************************/
 /********** Set file names and check if they exist ************/
 /**************************************************************/
diff --git a/lib/gnuastro-internal/checkset.h b/lib/gnuastro-internal/checkset.h
index 09cfda3c..8dc32e52 100644
--- a/lib/gnuastro-internal/checkset.h
+++ b/lib/gnuastro-internal/checkset.h
@@ -104,6 +104,12 @@ int
 gal_checkset_noprefix_isequal(char *string, char *prefix,
                               const char *tocompare);
 
+/**************************************************************/
+/**********               Run commands             ************/
+/**************************************************************/
+int
+gal_checkset_exec(char *executable_abs_address, gal_list_str_t *args);
+
 
 /**************************************************************/
 /********** Set file names and check if they exist ************/
diff --git a/lib/pdf.c b/lib/pdf.c
index 497cafbf..030fec98 100644
--- a/lib/pdf.c
+++ b/lib/pdf.c
@@ -28,11 +28,11 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <sys/wait.h>
 
 #include <gnuastro/eps.h>
 #include <gnuastro/pdf.h>
 #include <gnuastro/jpeg.h>
+#include <gnuastro/pointer.h>
 
 #include <gnuastro-internal/checkset.h>
 
@@ -104,9 +104,9 @@ gal_pdf_write(gal_data_t *in, char *filename, float 
widthincm,
               uint32_t borderwidth, uint8_t bordercolor,
               int dontoptimize, gal_data_t *marks)
 {
-  pid_t pid;
-  int childstat=0;
+  int execstat=0;
   size_t w_h_in_pt[2];
+  gal_list_str_t *command=NULL;
   char *device, *devwp, *devhp, *devopt;
   char *epsname=gal_checkset_malloc_cat(filename, ".ps");
 
@@ -132,42 +132,37 @@ gal_pdf_write(gal_data_t *in, char *filename, float 
widthincm,
     error(EXIT_FAILURE, 0, "%s: asprintf allocation error", __func__);
 
   /* Run Ghostscript (if the command changes, also change the command in
-     the error message). We are not using the 'system()' command because
-     that call '/bin/sh', which may not always be usable within the running
-     environment; see https://savannah.nongnu.org/bugs/?65677.
-
-     For a very nice summary on fork/execl, see the first answer in the
-     link below.
-     
https://stackoverflow.com/questions/4204915/please-explain-the-exec-function-and-its-family
-
-     In summary: the child gets 'pid=0' and the parent gets the process ID
-     of the child. The parent then waits for the child to finish and
-     continues. */
-  pid=fork();
-  if(pid<0) error(EXIT_FAILURE, 0, "%s: could not build fork", __func__);
-  if(pid==0)
-    execl(PATH_GHOSTSCRIPT, "gs", "-q", "-o", filename, devopt,
-          devwp, devhp, "-dPDFFitPage", epsname, NULL);
-  else waitpid(pid, &childstat, 0);
-  if(childstat)
+     the error message).  */
+  gal_list_str_add(&command, PATH_GHOSTSCRIPT, 0);
+  gal_list_str_add(&command, "-q", 0);
+  gal_list_str_add(&command, "-o", 0);
+  gal_list_str_add(&command, filename, 0);
+  gal_list_str_add(&command, devopt, 0);
+  gal_list_str_add(&command, devwp, 0);
+  gal_list_str_add(&command, devhp, 0);
+  gal_list_str_add(&command, "-dPDFFitPage", 0);
+  gal_list_str_add(&command, epsname, 0);
+  gal_list_str_reverse(&command);
+  execstat=gal_checkset_exec(PATH_GHOSTSCRIPT, command);
+  if(execstat)
     error(EXIT_FAILURE, 0, "the Ghostscript command (printed at the "
           "end of this message) to convert/compile the EPS file (made "
           "by Gnuastro) to PDF was not successful (Ghostscript returned "
           "with status %d; its error message is shown above)! The EPS "
           "file ('%s') is left if you want to convert it through any "
           "other means (for example the 'epspdf' program). The "
-          "Ghostscript command was: %s -q -o %s %s %s %s -dPDFFitPage "
-          "%s", childstat, epsname, PATH_GHOSTSCRIPT, filename, devopt,
-          devwp, devhp, epsname);
+          "Ghostscript command was: %s", execstat, epsname,
+          gal_list_str_cat(command, ' '));
 
   /* Delete the EPS file. */
   errno=0;
   if(unlink(epsname))
     error(EXIT_FAILURE, errno, "%s", epsname);
 
-  /* Clean up. */
+  /* Clean up the command list and delete the EPS file. */
   free(devhp);
   free(devwp);
   free(devopt);
   free(epsname);
+  gal_list_str_free(command, 0);
 }
diff --git a/lib/pointer.c b/lib/pointer.c
index b7d5bb3c..8c91b389 100644
--- a/lib/pointer.c
+++ b/lib/pointer.c
@@ -94,7 +94,8 @@ gal_pointer_allocate(uint8_t type, size_t size, int clear,
               size * gal_type_sizeof(type), varname);
       else
         error(EXIT_FAILURE, errno, "%s: %zu bytes couldn't be allocated",
-              funcname ? funcname : __func__, size * gal_type_sizeof(type));
+              funcname ? funcname : __func__,
+              size * gal_type_sizeof(type));
     }
 
   return array;
diff --git a/lib/type.c b/lib/type.c
index 08b55578..1b4b0c26 100644
--- a/lib/type.c
+++ b/lib/type.c
@@ -72,26 +72,26 @@ gal_type_sizeof(uint8_t type)
 
     case GAL_TYPE_FLOAT32:
       if( sizeof (float) != 4 )
-        error(EXIT_FAILURE, 0, "%s: 'float' is not 32 bits on this machine",
-              __func__);
+        error(EXIT_FAILURE, 0, "%s: 'float' is not 32 bits on this "
+              "machine", __func__);
       return sizeof (float);
 
     case GAL_TYPE_FLOAT64:
       if( sizeof (double) != 8 )
-        error(EXIT_FAILURE, 0, "%s: 'double' is not 64 bits on this machine",
-              __func__);
+        error(EXIT_FAILURE, 0, "%s: 'double' is not 64 bits on this "
+              "machine", __func__);
       return sizeof (double);
 
     case GAL_TYPE_COMPLEX32:
       if( sizeof (float) != 4 )
-        error(EXIT_FAILURE, 0, "%s: 'float' is not 32 bits on this machine",
-              __func__);
+        error(EXIT_FAILURE, 0, "%s: 'float' is not 32 bits on this "
+              "machine", __func__);
       return sizeof (gsl_complex_float);
 
     case GAL_TYPE_COMPLEX64:
       if( sizeof (double) != 8 )
-        error(EXIT_FAILURE, 0, "%s: 'double' is not 64 bits on this machine",
-              __func__);
+        error(EXIT_FAILURE, 0, "%s: 'double' is not 64 bits on this "
+              "machine", __func__);
       return sizeof (gsl_complex);
 
     case GAL_TYPE_STRING:
@@ -102,9 +102,9 @@ gal_type_sizeof(uint8_t type)
             __func__, type);
     }
 
-  error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s so we can find "
-        "the cause of the problem. Control should not have reached the end of "
-        "this function", __func__, PACKAGE_BUGREPORT);
+  error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s so we can "
+        "find the cause of the problem. Control should not have reached "
+        "the end of this function", __func__, PACKAGE_BUGREPORT);
   return -1;
 }
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]