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