Bring over lost listing bits from emc-97r1-branch.
authorRichard Henderson <rth@redhat.com>
Tue, 27 Jan 1998 14:45:09 +0000 (14:45 +0000)
committerRichard Henderson <rth@redhat.com>
Tue, 27 Jan 1998 14:45:09 +0000 (14:45 +0000)
gas/ChangeLog
gas/as.c
gas/listing.c

index 70cb618..8379fe7 100644 (file)
@@ -1,3 +1,14 @@
+Tue Jan 27 06:38:35 1998  Richard Henderson  <rth@cygnus.com>
+
+       * as.c (parse_args): Add --listing-lhs-width, --listing-lhs-width2,
+       --listing-rhs-width, --listing-cont-lines.
+       (show_usage): Update.
+       * listing.c (listing_lhs_width, listing_lhs_width_second): New vars.
+       (listing_lhs_cont_lines, listing_rhs_width): New vars.
+       (print_lines): Use the variables instead of the constants.
+       (listing_listing): Likewise.    
+       * listing.h: Declare the new vars.
+       
 Tue Jan 27 05:32:05 1998  Richard Henderson  <rth@cygnus.com>
 
        * as.c (parse_args): Add --keep-locals alias for -L.
 Tue Jan 27 05:32:05 1998  Richard Henderson  <rth@cygnus.com>
 
        * as.c (parse_args): Add --keep-locals alias for -L.
index 1d7bd8b..4261308 100644 (file)
--- a/gas/as.c
+++ b/gas/as.c
@@ -166,6 +166,16 @@ Options:\n\
 -w                     ignored\n\
 -X                     ignored\n\
 -Z                     generate object file even after errors\n");
 -w                     ignored\n\
 -X                     ignored\n\
 -Z                     generate object file even after errors\n");
+  fprintf (stream, "\
+--listing-lhs-width    set the width in words of the output data column of\n\
+                       the listing\n\
+--listing-lhs-width2   set the width in words of the continuation lines\n\
+                       of the output data column; ignored if smaller than\n\
+                       the width of the first line\n\
+--listing-rhs-width    set the max width in characters of the lines from\n\
+                       the source file\n\
+--listing-cont-lines   set the maximum number of continuation lines used\n\
+                       for the output data column of the listing\n");
 
   md_show_usage (stream);
 
 
   md_show_usage (stream);
 
@@ -333,11 +343,19 @@ parse_args (pargc, pargv)
        formats are added to the built-in set of instructions, and
        mnemonics for new registers may also be defined.  */
     {"itbl", required_argument, NULL, OPTION_INSTTBL},
        formats are added to the built-in set of instructions, and
        mnemonics for new registers may also be defined.  */
     {"itbl", required_argument, NULL, OPTION_INSTTBL},
-#define OPTION_DEPFILE (OPTION_STD_BASE + 9)
+#define OPTION_LISTING_LHS_WIDTH (OPTION_STD_BASE + 9)
+    {"listing-lhs-width", required_argument, NULL, OPTION_LISTING_LHS_WIDTH},
+#define OPTION_LISTING_LHS_WIDTH2 (OPTION_STD_BASE + 10)
+    {"listing-lhs-width", required_argument, NULL, OPTION_LISTING_LHS_WIDTH2},
+#define OPTION_LISTING_RHS_WIDTH (OPTION_STD_BASE + 11)
+    {"listing-rhs-width", required_argument, NULL, OPTION_LISTING_RHS_WIDTH},
+#define OPTION_LISTING_CONT_LINES (OPTION_STD_BASE + 12)
+    {"listing-cont-lines", required_argument, NULL, OPTION_LISTING_CONT_LINES},
+#define OPTION_DEPFILE (OPTION_STD_BASE + 13)
     {"MD", required_argument, NULL, OPTION_DEPFILE},
     {"MD", required_argument, NULL, OPTION_DEPFILE},
-#define OPTION_GSTABS (OPTION_STD_BASE + 10)
+#define OPTION_GSTABS (OPTION_STD_BASE + 14)
     {"gstabs", no_argument, NULL, OPTION_GSTABS},
     {"gstabs", no_argument, NULL, OPTION_GSTABS},
