Merge from coreutils.
[gnulib.git] / lib / getloadavg.c
index ed079b2..8b6067b 100644 (file)
@@ -48,8 +48,6 @@
                                not an array.
    HAVE_STRUCT_NLIST_N_UN_N_NAME `n_un.n_name' is member of `struct nlist'.
    LINUX_LDAV_FILE             [__linux__]: File containing load averages.
-   HAVE_LOCALE_H                locale.h is available.
-   HAVE_SETLOCALE               The `setlocale' function is available.
 
    Specific system predefines this file uses, aside from setting
    default values if not emacs:
@@ -70,9 +68,9 @@
    UMAX4_3
    VMS
    WINDOWS32                   No-op for Windows95/NT.
-   __linux__                   Linux: assumes /proc filesystem mounted.
+   __linux__                   Linux: assumes /proc file system mounted.
                                Support from Michael K. Johnson.
-   __NetBSD__                  NetBSD: assumes /kern filesystem mounted.
+   __NetBSD__                  NetBSD: assumes /kern file system mounted.
 
    In addition, to avoid nesting many #ifdefs, we internally set
    LDAV_DONE to indicate that the load average has been computed.
 # include <config.h>
 #endif
 
-#include <sys/types.h>
-
-/* Both the Emacs and non-Emacs sections want this.  Some
-   configuration files' definitions for the LOAD_AVE_CVT macro (like
-   sparc.h's) use macros like FSCALE, defined here.  */
-#if defined (unix) || defined (__unix)
-# include <sys/param.h>
-#endif
-
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 /* Exclude all the code except the test program at the end
-   if the system has its own `getloadavg' function.
-
-   The declaration of `errno' is needed by the test program
-   as well as the function itself, so it comes first.  */
+   if the system has its own `getloadavg' function.  */
 
-#include <errno.h>
+#ifndef HAVE_GETLOADAVG
 
-#ifndef errno
-extern int errno;
-#endif
+# include <sys/types.h>
 
-#ifdef HAVE_LOCALE_H
-# include <locale.h>
-#endif
-#ifndef HAVE_SETLOCALE
-# define setlocale(Category, Locale) ((char *) NULL)
-#endif
-
-#include "cloexec.h"
-#include "xalloc.h"
+/* Both the Emacs and non-Emacs sections want this.  Some
+   configuration files' definitions for the LOAD_AVE_CVT macro (like
+   sparc.h's) use macros like FSCALE, defined here.  */
+# if defined (unix) || defined (__unix)
+#  include <sys/param.h>
+# endif
 
-#ifndef HAVE_GETLOADAVG
+# include "c-strtod.h"
+# include "cloexec.h"
+# include "xalloc.h"
 
 /* The existing Emacs configuration files define a macro called
    LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and
@@ -362,7 +349,7 @@ extern int errno;
 #  include <unistd.h>
 # endif
 
-# include <stdio.h>
+# include <limits.h>
 
 /* LOAD_AVE_TYPE should only get defined if we're going to use the
    nlist method.  */
@@ -436,7 +423,6 @@ extern int errno;
 # endif /* sgi */
 
 # ifdef UMAX
-#  include <stdio.h>
 #  include <signal.h>
 #  include <sys/time.h>
 #  include <sys/wait.h>
@@ -472,7 +458,7 @@ extern int errno;
 
 # ifdef NeXT
 static processor_set_t default_set;
-static int getloadavg_initialized;
+static bool getloadavg_initialized;
 # endif /* NeXT */
 
 # ifdef UMAX
@@ -487,8 +473,8 @@ static struct dg_sys_info_load_info load_info;      /* what-a-mouthful! */
 # if !defined (HAVE_LIBKSTAT) && defined (LOAD_AVE_TYPE)
 /* File descriptor open to /dev/kmem or VMS load ave driver.  */
 static int channel;
-/* Nonzero iff channel is valid.  */
-static int getloadavg_initialized;
+/* True iff channel is valid.  */
+static bool getloadavg_initialized;
 /* Offset in kmem to seek to read load average, or 0 means invalid.  */
 static long offset;
 
@@ -592,33 +578,37 @@ getloadavg (double loadavg[], int nelem)
 #   define LINUX_LDAV_FILE "/proc/loadavg"
 #  endif
 
-  char ldavgbuf[40];
-  double load_ave[3];
+/* Upper bound on the string length of an integer converted to string.
+   302 / 1000 is ceil (log10 (2.0)).  Subtract 1 for the sign bit;
+   add 1 for integer division truncation; add 1 more for a minus sign.  */
+#  define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2)
+
+  char ldavgbuf[3 * (INT_STRLEN_BOUND (long int) + sizeof ".00")];
+  char const *ptr = ldavgbuf;
   int fd, count;
-  char *old_locale;
 
   fd = open (LINUX_LDAV_FILE, O_RDONLY);
   if (fd == -1)
     return -1;
-  count = read (fd, ldavgbuf, 40);
+  count = read (fd, ldavgbuf, sizeof ldavgbuf - 1);
   (void) close (fd);
   if (count <= 0)
     return -1;
+  ldavgbuf[count] = '\0';
 
