1 /* listing.c - maintain assembly listings
2    Copyright (C) 1991-2020 Free Software Foundation, Inc.
3 
4    This file is part of GAS, the GNU Assembler.
5 
6    GAS is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    GAS is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with GAS; see the file COPYING.  If not, write to the Free
18    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19    02110-1301, USA.  */
20 
21 /* Contributed by Steve Chamberlain <sac@cygnus.com>
22 
23  A listing page looks like:
24 
25  LISTING_HEADER  sourcefilename pagenumber
26  TITLE LINE
27  SUBTITLE LINE
28  linenumber address data  source
29  linenumber address data  source
30  linenumber address data  source
31  linenumber address data  source
32 
33  If not overridden, the listing commands are:
34 
35  .title  "stuff"
36  	Put "stuff" onto the title line
37  .sbttl  "stuff"
38         Put stuff onto the subtitle line
39 
40   If these commands come within 10 lines of the top of the page, they
41   will affect the page they are on, as well as any subsequent page
42 
43  .eject
44  	Throw a page
45  .list
46  	Increment the enable listing counter
47  .nolist
48  	Decrement the enable listing counter
49 
50  .psize Y[,X]
51  	Set the paper size to X wide and Y high. Setting a psize Y of
52 	zero will suppress form feeds except where demanded by .eject
53 
54  If the counter goes below zero, listing is suppressed.
55 
56  Listings are a maintained by read calling various listing_<foo>
57  functions.  What happens most is that the macro NO_LISTING is not
58  defined (from the Makefile), then the macro LISTING_NEWLINE expands
59  into a call to listing_newline.  The call is done from read.c, every
60  time it sees a newline, and -l is on the command line.
61 
62  The function listing_newline remembers the frag associated with the
63  newline, and creates a new frag - note that this is wasteful, but not
64  a big deal, since listing slows things down a lot anyway.  The
65  function also remembers when the filename changes.
66 
67  When all the input has finished, and gas has had a chance to settle
68  down, the listing is output. This is done by running down the list of
69  frag/source file records, and opening the files as needed and printing
70  out the bytes and chars associated with them.
71 
72  The only things which the architecture can change about the listing
73  are defined in these macros:
74 
75  LISTING_HEADER		The name of the architecture
76  LISTING_WORD_SIZE      The make of the number of bytes in a word, this determines
77  			the clumping of the output data. eg a value of
78 			2 makes words look like 1234 5678, whilst 1
79 			would make the same value look like 12 34 56
80 			78
81  LISTING_LHS_WIDTH      Number of words of above size for the lhs
82 
83  LISTING_LHS_WIDTH_SECOND   Number of words for the data on the lhs
84  			for the second line
85 
86  LISTING_LHS_CONT_LINES	Max number of lines to use up for a continuation
87  LISTING_RHS_WIDTH      Number of chars from the input file to print
88                         on a line.  */
89 
90 #include "as.h"
91 #include "filenames.h"
92 #include "safe-ctype.h"
93 #include "input-file.h"
94 #include "subsegs.h"
95 #include "bfdver.h"
96 #include <time.h>
97 #include <stdarg.h>
98 
99 #ifndef NO_LISTING
100 
101 #ifndef LISTING_HEADER
102 #define LISTING_HEADER "GAS LISTING"
103 #endif
104 #ifndef LISTING_WORD_SIZE
105 #define LISTING_WORD_SIZE 4
106 #endif
107 #ifndef LISTING_LHS_WIDTH
108 #define LISTING_LHS_WIDTH ((LISTING_WORD_SIZE) > 4 ? 1 : 4 / (LISTING_WORD_SIZE))
109 #endif
110 #ifndef LISTING_LHS_WIDTH_SECOND
111 #define LISTING_LHS_WIDTH_SECOND LISTING_LHS_WIDTH
112 #endif
113 #ifndef LISTING_RHS_WIDTH
114 #define LISTING_RHS_WIDTH 100
115 #endif
116 #ifndef LISTING_LHS_CONT_LINES
117 #define LISTING_LHS_CONT_LINES 4
118 #endif
119 #define MAX_DATELEN 30
120 
121 /* This structure remembers which .s were used.  */
122 typedef struct file_info_struct
123 {
124   struct file_info_struct * next;
125   char *                    filename;
126   long                      pos;
127   unsigned int              linenum;
128   int                       at_end;
129 } file_info_type;
130 
131 enum edict_enum
132 {
133   EDICT_NONE,
134   EDICT_SBTTL,
135   EDICT_TITLE,
136   EDICT_NOLIST,
137   EDICT_LIST,
138   EDICT_NOLIST_NEXT,
139   EDICT_EJECT
140 };
141 
142 
143 struct list_message
144 {
145   char *message;
146   struct list_message *next;
147 };
148 
149 /* This structure remembers which line from which file goes into which
150    frag.  */
151 struct list_info_struct
152 {
153   /* Frag which this line of source is nearest to.  */
154   fragS *frag;
155 
156   /* The actual line in the source file.  */
157   unsigned int line;
158 
159   /* Pointer to the file info struct for the file which this line
160      belongs to.  */
161   file_info_type *file;
162 
163   /* The expanded text of any macro that may have been executing.  */
164   char *line_contents;
165 
166   /* Next in list.  */
167   struct list_info_struct *next;
168 
169   /* Pointer to the file info struct for the high level language
170      source line that belongs here.  */
171   file_info_type *hll_file;
172 
173   /* High level language source line.  */
174   unsigned int hll_line;
175 
176   /* Pointers to linked list of messages associated with this line.  */
177   struct list_message *messages, *last_message;
178 
179   enum edict_enum edict;
180   char *edict_arg;
181 
182   /* Nonzero if this line is to be omitted because it contains
183      debugging information.  This can become a flags field if we come
184      up with more information to store here.  */
185   int debugging;
186 };
187 
188 typedef struct list_info_struct list_info_type;
189 
190 int listing_lhs_width        = LISTING_LHS_WIDTH;
191 int listing_lhs_width_second = LISTING_LHS_WIDTH_SECOND;
192 int listing_lhs_cont_lines   = LISTING_LHS_CONT_LINES;
193 int listing_rhs_width        = LISTING_RHS_WIDTH;
194 
195 struct list_info_struct *        listing_tail;
196 
197 static file_info_type *          file_info_head;
198 static file_info_type *          last_open_file_info;
199 static FILE *                    last_open_file;
200 static struct list_info_struct * head;
201 static int                       paper_width = 200;
202 static int                       paper_height = 60;
203 
204 extern int                       listing;
205 
206 /* File to output listings to.  */
207 static FILE *list_file;
208 
209 /* This static array is used to keep the text of data to be printed
210    before the start of the line.  */
211 
212 #define MAX_BYTES							\
213   (((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width			\
214    + ((((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second)	\
215       * listing_lhs_cont_lines)						\
216    + 20)
217 
218 static char *data_buffer;
219 
220 /* Prototypes.  */
221 static void listing_message (const char *, const char *);
222 static file_info_type *file_info (const char *);
223 static void new_frag (void);
224 static void listing_page (list_info_type *);
225 static unsigned int calc_hex (list_info_type *);
226 static void print_lines (list_info_type *, unsigned int, const char *,
227 			 unsigned int);
228 static void list_symbol_table (void);
229 static int debugging_pseudo (list_info_type *, const char *);
230 static void listing_listing (char *);
231 
232 static void
233 listing_message (const char *name, const char *message)
234 {
235   if (listing_tail != (list_info_type *) NULL)
236     {
237       char *n = concat (name, message, (char *) NULL);
238       struct list_message *lm = XNEW (struct list_message);
239       lm->message = n;
240       lm->next = NULL;
241 
242       if (listing_tail->last_message)
243 	listing_tail->last_message->next = lm;
244       else
245 	listing_tail->messages = lm;
246       listing_tail->last_message = lm;
247     }
248 }
249 
250 void
251 listing_warning (const char *message)
252 {
253   listing_message (_("Warning: "), message);
254 }
255 
256 void
257 listing_error (const char *message)
258 {
259   listing_message (_("Error: "), message);
260 }
261 
262 static file_info_type *
263 file_info (const char *file_name)
264 {
265   /* Find an entry with this file name.  */
266   file_info_type *p = file_info_head;
267 
268   while (p != (file_info_type *) NULL)
269     {
270       if (filename_cmp (p->filename, file_name) == 0)
271 	return p;
272       p = p->next;
273     }
274 
275   /* Make new entry.  */
276   p = XNEW (file_info_type);
277   p->next = file_info_head;
278   file_info_head = p;
279   p->filename = xstrdup (file_name);
280   p->pos = 0;
281   p->linenum = 0;
282   p->at_end = 0;
283 
284   return p;
285 }
286 
287 static void
288 new_frag (void)
289 {
290   frag_wane (frag_now);
291   frag_new (0);
292 }
293 
294 void
295 listing_newline (char *ps)
296 {
297   const char *file;
298   unsigned int line;
299   static unsigned int last_line = 0xffff;
300   static const char *last_file = NULL;
301   list_info_type *new_i = NULL;
302 
303   if (listing == 0)
304     return;
305 
306   if (now_seg == absolute_section)
307     return;
308 
309 #ifdef OBJ_ELF
310   /* In ELF, anything in a section beginning with .debug or .line is
311      considered to be debugging information.  This includes the
312      statement which switches us into the debugging section, which we
313      can only set after we are already in the debugging section.  */
314   if ((listing & LISTING_NODEBUG) != 0
315       && listing_tail != NULL
316       && ! listing_tail->debugging)
317     {
318       const char *segname;
319 
320       segname = segment_name (now_seg);
321       if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0
322 	  || strncmp (segname, ".line", sizeof ".line" - 1) == 0)
323 	listing_tail->debugging = 1;
324     }
325 #endif
326 
327   /* PR 21977 - use the physical file name not the logical one unless high
328      level source files are being included in the listing.  */
329   if (listing & LISTING_HLL)
330     file = as_where (&line);
331   else
332     file = as_where_physical (&line);
333 
334   if (ps == NULL)
335     {
336       if (line == last_line
337 	  && !(last_file && file && filename_cmp (file, last_file)))
338 	return;
339 
340       new_i = XNEW (list_info_type);
341 
342       /* Detect if we are reading from stdin by examining the file
343 	 name returned by as_where().
344 
345 	 [FIXME: We rely upon the name in the strcmp below being the
346 	 same as the one used by input_scrub_new_file(), if that is
347 	 not true, then this code will fail].
348 
349 	 If we are reading from stdin, then we need to save each input
350 	 line here (assuming of course that we actually have a line of
351 	 input to read), so that it can be displayed in the listing
352 	 that is produced at the end of the assembly.  */
353       if (strcmp (file, _("{standard input}")) == 0
354 	  && input_line_pointer != NULL)
355 	{
356 	  char *copy, *src, *dest;
357 	  int len;
358 	  int seen_quote = 0;
359 	  int seen_slash = 0;
360 
361 	  for (copy = input_line_pointer;
362 	       *copy && (seen_quote
363 			 || is_end_of_line [(unsigned char) *copy] != 1);
364 	       copy++)
365 	    {
366 	      if (seen_slash)
367 		seen_slash = 0;
368 	      else if (*copy == '\\')
369 		seen_slash = 1;
370 	      else if (*copy == '"')
371 		seen_quote = !seen_quote;
372 	    }
373 
374 	  len = copy - input_line_pointer + 1;
375 
376 	  copy = XNEWVEC (char, len);
377 
378 	  src = input_line_pointer;
379 	  dest = copy;
380 
381 	  while (--len)
382 	    {
383 	      unsigned char c = *src++;
384 
385 	      /* Omit control characters in the listing.  */
386 	      if (!ISCNTRL (c))
387 		*dest++ = c;
388 	    }
389 
390 	  *dest = 0;
391 
392 	  new_i->line_contents = copy;
393 	}
394       else
395 	new_i->line_contents = NULL;
396     }
397   else
398     {
399       new_i = XNEW (list_info_type);
400       new_i->line_contents = ps;
401     }
402 
403   last_line = line;
404   last_file = file;
405 
406   new_frag ();
407 
408   if (listing_tail)
409     listing_tail->next = new_i;
410   else
411     head = new_i;
412 
413   listing_tail = new_i;
414 
415   new_i->frag = frag_now;
416   new_i->line = line;
417   new_i->file = file_info (file);
418   new_i->next = (list_info_type *) NULL;
419   new_i->messages = NULL;
420   new_i->last_message = NULL;
421   new_i->edict = EDICT_NONE;
422   new_i->hll_file = (file_info_type *) NULL;
423   new_i->hll_line = 0;
424   new_i->debugging = 0;
425 
426   new_frag ();
427 
428 #ifdef OBJ_ELF
429   /* In ELF, anything in a section beginning with .debug or .line is
430      considered to be debugging information.  */
431   if ((listing & LISTING_NODEBUG) != 0)
432     {
433       const char *segname;
434 
435       segname = segment_name (now_seg);
436       if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0
437 	  || strncmp (segname, ".line", sizeof ".line" - 1) == 0)
438 	new_i->debugging = 1;
439     }
440 #endif
441 }
442 
443 /* Attach all current frags to the previous line instead of the
444    current line.  This is called by the MIPS backend when it discovers
445    that it needs to add some NOP instructions; the added NOP
446    instructions should go with the instruction that has the delay, not
447    with the new instruction.  */
448 
449 void
450 listing_prev_line (void)
451 {
452   list_info_type *l;
453   fragS *f;
454 
455   if (head == (list_info_type *) NULL
456       || head == listing_tail)
457     return;
458 
459   new_frag ();
460 
461   for (l = head; l->next != listing_tail; l = l->next)
462     ;
463 
464   for (f = frchain_now->frch_root; f != (fragS *) NULL; f = f->fr_next)
465     if (f->line == listing_tail)
466       f->line = l;
467 
468   listing_tail->frag = frag_now;
469   new_frag ();
470 }
471 
472 /* This function returns the next source line from the file supplied,
473    truncated to size.  It appends a fake line to the end of each input
474    file to make using the returned buffer simpler.  */
475 
476 static const char *
477 buffer_line (file_info_type *file, char *line, unsigned int size)
478 {
479   unsigned int count = 0;
480   int c;
481   char *p = line;
482 
483   /* If we couldn't open the file, return an empty line.  */
484   if (file->at_end)
485     return "";
486 
487   /* Check the cache and see if we last used this file.  */
488   if (!last_open_file_info || file != last_open_file_info)
489     {
490       if (last_open_file)
491 	{
492 	  last_open_file_info->pos = ftell (last_open_file);
493 	  fclose (last_open_file);
494 	}
495 
496       /* Open the file in the binary mode so that ftell above can
497 	 return a reliable value that we can feed to fseek below.  */
498       last_open_file_info = file;
499       last_open_file = fopen (file->filename, FOPEN_RB);
500       if (last_open_file == NULL)
501 	{
502 	  file->at_end = 1;
503 	  return "";
504 	}
505 
506       /* Seek to where we were last time this file was open.  */
507       if (file->pos)
508 	fseek (last_open_file, file->pos, SEEK_SET);
509     }
510 
511   /* Leave room for null.  */
512   size -= 1;
513 
514   c = fgetc (last_open_file);
515 
516   while (c != EOF && c != '\n' && c != '\r')
517     {
518       if (count < size)
519 	*p++ = c;
520       count++;
521 
522       c = fgetc (last_open_file);
523     }
524 
525   /* If '\r' is followed by '\n', swallow that.  Likewise, if '\n'
526      is followed by '\r', swallow that as well.  */
527   if (c == '\r' || c == '\n')
528     {
529       int next = fgetc (last_open_file);
530 
531       if ((c == '\r' && next != '\n')
532 	  || (c == '\n' && next != '\r'))
533 	ungetc (next, last_open_file);
534     }
535 
536   if (c == EOF)
537     {
538       file->at_end = 1;
539       if (count + 2 < size)
540 	{
541 	  *p++ = '.';
542 	  *p++ = '.';
543 	  *p++ = '.';
544 	}
545     }
546   file->linenum++;
547   *p++ = 0;
548   return line;
549 }
550 
551 
552 /* This function rewinds the requested file back to the line requested,
553    reads it in again into the buffer provided and then restores the file
554    back to its original location.  */
555 
556 static void
557 rebuffer_line (file_info_type *  file,
558 	       unsigned int      linenum,
559 	       char *            buffer,
560 	       unsigned int      size)
561 {
562   unsigned int count = 0;
563   unsigned int current_line;
564   char * p = buffer;
565   long pos;
566   long pos2;
567   int c;
568   bfd_boolean found = FALSE;
569 
570   /* Sanity checks.  */
571   if (file == NULL || buffer == NULL || size <= 1 || file->linenum <= linenum)
572     return;
573 
574   /* Check the cache and see if we last used this file.  */
575   if (last_open_file_info == NULL || file != last_open_file_info)
576     {
577       if (last_open_file)
578 	{
579 	  last_open_file_info->pos = ftell (last_open_file);
580 	  fclose (last_open_file);
581 	}
582 
583       /* Open the file in the binary mode so that ftell above can
584 	 return a reliable value that we can feed to fseek below.  */
585       last_open_file_info = file;
586       last_open_file = fopen (file->filename, FOPEN_RB);
587       if (last_open_file == NULL)
588 	{
589 	  file->at_end = 1;
590 	  return;
591 	}
592 
593       /* Seek to where we were last time this file was open.  */
594       if (file->pos)
595 	fseek (last_open_file, file->pos, SEEK_SET);
596     }
597 
598   /* Remember where we are in the current file.  */
599   pos2 = pos = ftell (last_open_file);
600   if (pos < 3)
601     return;
602   current_line = file->linenum;
603 
604   /* Leave room for the nul at the end of the buffer.  */
605   size -= 1;
606   buffer[size] = 0;
607 
608   /* Increment the current line count by one.
609      This is to allow for the fact that we are searching for the
610      start of a previous line, but we do this by detecting end-of-line
611      character(s) not start-of-line characters.  */
612   ++ current_line;
613 
614   while (pos2 > 0 && ! found)
615     {
616       char * ptr;
617 
618       /* Move backwards through the file, looking for earlier lines.  */
619       pos2 = (long) size > pos2 ? 0 : pos2 - size;
620       fseek (last_open_file, pos2, SEEK_SET);
621 
622       /* Our caller has kindly provided us with a buffer, so we use it.  */
623       if (fread (buffer, 1, size, last_open_file) != size)
624 	{
625 	  as_warn (_("unable to rebuffer file: %s\n"), file->filename);
626 	  return;
627 	}
628 
629       for (ptr = buffer + size; ptr >= buffer; -- ptr)
630 	{
631 	  if (*ptr == '\n')
632 	    {
633 	      -- current_line;
634 
635 	      if (current_line == linenum)
636 		{
637 		  /* We have found the start of the line we seek.  */
638 		  found = TRUE;
639 
640 		  /* FIXME: We could skip the read-in-the-line code
641 		     below if we know that we already have the whole
642 		     line in the buffer.  */
643 
644 		  /* Advance pos2 to the newline character we have just located.  */
645 		  pos2 += (ptr - buffer);
646 
647 		  /* Skip the newline and, if present, the carriage return.  */
648 		  if (ptr + 1 == buffer + size)
649 		    {
650 		      ++pos2;
651 		      if (fgetc (last_open_file) == '\r')
652 			++ pos2;
653 		    }
654 		  else
655 		    pos2 += (ptr[1] == '\r' ? 2 : 1);
656 
657 		  /* Move the file pointer to this location.  */
658 		  fseek (last_open_file, pos2, SEEK_SET);
659 		  break;
660 		}
661 	    }
662 	}
663     }
664 
665   /* Read in the line.  */
666   c = fgetc (last_open_file);
667 
668   while (c != EOF && c != '\n' && c != '\r')
669     {
670       if (count < size)
671 	*p++ = c;
672       count++;
673 
674       c = fgetc (last_open_file);
675     }
676 
677   /* If '\r' is followed by '\n', swallow that.  Likewise, if '\n'
678      is followed by '\r', swallow that as well.  */
679   if (c == '\r' || c == '\n')
680     {
681       int next = fgetc (last_open_file);
682 
683       if ((c == '\r' && next != '\n')
684 	  || (c == '\n' && next != '\r'))
685 	ungetc (next, last_open_file);
686     }
687 
688   /* Terminate the line.  */
689   *p++ = 0;
690 
691   /* Reset the file position.  */
692   fseek (last_open_file, pos, SEEK_SET);
693 }
694 
695 static const char *fn;
696 static unsigned int eject;	/* Eject pending.  */
697 static unsigned int page;	/* Current page number.  */
698 static const char *title;	/* Current title.  */
699 static const char *subtitle;	/* Current subtitle.  */
700 static unsigned int on_page;	/* Number of lines printed on current page.  */
701 
702 static void
703 listing_page (list_info_type *list)
704 {
705   /* Grope around, see if we can see a title or subtitle edict coming up
706      soon.  (we look down 10 lines of the page and see if it's there)  */
707   if ((eject || (on_page >= (unsigned int) paper_height))
708       && paper_height != 0)
709     {
710       unsigned int c = 10;
711       int had_title = 0;
712       int had_subtitle = 0;
713 
714       page++;
715 
716       while (c != 0 && list)
717 	{
718 	  if (list->edict == EDICT_SBTTL && !had_subtitle)
719 	    {
720 	      had_subtitle = 1;
721 	      subtitle = list->edict_arg;
722 	    }
723 	  if (list->edict == EDICT_TITLE && !had_title)
724 	    {
725 	      had_title = 1;
726 	      title = list->edict_arg;
727 	    }
728 	  list = list->next;
729 	  c--;
730 	}
731 
732       if (page > 1)
733 	{
734 	  fprintf (list_file, "\f");
735 	}
736 
737       fprintf (list_file, "%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page);
738       fprintf (list_file, "%s\n", title);
739       fprintf (list_file, "%s\n", subtitle);
740       on_page = 3;
741       eject = 0;
742     }
743 }
744 
745 /* Print a line into the list_file.  Update the line count
746    and if necessary start a new page.  */
747 
748 static void
749 emit_line (list_info_type * list, const char * format, ...)
750 {
751   va_list args;
752 
753   va_start (args, format);
754 
755   vfprintf (list_file, format, args);
756   on_page++;
757   listing_page (list);
758 
759   va_end (args);
760 }
761 
762 static unsigned int
763 calc_hex (list_info_type *list)
764 {
765   int data_buffer_size;
766   list_info_type *first = list;
767   unsigned int address = ~(unsigned int) 0;
768   fragS *frag;
769   fragS *frag_ptr;
770   unsigned int octet_in_frag;
771 
772   /* Find first frag which says it belongs to this line.  */
773   frag = list->frag;
774   while (frag && frag->line != list)
775     frag = frag->fr_next;
776 
777   frag_ptr = frag;
778 
779   data_buffer_size = 0;
780 
781   /* Dump all the frags which belong to this line.  */
782   while (frag_ptr != (fragS *) NULL && frag_ptr->line == first)
783     {
784       /* Print as many bytes from the fixed part as is sensible.  */
785       octet_in_frag = 0;
786       while (octet_in_frag < frag_ptr->fr_fix
787 	     && data_buffer_size < MAX_BYTES - 3)
788 	{
789 	  if (address == ~(unsigned int) 0)
790 	    address = frag_ptr->fr_address / OCTETS_PER_BYTE;
791 
792 	  sprintf (data_buffer + data_buffer_size,
793 		   "%02X",
794 		   (frag_ptr->fr_literal[octet_in_frag]) & 0xff);
795 	  data_buffer_size += 2;
796 	  octet_in_frag++;
797 	}
798       if (frag_ptr->fr_type == rs_fill)
799 	{
800 	  unsigned int var_rep_max = octet_in_frag;
801 	  unsigned int var_rep_idx = octet_in_frag;
802 
803 	  /* Print as many bytes from the variable part as is sensible.  */
804 	  while ((octet_in_frag
805 		  < frag_ptr->fr_fix + frag_ptr->fr_var * frag_ptr->fr_offset)
806 		 && data_buffer_size < MAX_BYTES - 3)
807 	    {
808 	      if (address == ~(unsigned int) 0)
809 		address = frag_ptr->fr_address / OCTETS_PER_BYTE;
810 
811 	      sprintf (data_buffer + data_buffer_size,
812 		       "%02X",
813 		       (frag_ptr->fr_literal[var_rep_idx]) & 0xff);
814 	      data_buffer_size += 2;
815 
816 	      var_rep_idx++;
817 	      octet_in_frag++;
818 
819 	      if (var_rep_idx >= frag_ptr->fr_fix + frag_ptr->fr_var)
820 		var_rep_idx = var_rep_max;
821 	    }
822 	}
823 
824       frag_ptr = frag_ptr->fr_next;
825     }
826   data_buffer[data_buffer_size] = '\0';
827   return address;
828 }
829 
830 static void
831 print_lines (list_info_type *list, unsigned int lineno,
832 	     const char *string, unsigned int address)
833 {
834   unsigned int idx;
835   unsigned int nchars;
836   unsigned int lines;
837   unsigned int octet_in_word = 0;
838   char *src = data_buffer;
839   int cur;
840   struct list_message *msg;
841 
842   /* Print the stuff on the first line.  */
843   listing_page (list);
844   nchars = (LISTING_WORD_SIZE * 2 + 1) * listing_lhs_width;
845 
846   /* Print the hex for the first line.  */
847   if (address == ~(unsigned int) 0)
848     {
849       fprintf (list_file, "% 4d     ", lineno);
850       for (idx = 0; idx < nchars; idx++)
851 	fprintf (list_file, " ");
852 
853       emit_line (NULL, "\t%s\n", string ? string : "");
854       return;
855     }
856 
857   if (had_errors ())
858     fprintf (list_file, "% 4d ???? ", lineno);
859   else
860     fprintf (list_file, "% 4d %04x ", lineno, address);
861 
862   /* And the data to go along with it.  */
863   idx = 0;
864   cur = 0;
865   while (src[cur] && idx < nchars)
866     {
867       int offset;
868       offset = cur;
869       fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
870       cur += 2;
871       octet_in_word++;
872 
873       if (octet_in_word == LISTING_WORD_SIZE)
874 	{
875 	  fprintf (list_file, " ");
876 	  idx++;
877 	  octet_in_word = 0;
878 	}
879 
880       idx += 2;
881     }
882 
883   for (; idx < nchars; idx++)
884     fprintf (list_file, " ");
885 
886   emit_line (list, "\t%s\n", string ? string : "");
887 
888   for (msg = list->messages; msg; msg = msg->next)
889     emit_line (list, "****  %s\n", msg->message);
890 
891   for (lines = 0;
892        lines < (unsigned int) listing_lhs_cont_lines
893 	 && src[cur];
894        lines++)
895     {
896       nchars = ((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second - 1;
897       idx = 0;
898 
899       /* Print any more lines of data, but more compactly.  */
900       fprintf (list_file, "% 4d      ", lineno);
901 
902       while (src[cur] && idx < nchars)
903 	{
904 	  int offset;
905 	  offset = cur;
906 	  fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
907 	  cur += 2;
908 	  idx += 2;
909 	  octet_in_word++;
910 
911 	  if (octet_in_word == LISTING_WORD_SIZE)
912 	    {
913 	      fprintf (list_file, " ");
914 	      idx++;
915 	      octet_in_word = 0;
916 	    }
917 	}
918 
919       emit_line (list, "\n");
920     }
921 }
922 
923 static void
924 list_symbol_table (void)
925 {
926   extern symbolS *symbol_rootP;
927   int got_some = 0;
928 
929   symbolS *ptr;
930   eject = 1;
931   listing_page (NULL);
932 
933   for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
934     {
935       if (SEG_NORMAL (S_GET_SEGMENT (ptr))
936 	  || S_GET_SEGMENT (ptr) == absolute_section)
937 	{
938 	  /* Don't report section symbols.  They are not interesting.  */
939 	  if (symbol_section_p (ptr))
940 	    continue;
941 
942 	  if (S_GET_NAME (ptr))
943 	    {
944 	      char buf[30], fmt[8];
945 	      valueT val = S_GET_VALUE (ptr);
946 
947 	      /* @@ Note that this is dependent on the compilation options,
948 		 not solely on the target characteristics.  */
949 	      if (sizeof (val) == 4 && sizeof (int) == 4)
950 		sprintf (buf, "%08lx", (unsigned long) val);
951 	      else if (sizeof (val) <= sizeof (unsigned long))
952 		{
953 		  sprintf (fmt, "%%0%lulx",
954 			   (unsigned long) (sizeof (val) * 2));
955 		  sprintf (buf, fmt, (unsigned long) val);
956 		}
957 #if defined (BFD64)
958 	      else if (sizeof (val) > 4)
959 		sprintf_vma (buf, val);
960 #endif
961 	      else
962 		abort ();
963 
964 	      if (!got_some)
965 		{
966 		  fprintf (list_file, "DEFINED SYMBOLS\n");
967 		  on_page++;
968 		  got_some = 1;
969 		}
970 
971 	      if (symbol_get_frag (ptr) && symbol_get_frag (ptr)->line)
972 		{
973 		  fprintf (list_file, "%20s:%-5d  %s:%s %s\n",
974 			   symbol_get_frag (ptr)->line->file->filename,
975 			   symbol_get_frag (ptr)->line->line,
976 			   segment_name (S_GET_SEGMENT (ptr)),
977 			   buf, S_GET_NAME (ptr));
978 		}
979 	      else
980 		{
981 		  fprintf (list_file, "%33s:%s %s\n",
982 			   segment_name (S_GET_SEGMENT (ptr)),
983 			   buf, S_GET_NAME (ptr));
984 		}
985 
986 	      on_page++;
987 	      listing_page (NULL);
988 	    }
989 	}
990 
991     }
992   if (!got_some)
993     {
994       fprintf (list_file, "NO DEFINED SYMBOLS\n");
995       on_page++;
996     }
997   emit_line (NULL, "\n");
998 
999   got_some = 0;
1000 
1001   for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
1002     {
1003       if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0)
1004 	{
1005 	  if (S_GET_SEGMENT (ptr) == undefined_section)
1006 	    {
1007 	      if (!got_some)
1008 		{
1009 		  got_some = 1;
1010 
1011 		  emit_line (NULL, "UNDEFINED SYMBOLS\n");
1012 		}
1013 
1014 	      emit_line (NULL, "%s\n", S_GET_NAME (ptr));
1015 	    }
1016 	}
1017     }
1018 
1019   if (!got_some)
1020     emit_line (NULL, "NO UNDEFINED SYMBOLS\n");
1021 }
1022 
1023 typedef struct cached_line
1024 {
1025   file_info_type * file;
1026   unsigned int     line;
1027   char             buffer [LISTING_RHS_WIDTH];
1028 } cached_line;
1029 
1030 static void
1031 print_source (file_info_type *  current_file,
1032 	      list_info_type *  list,
1033 	      unsigned int      width)
1034 {
1035 #define NUM_CACHE_LINES  3
1036   static cached_line cached_lines[NUM_CACHE_LINES];
1037   static int next_free_line = 0;
1038   cached_line * cache = NULL;
1039 
1040   if (current_file->linenum > list->hll_line
1041       && list->hll_line > 0)
1042     {
1043       /* This can happen with modern optimizing compilers.  The source
1044 	 lines from the high level language input program are split up
1045 	 and interleaved, meaning the line number we want to display
1046 	 (list->hll_line) can have already been displayed.  We have
1047 	 three choices:
1048 
1049 	   a. Do nothing, since we have already displayed the source
1050 	      line.  This was the old behaviour.
1051 
1052 	   b. Display the particular line requested again, but only
1053 	      that line.  This is the new behaviour.
1054 
1055 	   c. Display the particular line requested again and reset
1056 	      the current_file->line_num value so that we redisplay
1057 	      all the following lines as well the next time we
1058 	      encounter a larger line number.  */
1059       int i;
1060 
1061       /* Check the cache, maybe we already have the line saved.  */
1062       for (i = 0; i < NUM_CACHE_LINES; i++)
1063 	if (cached_lines[i].file == current_file
1064 	    && cached_lines[i].line == list->hll_line)
1065 	  {
1066 	    cache = cached_lines + i;
1067 	    break;
1068 	  }
1069 
1070       if (i == NUM_CACHE_LINES)
1071 	{
1072 	  cache = cached_lines + next_free_line;
1073 	  next_free_line ++;
1074 	  if (next_free_line == NUM_CACHE_LINES)
1075 	    next_free_line = 0;
1076 
1077 	  cache->file = current_file;
1078 	  cache->line = list->hll_line;
1079 	  cache->buffer[0] = 0;
1080 	  rebuffer_line (current_file, cache->line, cache->buffer, width);
1081 	}
1082 
1083       emit_line (list, "%4u:%-13s **** %s\n",
1084 		 cache->line, cache->file->filename, cache->buffer);
1085       return;
1086     }
1087 
1088   if (!current_file->at_end)
1089     {
1090       int num_lines_shown = 0;
1091 
1092       while (current_file->linenum < list->hll_line
1093 	     && !current_file->at_end)
1094 	{
1095 	  const char *p;
1096 
1097 	  cache = cached_lines + next_free_line;
1098 	  cache->file = current_file;
1099 	  cache->line = current_file->linenum + 1;
1100 	  cache->buffer[0] = 0;
1101 	  p = buffer_line (current_file, cache->buffer, width);
1102 
1103 	  /* Cache optimization:  If printing a group of lines
1104 	     cache the first and last lines in the group.  */
1105 	  if (num_lines_shown == 0)
1106 	    {
1107 	      next_free_line ++;
1108 	      if (next_free_line == NUM_CACHE_LINES)
1109 		next_free_line = 0;
1110 	    }
1111 
1112 	  emit_line (list, "%4u:%-13s **** %s\n",
1113 		     cache->line, cache->file->filename, p);
1114 	  num_lines_shown ++;
1115 	}
1116     }
1117 }
1118 
1119 /* Sometimes the user doesn't want to be bothered by the debugging
1120    records inserted by the compiler, see if the line is suspicious.  */
1121 
1122 static int
1123 debugging_pseudo (list_info_type *list, const char *line)
1124 {
1125 #ifdef OBJ_ELF
1126   static int in_debug;
1127   int was_debug;
1128 #endif
1129 
1130   if (list->debugging)
1131     {
1132 #ifdef OBJ_ELF
1133       in_debug = 1;
1134 #endif
1135       return 1;
1136     }
1137 #ifdef OBJ_ELF
1138   was_debug = in_debug;
1139   in_debug = 0;
1140 #endif
1141 
1142   while (ISSPACE (*line))
1143     line++;
1144 
1145   if (*line != '.')
1146     {
1147 #ifdef OBJ_ELF
1148       /* The ELF compiler sometimes emits blank lines after switching
1149          out of a debugging section.  If the next line drops us back
1150          into debugging information, then don't print the blank line.
1151          This is a hack for a particular compiler behaviour, not a
1152          general case.  */
1153       if (was_debug
1154 	  && *line == '\0'
1155 	  && list->next != NULL
1156 	  && list->next->debugging)
1157 	{
1158 	  in_debug = 1;
1159 	  return 1;
1160 	}
1161 #endif
1162 
1163       return 0;
1164     }
1165 
1166   line++;
1167 
1168   if (strncmp (line, "def", 3) == 0)
1169     return 1;
1170   if (strncmp (line, "val", 3) == 0)
1171     return 1;
1172   if (strncmp (line, "scl", 3) == 0)
1173     return 1;
1174   if (strncmp (line, "line", 4) == 0)
1175     return 1;
1176   if (strncmp (line, "endef", 5) == 0)
1177     return 1;
1178   if (strncmp (line, "ln", 2) == 0)
1179     return 1;
1180   if (strncmp (line, "type", 4) == 0)
1181     return 1;
1182   if (strncmp (line, "size", 4) == 0)
1183     return 1;
1184   if (strncmp (line, "dim", 3) == 0)
1185     return 1;
1186   if (strncmp (line, "tag", 3) == 0)
1187     return 1;
1188   if (strncmp (line, "stabs", 5) == 0)
1189     return 1;
1190   if (strncmp (line, "stabn", 5) == 0)
1191     return 1;
1192 
1193   return 0;
1194 }
1195 
1196 static void
1197 listing_listing (char *name ATTRIBUTE_UNUSED)
1198 {
1199   list_info_type *list = head;
1200   file_info_type *current_hll_file = (file_info_type *) NULL;
1201   char *buffer;
1202   const char *p;
1203   int show_listing = 1;
1204   unsigned int width;
1205 
1206   buffer = XNEWVEC (char, listing_rhs_width);
1207   data_buffer = XNEWVEC (char, MAX_BYTES);
1208   eject = 1;
1209   list = head->next;
1210 
1211   while (list)
1212     {
1213       unsigned int list_line;
1214 
1215       width = listing_rhs_width > paper_width ? paper_width :
1216 	listing_rhs_width;
1217 
1218       list_line = list->line;
1219       switch (list->edict)
1220 	{
1221 	case EDICT_LIST:
1222 	  /* Skip all lines up to the current.  */
1223 	  list_line--;
1224 	  break;
1225 	case EDICT_NOLIST:
1226 	  show_listing--;
1227 	  break;
1228 	case EDICT_NOLIST_NEXT:
1229 	  if (show_listing == 0)
1230 	    list_line--;
1231 	  break;
1232 	case EDICT_EJECT:
1233 	  break;
1234 	case EDICT_NONE:
1235 	  break;
1236 	case EDICT_TITLE:
1237 	  title = list->edict_arg;
1238 	  break;
1239 	case EDICT_SBTTL:
1240 	  subtitle = list->edict_arg;
1241 	  break;
1242 	default:
1243 	  abort ();
1244 	}
1245 
1246       if (show_listing <= 0)
1247 	{
1248 	  while (list->file->linenum < list_line
1249 		 && !list->file->at_end)
1250 	    p = buffer_line (list->file, buffer, width);
1251 	}
1252 
1253       if (list->edict == EDICT_LIST
1254 	  || (list->edict == EDICT_NOLIST_NEXT && show_listing == 0))
1255 	{
1256 	  /* Enable listing for the single line that caused the enable.  */
1257 	  list_line++;
1258 	  show_listing++;
1259 	}
1260 
1261       if (show_listing > 0)
1262 	{
1263 	  /* Scan down the list and print all the stuff which can be done
1264 	     with this line (or lines).  */
1265 	  if (list->hll_file)
1266 	    current_hll_file = list->hll_file;
1267 
1268 	  if (current_hll_file && list->hll_line && (listing & LISTING_HLL))
1269 	    print_source (current_hll_file, list, width);
1270 
1271 	  if (list->line_contents)
1272 	    {
1273 	      if (!((listing & LISTING_NODEBUG)
1274 		    && debugging_pseudo (list, list->line_contents)))
1275 		print_lines (list,
1276 			     list->file->linenum == 0 ? list->line : list->file->linenum,
1277 			     list->line_contents, calc_hex (list));
1278 
1279 	      free (list->line_contents);
1280 	      list->line_contents = NULL;
1281 	    }
1282 	  else
1283 	    {
1284 	      while (list->file->linenum < list_line
1285 		     && !list->file->at_end)
1286 		{
1287 		  unsigned int address;
1288 
1289 		  p = buffer_line (list->file, buffer, width);
1290 
1291 		  if (list->file->linenum < list_line)
1292 		    address = ~(unsigned int) 0;
1293 		  else
1294 		    address = calc_hex (list);
1295 
1296 		  if (!((listing & LISTING_NODEBUG)
1297 			&& debugging_pseudo (list, p)))
1298 		    print_lines (list, list->file->linenum, p, address);
1299 		}
1300 	    }
1301 
1302 	  if (list->edict == EDICT_EJECT)
1303 	    eject = 1;
1304 	}
1305 
1306       if (list->edict == EDICT_NOLIST_NEXT && show_listing == 1)
1307 	--show_listing;
1308 
1309       list = list->next;
1310     }
1311 
1312   free (buffer);
1313   free (data_buffer);
1314   data_buffer = NULL;
1315 }
1316 
1317 /* Print time stamp in ISO format:  yyyy-mm-ddThh:mm:ss.ss+/-zzzz.  */
1318 
1319 static void
1320 print_timestamp (void)
1321 {
1322   const time_t now = time (NULL);
1323   struct tm * timestamp;
1324   char stampstr[MAX_DATELEN];
1325 
1326   /* Any portable way to obtain subsecond values???  */
1327   timestamp = localtime (&now);
1328   strftime (stampstr, MAX_DATELEN, "%Y-%m-%dT%H:%M:%S.000%z", timestamp);
1329   fprintf (list_file, _("\n time stamp    \t: %s\n\n"), stampstr);
1330 }
1331 
1332 static void
1333 print_single_option (char * opt, int *pos)
1334 {
1335   int opt_len = strlen (opt);
1336 
1337    if ((*pos + opt_len) < paper_width)
1338      {
1339         fprintf (list_file, _("%s "), opt);
1340         *pos = *pos + opt_len;
1341      }
1342    else
1343      {
1344         fprintf (list_file, _("\n\t%s "), opt);
1345         *pos = opt_len;
1346      }
1347 }
1348 
1349 /* Print options passed to as.  */
1350 
1351 static void
1352 print_options (char ** argv)
1353 {
1354   const char *field_name = _("\n options passed\t: ");
1355   int pos = strlen (field_name);
1356   char **p;
1357 
1358   fputs (field_name, list_file);
1359   for (p = &argv[1]; *p != NULL; p++)
1360     if (**p == '-')
1361       {
1362         /* Ignore these.  */
1363         if (strcmp (*p, "-o") == 0)
1364           {
1365             if (p[1] != NULL)
1366               p++;
1367             continue;
1368           }
1369         if (strcmp (*p, "-v") == 0)
1370           continue;
1371 
1372         print_single_option (*p, &pos);
1373       }
1374 }
1375 
1376 /* Print a first section with basic info like file names, as version,
1377    options passed, target, and timestamp.
1378    The format of this section is as follows:
1379 
1380    AS VERSION
1381 
1382    fieldname TAB ':' fieldcontents
1383   { TAB fieldcontents-cont }  */
1384 
1385 static void
1386 listing_general_info (char ** argv)
1387 {
1388   /* Print the stuff on the first line.  */
1389   eject = 1;
1390   listing_page (NULL);
1391 
1392   fprintf (list_file,
1393            _(" GNU assembler version %s (%s)\n\t using BFD version %s."),
1394            VERSION, TARGET_ALIAS, BFD_VERSION_STRING);
1395   print_options (argv);
1396   fprintf (list_file, _("\n input file    \t: %s"), fn);
1397   fprintf (list_file, _("\n output file   \t: %s"), out_file_name);
1398   fprintf (list_file, _("\n target        \t: %s"), TARGET_CANONICAL);
1399   print_timestamp ();
1400 }
1401 
1402 void
1403 listing_print (char *name, char **argv)
1404 {
1405   int using_stdout;
1406 
1407   title = "";
1408   subtitle = "";
1409 
1410   if (name == NULL)
1411     {
1412       list_file = stdout;
1413       using_stdout = 1;
1414     }
1415   else
1416     {
1417       list_file = fopen (name, FOPEN_WT);
1418       if (list_file != NULL)
1419 	using_stdout = 0;
1420       else
1421 	{
1422 	  as_warn (_("can't open %s: %s"), name, xstrerror (errno));
1423 	  list_file = stdout;
1424 	  using_stdout = 1;
1425 	}
1426     }
1427 
1428   if (listing & LISTING_NOFORM)
1429     paper_height = 0;
1430 
1431   if (listing & LISTING_GENERAL)
1432     listing_general_info (argv);
1433 
1434   if (listing & LISTING_LISTING)
1435     listing_listing (name);
1436 
1437   if (listing & LISTING_SYMBOLS)
1438     list_symbol_table ();
1439 
1440   if (! using_stdout)
1441     {
1442       if (fclose (list_file) == EOF)
1443 	as_warn (_("can't close %s: %s"), name, xstrerror (errno));
1444     }
1445 
1446   if (last_open_file)
1447     fclose (last_open_file);
1448 }
1449 
1450 void
1451 listing_file (const char *name)
1452 {
1453   fn = name;
1454 }
1455 
1456 void
1457 listing_eject (int ignore ATTRIBUTE_UNUSED)
1458 {
1459   if (listing)
1460     listing_tail->edict = EDICT_EJECT;
1461 }
1462 
1463 /* Turn listing on or off.  An argument of 0 means to turn off
1464    listing.  An argument of 1 means to turn on listing.  An argument
1465    of 2 means to turn off listing, but as of the next line; that is,
1466    the current line should be listed, but the next line should not.  */
1467 
1468 void
1469 listing_list (int on)
1470 {
1471   if (listing)
1472     {
1473       switch (on)
1474 	{
1475 	case 0:
1476 	  if (listing_tail->edict == EDICT_LIST)
1477 	    listing_tail->edict = EDICT_NONE;
1478 	  else
1479 	    listing_tail->edict = EDICT_NOLIST;
1480 	  break;
1481 	case 1:
1482 	  if (listing_tail->edict == EDICT_NOLIST
1483 	      || listing_tail->edict == EDICT_NOLIST_NEXT)
1484 	    listing_tail->edict = EDICT_NONE;
1485 	  else
1486 	    listing_tail->edict = EDICT_LIST;
1487 	  break;
1488 	case 2:
1489 	  listing_tail->edict = EDICT_NOLIST_NEXT;
1490 	  break;
1491 	default:
1492 	  abort ();
1493 	}
1494     }
1495 }
1496 
1497 void
1498 listing_psize (int width_only)
1499 {
1500   if (! width_only)
1501     {
1502       paper_height = get_absolute_expression ();
1503 
1504       if (paper_height < 0 || paper_height > 1000)
1505 	{
1506 	  paper_height = 0;
1507 	  as_warn (_("strange paper height, set to no form"));
1508 	}
1509 
1510       if (*input_line_pointer != ',')
1511 	{
1512 	  demand_empty_rest_of_line ();
1513 	  return;
1514 	}
1515 
1516       ++input_line_pointer;
1517     }
1518 
1519   paper_width = get_absolute_expression ();
1520 
1521   demand_empty_rest_of_line ();
1522 }
1523 
1524 void
1525 listing_nopage (int ignore ATTRIBUTE_UNUSED)
1526 {
1527   paper_height = 0;
1528 }
1529 
1530 void
1531 listing_title (int depth)
1532 {
1533   int quoted;
1534   char *start;
1535   char *ttl;
1536   unsigned int length;
1537 
1538   SKIP_WHITESPACE ();
1539   if (*input_line_pointer != '\"')
1540     quoted = 0;
1541   else
1542     {
1543       quoted = 1;
1544       ++input_line_pointer;
1545     }
1546 
1547   start = input_line_pointer;
1548 
1549   while (*input_line_pointer)
1550     {
1551       if (quoted
1552 	  ? *input_line_pointer == '\"'
1553 	  : is_end_of_line[(unsigned char) *input_line_pointer])
1554 	{
1555 	  if (listing)
1556 	    {
1557 	      length = input_line_pointer - start;
1558 	      ttl = xmemdup0 (start, length);
1559 	      listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE;
1560 	      listing_tail->edict_arg = ttl;
1561 	    }
1562 	  if (quoted)
1563 	    input_line_pointer++;
1564 	  demand_empty_rest_of_line ();
1565 	  return;
1566 	}
1567       else if (*input_line_pointer == '\n')
1568 	{
1569 	  as_bad (_("new line in title"));
1570 	  demand_empty_rest_of_line ();
1571 	  return;
1572 	}
1573       else
1574 	{
1575 	  input_line_pointer++;
1576 	}
1577     }
1578 }
1579 
1580 void
1581 listing_source_line (unsigned int line)
1582 {
1583   if (listing)
1584     {
1585       new_frag ();
1586       listing_tail->hll_line = line;
1587       new_frag ();
1588     }
1589 }
1590 
1591 void
1592 listing_source_file (const char *file)
1593 {
1594   if (listing)
1595     listing_tail->hll_file = file_info (file);
1596 }
1597 
1598 #else
1599 
1600 /* Dummy functions for when compiled without listing enabled.  */
1601 
1602 void
1603 listing_list (int on)
1604 {
1605   s_ignore (0);
1606 }
1607 
1608 void
1609 listing_eject (int ignore)
1610 {
1611   s_ignore (0);
1612 }
1613 
1614 void
1615 listing_psize (int ignore)
1616 {
1617   s_ignore (0);
1618 }
1619 
1620 void
1621 listing_nopage (int ignore)
1622 {
1623   s_ignore (0);
1624 }
1625 
1626 void
1627 listing_title (int depth)
1628 {
1629   s_ignore (0);
1630 }
1631 
1632 void
1633 listing_file (const char *name)
1634 {
1635 }
1636 
1637 void
1638 listing_newline (char *name)
1639 {
1640 }
1641 
1642 void
1643 listing_source_line (unsigned int n)
1644 {
1645 }
1646 
1647 void
1648 listing_source_file (const char *n)
1649 {
1650 }
1651 
1652 #endif
1653