-#define OPTION_STRIP_LOCAL_ABSOLUTE (OPTION_STD_BASE + 11)
+#define OPTION_STRIP_LOCAL_ABSOLUTE (OPTION_STD_BASE + 15)
     {"strip-local-absolute", no_argument, NULL, OPTION_STRIP_LOCAL_ABSOLUTE}
   };
 
     {"strip-local-absolute", no_argument, NULL, OPTION_STRIP_LOCAL_ABSOLUTE}
   };
 
@@ -529,6 +547,25 @@ the GNU General Public License.  This program has absolutely no warranty.\n");
          flag_keep_locals = 1;
          break;
 
          flag_keep_locals = 1;
          break;
 
+       case OPTION_LISTING_LHS_WIDTH:
+         listing_lhs_width = atoi(optarg);
+         if (listing_lhs_width_second < listing_lhs_width)
+           listing_lhs_width_second = listing_lhs_width;
+         break;
+       case OPTION_LISTING_LHS_WIDTH2:
+         {
+           int tmp = atoi(optarg);
+           if (tmp > listing_lhs_width)
+             listing_lhs_width_second = tmp;
+         }
+         break;
+       case OPTION_LISTING_RHS_WIDTH:
+         listing_rhs_width = atoi(optarg);
+         break;
+       case OPTION_LISTING_CONT_LINES:
+         listing_lhs_cont_lines = atoi(optarg);
+         break;
+
        case 'M':
          flag_mri = 1;
 #ifdef TC_M68K
        case 'M':
          flag_mri = 1;
 #ifdef TC_M68K
index b42f146..5e23e66 100644 (file)
@@ -1,5 +1,5 @@
 /* listing.c - mainting assembly listings
 /* listing.c - mainting assembly listings
-   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
 This file is part of GAS, the GNU Assembler.
 
 
 This file is part of GAS, the GNU Assembler.
 
@@ -14,8 +14,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GAS; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+along with GAS; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
 
 /*
  Contributed by Steve Chamberlain
 
 /*
  Contributed by Steve Chamberlain
@@ -99,6 +100,7 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307
 #include "subsegs.h"
 
 #ifndef NO_LISTING
 #include "subsegs.h"
 
 #ifndef NO_LISTING
+
 #ifndef LISTING_HEADER
 #define LISTING_HEADER "GAS LISTING"
 #endif
 #ifndef LISTING_HEADER
 #define LISTING_HEADER "GAS LISTING"
 #endif
@@ -118,46 +120,43 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307
 #define LISTING_LHS_CONT_LINES 4
 #endif
 
 #define LISTING_LHS_CONT_LINES 4
 #endif
 
-
-
-
 /* This structure remembers which .s were used */
 typedef struct file_info_struct
 {
 /* This structure remembers which .s were used */
 typedef struct file_info_struct
 {
+  struct file_info_struct *next;
   char *filename;
   char *filename;
+  long pos;
   int linenum;
   int linenum;
-  FILE *file;
-  struct file_info_struct *next;
   int at_end;
 }
   int at_end;
 }
-
 file_info_type;
 
 
 /* this structure rememebrs which line from which file goes into which
    frag */
 file_info_type;
 
 
 /* this structure rememebrs which line from which file goes into which
    frag */
