1130561Sobrien/* listing.c - maintain assembly listings
277298Sobrien   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3218822Sdim   2001, 2002, 2003, 2005, 2006
438889Sjdp   Free Software Foundation, Inc.
533965Sjdp
6130561Sobrien   This file is part of GAS, the GNU Assembler.
733965Sjdp
8130561Sobrien   GAS is free software; you can redistribute it and/or modify
9130561Sobrien   it under the terms of the GNU General Public License as published by
10130561Sobrien   the Free Software Foundation; either version 2, or (at your option)
11130561Sobrien   any later version.
1233965Sjdp
13130561Sobrien   GAS is distributed in the hope that it will be useful,
14130561Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
15130561Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16130561Sobrien   GNU General Public License for more details.
1733965Sjdp
18130561Sobrien   You should have received a copy of the GNU General Public License
19130561Sobrien   along with GAS; see the file COPYING.  If not, write to the Free
20218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21218822Sdim   02110-1301, USA.  */
2233965Sjdp
23130561Sobrien/* Contributed by Steve Chamberlain <sac@cygnus.com>
2433965Sjdp
2533965Sjdp A listing page looks like:
2633965Sjdp
2733965Sjdp LISTING_HEADER  sourcefilename pagenumber
2833965Sjdp TITLE LINE
2933965Sjdp SUBTITLE LINE
3033965Sjdp linenumber address data  source
3133965Sjdp linenumber address data  source
3233965Sjdp linenumber address data  source
3333965Sjdp linenumber address data  source
3433965Sjdp
3533965Sjdp If not overridden, the listing commands are:
3633965Sjdp
3733965Sjdp .title  "stuff"
3833965Sjdp 	Put "stuff" onto the title line
3933965Sjdp .sbttl  "stuff"
4033965Sjdp        Put stuff onto the subtitle line
4133965Sjdp
4233965Sjdp  If these commands come within 10 lines of the top of the page, they
4333965Sjdp  will affect the page they are on, as well as any subsequent page
4433965Sjdp
4533965Sjdp .eject
4633965Sjdp 	Thow a page
4733965Sjdp .list
4833965Sjdp 	Increment the enable listing counter
4933965Sjdp .nolist
5033965Sjdp 	Decrement the enable listing counter
5133965Sjdp
5233965Sjdp .psize Y[,X]
5333965Sjdp 	Set the paper size to X wide and Y high. Setting a psize Y of
5433965Sjdp	zero will suppress form feeds except where demanded by .eject
5533965Sjdp
5633965Sjdp If the counter goes below zero, listing is suppressed.
5733965Sjdp
5833965Sjdp Listings are a maintained by read calling various listing_<foo>
5933965Sjdp functions.  What happens most is that the macro NO_LISTING is not
6033965Sjdp defined (from the Makefile), then the macro LISTING_NEWLINE expands
6133965Sjdp into a call to listing_newline.  The call is done from read.c, every
6233965Sjdp time it sees a newline, and -l is on the command line.
6333965Sjdp
6433965Sjdp The function listing_newline remembers the frag associated with the
6533965Sjdp newline, and creates a new frag - note that this is wasteful, but not
6633965Sjdp a big deal, since listing slows things down a lot anyway.  The
67130561Sobrien function also remembers when the filename changes.
6833965Sjdp
6933965Sjdp When all the input has finished, and gas has had a chance to settle
7033965Sjdp down, the listing is output. This is done by running down the list of
7133965Sjdp frag/source file records, and opening the files as needed and printing
7233965Sjdp out the bytes and chars associated with them.
7333965Sjdp
7433965Sjdp The only things which the architecture can change about the listing
7533965Sjdp are defined in these macros:
7633965Sjdp
7733965Sjdp LISTING_HEADER		The name of the architecture
7833965Sjdp LISTING_WORD_SIZE      The make of the number of bytes in a word, this determines
7933965Sjdp 			the clumping of the output data. eg a value of
8033965Sjdp			2 makes words look like 1234 5678, whilst 1
8133965Sjdp			would make the same value look like 12 34 56
8233965Sjdp			78
8333965Sjdp LISTING_LHS_WIDTH      Number of words of above size for the lhs
8433965Sjdp
8533965Sjdp LISTING_LHS_WIDTH_SECOND   Number of words for the data on the lhs
8633965Sjdp 			for the second line
8733965Sjdp
88130561Sobrien LISTING_LHS_CONT_LINES	Max number of lines to use up for a continuation
8933965Sjdp LISTING_RHS_WIDTH      Number of chars from the input file to print
90130561Sobrien                        on a line.  */
9133965Sjdp
9233965Sjdp#include "as.h"
93104834Sobrien#include "obstack.h"
9489857Sobrien#include "safe-ctype.h"
9533965Sjdp#include "input-file.h"
9633965Sjdp#include "subsegs.h"
9733965Sjdp
9833965Sjdp#ifndef NO_LISTING
9938889Sjdp
10033965Sjdp#ifndef LISTING_HEADER
10133965Sjdp#define LISTING_HEADER "GAS LISTING"
10233965Sjdp#endif
10333965Sjdp#ifndef LISTING_WORD_SIZE
10433965Sjdp#define LISTING_WORD_SIZE 4
10533965Sjdp#endif
10633965Sjdp#ifndef LISTING_LHS_WIDTH
10760484Sobrien#define LISTING_LHS_WIDTH ((LISTING_WORD_SIZE) > 4 ? 1 : 4 / (LISTING_WORD_SIZE))
10833965Sjdp#endif
10933965Sjdp#ifndef LISTING_LHS_WIDTH_SECOND
11060484Sobrien#define LISTING_LHS_WIDTH_SECOND LISTING_LHS_WIDTH
11133965Sjdp#endif
11233965Sjdp#ifndef LISTING_RHS_WIDTH
11333965Sjdp#define LISTING_RHS_WIDTH 100
11433965Sjdp#endif
11533965Sjdp#ifndef LISTING_LHS_CONT_LINES
11633965Sjdp#define LISTING_LHS_CONT_LINES 4
11733965Sjdp#endif
11833965Sjdp
11977298Sobrien/* This structure remembers which .s were used.  */
120130561Sobrientypedef struct file_info_struct
121130561Sobrien{
12260484Sobrien  struct file_info_struct * next;
12360484Sobrien  char *                    filename;
12460484Sobrien  long                      pos;
12560484Sobrien  unsigned int              linenum;
12660484Sobrien  int                       at_end;
12777298Sobrien} file_info_type;
12833965Sjdp
129130561Sobrien/* This structure remembers which line from which file goes into which
13077298Sobrien   frag.  */
131130561Sobrienstruct list_info_struct
132130561Sobrien{
13377298Sobrien  /* Frag which this line of source is nearest to.  */
13477298Sobrien  fragS *frag;
13538889Sjdp
13677298Sobrien  /* The actual line in the source file.  */
13733965Sjdp  unsigned int line;
138130561Sobrien
13933965Sjdp  /* Pointer to the file info struct for the file which this line
14077298Sobrien     belongs to.  */
14177298Sobrien  file_info_type *file;
14233965Sjdp
14338889Sjdp  /* The expanded text of any macro that may have been executing.  */
14477298Sobrien  char *line_contents;
14538889Sjdp
14677298Sobrien  /* Next in list.  */
14777298Sobrien  struct list_info_struct *next;
14833965Sjdp
14933965Sjdp  /* Pointer to the file info struct for the high level language
15077298Sobrien     source line that belongs here.  */
15177298Sobrien  file_info_type *hll_file;
152130561Sobrien
15377298Sobrien  /* High level language source line.  */
15438889Sjdp  unsigned int hll_line;
15533965Sjdp
15677298Sobrien  /* Pointer to any error message associated with this line.  */
15777298Sobrien  char *message;
15833965Sjdp
159130561Sobrien  enum
160130561Sobrien    {
161130561Sobrien      EDICT_NONE,
162130561Sobrien      EDICT_SBTTL,
163130561Sobrien      EDICT_TITLE,
164130561Sobrien      EDICT_NOLIST,
165130561Sobrien      EDICT_LIST,
166130561Sobrien      EDICT_NOLIST_NEXT,
167130561Sobrien      EDICT_EJECT
168130561Sobrien    } edict;
16977298Sobrien  char *edict_arg;
17033965Sjdp
17138889Sjdp  /* Nonzero if this line is to be omitted because it contains
17238889Sjdp     debugging information.  This can become a flags field if we come
17338889Sjdp     up with more information to store here.  */
17438889Sjdp  int debugging;
17538889Sjdp};
17633965Sjdp
17738889Sjdptypedef struct list_info_struct list_info_type;
17833965Sjdp
17960484Sobrienint listing_lhs_width        = LISTING_LHS_WIDTH;
18060484Sobrienint listing_lhs_width_second = LISTING_LHS_WIDTH_SECOND;
18160484Sobrienint listing_lhs_cont_lines   = LISTING_LHS_CONT_LINES;
18260484Sobrienint listing_rhs_width        = LISTING_RHS_WIDTH;
18333965Sjdp
18460484Sobrienstruct list_info_struct *        listing_tail;
18560484Sobrien
18660484Sobrienstatic file_info_type *          file_info_head;
18760484Sobrienstatic file_info_type *          last_open_file_info;
18860484Sobrienstatic FILE *                    last_open_file;
18960484Sobrienstatic struct list_info_struct * head;
19060484Sobrienstatic int                       paper_width = 200;
19160484Sobrienstatic int                       paper_height = 60;
19260484Sobrien
19360484Sobrienextern int                       listing;
19460484Sobrien
19533965Sjdp/* File to output listings to.  */
19677298Sobrienstatic FILE *list_file;
19733965Sjdp
19838889Sjdp/* This static array is used to keep the text of data to be printed
19938889Sjdp   before the start of the line.  */
20033965Sjdp
20138889Sjdp#define MAX_BYTES							\
20238889Sjdp  (((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width			\
20338889Sjdp   + ((((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second)	\
20438889Sjdp      * listing_lhs_cont_lines)						\
20538889Sjdp   + 20)
20633965Sjdp
20777298Sobrienstatic char *data_buffer;
20833965Sjdp
20933965Sjdp/* Prototypes.  */
210130561Sobrienstatic void listing_message (const char *, const char *);
211130561Sobrienstatic file_info_type *file_info (const char *);
212130561Sobrienstatic void new_frag (void);
213130561Sobrienstatic char *buffer_line (file_info_type *, char *, unsigned int);
214130561Sobrienstatic void listing_page (list_info_type *);
215130561Sobrienstatic unsigned int calc_hex (list_info_type *);
216130561Sobrienstatic void print_lines (list_info_type *, unsigned int, char *, unsigned int);
217130561Sobrienstatic void list_symbol_table (void);
218130561Sobrienstatic void print_source (file_info_type *, list_info_type *, char *, unsigned int);
219130561Sobrienstatic int debugging_pseudo (list_info_type *, const char *);
220130561Sobrienstatic void listing_listing (char *);
22133965Sjdp
22233965Sjdpstatic void
223130561Sobrienlisting_message (const char *name, const char *message)
22433965Sjdp{
22533965Sjdp  if (listing_tail != (list_info_type *) NULL)
22633965Sjdp    {
22777298Sobrien      unsigned int l = strlen (name) + strlen (message) + 1;
22877298Sobrien      char *n = (char *) xmalloc (l);
22977298Sobrien      strcpy (n, name);
23077298Sobrien      strcat (n, message);
23133965Sjdp      listing_tail->message = n;
23233965Sjdp    }
23333965Sjdp}
23433965Sjdp
23533965Sjdpvoid
236130561Sobrienlisting_warning (const char *message)
23733965Sjdp{
23860484Sobrien  listing_message (_("Warning:"), message);
23933965Sjdp}
24033965Sjdp
24133965Sjdpvoid
242130561Sobrienlisting_error (const char *message)
24333965Sjdp{
24460484Sobrien  listing_message (_("Error:"), message);
24533965Sjdp}
24633965Sjdp
24733965Sjdpstatic file_info_type *
248130561Sobrienfile_info (const char *file_name)
24933965Sjdp{
25077298Sobrien  /* Find an entry with this file name.  */
25133965Sjdp  file_info_type *p = file_info_head;
25233965Sjdp
25333965Sjdp  while (p != (file_info_type *) NULL)
25433965Sjdp    {
25533965Sjdp      if (strcmp (p->filename, file_name) == 0)
25633965Sjdp	return p;
25733965Sjdp      p = p->next;
25833965Sjdp    }
25933965Sjdp
26077298Sobrien  /* Make new entry.  */
261130561Sobrien  p = xmalloc (sizeof (file_info_type));
26233965Sjdp  p->next = file_info_head;
26333965Sjdp  file_info_head = p;
264104834Sobrien  p->filename = xstrdup (file_name);
26538889Sjdp  p->pos = 0;
26633965Sjdp  p->linenum = 0;
26733965Sjdp  p->at_end = 0;
26833965Sjdp
26933965Sjdp  return p;
27033965Sjdp}
27133965Sjdp
27233965Sjdpstatic void
273130561Sobriennew_frag (void)
27433965Sjdp{
27533965Sjdp  frag_wane (frag_now);
27633965Sjdp  frag_new (0);
27733965Sjdp}
27833965Sjdp
27933965Sjdpvoid
280130561Sobrienlisting_newline (char *ps)
28133965Sjdp{
28233965Sjdp  char *file;
28333965Sjdp  unsigned int line;
28433965Sjdp  static unsigned int last_line = 0xffff;
28533965Sjdp  static char *last_file = NULL;
28638889Sjdp  list_info_type *new = NULL;
28733965Sjdp
28833965Sjdp  if (listing == 0)
28933965Sjdp    return;
29033965Sjdp
29133965Sjdp  if (now_seg == absolute_section)
29233965Sjdp    return;
29333965Sjdp
29438889Sjdp#ifdef OBJ_ELF
29538889Sjdp  /* In ELF, anything in a section beginning with .debug or .line is
29638889Sjdp     considered to be debugging information.  This includes the
29738889Sjdp     statement which switches us into the debugging section, which we
29838889Sjdp     can only set after we are already in the debugging section.  */
29938889Sjdp  if ((listing & LISTING_NODEBUG) != 0
30038889Sjdp      && listing_tail != NULL
30138889Sjdp      && ! listing_tail->debugging)
30238889Sjdp    {
30338889Sjdp      const char *segname;
30438889Sjdp
30538889Sjdp      segname = segment_name (now_seg);
30638889Sjdp      if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0
30738889Sjdp	  || strncmp (segname, ".line", sizeof ".line" - 1) == 0)
30838889Sjdp	listing_tail->debugging = 1;
30938889Sjdp    }
31038889Sjdp#endif
31138889Sjdp
31233965Sjdp  as_where (&file, &line);
31338889Sjdp  if (ps == NULL)
31433965Sjdp    {
31577298Sobrien      if (line == last_line
31677298Sobrien	  && !(last_file && file && strcmp (file, last_file)))
31738889Sjdp	return;
31833965Sjdp
31933965Sjdp      new = (list_info_type *) xmalloc (sizeof (list_info_type));
32060484Sobrien
32160484Sobrien      /* Detect if we are reading from stdin by examining the file
32260484Sobrien	 name returned by as_where().
32360484Sobrien
32460484Sobrien	 [FIXME: We rely upon the name in the strcmp below being the
32560484Sobrien	 same as the one used by input_scrub_new_file(), if that is
32660484Sobrien	 not true, then this code will fail].
32760484Sobrien
32877298Sobrien	 If we are reading from stdin, then we need to save each input
32977298Sobrien	 line here (assuming of course that we actually have a line of
33077298Sobrien	 input to read), so that it can be displayed in the listing
33177298Sobrien	 that is produced at the end of the assembly.  */
33260484Sobrien      if (strcmp (file, _("{standard input}")) == 0
33360484Sobrien	  && input_line_pointer != NULL)
33460484Sobrien	{
33577298Sobrien	  char *copy;
33660484Sobrien	  int len;
33760484Sobrien	  int seen_quote = 0;
33860484Sobrien
33960484Sobrien	  for (copy = input_line_pointer - 1;
34077298Sobrien	       *copy && (seen_quote
34177298Sobrien			 || (! is_end_of_line [(unsigned char) *copy]));
34277298Sobrien	       copy++)
34377298Sobrien	    if (*copy == '"' && copy[-1] != '\\')
34460484Sobrien	      seen_quote = ! seen_quote;
34560484Sobrien
34660484Sobrien	  len = (copy - input_line_pointer) + 2;
34760484Sobrien
34860484Sobrien	  copy = xmalloc (len);
34960484Sobrien
35060484Sobrien	  if (copy != NULL)
35160484Sobrien	    {
35277298Sobrien	      char *src = input_line_pointer - 1;
35377298Sobrien	      char *dest = copy;
35477298Sobrien
35560484Sobrien	      while (--len)
35660484Sobrien		{
35777298Sobrien		  unsigned char c = *src++;
35860484Sobrien
35960484Sobrien		  /* Omit control characters in the listing.  */
36089857Sobrien		  if (!ISCNTRL (c))
36177298Sobrien		    *dest++ = c;
36260484Sobrien		}
36377298Sobrien
36460484Sobrien	      *dest = 0;
36560484Sobrien	    }
36677298Sobrien
36760484Sobrien	  new->line_contents = copy;
36860484Sobrien	}
36960484Sobrien      else
37060484Sobrien	new->line_contents = NULL;
37138889Sjdp    }
37238889Sjdp  else
37338889Sjdp    {
374130561Sobrien      new = xmalloc (sizeof (list_info_type));
37538889Sjdp      new->line_contents = ps;
37638889Sjdp    }
37733965Sjdp
37838889Sjdp  last_line = line;
37938889Sjdp  last_file = file;
38077298Sobrien
38138889Sjdp  new_frag ();
38238889Sjdp
38338889Sjdp  if (listing_tail)
38460484Sobrien    listing_tail->next = new;
38538889Sjdp  else
38660484Sobrien    head = new;
38777298Sobrien
38838889Sjdp  listing_tail = new;
38938889Sjdp
39038889Sjdp  new->frag = frag_now;
39138889Sjdp  new->line = line;
39238889Sjdp  new->file = file_info (file);
39338889Sjdp  new->next = (list_info_type *) NULL;
39438889Sjdp  new->message = (char *) NULL;
39538889Sjdp  new->edict = EDICT_NONE;
39638889Sjdp  new->hll_file = (file_info_type *) NULL;
39738889Sjdp  new->hll_line = 0;
39838889Sjdp  new->debugging = 0;
39977298Sobrien
40038889Sjdp  new_frag ();
40138889Sjdp
40238889Sjdp#ifdef OBJ_ELF
40338889Sjdp  /* In ELF, anything in a section beginning with .debug or .line is
40438889Sjdp     considered to be debugging information.  */
40538889Sjdp  if ((listing & LISTING_NODEBUG) != 0)
40638889Sjdp    {
40738889Sjdp      const char *segname;
40838889Sjdp
40938889Sjdp      segname = segment_name (now_seg);
41038889Sjdp      if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0
41138889Sjdp	  || strncmp (segname, ".line", sizeof ".line" - 1) == 0)
41238889Sjdp	new->debugging = 1;
41338889Sjdp    }
41438889Sjdp#endif
41533965Sjdp}
41633965Sjdp
41733965Sjdp/* Attach all current frags to the previous line instead of the
41833965Sjdp   current line.  This is called by the MIPS backend when it discovers
41933965Sjdp   that it needs to add some NOP instructions; the added NOP
42033965Sjdp   instructions should go with the instruction that has the delay, not
42133965Sjdp   with the new instruction.  */
42233965Sjdp
42333965Sjdpvoid
424130561Sobrienlisting_prev_line (void)
42533965Sjdp{
42633965Sjdp  list_info_type *l;
42733965Sjdp  fragS *f;
42833965Sjdp
42933965Sjdp  if (head == (list_info_type *) NULL
43033965Sjdp      || head == listing_tail)
43133965Sjdp    return;
43233965Sjdp
43333965Sjdp  new_frag ();
43433965Sjdp
43533965Sjdp  for (l = head; l->next != listing_tail; l = l->next)
43633965Sjdp    ;
43733965Sjdp
43833965Sjdp  for (f = frchain_now->frch_root; f != (fragS *) NULL; f = f->fr_next)
43933965Sjdp    if (f->line == listing_tail)
44033965Sjdp      f->line = l;
44133965Sjdp
44233965Sjdp  listing_tail->frag = frag_now;
44333965Sjdp  new_frag ();
44433965Sjdp}
44533965Sjdp
44677298Sobrien/* This function returns the next source line from the file supplied,
44777298Sobrien   truncated to size.  It appends a fake line to the end of each input
44877298Sobrien   file to make.  */
44933965Sjdp
45033965Sjdpstatic char *
451130561Sobrienbuffer_line (file_info_type *file, char *line, unsigned int size)
45233965Sjdp{
45333965Sjdp  unsigned int count = 0;
45433965Sjdp  int c;
45533965Sjdp
45633965Sjdp  char *p = line;
45733965Sjdp
45877298Sobrien  /* If we couldn't open the file, return an empty line.  */
45938889Sjdp  if (file->at_end)
46038889Sjdp    return "";
46138889Sjdp
46238889Sjdp  /* Check the cache and see if we last used this file.  */
46338889Sjdp  if (!last_open_file_info || file != last_open_file_info)
46433965Sjdp    {
46538889Sjdp      if (last_open_file)
46638889Sjdp	{
46738889Sjdp	  last_open_file_info->pos = ftell (last_open_file);
46838889Sjdp	  fclose (last_open_file);
46938889Sjdp	}
47038889Sjdp
47138889Sjdp      last_open_file_info = file;
47289857Sobrien      last_open_file = fopen (file->filename, FOPEN_RT);
47338889Sjdp      if (last_open_file == NULL)
47438889Sjdp	{
47538889Sjdp	  file->at_end = 1;
47638889Sjdp	  return "";
47738889Sjdp	}
47877298Sobrien
47938889Sjdp      /* Seek to where we were last time this file was open.  */
48038889Sjdp      if (file->pos)
48177298Sobrien	fseek (last_open_file, file->pos, SEEK_SET);
48233965Sjdp    }
48333965Sjdp
48438889Sjdp  c = fgetc (last_open_file);
48533965Sjdp
48677298Sobrien  /* Leave room for null.  */
48777298Sobrien  size -= 1;
48833965Sjdp
48933965Sjdp  while (c != EOF && c != '\n')
49033965Sjdp    {
49133965Sjdp      if (count < size)
49233965Sjdp	*p++ = c;
49333965Sjdp      count++;
49433965Sjdp
49538889Sjdp      c = fgetc (last_open_file);
49633965Sjdp
49733965Sjdp    }
49833965Sjdp  if (c == EOF)
49933965Sjdp    {
50033965Sjdp      file->at_end = 1;
50189857Sobrien      if (count + 2 < size)
50289857Sobrien	{
50389857Sobrien	  *p++ = '.';
50489857Sobrien	  *p++ = '.';
50589857Sobrien	  *p++ = '.';
50689857Sobrien	}
50733965Sjdp    }
50833965Sjdp  file->linenum++;
50933965Sjdp  *p++ = 0;
51033965Sjdp  return line;
51133965Sjdp}
51233965Sjdp
51333965Sjdpstatic const char *fn;
51433965Sjdp
51533965Sjdpstatic unsigned int eject;	/* Eject pending */
51633965Sjdpstatic unsigned int page;	/* Current page number */
51777298Sobrienstatic char *title;		/* Current title */
51877298Sobrienstatic char *subtitle;		/* Current subtitle */
51977298Sobrienstatic unsigned int on_page;	/* Number of lines printed on current page */
52033965Sjdp
52133965Sjdpstatic void
522130561Sobrienlisting_page (list_info_type *list)
52333965Sjdp{
52433965Sjdp  /* Grope around, see if we can see a title or subtitle edict coming up
52577298Sobrien     soon.  (we look down 10 lines of the page and see if it's there)  */
52677298Sobrien  if ((eject || (on_page >= (unsigned int) paper_height))
52777298Sobrien      && paper_height != 0)
52833965Sjdp    {
52933965Sjdp      unsigned int c = 10;
53033965Sjdp      int had_title = 0;
53133965Sjdp      int had_subtitle = 0;
53233965Sjdp
53333965Sjdp      page++;
53433965Sjdp
53533965Sjdp      while (c != 0 && list)
53633965Sjdp	{
53733965Sjdp	  if (list->edict == EDICT_SBTTL && !had_subtitle)
53833965Sjdp	    {
53933965Sjdp	      had_subtitle = 1;
54033965Sjdp	      subtitle = list->edict_arg;
54133965Sjdp	    }
54233965Sjdp	  if (list->edict == EDICT_TITLE && !had_title)
54333965Sjdp	    {
54433965Sjdp	      had_title = 1;
54533965Sjdp	      title = list->edict_arg;
54633965Sjdp	    }
54733965Sjdp	  list = list->next;
54833965Sjdp	  c--;
54933965Sjdp	}
55033965Sjdp
55133965Sjdp      if (page > 1)
55233965Sjdp	{
55333965Sjdp	  fprintf (list_file, "\f");
55433965Sjdp	}
55533965Sjdp
55633965Sjdp      fprintf (list_file, "%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page);
55733965Sjdp      fprintf (list_file, "%s\n", title);
55833965Sjdp      fprintf (list_file, "%s\n", subtitle);
55933965Sjdp      on_page = 3;
56033965Sjdp      eject = 0;
56133965Sjdp    }
56233965Sjdp}
56333965Sjdp
56433965Sjdpstatic unsigned int
565130561Sobriencalc_hex (list_info_type *list)
56633965Sjdp{
56738889Sjdp  int data_buffer_size;
56833965Sjdp  list_info_type *first = list;
56977298Sobrien  unsigned int address = ~(unsigned int) 0;
57033965Sjdp  fragS *frag;
57133965Sjdp  fragS *frag_ptr;
57260484Sobrien  unsigned int octet_in_frag;
57333965Sjdp
57477298Sobrien  /* Find first frag which says it belongs to this line.  */
57533965Sjdp  frag = list->frag;
57633965Sjdp  while (frag && frag->line != list)
57733965Sjdp    frag = frag->fr_next;
57833965Sjdp
57933965Sjdp  frag_ptr = frag;
58033965Sjdp
58133965Sjdp  data_buffer_size = 0;
58233965Sjdp
58377298Sobrien  /* Dump all the frags which belong to this line.  */
58433965Sjdp  while (frag_ptr != (fragS *) NULL && frag_ptr->line == first)
58533965Sjdp    {
58677298Sobrien      /* Print as many bytes from the fixed part as is sensible.  */
58760484Sobrien      octet_in_frag = 0;
58860484Sobrien      while ((offsetT) octet_in_frag < frag_ptr->fr_fix
58938889Sjdp	     && data_buffer_size < MAX_BYTES - 3)
59033965Sjdp	{
59177298Sobrien	  if (address == ~(unsigned int) 0)
592130561Sobrien	    address = frag_ptr->fr_address / OCTETS_PER_BYTE;
59333965Sjdp
59433965Sjdp	  sprintf (data_buffer + data_buffer_size,
59533965Sjdp		   "%02X",
59660484Sobrien		   (frag_ptr->fr_literal[octet_in_frag]) & 0xff);
59733965Sjdp	  data_buffer_size += 2;
59860484Sobrien	  octet_in_frag++;
59933965Sjdp	}
600104834Sobrien      if (frag_ptr->fr_type == rs_fill)
601104834Sobrien	{
602104834Sobrien	  unsigned int var_rep_max = octet_in_frag;
603104834Sobrien	  unsigned int var_rep_idx = octet_in_frag;
60433965Sjdp
605104834Sobrien	  /* Print as many bytes from the variable part as is sensible.  */
606104834Sobrien	  while (((offsetT) octet_in_frag
607104834Sobrien		  < (frag_ptr->fr_fix + frag_ptr->fr_var * frag_ptr->fr_offset))
608104834Sobrien		 && data_buffer_size < MAX_BYTES - 3)
609104834Sobrien	    {
610104834Sobrien	      if (address == ~(unsigned int) 0)
611130561Sobrien		address = frag_ptr->fr_address / OCTETS_PER_BYTE;
612130561Sobrien
613104834Sobrien	      sprintf (data_buffer + data_buffer_size,
614104834Sobrien		       "%02X",
615104834Sobrien		       (frag_ptr->fr_literal[var_rep_idx]) & 0xff);
616104834Sobrien	      data_buffer_size += 2;
61733965Sjdp
618104834Sobrien	      var_rep_idx++;
619104834Sobrien	      octet_in_frag++;
62033965Sjdp
621104834Sobrien	      if ((offsetT) var_rep_idx >= frag_ptr->fr_fix + frag_ptr->fr_var)
622104834Sobrien		var_rep_idx = var_rep_max;
623104834Sobrien	    }
624104834Sobrien	}
62533965Sjdp
62633965Sjdp      frag_ptr = frag_ptr->fr_next;
62733965Sjdp    }
62838889Sjdp  data_buffer[data_buffer_size] = '\0';
62933965Sjdp  return address;
63033965Sjdp}
63133965Sjdp
63233965Sjdpstatic void
633130561Sobrienprint_lines (list_info_type *list, unsigned int lineno,
634130561Sobrien	     char *string, unsigned int address)
63533965Sjdp{
63633965Sjdp  unsigned int idx;
63733965Sjdp  unsigned int nchars;
63833965Sjdp  unsigned int lines;
63960484Sobrien  unsigned int octet_in_word = 0;
64033965Sjdp  char *src = data_buffer;
64160484Sobrien  int cur;
64233965Sjdp
64377298Sobrien  /* Print the stuff on the first line.  */
64433965Sjdp  listing_page (list);
64538889Sjdp  nchars = (LISTING_WORD_SIZE * 2 + 1) * listing_lhs_width;
64677298Sobrien
64777298Sobrien  /* Print the hex for the first line.  */
64877298Sobrien  if (address == ~(unsigned int) 0)
64933965Sjdp    {
65033965Sjdp      fprintf (list_file, "% 4d     ", lineno);
65133965Sjdp      for (idx = 0; idx < nchars; idx++)
65233965Sjdp	fprintf (list_file, " ");
65333965Sjdp
65433965Sjdp      fprintf (list_file, "\t%s\n", string ? string : "");
65577298Sobrien
65677298Sobrien      on_page++;
65777298Sobrien
65833965Sjdp      listing_page (0);
65933965Sjdp
66060484Sobrien      return;
66133965Sjdp    }
66260484Sobrien
66360484Sobrien  if (had_errors ())
66460484Sobrien    fprintf (list_file, "% 4d ???? ", lineno);
66533965Sjdp  else
66660484Sobrien    fprintf (list_file, "% 4d %04x ", lineno, address);
66760484Sobrien
66877298Sobrien  /* And the data to go along with it.  */
66960484Sobrien  idx = 0;
67060484Sobrien  cur = 0;
67160484Sobrien  while (src[cur] && idx < nchars)
67233965Sjdp    {
67360484Sobrien      int offset;
67460484Sobrien      offset = cur;
67577298Sobrien      fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
67660484Sobrien      cur += 2;
67760484Sobrien      octet_in_word++;
67877298Sobrien
67960484Sobrien      if (octet_in_word == LISTING_WORD_SIZE)
68033965Sjdp	{
68160484Sobrien	  fprintf (list_file, " ");
68260484Sobrien	  idx++;
68360484Sobrien	  octet_in_word = 0;
68433965Sjdp	}
68577298Sobrien
68660484Sobrien      idx += 2;
68760484Sobrien    }
68877298Sobrien
68960484Sobrien  for (; idx < nchars; idx++)
69060484Sobrien    fprintf (list_file, " ");
69177298Sobrien
69260484Sobrien  fprintf (list_file, "\t%s\n", string ? string : "");
69360484Sobrien  on_page++;
69460484Sobrien  listing_page (list);
69577298Sobrien
69660484Sobrien  if (list->message)
69760484Sobrien    {
69860484Sobrien      fprintf (list_file, "****  %s\n", list->message);
69960484Sobrien      listing_page (list);
70060484Sobrien      on_page++;
70160484Sobrien    }
70277298Sobrien
70360484Sobrien  for (lines = 0;
70460484Sobrien       lines < (unsigned int) listing_lhs_cont_lines
70560484Sobrien	 && src[cur];
70677298Sobrien       lines++)
70760484Sobrien    {
70877298Sobrien      nchars = ((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second - 1;
70933965Sjdp      idx = 0;
71077298Sobrien
71177298Sobrien      /* Print any more lines of data, but more compactly.  */
71260484Sobrien      fprintf (list_file, "% 4d      ", lineno);
71377298Sobrien
71460484Sobrien      while (src[cur] && idx < nchars)
71533965Sjdp	{
71677298Sobrien	  int offset;
71777298Sobrien	  offset = cur;
71877298Sobrien	  fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
71960484Sobrien	  cur += 2;
72060484Sobrien	  idx += 2;
72160484Sobrien	  octet_in_word++;
72277298Sobrien
72360484Sobrien	  if (octet_in_word == LISTING_WORD_SIZE)
72433965Sjdp	    {
72533965Sjdp	      fprintf (list_file, " ");
72633965Sjdp	      idx++;
72760484Sobrien	      octet_in_word = 0;
72833965Sjdp	    }
72933965Sjdp	}
73077298Sobrien
73160484Sobrien      fprintf (list_file, "\n");
73277298Sobrien      on_page++;
73333965Sjdp      listing_page (list);
73433965Sjdp    }
73533965Sjdp}
73633965Sjdp
73733965Sjdpstatic void
738130561Sobrienlist_symbol_table (void)
73933965Sjdp{
74033965Sjdp  extern symbolS *symbol_rootP;
74133965Sjdp  int got_some = 0;
74233965Sjdp
74333965Sjdp  symbolS *ptr;
74433965Sjdp  eject = 1;
74533965Sjdp  listing_page (0);
74633965Sjdp
74733965Sjdp  for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
74833965Sjdp    {
74938889Sjdp      if (SEG_NORMAL (S_GET_SEGMENT (ptr))
75038889Sjdp	  || S_GET_SEGMENT (ptr) == absolute_section)
75133965Sjdp	{
75238889Sjdp	  /* Don't report section symbols.  They are not interesting.  */
75360484Sobrien	  if (symbol_section_p (ptr))
75438889Sjdp	    continue;
755218822Sdim
75633965Sjdp	  if (S_GET_NAME (ptr))
75733965Sjdp	    {
75833965Sjdp	      char buf[30], fmt[8];
75933965Sjdp	      valueT val = S_GET_VALUE (ptr);
76033965Sjdp
76133965Sjdp	      /* @@ Note that this is dependent on the compilation options,
76233965Sjdp		 not solely on the target characteristics.  */
76333965Sjdp	      if (sizeof (val) == 4 && sizeof (int) == 4)
76433965Sjdp		sprintf (buf, "%08lx", (unsigned long) val);
76533965Sjdp	      else if (sizeof (val) <= sizeof (unsigned long))
76633965Sjdp		{
76733965Sjdp		  sprintf (fmt, "%%0%lulx",
76833965Sjdp			   (unsigned long) (sizeof (val) * 2));
76933965Sjdp		  sprintf (buf, fmt, (unsigned long) val);
77033965Sjdp		}
77133965Sjdp#if defined (BFD64)
77233965Sjdp	      else if (sizeof (val) > 4)
77333965Sjdp		sprintf_vma (buf, val);
77433965Sjdp#endif
77533965Sjdp	      else
77633965Sjdp		abort ();
77733965Sjdp
77833965Sjdp	      if (!got_some)
77933965Sjdp		{
78033965Sjdp		  fprintf (list_file, "DEFINED SYMBOLS\n");
78133965Sjdp		  on_page++;
78233965Sjdp		  got_some = 1;
78333965Sjdp		}
78433965Sjdp
78560484Sobrien	      if (symbol_get_frag (ptr) && symbol_get_frag (ptr)->line)
78638889Sjdp		{
78738889Sjdp		  fprintf (list_file, "%20s:%-5d  %s:%s %s\n",
78860484Sobrien			   symbol_get_frag (ptr)->line->file->filename,
78960484Sobrien			   symbol_get_frag (ptr)->line->line,
79038889Sjdp			   segment_name (S_GET_SEGMENT (ptr)),
79138889Sjdp			   buf, S_GET_NAME (ptr));
79238889Sjdp		}
79338889Sjdp	      else
79438889Sjdp		{
79538889Sjdp		  fprintf (list_file, "%33s:%s %s\n",
79638889Sjdp			   segment_name (S_GET_SEGMENT (ptr)),
79738889Sjdp			   buf, S_GET_NAME (ptr));
79838889Sjdp		}
79933965Sjdp
80077298Sobrien	      on_page++;
80133965Sjdp	      listing_page (0);
80233965Sjdp	    }
80333965Sjdp	}
80433965Sjdp
80533965Sjdp    }
80633965Sjdp  if (!got_some)
80733965Sjdp    {
80833965Sjdp      fprintf (list_file, "NO DEFINED SYMBOLS\n");
80933965Sjdp      on_page++;
81033965Sjdp    }
81133965Sjdp  fprintf (list_file, "\n");
81233965Sjdp  on_page++;
81333965Sjdp  listing_page (0);
81433965Sjdp
81533965Sjdp  got_some = 0;
81633965Sjdp
81733965Sjdp  for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
81833965Sjdp    {
81933965Sjdp      if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0)
82033965Sjdp	{
82138889Sjdp	  if (S_GET_SEGMENT (ptr) == undefined_section)
82233965Sjdp	    {
82333965Sjdp	      if (!got_some)
82433965Sjdp		{
82533965Sjdp		  got_some = 1;
82633965Sjdp		  fprintf (list_file, "UNDEFINED SYMBOLS\n");
82733965Sjdp		  on_page++;
82833965Sjdp		  listing_page (0);
82933965Sjdp		}
83033965Sjdp	      fprintf (list_file, "%s\n", S_GET_NAME (ptr));
83133965Sjdp	      on_page++;
83233965Sjdp	      listing_page (0);
83333965Sjdp	    }
83433965Sjdp	}
83533965Sjdp    }
83633965Sjdp  if (!got_some)
83733965Sjdp    {
83833965Sjdp      fprintf (list_file, "NO UNDEFINED SYMBOLS\n");
83933965Sjdp      on_page++;
84033965Sjdp      listing_page (0);
84133965Sjdp    }
84233965Sjdp}
84333965Sjdp
84433965Sjdpstatic void
845130561Sobrienprint_source (file_info_type *current_file, list_info_type *list,
846130561Sobrien	      char *buffer, unsigned int width)
84733965Sjdp{
84838889Sjdp  if (!current_file->at_end)
84933965Sjdp    {
85033965Sjdp      while (current_file->linenum < list->hll_line
85133965Sjdp	     && !current_file->at_end)
85233965Sjdp	{
85333965Sjdp	  char *p = buffer_line (current_file, buffer, width);
854130561Sobrien
85538889Sjdp	  fprintf (list_file, "%4u:%-13s **** %s\n", current_file->linenum,
85633965Sjdp		   current_file->filename, p);
85733965Sjdp	  on_page++;
85833965Sjdp	  listing_page (list);
85933965Sjdp	}
86033965Sjdp    }
86133965Sjdp}
86233965Sjdp
86333965Sjdp/* Sometimes the user doesn't want to be bothered by the debugging
86438889Sjdp   records inserted by the compiler, see if the line is suspicious.  */
86533965Sjdp
86633965Sjdpstatic int
867130561Sobriendebugging_pseudo (list_info_type *list, const char *line)
86833965Sjdp{
86938889Sjdp  static int in_debug;
87038889Sjdp  int was_debug;
87138889Sjdp
87238889Sjdp  if (list->debugging)
87338889Sjdp    {
87438889Sjdp      in_debug = 1;
87538889Sjdp      return 1;
87638889Sjdp    }
87738889Sjdp
87838889Sjdp  was_debug = in_debug;
87938889Sjdp  in_debug = 0;
88038889Sjdp
88189857Sobrien  while (ISSPACE (*line))
88233965Sjdp    line++;
88333965Sjdp
88433965Sjdp  if (*line != '.')
88538889Sjdp    {
88638889Sjdp#ifdef OBJ_ELF
88738889Sjdp      /* The ELF compiler sometimes emits blank lines after switching
88838889Sjdp         out of a debugging section.  If the next line drops us back
88938889Sjdp         into debugging information, then don't print the blank line.
89038889Sjdp         This is a hack for a particular compiler behaviour, not a
89138889Sjdp         general case.  */
89238889Sjdp      if (was_debug
89338889Sjdp	  && *line == '\0'
89438889Sjdp	  && list->next != NULL
89538889Sjdp	  && list->next->debugging)
89638889Sjdp	{
89738889Sjdp	  in_debug = 1;
89838889Sjdp	  return 1;
89938889Sjdp	}
90038889Sjdp#endif
90133965Sjdp
90238889Sjdp      return 0;
90338889Sjdp    }
90438889Sjdp
90533965Sjdp  line++;
90633965Sjdp
90733965Sjdp  if (strncmp (line, "def", 3) == 0)
90833965Sjdp    return 1;
90933965Sjdp  if (strncmp (line, "val", 3) == 0)
91033965Sjdp    return 1;
91133965Sjdp  if (strncmp (line, "scl", 3) == 0)
91233965Sjdp    return 1;
91333965Sjdp  if (strncmp (line, "line", 4) == 0)
91433965Sjdp    return 1;
91533965Sjdp  if (strncmp (line, "endef", 5) == 0)
91633965Sjdp    return 1;
91733965Sjdp  if (strncmp (line, "ln", 2) == 0)
91833965Sjdp    return 1;
91933965Sjdp  if (strncmp (line, "type", 4) == 0)
92033965Sjdp    return 1;
92133965Sjdp  if (strncmp (line, "size", 4) == 0)
92233965Sjdp    return 1;
92333965Sjdp  if (strncmp (line, "dim", 3) == 0)
92433965Sjdp    return 1;
92533965Sjdp  if (strncmp (line, "tag", 3) == 0)
92633965Sjdp    return 1;
92733965Sjdp  if (strncmp (line, "stabs", 5) == 0)
92833965Sjdp    return 1;
92933965Sjdp  if (strncmp (line, "stabn", 5) == 0)
93033965Sjdp    return 1;
93133965Sjdp
93233965Sjdp  return 0;
93333965Sjdp}
93433965Sjdp
93533965Sjdpstatic void
936130561Sobrienlisting_listing (char *name ATTRIBUTE_UNUSED)
93733965Sjdp{
93833965Sjdp  list_info_type *list = head;
93933965Sjdp  file_info_type *current_hll_file = (file_info_type *) NULL;
94033965Sjdp  char *message;
94133965Sjdp  char *buffer;
94233965Sjdp  char *p;
94333965Sjdp  int show_listing = 1;
94433965Sjdp  unsigned int width;
94533965Sjdp
94638889Sjdp  buffer = xmalloc (listing_rhs_width);
94738889Sjdp  data_buffer = xmalloc (MAX_BYTES);
94833965Sjdp  eject = 1;
94933965Sjdp  list = head->next;
95033965Sjdp
95133965Sjdp  while (list)
95233965Sjdp    {
95360484Sobrien      unsigned int list_line;
95460484Sobrien
95538889Sjdp      width = listing_rhs_width > paper_width ? paper_width :
95638889Sjdp	listing_rhs_width;
95733965Sjdp
95860484Sobrien      list_line = list->line;
95933965Sjdp      switch (list->edict)
96033965Sjdp	{
96133965Sjdp	case EDICT_LIST:
96260484Sobrien	  /* Skip all lines up to the current.  */
96360484Sobrien	  list_line--;
96433965Sjdp	  break;
96533965Sjdp	case EDICT_NOLIST:
96633965Sjdp	  show_listing--;
96733965Sjdp	  break;
96833965Sjdp	case EDICT_NOLIST_NEXT:
96977298Sobrien	  if (show_listing == 0)
97077298Sobrien	    list_line--;
97133965Sjdp	  break;
97233965Sjdp	case EDICT_EJECT:
97333965Sjdp	  break;
97433965Sjdp	case EDICT_NONE:
97533965Sjdp	  break;
97633965Sjdp	case EDICT_TITLE:
97733965Sjdp	  title = list->edict_arg;
97833965Sjdp	  break;
97933965Sjdp	case EDICT_SBTTL:
98033965Sjdp	  subtitle = list->edict_arg;
98133965Sjdp	  break;
98233965Sjdp	default:
98333965Sjdp	  abort ();
98433965Sjdp	}
98533965Sjdp
98660484Sobrien      if (show_listing <= 0)
98760484Sobrien	{
98860484Sobrien	  while (list->file->linenum < list_line
98960484Sobrien		 && !list->file->at_end)
99060484Sobrien	    p = buffer_line (list->file, buffer, width);
99160484Sobrien	}
99260484Sobrien
99377298Sobrien      if (list->edict == EDICT_LIST
99477298Sobrien	  || (list->edict == EDICT_NOLIST_NEXT && show_listing == 0))
99560484Sobrien	{
99660484Sobrien	  /* Enable listing for the single line that caused the enable.  */
99760484Sobrien	  list_line++;
99860484Sobrien	  show_listing++;
99960484Sobrien	}
100060484Sobrien
100133965Sjdp      if (show_listing > 0)
100233965Sjdp	{
100333965Sjdp	  /* Scan down the list and print all the stuff which can be done
100433965Sjdp	     with this line (or lines).  */
100533965Sjdp	  message = 0;
100633965Sjdp
100733965Sjdp	  if (list->hll_file)
1008130561Sobrien	    current_hll_file = list->hll_file;
100933965Sjdp
101038889Sjdp	  if (current_hll_file && list->hll_line && (listing & LISTING_HLL))
1011130561Sobrien	    print_source (current_hll_file, list, buffer, width);
101233965Sjdp
101338889Sjdp	  if (list->line_contents)
101433965Sjdp	    {
101538889Sjdp	      if (!((listing & LISTING_NODEBUG)
101638889Sjdp		    && debugging_pseudo (list, list->line_contents)))
1017130561Sobrien		print_lines (list,
1018130561Sobrien			     list->file->linenum == 0 ? list->line : list->file->linenum,
1019130561Sobrien			     list->line_contents, calc_hex (list));
1020130561Sobrien
102160484Sobrien	      free (list->line_contents);
102260484Sobrien	      list->line_contents = NULL;
102338889Sjdp	    }
102438889Sjdp	  else
102538889Sjdp	    {
102660484Sobrien	      while (list->file->linenum < list_line
102738889Sjdp		     && !list->file->at_end)
102838889Sjdp		{
102938889Sjdp		  unsigned int address;
103033965Sjdp
103138889Sjdp		  p = buffer_line (list->file, buffer, width);
103233965Sjdp
103360484Sobrien		  if (list->file->linenum < list_line)
103477298Sobrien		    address = ~(unsigned int) 0;
103538889Sjdp		  else
103638889Sjdp		    address = calc_hex (list);
103733965Sjdp
103838889Sjdp		  if (!((listing & LISTING_NODEBUG)
103938889Sjdp			&& debugging_pseudo (list, p)))
104038889Sjdp		    print_lines (list, list->file->linenum, p, address);
104138889Sjdp		}
104233965Sjdp	    }
104333965Sjdp
104433965Sjdp	  if (list->edict == EDICT_EJECT)
1045130561Sobrien	    eject = 1;
104633965Sjdp	}
104733965Sjdp
104877298Sobrien      if (list->edict == EDICT_NOLIST_NEXT && show_listing == 1)
104933965Sjdp	--show_listing;
105033965Sjdp
105133965Sjdp      list = list->next;
105233965Sjdp    }
105338889Sjdp
105433965Sjdp  free (buffer);
105538889Sjdp  free (data_buffer);
105638889Sjdp  data_buffer = NULL;
105733965Sjdp}
105833965Sjdp
105933965Sjdpvoid
1060130561Sobrienlisting_print (char *name)
106133965Sjdp{
106233965Sjdp  int using_stdout;
106377298Sobrien
106433965Sjdp  title = "";
106533965Sjdp  subtitle = "";
106633965Sjdp
106733965Sjdp  if (name == NULL)
106833965Sjdp    {
106933965Sjdp      list_file = stdout;
107033965Sjdp      using_stdout = 1;
107133965Sjdp    }
107233965Sjdp  else
107333965Sjdp    {
107489857Sobrien      list_file = fopen (name, FOPEN_WT);
107533965Sjdp      if (list_file != NULL)
107633965Sjdp	using_stdout = 0;
107733965Sjdp      else
107833965Sjdp	{
1079218822Sdim	  as_warn (_("can't open %s: %s"), name, xstrerror (errno));
108033965Sjdp	  list_file = stdout;
108133965Sjdp	  using_stdout = 1;
108233965Sjdp	}
108333965Sjdp    }
108433965Sjdp
108533965Sjdp  if (listing & LISTING_NOFORM)
1086130561Sobrien    paper_height = 0;
108733965Sjdp
108833965Sjdp  if (listing & LISTING_LISTING)
1089130561Sobrien    listing_listing (name);
109033965Sjdp
109133965Sjdp  if (listing & LISTING_SYMBOLS)
1092130561Sobrien    list_symbol_table ();
109333965Sjdp
109433965Sjdp  if (! using_stdout)
109533965Sjdp    {
109633965Sjdp      if (fclose (list_file) == EOF)
1097218822Sdim	as_warn (_("can't close %s: %s"), name, xstrerror (errno));
109833965Sjdp    }
109933965Sjdp
110038889Sjdp  if (last_open_file)
1101130561Sobrien    fclose (last_open_file);
110233965Sjdp}
110333965Sjdp
110433965Sjdpvoid
1105130561Sobrienlisting_file (const char *name)
110633965Sjdp{
110733965Sjdp  fn = name;
110833965Sjdp}
110933965Sjdp
111033965Sjdpvoid
1111130561Sobrienlisting_eject (int ignore ATTRIBUTE_UNUSED)
111233965Sjdp{
111333965Sjdp  if (listing)
111433965Sjdp    listing_tail->edict = EDICT_EJECT;
111533965Sjdp}
111633965Sjdp
111733965Sjdpvoid
1118130561Sobrienlisting_flags (int ignore ATTRIBUTE_UNUSED)
111933965Sjdp{
112033965Sjdp  while ((*input_line_pointer++) && (*input_line_pointer != '\n'))
112133965Sjdp    input_line_pointer++;
112233965Sjdp
112333965Sjdp}
112433965Sjdp
112533965Sjdp/* Turn listing on or off.  An argument of 0 means to turn off
112633965Sjdp   listing.  An argument of 1 means to turn on listing.  An argument
112733965Sjdp   of 2 means to turn off listing, but as of the next line; that is,
112833965Sjdp   the current line should be listed, but the next line should not.  */
112933965Sjdp
113033965Sjdpvoid
1131130561Sobrienlisting_list (int on)
113233965Sjdp{
113333965Sjdp  if (listing)
113433965Sjdp    {
113533965Sjdp      switch (on)
113633965Sjdp	{
113733965Sjdp	case 0:
113833965Sjdp	  if (listing_tail->edict == EDICT_LIST)
113933965Sjdp	    listing_tail->edict = EDICT_NONE;
114033965Sjdp	  else
114133965Sjdp	    listing_tail->edict = EDICT_NOLIST;
114233965Sjdp	  break;
114333965Sjdp	case 1:
114433965Sjdp	  if (listing_tail->edict == EDICT_NOLIST
114533965Sjdp	      || listing_tail->edict == EDICT_NOLIST_NEXT)
114633965Sjdp	    listing_tail->edict = EDICT_NONE;
114733965Sjdp	  else
114833965Sjdp	    listing_tail->edict = EDICT_LIST;
114933965Sjdp	  break;
115033965Sjdp	case 2:
115133965Sjdp	  listing_tail->edict = EDICT_NOLIST_NEXT;
115233965Sjdp	  break;
115333965Sjdp	default:
115433965Sjdp	  abort ();
115533965Sjdp	}
115633965Sjdp    }
115733965Sjdp}
115833965Sjdp
115933965Sjdpvoid
1160130561Sobrienlisting_psize (int width_only)
116133965Sjdp{
116233965Sjdp  if (! width_only)
116333965Sjdp    {
116433965Sjdp      paper_height = get_absolute_expression ();
116533965Sjdp
116633965Sjdp      if (paper_height < 0 || paper_height > 1000)
116733965Sjdp	{
116833965Sjdp	  paper_height = 0;
116960484Sobrien	  as_warn (_("strange paper height, set to no form"));
117033965Sjdp	}
117133965Sjdp
117233965Sjdp      if (*input_line_pointer != ',')
117333965Sjdp	{
117433965Sjdp	  demand_empty_rest_of_line ();
117533965Sjdp	  return;
117633965Sjdp	}
117733965Sjdp
117833965Sjdp      ++input_line_pointer;
117933965Sjdp    }
118033965Sjdp
118133965Sjdp  paper_width = get_absolute_expression ();
118233965Sjdp
118333965Sjdp  demand_empty_rest_of_line ();
118433965Sjdp}
118533965Sjdp
118633965Sjdpvoid
1187130561Sobrienlisting_nopage (int ignore ATTRIBUTE_UNUSED)
118833965Sjdp{
118933965Sjdp  paper_height = 0;
119033965Sjdp}
119133965Sjdp
119233965Sjdpvoid
1193130561Sobrienlisting_title (int depth)
119433965Sjdp{
119533965Sjdp  int quoted;
119633965Sjdp  char *start;
119733965Sjdp  char *ttl;
119833965Sjdp  unsigned int length;
119933965Sjdp
120033965Sjdp  SKIP_WHITESPACE ();
120133965Sjdp  if (*input_line_pointer != '\"')
120233965Sjdp    quoted = 0;
120333965Sjdp  else
120433965Sjdp    {
120533965Sjdp      quoted = 1;
120633965Sjdp      ++input_line_pointer;
120733965Sjdp    }
120833965Sjdp
120933965Sjdp  start = input_line_pointer;
121033965Sjdp
121133965Sjdp  while (*input_line_pointer)
121233965Sjdp    {
121333965Sjdp      if (quoted
121433965Sjdp	  ? *input_line_pointer == '\"'
121533965Sjdp	  : is_end_of_line[(unsigned char) *input_line_pointer])
121633965Sjdp	{
121733965Sjdp	  if (listing)
121833965Sjdp	    {
121933965Sjdp	      length = input_line_pointer - start;
122033965Sjdp	      ttl = xmalloc (length + 1);
122133965Sjdp	      memcpy (ttl, start, length);
122233965Sjdp	      ttl[length] = 0;
122333965Sjdp	      listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE;
122433965Sjdp	      listing_tail->edict_arg = ttl;
122533965Sjdp	    }
122633965Sjdp	  if (quoted)
122733965Sjdp	    input_line_pointer++;
122833965Sjdp	  demand_empty_rest_of_line ();
122933965Sjdp	  return;
123033965Sjdp	}
123133965Sjdp      else if (*input_line_pointer == '\n')
123233965Sjdp	{
123389857Sobrien	  as_bad (_("new line in title"));
123433965Sjdp	  demand_empty_rest_of_line ();
123533965Sjdp	  return;
123633965Sjdp	}
123733965Sjdp      else
123833965Sjdp	{
123933965Sjdp	  input_line_pointer++;
124033965Sjdp	}
124133965Sjdp    }
124233965Sjdp}
124333965Sjdp
124433965Sjdpvoid
1245130561Sobrienlisting_source_line (unsigned int line)
124633965Sjdp{
124733965Sjdp  if (listing)
124833965Sjdp    {
124933965Sjdp      new_frag ();
125033965Sjdp      listing_tail->hll_line = line;
125133965Sjdp      new_frag ();
125233965Sjdp    }
125333965Sjdp}
125433965Sjdp
125533965Sjdpvoid
1256130561Sobrienlisting_source_file (const char *file)
125733965Sjdp{
125833965Sjdp  if (listing)
125933965Sjdp    listing_tail->hll_file = file_info (file);
126033965Sjdp}
126133965Sjdp
126233965Sjdp#else
126333965Sjdp
126477298Sobrien/* Dummy functions for when compiled without listing enabled.  */
126533965Sjdp
126633965Sjdpvoid
1267130561Sobrienlisting_flags (int ignore)
126833965Sjdp{
126933965Sjdp  s_ignore (0);
127033965Sjdp}
127133965Sjdp
127277298Sobrienvoid
1273130561Sobrienlisting_list (int on)
127433965Sjdp{
127533965Sjdp  s_ignore (0);
127633965Sjdp}
127733965Sjdp
127877298Sobrienvoid
1279130561Sobrienlisting_eject (int ignore)
128033965Sjdp{
128133965Sjdp  s_ignore (0);
128233965Sjdp}
128333965Sjdp
128477298Sobrienvoid
1285130561Sobrienlisting_psize (int ignore)
128633965Sjdp{
128733965Sjdp  s_ignore (0);
128833965Sjdp}
128933965Sjdp
129033965Sjdpvoid
1291130561Sobrienlisting_nopage (int ignore)
129233965Sjdp{
129333965Sjdp  s_ignore (0);
129433965Sjdp}
129533965Sjdp
129677298Sobrienvoid
1297130561Sobrienlisting_title (int depth)
129833965Sjdp{
129933965Sjdp  s_ignore (0);
130033965Sjdp}
130133965Sjdp
130233965Sjdpvoid
1303130561Sobrienlisting_file (const char *name)
130433965Sjdp{
130533965Sjdp}
130633965Sjdp
130777298Sobrienvoid
1308130561Sobrienlisting_newline (char *name)
130933965Sjdp{
131033965Sjdp}
131133965Sjdp
131277298Sobrienvoid
1313130561Sobrienlisting_source_line (unsigned int n)
131433965Sjdp{
131533965Sjdp}
131677298Sobrien
131777298Sobrienvoid
1318130561Sobrienlisting_source_file (const char *n)
131933965Sjdp{
132033965Sjdp}
132133965Sjdp
132233965Sjdp#endif
1323