* print.c (float_to_string): Detect width overflow more reliably.
[bpt/emacs.git] / src / print.c
index 6a331cb..f47dc98 100644 (file)
@@ -46,10 +46,7 @@ static Lisp_Object Qtemp_buffer_setup_hook;
 static Lisp_Object Qfloat_output_format;
 
 #include <math.h>
-
-#if STDC_HEADERS
 #include <float.h>
-#endif
 #include <ftoastr.h>
 
 /* Default to values appropriate for IEEE floating point.  */
@@ -159,8 +156,9 @@ int print_output_debug_flag EXTERNALLY_VISIBLE = 1;
         }                                                              \
        else                                                            \
         {                                                              \
-           print_buffer_size = 1000;                                   \
-           print_buffer = (char *) xmalloc (print_buffer_size);                \
+          ptrdiff_t new_size = 1000;                                   \
+          print_buffer = (char *) xmalloc (new_size);                  \
+          print_buffer_size = new_size;                                \
           free_print_buffer = 1;                                       \
         }                                                              \
        print_buffer_pos = 0;                                           \
@@ -235,9 +233,15 @@ printchar (unsigned int ch, Lisp_Object fun)
 
       if (NILP (fun))
        {
-         if (print_buffer_pos_byte + len >= print_buffer_size)
-           print_buffer = (char *) xrealloc (print_buffer,
-                                             print_buffer_size *= 2);
+         if (print_buffer_size - len <= print_buffer_pos_byte)
+           {
+             ptrdiff_t new_size;
+             if (STRING_BYTES_BOUND / 2 < print_buffer_size)
+               string_overflow ();
+             new_size = print_buffer_size * 2;
+             print_buffer = (char *) xrealloc (print_buffer, new_size);
+             print_buffer_size = new_size;
+           }
          memcpy (print_buffer + print_buffer_pos_byte, str, len);
          print_buffer_pos += 1;
          print_buffer_pos_byte += len;
@@ -280,11 +284,14 @@ strout (const char *ptr, EMACS_INT size, EMACS_INT size_byte,
 
   if (NILP (printcharfun))
     {
-      if (print_buffer_pos_byte + size_byte > print_buffer_size)
+      if (print_buffer_size - size_byte < print_buffer_pos_byte)
        {
-         print_buffer_size = print_buffer_size * 2 + size_byte;
-         print_buffer = (char *) xrealloc (print_buffer,
-                                           print_buffer_size);
+         ptrdiff_t new_size;
+         if (STRING_BYTES_BOUND / 2 - size_byte < print_buffer_size)
+           string_overflow ();
+         new_size = print_buffer_size * 2 + size_byte;
+         print_buffer = (char *) xrealloc (print_buffer, new_size);
+         print_buffer_size = new_size;
        }
       memcpy (print_buffer + print_buffer_pos_byte, ptr, size_byte);
       print_buffer_pos += size;
@@ -381,7 +388,7 @@ print_string (Lisp_Object string, Lisp_Object printcharfun)
          EMACS_INT bytes;
 
          chars = SBYTES (string);
-         bytes = parse_str_to_multibyte (SDATA (string), chars);
+         bytes = count_size_as_multibyte (SDATA (string), chars);
          if (chars < bytes)
            {
              newstr = make_uninit_multibyte_string (chars, bytes);
@@ -808,10 +815,9 @@ safe_debug_print (Lisp_Object arg)
   if (valid > 0)
     debug_print (arg);
   else
-    fprintf (stderr, "#<%s_LISP_OBJECT 0x%08lx>\r\n",
+    fprintf (stderr, "#<%s_LISP_OBJECT 0x%08"pI"x>\r\n",
             !valid ? "INVALID" : "SOME",
-            (unsigned long) XHASH (arg)
-            );
+            XHASH (arg));
 }
 
 \f
@@ -1010,12 +1016,15 @@ float_to_string (char *buf, double data)
        {
          width = 0;
          do
-           width = (width * 10) + (*cp++ - '0');
+           {
+             width = (width * 10) + (*cp++ - '0');
+             if (DBL_DIG < width)
+               goto lose;
+           }
          while (*cp >= '0' && *cp <= '9');
 
          /* A precision of zero is valid only for %f.  */
-         if (width > DBL_DIG
-             || (width == 0 && *cp != 'f'))
+         if (width == 0 && *cp != 'f')
            goto lose;
        }
 
@@ -1083,7 +1092,7 @@ print (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag)
             Maybe a better way to do that is to copy elements to
             a new hash table.  */
          struct Lisp_Hash_Table *h = XHASH_TABLE (Vprint_number_table);
-         int i;
+         EMACS_INT i;
 
          for (i = 0; i < HASH_TABLE_SIZE (h); ++i)
            if (!NILP (HASH_HASH (h, i))
@@ -1199,7 +1208,7 @@ print_preprocess (Lisp_Object obj)
          goto loop;
 
        case Lisp_Vectorlike:
-         size = XVECTOR (obj)->size;
+         size = ASIZE (obj);
          if (size & PSEUDOVECTOR_FLAG)
            size &= PSEUDOVECTOR_SIZE_MASK;
          for (i = 0; i < size; i++)
@@ -1308,7 +1317,9 @@ print_prune_string_charset (Lisp_Object string)
 static void
 print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag)
 {
-  char buf[40];
+  char buf[max (sizeof "from..to..in " + 2 * INT_STRLEN_BOUND (EMACS_INT),
+               max (sizeof " . #" + INT_STRLEN_BOUND (printmax_t),
+                    40))];
 
   QUIT;
 
@@ -1338,11 +1349,11 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
          Lisp_Object num = Fgethash (obj, Vprint_number_table, Qnil);
          if (INTEGERP (num))
            {
-             int n = XINT (num);
+             EMACS_INT n = XINT (num);
              if (n < 0)
                { /* Add a prefix #n= if OBJ has not yet been printed;
                     that is, its status field is nil.  */
-                 sprintf (buf, "#%d=", -n);
+                 sprintf (buf, "#%"pI"d=", -n);
                  strout (buf, -1, -1, printcharfun);
                  /* OBJ is going to be printed.  Remember that fact.  */
                  Fputhash (obj, make_number (- n), Vprint_number_table);
@@ -1350,7 +1361,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
              else
                {
                  /* Just print #n# if OBJ has already been printed.  */
-                 sprintf (buf, "#%d#", n);
+                 sprintf (buf, "#%"pI"d#", n);
                  strout (buf, -1, -1, printcharfun);
                  return;
                }
@@ -1363,12 +1374,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
   switch (XTYPE (obj))
     {
     case_Lisp_Int:
-      if (sizeof (int) == sizeof (EMACS_INT))
-       sprintf (buf, "%d", (int) XINT (obj));
-      else if (sizeof (long) == sizeof (EMACS_INT))
-       sprintf (buf, "%ld", (long) XINT (obj));
-      else
-       abort ();
+      sprintf (buf, "%"pI"d", XINT (obj));
       strout (buf, -1, -1, printcharfun);
       break;
 
@@ -1535,13 +1541,19 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
        else
          confusing = 0;
 
+       size_byte = SBYTES (name);
+
        if (! NILP (Vprint_gensym) && !SYMBOL_INTERNED_P (obj))
          {
            PRINTCHAR ('#');
            PRINTCHAR (':');
          }
-
-       size_byte = SBYTES (name);
+       else if (size_byte == 0)
+         {
+           PRINTCHAR ('#');
+           PRINTCHAR ('#');
+           break;
+         }
 
        for (i = 0, i_byte = 0; i_byte < size_byte;)
          {
@@ -1554,7 +1566,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
              {
                if (c == '\"' || c == '\\' || c == '\''
                    || c == ';' || c == '#' || c == '(' || c == ')'
-                   || c == ',' || c =='.' || c == '`'
+                   || c == ',' || c == '.' || c == '`'
                    || c == '[' || c == ']' || c == '?' || c <= 040
                    || confusing)
                  PRINTCHAR ('\\'), confusing = 0;
@@ -1607,8 +1619,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
          PRINTCHAR ('(');
 
          {
-           EMACS_INT print_length;
-           int i;
+           printmax_t i, print_length;
            Lisp_Object halftail = obj;
 
            /* Negative values of print-length are invalid in CL.
@@ -1616,7 +1627,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
            if (NATNUMP (Vprint_length))
              print_length = XFASTINT (Vprint_length);
            else
-             print_length = 0;
+             print_length = TYPE_MAXIMUM (printmax_t);
 
            i = 0;
            while (CONSP (obj))
@@ -1627,7 +1638,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
                    /* Simple but imcomplete way.  */
                    if (i != 0 && EQ (obj, halftail))
                      {
-                       sprintf (buf, " . #%d", i / 2);
+                       sprintf (buf, " . #%"pMd, i / 2);
                        strout (buf, -1, -1, printcharfun);
                        goto end_of_list;
                      }
@@ -1647,15 +1658,16 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
                      }
                  }
 
-               if (i++)
+               if (i)
                  PRINTCHAR (' ');
 
-               if (print_length && i > print_length)
+               if (print_length <= i)
                  {
                    strout ("...", 3, 3, printcharfun);
                    goto end_of_list;
                  }
 
+               i++;
                print_object (XCAR (obj), printcharfun, escapeflag);
 
                obj = XCDR (obj);
@@ -1701,7 +1713,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
 
          PRINTCHAR ('#');
          PRINTCHAR ('&');
-         sprintf (buf, "%ld", (long) XBOOL_VECTOR (obj)->size);
+         sprintf (buf, "%"pI"d", XBOOL_VECTOR (obj)->size);
          strout (buf, -1, -1, printcharfun);
          PRINTCHAR ('\"');
 
@@ -1754,7 +1766,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
       else if (WINDOWP (obj))
        {
          strout ("#<window ", -1, -1, printcharfun);
-         sprintf (buf, "%ld", (long) XFASTINT (XWINDOW (obj)->sequence_number));
+         sprintf (buf, "%"pI"d", XFASTINT (XWINDOW (obj)->sequence_number));
          strout (buf, -1, -1, printcharfun);
          if (!NILP (XWINDOW (obj)->buffer))
            {
@@ -1791,19 +1803,17 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
              PRINTCHAR (' ');
              strout (SDATA (SYMBOL_NAME (h->weak)), -1, -1, printcharfun);
              PRINTCHAR (' ');
-             sprintf (buf, "%ld/%ld", (long) h->count,
-                      (long) XVECTOR (h->next)->size);
+             sprintf (buf, "%"pI"d/%"pI"d", h->count, ASIZE (h->next));
              strout (buf, -1, -1, printcharfun);
            }
-         sprintf (buf, " 0x%lx", (unsigned long) h);
+         sprintf (buf, " %p", h);
          strout (buf, -1, -1, printcharfun);
          PRINTCHAR ('>');
 #endif
          /* Implement a readable output, e.g.:
            #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
          /* Always print the size. */
-         sprintf (buf, "#s(hash-table size %ld",
-                  (long) XVECTOR (h->next)->size);
+         sprintf (buf, "#s(hash-table size %"pI"d", ASIZE (h->next));
          strout (buf, -1, -1, printcharfun);
 
          if (!NILP (h->test))
@@ -1881,7 +1891,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
                   ? "#<frame " : "#<dead frame "),
                  -1, -1, printcharfun);
          print_string (XFRAME (obj)->name, printcharfun);
-         sprintf (buf, " 0x%lx", (unsigned long) (XFRAME (obj)));
+         sprintf (buf, " %p", XFRAME (obj));
          strout (buf, -1, -1, printcharfun);
          PRINTCHAR ('>');
        }
@@ -1915,7 +1925,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
        }
       else
        {
-         EMACS_INT size = XVECTOR (obj)->size;
+         EMACS_INT size = ASIZE (obj);
          if (COMPILEDP (obj))
            {
              PRINTCHAR ('#');
@@ -1978,7 +1988,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
            strout ("in no buffer", -1, -1, printcharfun);
          else
            {
-             sprintf (buf, "at %ld", (long)marker_position (obj));
+             sprintf (buf, "at %"pI"d", marker_position (obj));
              strout (buf, -1, -1, printcharfun);
              strout (" in ", -1, -1, printcharfun);
              print_string (BVAR (XMARKER (obj)->buffer, name), printcharfun);
@@ -1992,9 +2002,9 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
            strout ("in no buffer", -1, -1, printcharfun);
          else
            {
-             sprintf (buf, "from %ld to %ld in ",
-                      (long)marker_position (OVERLAY_START (obj)),
-                      (long)marker_position (OVERLAY_END   (obj)));
+             sprintf (buf, "from %"pI"d to %"pI"d in ",
+                      marker_position (OVERLAY_START (obj)),
+                      marker_position (OVERLAY_END   (obj)));
              strout (buf, -1, -1, printcharfun);
              print_string (BVAR (XMARKER (OVERLAY_START (obj))->buffer, name),
                            printcharfun);
@@ -2010,8 +2020,8 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
 
        case Lisp_Misc_Save_Value:
          strout ("#<save_value ", -1, -1, printcharfun);
-         sprintf(buf, "ptr=0x%08lx int=%d",
-                 (unsigned long) XSAVE_VALUE (obj)->pointer,
+         sprintf(buf, "ptr=%p int=%"pD"d",
+                 XSAVE_VALUE (obj)->pointer,
                  XSAVE_VALUE (obj)->integer);
          strout (buf, -1, -1, printcharfun);
          PRINTCHAR ('>');
@@ -2031,7 +2041,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
        if (MISCP (obj))
          sprintf (buf, "(MISC 0x%04x)", (int) XMISCTYPE (obj));
        else if (VECTORLIKEP (obj))
-         sprintf (buf, "(PVEC 0x%08x)", (int) XVECTOR (obj)->size);
+         sprintf (buf, "(PVEC 0x%08"pI"x)", ASIZE (obj));
        else
          sprintf (buf, "(0x%02x)", (int) XTYPE (obj));
        strout (buf, -1, -1, printcharfun);
@@ -2065,8 +2075,7 @@ print_interval (INTERVAL interval, Lisp_Object printcharfun)
 void
 syms_of_print (void)
 {
-  Qtemp_buffer_setup_hook = intern_c_string ("temp-buffer-setup-hook");
-  staticpro (&Qtemp_buffer_setup_hook);
+  DEFSYM (Qtemp_buffer_setup_hook, "temp-buffer-setup-hook");
 
   DEFVAR_LISP ("standard-output", Vstandard_output,
               doc: /* Output stream `print' uses by default for outputting a character.
@@ -2075,8 +2084,7 @@ It may also be a buffer (output is inserted before point)
 or a marker (output is inserted and the marker is advanced)
 or the symbol t (output appears in the echo area).  */);
   Vstandard_output = Qt;
-  Qstandard_output = intern_c_string ("standard-output");
-  staticpro (&Qstandard_output);
+  DEFSYM (Qstandard_output, "standard-output");
 
   DEFVAR_LISP ("float-output-format", Vfloat_output_format,
               doc: /* The format descriptor string used to print floats.
@@ -2095,8 +2103,7 @@ decimal point.  0 is not allowed with `e' or `g'.
 A value of nil means to use the shortest notation
 that represents the number without losing information.  */);
   Vfloat_output_format = Qnil;
-  Qfloat_output_format = intern_c_string ("float-output-format");
-  staticpro (&Qfloat_output_format);
+  DEFSYM (Qfloat_output_format, "float-output-format");
 
   DEFVAR_LISP ("print-length", Vprint_length,
               doc: /* Maximum length of list to print before abbreviating.
@@ -2201,17 +2208,10 @@ priorities.  */);
   defsubr (&Sredirect_debugging_output);
 #endif
 
-  Qexternal_debugging_output = intern_c_string ("external-debugging-output");
-  staticpro (&Qexternal_debugging_output);
-
-  Qprint_escape_newlines = intern_c_string ("print-escape-newlines");
-  staticpro (&Qprint_escape_newlines);
-
-  Qprint_escape_multibyte = intern_c_string ("print-escape-multibyte");
-  staticpro (&Qprint_escape_multibyte);
-
-  Qprint_escape_nonascii = intern_c_string ("print-escape-nonascii");
-  staticpro (&Qprint_escape_nonascii);
+  DEFSYM (Qexternal_debugging_output, "external-debugging-output");
+  DEFSYM (Qprint_escape_newlines, "print-escape-newlines");
+  DEFSYM (Qprint_escape_multibyte, "print-escape-multibyte");
+  DEFSYM (Qprint_escape_nonascii, "print-escape-nonascii");
 
   print_prune_charset_plist = Qnil;
   staticpro (&print_prune_charset_plist);