-typedef struct list_info_struct
+struct list_info_struct
 {
   /* Frag which this line of source is nearest to */
   fragS *frag;
 {
   /* Frag which this line of source is nearest to */
   fragS *frag;
+
   /* The actual line in the source file */
   unsigned int line;
   /* Pointer to the file info struct for the file which this line
      belongs to */
   file_info_type *file;
 
   /* The actual line in the source file */
   unsigned int line;
   /* Pointer to the file info struct for the file which this line
      belongs to */
   file_info_type *file;
 
+  /* The expanded text of any macro that may have been executing.  */
+  char *line_contents;
+
   /* Next in list */
   struct list_info_struct *next;
 
   /* Next in list */
   struct list_info_struct *next;
 
-
   /* Pointer to the file info struct for the high level language
      source line that belongs here */
   file_info_type *hll_file;
   /* Pointer to the file info struct for the high level language
      source line that belongs here */
   file_info_type *hll_file;
-
   /* High level language source line */
   int hll_line;
 
   /* High level language source line */
   int hll_line;
 
-
   /* Pointer to any error message associated with this line */
   char *message;
 
   /* Pointer to any error message associated with this line */
   char *message;
 
@@ -168,14 +167,18 @@ typedef struct list_info_struct
       EDICT_TITLE,
       EDICT_NOLIST,
       EDICT_LIST,
       EDICT_TITLE,
       EDICT_NOLIST,
       EDICT_LIST,
+      EDICT_NOLIST_NEXT,
       EDICT_EJECT
     } edict;
   char *edict_arg;
 
       EDICT_EJECT
     } edict;
   char *edict_arg;
 
-}
-
-list_info_type;
+  /* Nonzero if this line is to be omitted because it contains
+     debugging information.  This can become a flags field if we come
+     up with more information to store here.  */
+  int debugging;
+};
 
 
+typedef struct list_info_struct list_info_type;
 
 static struct list_info_struct *head;
 struct list_info_struct *listing_tail;
 
 static struct list_info_struct *head;
 struct list_info_struct *listing_tail;
@@ -187,15 +190,16 @@ static int paper_height = 60;
 /* File to output listings to.  */
 static FILE *list_file;
 
 /* File to output listings to.  */
 static FILE *list_file;
 
-/* this static array is used to keep the text of data to be printed
-   before the start of the line.
-    It is stored so we can give a bit more info on the next line.  To much, and large
-   initialized arrays will use up lots of paper.
- */
+/* This static array is used to keep the text of data to be printed
+   before the start of the line.  */
 
 
-static char data_buffer[100];
-static unsigned int data_buffer_size;
+#define MAX_BYTES                                                      \
+  (((LISTING_WORD_SIZE * 2) + 1) * LISTING_LHS_WIDTH                   \
+   + ((((LISTING_WORD_SIZE * 2) + 1) * LISTING_LHS_WIDTH_SECOND)       \
+      * LISTING_LHS_CONT_LINES)                                                \
+   + 20)
 
 
+static char data_buffer[MAX_BYTES];
 
 /* Prototypes.  */
 static void listing_message PARAMS ((const char *name, const char *message));
 
 /* Prototypes.  */
 static void listing_message PARAMS ((const char *name, const char *message));
@@ -205,15 +209,14 @@ static char *buffer_line PARAMS ((file_info_type *file,
                                  char *line, unsigned int size));
 static void listing_page PARAMS ((list_info_type *list));
 static unsigned int calc_hex PARAMS ((list_info_type *list));
                                  char *line, unsigned int size));
 static void listing_page PARAMS ((list_info_type *list));
 static unsigned int calc_hex PARAMS ((list_info_type *list));
-static void print_lines PARAMS ((list_info_type *list,
-                                char *string,
-                                unsigned int address));
+static void print_lines PARAMS ((list_info_type *, unsigned int,
+                                char *, unsigned int));
 static void list_symbol_table PARAMS ((void));
 static void print_source PARAMS ((file_info_type *current_file,
                                  list_info_type *list,
                                  char *buffer,
                                  unsigned int width));
 static void list_symbol_table PARAMS ((void));
 static void print_source PARAMS ((file_info_type *current_file,
                                  list_info_type *list,
                                  char *buffer,
                                  unsigned int width));
-static int debugging_pseudo PARAMS ((char *line));
+static int debugging_pseudo PARAMS ((list_info_type *, const char *));
 static void listing_listing PARAMS ((char *name));
 
 
 static void listing_listing PARAMS ((char *name));
 
 
@@ -247,9 +250,15 @@ listing_error (message)
 }
 
 
 }
 
 
