Coverage Report

Created: 2025-06-24 06:45

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