-  /* The following sscanf must use the C locale.  */
-  old_locale = setlocale (LC_NUMERIC, NULL);
-  if (old_locale)
-    old_locale = xstrdup (old_locale);
-  setlocale (LC_NUMERIC, "C");
-  count = sscanf (ldavgbuf, "%lf %lf %lf",
-                 &load_ave[0], &load_ave[1], &load_ave[2]);
-  setlocale (LC_NUMERIC, old_locale);
-  free (old_locale);
-  if (count < 1)
-    return -1;
-
-  for (elem = 0; elem < nelem && elem < count; elem++)
-    loadavg[elem] = load_ave[elem];
+  for (elem = 0; elem < nelem; elem++)
+    {
+      char *endptr;
+      double d = c_strtod (ptr, &endptr);
+      if (ptr == endptr)
+       {
+         if (elem == 0)
+           return -1;
+         break;
+       }
+      loadavg[elem] = d;
+      ptr = endptr;
+    }
 
   return elem;
 
@@ -659,7 +649,7 @@ getloadavg (double loadavg[], int nelem)
 
   host_t host;
   struct processor_set_basic_info info;
-  unsigned info_count;
+  unsigned int info_count;
 
   /* We only know how to get the 1-minute average for this system,
      so even if the caller asks for more than 1, we only return 1.  */
@@ -667,7 +657,7 @@ getloadavg (double loadavg[], int nelem)
   if (!getloadavg_initialized)
     {
       if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
-       getloadavg_initialized = 1;
+       getloadavg_initialized = true;
     }
 
   if (getloadavg_initialized)
@@ -676,7 +666,7 @@ getloadavg (double loadavg[], int nelem)
       if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
                              (processor_set_info_t) &info, &info_count)
          != KERN_SUCCESS)
-       getloadavg_initialized = 0;
+       getloadavg_initialized = false;
       else
        {
          if (nelem > 0)
@@ -837,7 +827,7 @@ getloadavg (double loadavg[], int nelem)
   /* VMS specific code -- read from the Load Ave driver.  */
 
   LOAD_AVE_TYPE load_ave[3];
-  static int getloadavg_initialized = 0;
+  static bool getloadavg_initialized;
 #  ifdef eunice
   struct
   {
@@ -857,7 +847,7 @@ getloadavg (double loadavg[], int nelem)
       $DESCRIPTOR (descriptor, "LAV0:");
 #  endif
       if (sys$assign (&descriptor, &channel, 0, 0) & 1)
-       getloadavg_initialized = 1;
+       getloadavg_initialized = true;
     }
 
   /* Read the load average vector.  */
@@ -866,7 +856,7 @@ getloadavg (double loadavg[], int nelem)
                     load_ave, 12, 0, 0, 0, 0) & 1))
     {
       sys$dassgn (channel);
-      getloadavg_initialized = 0;
+      getloadavg_initialized = false;
     }
 
   if (!getloadavg_initialized)
@@ -919,7 +909,7 @@ getloadavg (double loadavg[], int nelem)
 
       ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
       if (ldav_off != -1)
-       offset = (long) ldav_off & 0x7fffffff;
+       offset = (long int) ldav_off & 0x7fffffff;
 #  endif /* sgi */
     }
 
@@ -933,7 +923,7 @@ getloadavg (double loadavg[], int nelem)
          /* Set the channel to close on exec, so it does not
             litter any child's descriptor table.  */
          set_cloexec_flag (channel, true);
-         getloadavg_initialized = 1;
+         getloadavg_initialized = true;
        }
 #  else /* SUNOS_5 */
       /* We pass 0 for the kernel, corefile, and swapfile names
@@ -944,7 +934,7 @@ getloadavg (double loadavg[], int nelem)
          /* nlist the currently running kernel.  */
          kvm_nlist (kd, nl);
          offset = nl[0].n_value;
-         getloadavg_initialized = 1;
+         getloadavg_initialized = true;
        }
 #  endif /* SUNOS_5 */
     }
@@ -959,14 +949,14 @@ getloadavg (double loadavg[], int nelem)
          != sizeof (load_ave))
        {
          close (channel);
-         getloadavg_initialized = 0;
+         getloadavg_initialized = false;
        }
 #  else  /* SUNOS_5 */
       if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
          != sizeof (load_ave))
        {
          kvm_close (kd);
-         getloadavg_initialized = 0;
+         getloadavg_initialized = false;
        }
 #  endif /* SUNOS_5 */
     }
@@ -999,7 +989,7 @@ getloadavg (double loadavg[], int nelem)
 #endif /* ! HAVE_GETLOADAVG */
 \f
 #ifdef TEST
-void
+int
 main (int argc, char **argv)
 {
   int naptime = 0;
@@ -1017,7 +1007,7 @@ main (int argc, char **argv)
       if (loads == -1)
        {
          perror ("Error getting load average");
-         exit (1);
+         return EXIT_FAILURE;
        }
       if (loads > 0)
        printf ("1-minute: %f  ", avg[0]);
@@ -1033,6 +1023,6 @@ main (int argc, char **argv)
       sleep (naptime);
     }
 
-  exit (0);
+  return EXIT_SUCCESS;
 }
 #endif /* TEST */