+int listing_lhs_width = LISTING_LHS_WIDTH;
+int listing_lhs_width_second = LISTING_LHS_WIDTH_SECOND;
+int listing_lhs_cont_lines = LISTING_LHS_CONT_LINES;
+int listing_rhs_width = LISTING_RHS_WIDTH;
 
 
 static file_info_type *file_info_head;
 
 
 static file_info_type *file_info_head;
+static file_info_type *last_open_file_info;
+static FILE *last_open_file;
 
 static file_info_type *
 file_info (file_name)
 
 static file_info_type *
 file_info (file_name)
@@ -272,13 +281,10 @@ file_info (file_name)
   file_info_head = p;
   p->filename = xmalloc ((unsigned long) strlen (file_name) + 1);
   strcpy (p->filename, file_name);
   file_info_head = p;
   p->filename = xmalloc ((unsigned long) strlen (file_name) + 1);
   strcpy (p->filename, file_name);
+  p->pos = 0;
   p->linenum = 0;
   p->at_end = 0;
 
   p->linenum = 0;
   p->at_end = 0;
 
-  p->file = fopen (p->filename, "r");
-  if (p->file)
-    fgetc (p->file);
-
   return p;
 }
 
   return p;
 }
 
@@ -300,7 +306,7 @@ listing_newline (ps)
   unsigned int line;
   static unsigned int last_line = 0xffff;
   static char *last_file = NULL;
   unsigned int line;
   static unsigned int last_line = 0xffff;
   static char *last_file = NULL;
-  list_info_type *new;
+  list_info_type *new = NULL;
 
   if (listing == 0)
     return;
 
   if (listing == 0)
     return;
@@ -308,34 +314,77 @@ listing_newline (ps)
   if (now_seg == absolute_section)
     return;
 
   if (now_seg == absolute_section)
     return;
 
+#ifdef OBJ_ELF
+  /* In ELF, anything in a section beginning with .debug or .line is
+     considered to be debugging information.  This includes the
+     statement which switches us into the debugging section, which we
+     can only set after we are already in the debugging section.  */
+  if ((listing & LISTING_NODEBUG) != 0
+      && listing_tail != NULL
+      && ! listing_tail->debugging)
+    {
+      const char *segname;
+
+      segname = segment_name (now_seg);
+      if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0
+         || strncmp (segname, ".line", sizeof ".line" - 1) == 0)
+       listing_tail->debugging = 1;
+    }
+#endif
+
   as_where (&file, &line);
   as_where (&file, &line);
-  if (line != last_line || (last_file && file && strcmp(file, last_file)))
+  if (ps == NULL)
     {
     {
-      last_line = line;
-      last_file = file;
-      new_frag ();
+      if (line == last_line && !(last_file && file && strcmp(file, last_file)))
+       return;
 
       new = (list_info_type *) xmalloc (sizeof (list_info_type));
 
       new = (list_info_type *) xmalloc (sizeof (list_info_type));
-      new->frag = frag_now;
-      new->line = line;
-      new->file = file_info (file);
+      new->line_contents = NULL;
+    }
+  else
+    {
+      new = (list_info_type *) xmalloc (sizeof (list_info_type));
+      new->line_contents = ps;
+    }
 
 
-      if (listing_tail)
-       {
-         listing_tail->next = new;
-       }
-      else
-       {
-         head = new;
-       }
-      listing_tail = new;
-      new->next = (list_info_type *) NULL;
-      new->message = (char *) NULL;
-      new->edict = EDICT_NONE;
-      new->hll_file = (file_info_type *) NULL;
-      new->hll_line = 0;
-      new_frag ();
+  last_line = line;
+  last_file = file;
+  new_frag ();
+
+  if (listing_tail)
+    {
+      listing_tail->next = new;
+    }
+  else
+    {
+      head = new;
     }
     }
+  listing_tail = new;
+
+  new->frag = frag_now;
+  new->line = line;
+  new->file = file_info (file);
+  new->next = (list_info_type *) NULL;
+  new->message = (char *) NULL;
+  new->edict = EDICT_NONE;
+  new->hll_file = (file_info_type *) NULL;
+  new->hll_line = 0;
+  new->debugging = 0;
+  new_frag ();
+
+#ifdef OBJ_ELF
+  /* In ELF, anything in a section beginning with .debug or .line is
+     considered to be debugging information.  */
+  if ((listing & LISTING_NODEBUG) != 0)
+    {
+      const char *segname;
+
+      segname = segment_name (now_seg);
+      if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0
+         || strncmp (segname, ".line", sizeof ".line" - 1) == 0)
+       new->debugging = 1;
+    }
+#endif
 }
 
 /* Attach all current frags to the previous line instead of the
 }
 
 /* Attach all current frags to the previous line instead of the
@@ -385,15 +434,29 @@ buffer_line (file, line, size)
   char *p = line;
 
   /* If we couldn't open the file, return an empty line */
   char *p = line;
 
   /* If we couldn't open the file, return an empty line */
-  if (file->file == (FILE *) NULL || file->at_end)
+  if (file->at_end)
+    return "";
+
+  /* Check the cache and see if we last used this file.  */
+  if (!last_open_file_info || file != last_open_file_info)
     {
     {
-      return "";
-    }
+      if (last_open_file)
+       {
+         last_open_file_info->pos = ftell (last_open_file);
+         fclose (last_open_file);
+       }
 
 
-  if (file->linenum == 0)
-    rewind (file->file);
+      last_open_file_info = file;
+      last_open_file = fopen (file->filename, "r");
+      if (!last_open_file)
+       return "";
 
 
-  c = fgetc (file->file);
+      /* Seek to where we were last time this file was open.  */
+      if (file->pos)
+       fseek(last_open_file, file->pos, SEEK_SET);
+    }
+
+  c = fgetc (last_open_file);
 
   size -= 1;                   /* leave room for null */
 
 
   size -= 1;                   /* leave room for null */
 
@@ -403,7 +466,7 @@ buffer_line (file, line, size)
        *p++ = c;
       count++;
 
        *p++ = c;
       count++;
 
-      c = fgetc (file->file);
+      c = fgetc (last_open_file);
 
     }
   if (c == EOF)
 
     }
   if (c == EOF)
@@ -477,15 +540,13 @@ static unsigned int
 calc_hex (list)
      list_info_type * list;
 {
 calc_hex (list)
      list_info_type * list;
 {
+  int data_buffer_size;
   list_info_type *first = list;
   unsigned int address = (unsigned int) ~0;
   list_info_type *first = list;
   unsigned int address = (unsigned int) ~0;
-
   fragS *frag;
   fragS *frag_ptr;
   fragS *frag;
   fragS *frag_ptr;
-
   unsigned int byte_in_frag;
 
   unsigned int byte_in_frag;
 
-
   /* Find first frag which says it belongs to this line */
   frag = list->frag;
   while (frag && frag->line != list)
   /* Find first frag which says it belongs to this line */
   frag = list->frag;
   while (frag && frag->line != list)
@@ -500,7 +561,8 @@ calc_hex (list)
     {
       /* Print as many bytes from the fixed part as is sensible */
       byte_in_frag = 0;
     {
       /* Print as many bytes from the fixed part as is sensible */
       byte_in_frag = 0;
-      while (byte_in_frag < frag_ptr->fr_fix && data_buffer_size < sizeof (data_buffer) - 10)
+      while (byte_in_frag < frag_ptr->fr_fix
+            && data_buffer_size < sizeof (data_buffer) - 3)
        {
          if (address == ~0)
            {
        {
          if (address == ~0)
            {
@@ -520,7 +582,7 @@ calc_hex (list)
        /* Print as many bytes from the variable part as is sensible */
        while ((byte_in_frag
                < frag_ptr->fr_fix + frag_ptr->fr_var * frag_ptr->fr_offset)
        /* Print as many bytes from the variable part as is sensible */
        while ((byte_in_frag
                < frag_ptr->fr_fix + frag_ptr->fr_var * frag_ptr->fr_offset)
-              && data_buffer_size < sizeof (data_buffer) - 10)
+              && data_buffer_size < sizeof (data_buffer) - 3)
          {
            if (address == ~0)
              {
          {
            if (address == ~0)
              {
@@ -545,7 +607,7 @@ calc_hex (list)
 
       frag_ptr = frag_ptr->fr_next;
     }
 
       frag_ptr = frag_ptr->fr_next;
     }
-  data_buffer[data_buffer_size++] = 0;
+  data_buffer[data_buffer_size] = '\0';
   return address;
 }
 
   return address;
 }
 
@@ -555,8 +617,9 @@ calc_hex (list)
 
 
 static void
 
 
 static void
-print_lines (list, string, address)
+print_lines (list, lineno, string, address)
      list_info_type *list;
      list_info_type *list;
+     unsigned int lineno;
      char *string;
      unsigned int address;
 {
      char *string;
      unsigned int address;
 {
@@ -568,11 +631,11 @@ print_lines (list, string, address)
 
   /* Print the stuff on the first line */
   listing_page (list);
 
   /* Print the stuff on the first line */
   listing_page (list);
-  nchars = (LISTING_WORD_SIZE * 2 + 1) * LISTING_LHS_WIDTH;
+  nchars = (LISTING_WORD_SIZE * 2 + 1) * listing_lhs_width;
   /* Print the hex for the first line */
   if (address == ~0)
     {
   /* Print the hex for the first line */
   if (address == ~0)
     {
-      fprintf (list_file, "% 4d     ", list->line);
+      fprintf (list_file, "% 4d     ", lineno);
       for (idx = 0; idx < nchars; idx++)
        fprintf (list_file, " ");
 
       for (idx = 0; idx < nchars; idx++)
        fprintf (list_file, " ");
 
@@ -585,11 +648,11 @@ print_lines (list, string, address)
     {
       if (had_errors ())
        {
     {
       if (had_errors ())
        {
-         fprintf (list_file, "% 4d ???? ", list->line);
+         fprintf (list_file, "% 4d ???? ", lineno);
        }
       else
        {
        }
       else
        {
-         fprintf (list_file, "% 4d %04x ", list->line, address);
+         fprintf (list_file, "% 4d %04x ", lineno, address);
        }
 
       /* And the data to go along with it */
        }
 
       /* And the data to go along with it */
@@ -622,15 +685,13 @@ print_lines (list, string, address)
          on_page++;
        }
 
          on_page++;
        }
 
-      for (lines = 0;
-          lines < LISTING_LHS_CONT_LINES
-          && *src;
-          lines++)
+      for (lines = 0; lines < listing_lhs_cont_lines && *src; lines++)
        {
        {
-         nchars = ((LISTING_WORD_SIZE * 2) + 1) * LISTING_LHS_WIDTH_SECOND - 1;
+         nchars = (((LISTING_WORD_SIZE * 2) + 1)
+                   * listing_lhs_width_second - 1);
          idx = 0;
          /* Print any more lines of data, but more compactly */
          idx = 0;
          /* Print any more lines of data, but more compactly */
-         fprintf (list_file, "% 4d      ", list->line);
+         fprintf (list_file, "% 4d      ", lineno);
 
          while (*src && idx < nchars)
            {
 
          while (*src && idx < nchars)
            {
@@ -688,12 +749,7 @@ list_symbol_table ()
                }
 #if defined (BFD64)
              else if (sizeof (val) > 4)
                }
 #if defined (BFD64)
              else if (sizeof (val) > 4)
-               {
-                 char buf1[30];
-                 sprintf_vma (buf1, val);
-                 strcpy (buf, "00000000");
-                 strcpy (buf + 8 - strlen (buf1), buf1);
-               }
+               sprintf_vma (buf, val);
 #endif
              else
                abort ();
 #endif
              else
                abort ();
@@ -766,7 +822,7 @@ print_source (current_file, list, buffer, width)
      char *buffer;
      unsigned int width;
 {
      char *buffer;
      unsigned int width;
 {
-  if (current_file->file)
+  if (!current_file->at_end)
     {
       while (current_file->linenum < list->hll_line
             && !current_file->at_end)
     {
       while (current_file->linenum < list->hll_line
             && !current_file->at_end)
@@ -781,17 +837,48 @@ print_source (current_file, list, buffer, width)
 }
 
 /* Sometimes the user doesn't want to be bothered by the debugging
 }
 
 /* Sometimes the user doesn't want to be bothered by the debugging
-   records inserted by the compiler, see if the line is suspicious */
+   records inserted by the compiler, see if the line is suspicious */
 
 static int
 
 static int
-debugging_pseudo (line)
-     char *line;
+debugging_pseudo (list, line)
+     list_info_type *list;
+     const char *line;
 {
 {
+  static int in_debug;
+  int was_debug;
+
+  if (list->debugging)
+    {
+      in_debug = 1;
+      return 1;
+    }
+
+  was_debug = in_debug;
+  in_debug = 0;
+
   while (isspace (*line))
     line++;
 
   if (*line != '.')
   while (isspace (*line))
     line++;
 
   if (*line != '.')
-    return 0;
+    {
+#ifdef OBJ_ELF
+      /* The ELF compiler sometimes emits blank lines after switching
+         out of a debugging section.  If the next line drops us back
+         into debugging information, then don't print the blank line.
+         This is a hack for a particular compiler behaviour, not a
+         general case.  */
+      if (was_debug
+         && *line == '\0'
+         && list->next != NULL
+         && list->next->debugging)
+       {
+         in_debug = 1;
+         return 1;
+       }
+#endif
+
+      return 0;
+    }
 
   line++;
 
 
   line++;
 
@@ -822,7 +909,6 @@ debugging_pseudo (line)
     return 1;
 
   return 0;
     return 1;
 
   return 0;
-
 }
 
 static void
 }
 
 static void
@@ -837,7 +923,7 @@ listing_listing (name)
   int show_listing = 1;
   unsigned int width;
 
   int show_listing = 1;
   unsigned int width;
 
-  buffer = xmalloc (LISTING_RHS_WIDTH);
+  buffer = xmalloc (listing_rhs_width);
   eject = 1;
   list = head;
 
   eject = 1;
   list = head;
 
@@ -854,8 +940,8 @@ listing_listing (name)
 
   while (list)
     {
 
   while (list)
     {
-      width = LISTING_RHS_WIDTH > paper_width ? paper_width :
-       LISTING_RHS_WIDTH;
+      width = listing_rhs_width > paper_width ? paper_width :
+       listing_rhs_width;
 
       switch (list->edict)
        {
 
       switch (list->edict)
        {
@@ -865,6 +951,8 @@ listing_listing (name)
        case EDICT_NOLIST:
          show_listing--;
          break;
        case EDICT_NOLIST:
          show_listing--;
          break;
+       case EDICT_NOLIST_NEXT:
+         break;
        case EDICT_EJECT:
          break;
        case EDICT_NONE:
        case EDICT_EJECT:
          break;
        case EDICT_NONE:
@@ -890,20 +978,37 @@ listing_listing (name)
              current_hll_file = list->hll_file;
            }
 
              current_hll_file = list->hll_file;
            }
 
-         if (current_hll_file && list->hll_line && listing & LISTING_HLL)
+         if (current_hll_file && list->hll_line && (listing & LISTING_HLL))
            {
              print_source (current_hll_file, list, buffer, width);
            }
 
            {
              print_source (current_hll_file, list, buffer, width);
            }
 
-         while (list->file->file
-                && list->file->linenum < list->line
-                && !list->file->at_end)
+         if (list->line_contents)
            {
            {
-             p = buffer_line (list->file, buffer, width);
-
-             if (!((listing & LISTING_NODEBUG) && debugging_pseudo (p)))
+             if (!((listing & LISTING_NODEBUG)
+                   && debugging_pseudo (list, list->line_contents)))
                {
                {
-                 print_lines (list, p, calc_hex (list));
+                 print_lines (list, list->file->linenum,
+                              list->line_contents, calc_hex (list));
+               }
+           }
+         else
+           {
+             while (list->file->linenum < list->line
+                    && !list->file->at_end)
+               {
+                 unsigned int address;
+
+                 p = buffer_line (list->file, buffer, width);
+
+                 if (list->file->linenum < list->line)
+                   address = ~ (unsigned int) 0;
+                 else
+                   address = calc_hex (list);
+
+                 if (!((listing & LISTING_NODEBUG)
+                       && debugging_pseudo (list, p)))
+                   print_lines (list, list->file->linenum, p, address);
                }
            }
 
                }
            }
 
@@ -914,12 +1019,14 @@ listing_listing (name)
        }
       else
        {
        }
       else
        {
-         while (list->file->file
-                && list->file->linenum < list->line
+         while (list->file->linenum < list->line
                 && !list->file->at_end)
            p = buffer_line (list->file, buffer, width);
        }
 
                 && !list->file->at_end)
            p = buffer_line (list->file, buffer, width);
        }
 
+      if (list->edict == EDICT_NOLIST_NEXT)
+       --show_listing;
+
       list = list->next;
     }
   free (buffer);
       list = list->next;
     }
   free (buffer);
@@ -929,18 +1036,27 @@ void
 listing_print (name)
      char *name;
 {
 listing_print (name)
      char *name;
 {
+  int using_stdout;
+  file_info_type *fi;
+
   title = "";
   subtitle = "";
 
   if (name == NULL)
   title = "";
   subtitle = "";
 
   if (name == NULL)
-    list_file = stdout;
+    {
+      list_file = stdout;
+      using_stdout = 1;
+    }
   else
     {
       list_file = fopen (name, "w");
   else
     {
       list_file = fopen (name, "w");
-      if (list_file == NULL)
+      if (list_file != NULL)
+       using_stdout = 0;
+      else
        {
          as_perror ("can't open list file: %s", name);
          list_file = stdout;
        {
          as_perror ("can't open list file: %s", name);
          list_file = stdout;
+         using_stdout = 1;
        }
     }
 
        }
     }
 
@@ -952,12 +1068,23 @@ listing_print (name)
   if (listing & LISTING_LISTING)
     {
       listing_listing (name);
   if (listing & LISTING_LISTING)
     {
       listing_listing (name);
-
     }
     }
+
   if (listing & LISTING_SYMBOLS)
     {
       list_symbol_table ();
     }
   if (listing & LISTING_SYMBOLS)
     {
       list_symbol_table ();
     }
+
+  if (! using_stdout)
+    {
+      if (fclose (list_file) == EOF)
+       as_perror ("error closing list file: %s", name);
+    }
+
+  if (last_open_file)
+    {
+      fclose (last_open_file);
+    }
 }
 
 
 }
 
 
@@ -985,12 +1112,39 @@ listing_flags (ignore)
 
 }
 
 
 }
 
+/* Turn listing on or off.  An argument of 0 means to turn off
+   listing.  An argument of 1 means to turn on listing.  An argument
+   of 2 means to turn off listing, but as of the next line; that is,
+   the current line should be listed, but the next line should not.  */
+
 void
 listing_list (on)
      int on;
 {
   if (listing)
 void
 listing_list (on)
      int on;
 {
   if (listing)
-    listing_tail->edict = on ? EDICT_LIST : EDICT_NOLIST;
+    {
+      switch (on)
+       {
+       case 0:
+         if (listing_tail->edict == EDICT_LIST)
+           listing_tail->edict = EDICT_NONE;
+         else
+           listing_tail->edict = EDICT_NOLIST;
+         break;
+       case 1:
+         if (listing_tail->edict == EDICT_NOLIST
+             || listing_tail->edict == EDICT_NOLIST_NEXT)
+           listing_tail->edict = EDICT_NONE;
+         else
+           listing_tail->edict = EDICT_LIST;
+         break;
+       case 2:
+         listing_tail->edict = EDICT_NOLIST_NEXT;
+         break;
+       default:
+         abort ();
+       }
+    }
 }
 
 
 }