12a6b7db3Sskrll /* listing.c - maintain assembly listings
2*f22f0ef4Schristos Copyright (C) 1991-2022 Free Software Foundation, Inc.
32a6b7db3Sskrll
42a6b7db3Sskrll This file is part of GAS, the GNU Assembler.
52a6b7db3Sskrll
62a6b7db3Sskrll GAS is free software; you can redistribute it and/or modify
72a6b7db3Sskrll it under the terms of the GNU General Public License as published by
82a6b7db3Sskrll the Free Software Foundation; either version 3, or (at your option)
92a6b7db3Sskrll any later version.
102a6b7db3Sskrll
112a6b7db3Sskrll GAS is distributed in the hope that it will be useful,
122a6b7db3Sskrll but WITHOUT ANY WARRANTY; without even the implied warranty of
132a6b7db3Sskrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
142a6b7db3Sskrll GNU General Public License for more details.
152a6b7db3Sskrll
162a6b7db3Sskrll You should have received a copy of the GNU General Public License
172a6b7db3Sskrll along with GAS; see the file COPYING. If not, write to the Free
182a6b7db3Sskrll Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
192a6b7db3Sskrll 02110-1301, USA. */
202a6b7db3Sskrll
212a6b7db3Sskrll /* Contributed by Steve Chamberlain <sac@cygnus.com>
222a6b7db3Sskrll
232a6b7db3Sskrll A listing page looks like:
242a6b7db3Sskrll
252a6b7db3Sskrll LISTING_HEADER sourcefilename pagenumber
262a6b7db3Sskrll TITLE LINE
272a6b7db3Sskrll SUBTITLE LINE
282a6b7db3Sskrll linenumber address data source
292a6b7db3Sskrll linenumber address data source
302a6b7db3Sskrll linenumber address data source
312a6b7db3Sskrll linenumber address data source
322a6b7db3Sskrll
332a6b7db3Sskrll If not overridden, the listing commands are:
342a6b7db3Sskrll
352a6b7db3Sskrll .title "stuff"
362a6b7db3Sskrll Put "stuff" onto the title line
372a6b7db3Sskrll .sbttl "stuff"
382a6b7db3Sskrll Put stuff onto the subtitle line
392a6b7db3Sskrll
402a6b7db3Sskrll If these commands come within 10 lines of the top of the page, they
412a6b7db3Sskrll will affect the page they are on, as well as any subsequent page
422a6b7db3Sskrll
432a6b7db3Sskrll .eject
4498f124a6Schristos Throw a page
452a6b7db3Sskrll .list
462a6b7db3Sskrll Increment the enable listing counter
472a6b7db3Sskrll .nolist
482a6b7db3Sskrll Decrement the enable listing counter
492a6b7db3Sskrll
502a6b7db3Sskrll .psize Y[,X]
512a6b7db3Sskrll Set the paper size to X wide and Y high. Setting a psize Y of
522a6b7db3Sskrll zero will suppress form feeds except where demanded by .eject
532a6b7db3Sskrll
542a6b7db3Sskrll If the counter goes below zero, listing is suppressed.
552a6b7db3Sskrll
562a6b7db3Sskrll Listings are a maintained by read calling various listing_<foo>
572a6b7db3Sskrll functions. What happens most is that the macro NO_LISTING is not
582a6b7db3Sskrll defined (from the Makefile), then the macro LISTING_NEWLINE expands
592a6b7db3Sskrll into a call to listing_newline. The call is done from read.c, every
602a6b7db3Sskrll time it sees a newline, and -l is on the command line.
612a6b7db3Sskrll
622a6b7db3Sskrll The function listing_newline remembers the frag associated with the
632a6b7db3Sskrll newline, and creates a new frag - note that this is wasteful, but not
642a6b7db3Sskrll a big deal, since listing slows things down a lot anyway. The
652a6b7db3Sskrll function also remembers when the filename changes.
662a6b7db3Sskrll
672a6b7db3Sskrll When all the input has finished, and gas has had a chance to settle
682a6b7db3Sskrll down, the listing is output. This is done by running down the list of
692a6b7db3Sskrll frag/source file records, and opening the files as needed and printing
702a6b7db3Sskrll out the bytes and chars associated with them.
712a6b7db3Sskrll
722a6b7db3Sskrll The only things which the architecture can change about the listing
732a6b7db3Sskrll are defined in these macros:
742a6b7db3Sskrll
752a6b7db3Sskrll LISTING_HEADER The name of the architecture
762a6b7db3Sskrll LISTING_WORD_SIZE The make of the number of bytes in a word, this determines
772a6b7db3Sskrll the clumping of the output data. eg a value of
782a6b7db3Sskrll 2 makes words look like 1234 5678, whilst 1
792a6b7db3Sskrll would make the same value look like 12 34 56
802a6b7db3Sskrll 78
812a6b7db3Sskrll LISTING_LHS_WIDTH Number of words of above size for the lhs
822a6b7db3Sskrll
832a6b7db3Sskrll LISTING_LHS_WIDTH_SECOND Number of words for the data on the lhs
842a6b7db3Sskrll for the second line
852a6b7db3Sskrll
862a6b7db3Sskrll LISTING_LHS_CONT_LINES Max number of lines to use up for a continuation
872a6b7db3Sskrll LISTING_RHS_WIDTH Number of chars from the input file to print
882a6b7db3Sskrll on a line. */
892a6b7db3Sskrll
902a6b7db3Sskrll #include "as.h"
9105caefcfSchristos #include "filenames.h"
922a6b7db3Sskrll #include "safe-ctype.h"
932a6b7db3Sskrll #include "input-file.h"
942a6b7db3Sskrll #include "subsegs.h"
952a6b7db3Sskrll #include "bfdver.h"
962a6b7db3Sskrll #include <time.h>
97b075ecf2Schristos #include <stdarg.h>
982a6b7db3Sskrll
992a6b7db3Sskrll #ifndef NO_LISTING
1002a6b7db3Sskrll
1012a6b7db3Sskrll #ifndef LISTING_HEADER
1022a6b7db3Sskrll #define LISTING_HEADER "GAS LISTING"
1032a6b7db3Sskrll #endif
1042a6b7db3Sskrll #ifndef LISTING_WORD_SIZE
1052a6b7db3Sskrll #define LISTING_WORD_SIZE 4
1062a6b7db3Sskrll #endif
1072a6b7db3Sskrll #ifndef LISTING_LHS_WIDTH
1082a6b7db3Sskrll #define LISTING_LHS_WIDTH ((LISTING_WORD_SIZE) > 4 ? 1 : 4 / (LISTING_WORD_SIZE))
1092a6b7db3Sskrll #endif
1102a6b7db3Sskrll #ifndef LISTING_LHS_WIDTH_SECOND
1112a6b7db3Sskrll #define LISTING_LHS_WIDTH_SECOND LISTING_LHS_WIDTH
1122a6b7db3Sskrll #endif
1132a6b7db3Sskrll #ifndef LISTING_RHS_WIDTH
1142a6b7db3Sskrll #define LISTING_RHS_WIDTH 100
1152a6b7db3Sskrll #endif
1162a6b7db3Sskrll #ifndef LISTING_LHS_CONT_LINES
1172a6b7db3Sskrll #define LISTING_LHS_CONT_LINES 4
1182a6b7db3Sskrll #endif
1192a6b7db3Sskrll #define MAX_DATELEN 30
1202a6b7db3Sskrll
1212a6b7db3Sskrll /* This structure remembers which .s were used. */
1222a6b7db3Sskrll typedef struct file_info_struct
1232a6b7db3Sskrll {
1242a6b7db3Sskrll struct file_info_struct * next;
1252a6b7db3Sskrll char * filename;
1262a6b7db3Sskrll long pos;
1272a6b7db3Sskrll unsigned int linenum;
1282a6b7db3Sskrll int at_end;
1292a6b7db3Sskrll } file_info_type;
1302a6b7db3Sskrll
131b075ecf2Schristos enum edict_enum
132b075ecf2Schristos {
133b075ecf2Schristos EDICT_NONE,
134b075ecf2Schristos EDICT_SBTTL,
135b075ecf2Schristos EDICT_TITLE,
136b075ecf2Schristos EDICT_NOLIST,
137b075ecf2Schristos EDICT_LIST,
138b075ecf2Schristos EDICT_NOLIST_NEXT,
139b075ecf2Schristos EDICT_EJECT
140b075ecf2Schristos };
141b075ecf2Schristos
142b075ecf2Schristos
14305caefcfSchristos struct list_message
14405caefcfSchristos {
14505caefcfSchristos char *message;
14605caefcfSchristos struct list_message *next;
14705caefcfSchristos };
14805caefcfSchristos
1492a6b7db3Sskrll /* This structure remembers which line from which file goes into which
1502a6b7db3Sskrll frag. */
1512a6b7db3Sskrll struct list_info_struct
1522a6b7db3Sskrll {
1532a6b7db3Sskrll /* Frag which this line of source is nearest to. */
1542a6b7db3Sskrll fragS *frag;
1552a6b7db3Sskrll
1562a6b7db3Sskrll /* The actual line in the source file. */
1572a6b7db3Sskrll unsigned int line;
1582a6b7db3Sskrll
1592a6b7db3Sskrll /* Pointer to the file info struct for the file which this line
1602a6b7db3Sskrll belongs to. */
1612a6b7db3Sskrll file_info_type *file;
1622a6b7db3Sskrll
1632a6b7db3Sskrll /* The expanded text of any macro that may have been executing. */
1642a6b7db3Sskrll char *line_contents;
1652a6b7db3Sskrll
1662a6b7db3Sskrll /* Next in list. */
1672a6b7db3Sskrll struct list_info_struct *next;
1682a6b7db3Sskrll
1692a6b7db3Sskrll /* Pointer to the file info struct for the high level language
1702a6b7db3Sskrll source line that belongs here. */
1712a6b7db3Sskrll file_info_type *hll_file;
1722a6b7db3Sskrll
1732a6b7db3Sskrll /* High level language source line. */
1742a6b7db3Sskrll unsigned int hll_line;
1752a6b7db3Sskrll
17605caefcfSchristos /* Pointers to linked list of messages associated with this line. */
17705caefcfSchristos struct list_message *messages, *last_message;
1782a6b7db3Sskrll
179b075ecf2Schristos enum edict_enum edict;
1802a6b7db3Sskrll char *edict_arg;
1812a6b7db3Sskrll
1822a6b7db3Sskrll /* Nonzero if this line is to be omitted because it contains
1832a6b7db3Sskrll debugging information. This can become a flags field if we come
1842a6b7db3Sskrll up with more information to store here. */
1852a6b7db3Sskrll int debugging;
1862a6b7db3Sskrll };
1872a6b7db3Sskrll
1882a6b7db3Sskrll typedef struct list_info_struct list_info_type;
1892a6b7db3Sskrll
1902a6b7db3Sskrll int listing_lhs_width = LISTING_LHS_WIDTH;
1912a6b7db3Sskrll int listing_lhs_width_second = LISTING_LHS_WIDTH_SECOND;
1922a6b7db3Sskrll int listing_lhs_cont_lines = LISTING_LHS_CONT_LINES;
1932a6b7db3Sskrll int listing_rhs_width = LISTING_RHS_WIDTH;
1942a6b7db3Sskrll
1952a6b7db3Sskrll struct list_info_struct * listing_tail;
1962a6b7db3Sskrll
1972a6b7db3Sskrll static file_info_type * file_info_head;
1982a6b7db3Sskrll static file_info_type * last_open_file_info;
1992a6b7db3Sskrll static FILE * last_open_file;
2002a6b7db3Sskrll static struct list_info_struct * head;
2012a6b7db3Sskrll static int paper_width = 200;
2022a6b7db3Sskrll static int paper_height = 60;
2032a6b7db3Sskrll
2042a6b7db3Sskrll extern int listing;
2052a6b7db3Sskrll
2062a6b7db3Sskrll /* File to output listings to. */
2072a6b7db3Sskrll static FILE *list_file;
2082a6b7db3Sskrll
2092a6b7db3Sskrll /* This static array is used to keep the text of data to be printed
2102a6b7db3Sskrll before the start of the line. */
2112a6b7db3Sskrll
2122a6b7db3Sskrll #define MAX_BYTES \
2132a6b7db3Sskrll (((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width \
2142a6b7db3Sskrll + ((((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second) \
2152a6b7db3Sskrll * listing_lhs_cont_lines) \
2162a6b7db3Sskrll + 20)
2172a6b7db3Sskrll
2182a6b7db3Sskrll static char *data_buffer;
2192a6b7db3Sskrll
2202a6b7db3Sskrll /* Prototypes. */
2212a6b7db3Sskrll static void listing_message (const char *, const char *);
2222a6b7db3Sskrll static file_info_type *file_info (const char *);
2232a6b7db3Sskrll static void new_frag (void);
2242a6b7db3Sskrll static void listing_page (list_info_type *);
2252a6b7db3Sskrll static unsigned int calc_hex (list_info_type *);
22675f9f1baSchristos static void print_lines (list_info_type *, unsigned int, const char *,
22775f9f1baSchristos unsigned int);
2282a6b7db3Sskrll static void list_symbol_table (void);
2292a6b7db3Sskrll static int debugging_pseudo (list_info_type *, const char *);
2302a6b7db3Sskrll static void listing_listing (char *);
2312a6b7db3Sskrll
2322a6b7db3Sskrll static void
listing_message(const char * name,const char * message)2332a6b7db3Sskrll listing_message (const char *name, const char *message)
2342a6b7db3Sskrll {
2352a6b7db3Sskrll if (listing_tail != (list_info_type *) NULL)
2362a6b7db3Sskrll {
23775f9f1baSchristos char *n = concat (name, message, (char *) NULL);
23875f9f1baSchristos struct list_message *lm = XNEW (struct list_message);
23905caefcfSchristos lm->message = n;
24005caefcfSchristos lm->next = NULL;
24105caefcfSchristos
24205caefcfSchristos if (listing_tail->last_message)
24305caefcfSchristos listing_tail->last_message->next = lm;
24405caefcfSchristos else
24505caefcfSchristos listing_tail->messages = lm;
24605caefcfSchristos listing_tail->last_message = lm;
2472a6b7db3Sskrll }
2482a6b7db3Sskrll }
2492a6b7db3Sskrll
2502a6b7db3Sskrll void
listing_warning(const char * message)2512a6b7db3Sskrll listing_warning (const char *message)
2522a6b7db3Sskrll {
2532a6b7db3Sskrll listing_message (_("Warning: "), message);
2542a6b7db3Sskrll }
2552a6b7db3Sskrll
2562a6b7db3Sskrll void
listing_error(const char * message)2572a6b7db3Sskrll listing_error (const char *message)
2582a6b7db3Sskrll {
2592a6b7db3Sskrll listing_message (_("Error: "), message);
2602a6b7db3Sskrll }
2612a6b7db3Sskrll
2622a6b7db3Sskrll static file_info_type *
file_info(const char * file_name)2632a6b7db3Sskrll file_info (const char *file_name)
2642a6b7db3Sskrll {
2652a6b7db3Sskrll /* Find an entry with this file name. */
2662a6b7db3Sskrll file_info_type *p = file_info_head;
2672a6b7db3Sskrll
2682a6b7db3Sskrll while (p != (file_info_type *) NULL)
2692a6b7db3Sskrll {
27005caefcfSchristos if (filename_cmp (p->filename, file_name) == 0)
2712a6b7db3Sskrll return p;
2722a6b7db3Sskrll p = p->next;
2732a6b7db3Sskrll }
2742a6b7db3Sskrll
2752a6b7db3Sskrll /* Make new entry. */
27675f9f1baSchristos p = XNEW (file_info_type);
2772a6b7db3Sskrll p->next = file_info_head;
2782a6b7db3Sskrll file_info_head = p;
2792a6b7db3Sskrll p->filename = xstrdup (file_name);
2802a6b7db3Sskrll p->pos = 0;
2812a6b7db3Sskrll p->linenum = 0;
2822a6b7db3Sskrll p->at_end = 0;
2832a6b7db3Sskrll
2842a6b7db3Sskrll return p;
2852a6b7db3Sskrll }
2862a6b7db3Sskrll
2872a6b7db3Sskrll static void
new_frag(void)2882a6b7db3Sskrll new_frag (void)
2892a6b7db3Sskrll {
2902a6b7db3Sskrll frag_wane (frag_now);
2912a6b7db3Sskrll frag_new (0);
2922a6b7db3Sskrll }
2932a6b7db3Sskrll
2942a6b7db3Sskrll void
listing_newline(char * ps)2952a6b7db3Sskrll listing_newline (char *ps)
2962a6b7db3Sskrll {
29775f9f1baSchristos const char *file;
2982a6b7db3Sskrll unsigned int line;
2992a6b7db3Sskrll static unsigned int last_line = 0xffff;
30075f9f1baSchristos static const char *last_file = NULL;
301b075ecf2Schristos list_info_type *new_i = NULL;
3022a6b7db3Sskrll
3032a6b7db3Sskrll if (listing == 0)
3042a6b7db3Sskrll return;
3052a6b7db3Sskrll
3062a6b7db3Sskrll if (now_seg == absolute_section)
3072a6b7db3Sskrll return;
3082a6b7db3Sskrll
3092a6b7db3Sskrll #ifdef OBJ_ELF
3102a6b7db3Sskrll /* In ELF, anything in a section beginning with .debug or .line is
3112a6b7db3Sskrll considered to be debugging information. This includes the
3122a6b7db3Sskrll statement which switches us into the debugging section, which we
3132a6b7db3Sskrll can only set after we are already in the debugging section. */
3142a6b7db3Sskrll if ((listing & LISTING_NODEBUG) != 0
3152a6b7db3Sskrll && listing_tail != NULL
3162a6b7db3Sskrll && ! listing_tail->debugging)
3172a6b7db3Sskrll {
3182a6b7db3Sskrll const char *segname;
3192a6b7db3Sskrll
3202a6b7db3Sskrll segname = segment_name (now_seg);
321*f22f0ef4Schristos if (startswith (segname, ".debug")
322*f22f0ef4Schristos || startswith (segname, ".line"))
3232a6b7db3Sskrll listing_tail->debugging = 1;
3242a6b7db3Sskrll }
3252a6b7db3Sskrll #endif
3262a6b7db3Sskrll
32798f124a6Schristos /* PR 21977 - use the physical file name not the logical one unless high
32898f124a6Schristos level source files are being included in the listing. */
32998f124a6Schristos if (listing & LISTING_HLL)
33075f9f1baSchristos file = as_where (&line);
33198f124a6Schristos else
33298f124a6Schristos file = as_where_physical (&line);
33398f124a6Schristos
3342a6b7db3Sskrll if (ps == NULL)
3352a6b7db3Sskrll {
3362a6b7db3Sskrll if (line == last_line
33705caefcfSchristos && !(last_file && file && filename_cmp (file, last_file)))
3382a6b7db3Sskrll return;
3392a6b7db3Sskrll
34075f9f1baSchristos new_i = XNEW (list_info_type);
3412a6b7db3Sskrll
3422a6b7db3Sskrll /* Detect if we are reading from stdin by examining the file
3432a6b7db3Sskrll name returned by as_where().
3442a6b7db3Sskrll
3452a6b7db3Sskrll [FIXME: We rely upon the name in the strcmp below being the
3462a6b7db3Sskrll same as the one used by input_scrub_new_file(), if that is
3472a6b7db3Sskrll not true, then this code will fail].
3482a6b7db3Sskrll
3492a6b7db3Sskrll If we are reading from stdin, then we need to save each input
3502a6b7db3Sskrll line here (assuming of course that we actually have a line of
3512a6b7db3Sskrll input to read), so that it can be displayed in the listing
3522a6b7db3Sskrll that is produced at the end of the assembly. */
3532a6b7db3Sskrll if (strcmp (file, _("{standard input}")) == 0
3542a6b7db3Sskrll && input_line_pointer != NULL)
3552a6b7db3Sskrll {
35675f9f1baSchristos char *copy, *src, *dest;
3572a6b7db3Sskrll int len;
3582a6b7db3Sskrll int seen_quote = 0;
359b075ecf2Schristos int seen_slash = 0;
3602a6b7db3Sskrll
361b075ecf2Schristos for (copy = input_line_pointer;
3622a6b7db3Sskrll *copy && (seen_quote
363b075ecf2Schristos || is_end_of_line [(unsigned char) *copy] != 1);
3642a6b7db3Sskrll copy++)
365b075ecf2Schristos {
366b075ecf2Schristos if (seen_slash)
367b075ecf2Schristos seen_slash = 0;
368b075ecf2Schristos else if (*copy == '\\')
369b075ecf2Schristos seen_slash = 1;
370b075ecf2Schristos else if (*copy == '"')
3712a6b7db3Sskrll seen_quote = !seen_quote;
372b075ecf2Schristos }
3732a6b7db3Sskrll
374b075ecf2Schristos len = copy - input_line_pointer + 1;
3752a6b7db3Sskrll
37675f9f1baSchristos copy = XNEWVEC (char, len);
3772a6b7db3Sskrll
37875f9f1baSchristos src = input_line_pointer;
37975f9f1baSchristos dest = copy;
3802a6b7db3Sskrll
3812a6b7db3Sskrll while (--len)
3822a6b7db3Sskrll {
3832a6b7db3Sskrll unsigned char c = *src++;
3842a6b7db3Sskrll
3852a6b7db3Sskrll /* Omit control characters in the listing. */
3862a6b7db3Sskrll if (!ISCNTRL (c))
3872a6b7db3Sskrll *dest++ = c;
3882a6b7db3Sskrll }
3892a6b7db3Sskrll
3902a6b7db3Sskrll *dest = 0;
3912a6b7db3Sskrll
392b075ecf2Schristos new_i->line_contents = copy;
3932a6b7db3Sskrll }
3942a6b7db3Sskrll else
395b075ecf2Schristos new_i->line_contents = NULL;
3962a6b7db3Sskrll }
3972a6b7db3Sskrll else
3982a6b7db3Sskrll {
39975f9f1baSchristos new_i = XNEW (list_info_type);
400b075ecf2Schristos new_i->line_contents = ps;
4012a6b7db3Sskrll }
4022a6b7db3Sskrll
4032a6b7db3Sskrll last_line = line;
4042a6b7db3Sskrll last_file = file;
4052a6b7db3Sskrll
4062a6b7db3Sskrll new_frag ();
4072a6b7db3Sskrll
4082a6b7db3Sskrll if (listing_tail)
409b075ecf2Schristos listing_tail->next = new_i;
4102a6b7db3Sskrll else
411b075ecf2Schristos head = new_i;
4122a6b7db3Sskrll
413b075ecf2Schristos listing_tail = new_i;
4142a6b7db3Sskrll
415b075ecf2Schristos new_i->frag = frag_now;
416b075ecf2Schristos new_i->line = line;
417b075ecf2Schristos new_i->file = file_info (file);
418b075ecf2Schristos new_i->next = (list_info_type *) NULL;
41905caefcfSchristos new_i->messages = NULL;
42005caefcfSchristos new_i->last_message = NULL;
421b075ecf2Schristos new_i->edict = EDICT_NONE;
422b075ecf2Schristos new_i->hll_file = (file_info_type *) NULL;
423b075ecf2Schristos new_i->hll_line = 0;
424b075ecf2Schristos new_i->debugging = 0;
4252a6b7db3Sskrll
4262a6b7db3Sskrll new_frag ();
4272a6b7db3Sskrll
4282a6b7db3Sskrll #ifdef OBJ_ELF
4292a6b7db3Sskrll /* In ELF, anything in a section beginning with .debug or .line is
4302a6b7db3Sskrll considered to be debugging information. */
4312a6b7db3Sskrll if ((listing & LISTING_NODEBUG) != 0)
4322a6b7db3Sskrll {
4332a6b7db3Sskrll const char *segname;
4342a6b7db3Sskrll
4352a6b7db3Sskrll segname = segment_name (now_seg);
436*f22f0ef4Schristos if (startswith (segname, ".debug")
437*f22f0ef4Schristos || startswith (segname, ".line"))
438b075ecf2Schristos new_i->debugging = 1;
4392a6b7db3Sskrll }
4402a6b7db3Sskrll #endif
4412a6b7db3Sskrll }
4422a6b7db3Sskrll
4432a6b7db3Sskrll /* Attach all current frags to the previous line instead of the
4442a6b7db3Sskrll current line. This is called by the MIPS backend when it discovers
4452a6b7db3Sskrll that it needs to add some NOP instructions; the added NOP
4462a6b7db3Sskrll instructions should go with the instruction that has the delay, not
4472a6b7db3Sskrll with the new instruction. */
4482a6b7db3Sskrll
4492a6b7db3Sskrll void
listing_prev_line(void)4502a6b7db3Sskrll listing_prev_line (void)
4512a6b7db3Sskrll {
4522a6b7db3Sskrll list_info_type *l;
4532a6b7db3Sskrll fragS *f;
4542a6b7db3Sskrll
4552a6b7db3Sskrll if (head == (list_info_type *) NULL
4562a6b7db3Sskrll || head == listing_tail)
4572a6b7db3Sskrll return;
4582a6b7db3Sskrll
4592a6b7db3Sskrll new_frag ();
4602a6b7db3Sskrll
4612a6b7db3Sskrll for (l = head; l->next != listing_tail; l = l->next)
4622a6b7db3Sskrll ;
4632a6b7db3Sskrll
4642a6b7db3Sskrll for (f = frchain_now->frch_root; f != (fragS *) NULL; f = f->fr_next)
4652a6b7db3Sskrll if (f->line == listing_tail)
4662a6b7db3Sskrll f->line = l;
4672a6b7db3Sskrll
4682a6b7db3Sskrll listing_tail->frag = frag_now;
4692a6b7db3Sskrll new_frag ();
4702a6b7db3Sskrll }
4712a6b7db3Sskrll
4722a6b7db3Sskrll /* This function returns the next source line from the file supplied,
4732a6b7db3Sskrll truncated to size. It appends a fake line to the end of each input
474b075ecf2Schristos file to make using the returned buffer simpler. */
4752a6b7db3Sskrll
47675f9f1baSchristos static const char *
buffer_line(file_info_type * file,char * line,unsigned int size)4772a6b7db3Sskrll buffer_line (file_info_type *file, char *line, unsigned int size)
4782a6b7db3Sskrll {
4792a6b7db3Sskrll unsigned int count = 0;
4802a6b7db3Sskrll int c;
4812a6b7db3Sskrll char *p = line;
4822a6b7db3Sskrll
4832a6b7db3Sskrll /* If we couldn't open the file, return an empty line. */
4842a6b7db3Sskrll if (file->at_end)
4852a6b7db3Sskrll return "";
4862a6b7db3Sskrll
4872a6b7db3Sskrll /* Check the cache and see if we last used this file. */
4882a6b7db3Sskrll if (!last_open_file_info || file != last_open_file_info)
4892a6b7db3Sskrll {
4902a6b7db3Sskrll if (last_open_file)
4912a6b7db3Sskrll {
4922a6b7db3Sskrll last_open_file_info->pos = ftell (last_open_file);
4932a6b7db3Sskrll fclose (last_open_file);
4942a6b7db3Sskrll }
4952a6b7db3Sskrll
496b075ecf2Schristos /* Open the file in the binary mode so that ftell above can
497b075ecf2Schristos return a reliable value that we can feed to fseek below. */
4982a6b7db3Sskrll last_open_file_info = file;
499b075ecf2Schristos last_open_file = fopen (file->filename, FOPEN_RB);
5002a6b7db3Sskrll if (last_open_file == NULL)
5012a6b7db3Sskrll {
5022a6b7db3Sskrll file->at_end = 1;
5032a6b7db3Sskrll return "";
5042a6b7db3Sskrll }
5052a6b7db3Sskrll
5062a6b7db3Sskrll /* Seek to where we were last time this file was open. */
5072a6b7db3Sskrll if (file->pos)
5082a6b7db3Sskrll fseek (last_open_file, file->pos, SEEK_SET);
5092a6b7db3Sskrll }
5102a6b7db3Sskrll
511b075ecf2Schristos c = fgetc (last_open_file);
512b075ecf2Schristos
513b075ecf2Schristos while (c != EOF && c != '\n' && c != '\r')
5142a6b7db3Sskrll {
515*f22f0ef4Schristos if (++count < size)
5162a6b7db3Sskrll *p++ = c;
5172a6b7db3Sskrll c = fgetc (last_open_file);
5182a6b7db3Sskrll }
519b075ecf2Schristos
520b075ecf2Schristos /* If '\r' is followed by '\n', swallow that. Likewise, if '\n'
521b075ecf2Schristos is followed by '\r', swallow that as well. */
522b075ecf2Schristos if (c == '\r' || c == '\n')
523b075ecf2Schristos {
524b075ecf2Schristos int next = fgetc (last_open_file);
525b075ecf2Schristos
526b075ecf2Schristos if ((c == '\r' && next != '\n')
527b075ecf2Schristos || (c == '\n' && next != '\r'))
528b075ecf2Schristos ungetc (next, last_open_file);
529b075ecf2Schristos }
530b075ecf2Schristos
5312a6b7db3Sskrll if (c == EOF)
5322a6b7db3Sskrll {
5332a6b7db3Sskrll file->at_end = 1;
534*f22f0ef4Schristos if (count + 3 < size)
5352a6b7db3Sskrll {
5362a6b7db3Sskrll *p++ = '.';
5372a6b7db3Sskrll *p++ = '.';
5382a6b7db3Sskrll *p++ = '.';
5392a6b7db3Sskrll }
5402a6b7db3Sskrll }
5412a6b7db3Sskrll file->linenum++;
5422a6b7db3Sskrll *p++ = 0;
5432a6b7db3Sskrll return line;
5442a6b7db3Sskrll }
5452a6b7db3Sskrll
546b075ecf2Schristos
547b075ecf2Schristos /* This function rewinds the requested file back to the line requested,
548b075ecf2Schristos reads it in again into the buffer provided and then restores the file
54975f9f1baSchristos back to its original location. */
550b075ecf2Schristos
55175f9f1baSchristos static void
rebuffer_line(file_info_type * file,unsigned int linenum,char * buffer,unsigned int size)552b075ecf2Schristos rebuffer_line (file_info_type * file,
553b075ecf2Schristos unsigned int linenum,
554b075ecf2Schristos char * buffer,
555b075ecf2Schristos unsigned int size)
556b075ecf2Schristos {
557b075ecf2Schristos unsigned int count = 0;
5585ba6b03cSchristos unsigned int current_line;
559b075ecf2Schristos char * p = buffer;
560b075ecf2Schristos long pos;
5615ba6b03cSchristos long pos2;
562b075ecf2Schristos int c;
563*f22f0ef4Schristos bool found = false;
564b075ecf2Schristos
565b075ecf2Schristos /* Sanity checks. */
5665ba6b03cSchristos if (file == NULL || buffer == NULL || size <= 1 || file->linenum <= linenum)
56775f9f1baSchristos return;
568b075ecf2Schristos
569b075ecf2Schristos /* Check the cache and see if we last used this file. */
570b075ecf2Schristos if (last_open_file_info == NULL || file != last_open_file_info)
571b075ecf2Schristos {
572b075ecf2Schristos if (last_open_file)
573b075ecf2Schristos {
574b075ecf2Schristos last_open_file_info->pos = ftell (last_open_file);
575b075ecf2Schristos fclose (last_open_file);
576b075ecf2Schristos }
577b075ecf2Schristos
578b075ecf2Schristos /* Open the file in the binary mode so that ftell above can
579b075ecf2Schristos return a reliable value that we can feed to fseek below. */
580b075ecf2Schristos last_open_file_info = file;
581b075ecf2Schristos last_open_file = fopen (file->filename, FOPEN_RB);
582b075ecf2Schristos if (last_open_file == NULL)
583b075ecf2Schristos {
584b075ecf2Schristos file->at_end = 1;
58575f9f1baSchristos return;
586b075ecf2Schristos }
587b075ecf2Schristos
588b075ecf2Schristos /* Seek to where we were last time this file was open. */
589b075ecf2Schristos if (file->pos)
590b075ecf2Schristos fseek (last_open_file, file->pos, SEEK_SET);
591b075ecf2Schristos }
592b075ecf2Schristos
593b075ecf2Schristos /* Remember where we are in the current file. */
5945ba6b03cSchristos pos2 = pos = ftell (last_open_file);
5955ba6b03cSchristos if (pos < 3)
59675f9f1baSchristos return;
5975ba6b03cSchristos current_line = file->linenum;
598b075ecf2Schristos
599b075ecf2Schristos /* Leave room for the nul at the end of the buffer. */
600b075ecf2Schristos size -= 1;
6015ba6b03cSchristos buffer[size] = 0;
6025ba6b03cSchristos
6035ba6b03cSchristos /* Increment the current line count by one.
6045ba6b03cSchristos This is to allow for the fact that we are searching for the
6055ba6b03cSchristos start of a previous line, but we do this by detecting end-of-line
6065ba6b03cSchristos character(s) not start-of-line characters. */
6075ba6b03cSchristos ++ current_line;
6085ba6b03cSchristos
6095ba6b03cSchristos while (pos2 > 0 && ! found)
6105ba6b03cSchristos {
6115ba6b03cSchristos char * ptr;
6125ba6b03cSchristos
6135ba6b03cSchristos /* Move backwards through the file, looking for earlier lines. */
6145ba6b03cSchristos pos2 = (long) size > pos2 ? 0 : pos2 - size;
6155ba6b03cSchristos fseek (last_open_file, pos2, SEEK_SET);
6165ba6b03cSchristos
6175ba6b03cSchristos /* Our caller has kindly provided us with a buffer, so we use it. */
6185ba6b03cSchristos if (fread (buffer, 1, size, last_open_file) != size)
6195ba6b03cSchristos {
6205ba6b03cSchristos as_warn (_("unable to rebuffer file: %s\n"), file->filename);
62175f9f1baSchristos return;
6225ba6b03cSchristos }
6235ba6b03cSchristos
6245ba6b03cSchristos for (ptr = buffer + size; ptr >= buffer; -- ptr)
6255ba6b03cSchristos {
6265ba6b03cSchristos if (*ptr == '\n')
6275ba6b03cSchristos {
6285ba6b03cSchristos -- current_line;
6295ba6b03cSchristos
6305ba6b03cSchristos if (current_line == linenum)
6315ba6b03cSchristos {
6325ba6b03cSchristos /* We have found the start of the line we seek. */
633*f22f0ef4Schristos found = true;
6345ba6b03cSchristos
6355ba6b03cSchristos /* FIXME: We could skip the read-in-the-line code
6365ba6b03cSchristos below if we know that we already have the whole
6375ba6b03cSchristos line in the buffer. */
6385ba6b03cSchristos
6395ba6b03cSchristos /* Advance pos2 to the newline character we have just located. */
6405ba6b03cSchristos pos2 += (ptr - buffer);
6415ba6b03cSchristos
6425ba6b03cSchristos /* Skip the newline and, if present, the carriage return. */
6435ba6b03cSchristos if (ptr + 1 == buffer + size)
6445ba6b03cSchristos {
6455ba6b03cSchristos ++pos2;
6465ba6b03cSchristos if (fgetc (last_open_file) == '\r')
6475ba6b03cSchristos ++ pos2;
6485ba6b03cSchristos }
6495ba6b03cSchristos else
6505ba6b03cSchristos pos2 += (ptr[1] == '\r' ? 2 : 1);
6515ba6b03cSchristos
6525ba6b03cSchristos /* Move the file pointer to this location. */
6535ba6b03cSchristos fseek (last_open_file, pos2, SEEK_SET);
6545ba6b03cSchristos break;
6555ba6b03cSchristos }
6565ba6b03cSchristos }
6575ba6b03cSchristos }
6585ba6b03cSchristos }
659b075ecf2Schristos
660b075ecf2Schristos /* Read in the line. */
661b075ecf2Schristos c = fgetc (last_open_file);
662b075ecf2Schristos
663b075ecf2Schristos while (c != EOF && c != '\n' && c != '\r')
664b075ecf2Schristos {
665b075ecf2Schristos if (count < size)
666b075ecf2Schristos *p++ = c;
667b075ecf2Schristos count++;
668b075ecf2Schristos
669b075ecf2Schristos c = fgetc (last_open_file);
670b075ecf2Schristos }
671b075ecf2Schristos
672b075ecf2Schristos /* If '\r' is followed by '\n', swallow that. Likewise, if '\n'
673b075ecf2Schristos is followed by '\r', swallow that as well. */
674b075ecf2Schristos if (c == '\r' || c == '\n')
675b075ecf2Schristos {
676b075ecf2Schristos int next = fgetc (last_open_file);
677b075ecf2Schristos
678b075ecf2Schristos if ((c == '\r' && next != '\n')
679b075ecf2Schristos || (c == '\n' && next != '\r'))
680b075ecf2Schristos ungetc (next, last_open_file);
681b075ecf2Schristos }
682b075ecf2Schristos
683b075ecf2Schristos /* Terminate the line. */
684b075ecf2Schristos *p++ = 0;
685b075ecf2Schristos
686b075ecf2Schristos /* Reset the file position. */
687b075ecf2Schristos fseek (last_open_file, pos, SEEK_SET);
688b075ecf2Schristos }
689b075ecf2Schristos
6902a6b7db3Sskrll static const char *fn;
69175f9f1baSchristos static unsigned int eject; /* Eject pending. */
69275f9f1baSchristos static unsigned int page; /* Current page number. */
69375f9f1baSchristos static const char *title; /* Current title. */
69475f9f1baSchristos static const char *subtitle; /* Current subtitle. */
69575f9f1baSchristos static unsigned int on_page; /* Number of lines printed on current page. */
6962a6b7db3Sskrll
6972a6b7db3Sskrll static void
listing_page(list_info_type * list)6982a6b7db3Sskrll listing_page (list_info_type *list)
6992a6b7db3Sskrll {
7002a6b7db3Sskrll /* Grope around, see if we can see a title or subtitle edict coming up
7012a6b7db3Sskrll soon. (we look down 10 lines of the page and see if it's there) */
7022a6b7db3Sskrll if ((eject || (on_page >= (unsigned int) paper_height))
7032a6b7db3Sskrll && paper_height != 0)
7042a6b7db3Sskrll {
7052a6b7db3Sskrll unsigned int c = 10;
7062a6b7db3Sskrll int had_title = 0;
7072a6b7db3Sskrll int had_subtitle = 0;
7082a6b7db3Sskrll
7092a6b7db3Sskrll page++;
7102a6b7db3Sskrll
7112a6b7db3Sskrll while (c != 0 && list)
7122a6b7db3Sskrll {
7132a6b7db3Sskrll if (list->edict == EDICT_SBTTL && !had_subtitle)
7142a6b7db3Sskrll {
7152a6b7db3Sskrll had_subtitle = 1;
7162a6b7db3Sskrll subtitle = list->edict_arg;
7172a6b7db3Sskrll }
7182a6b7db3Sskrll if (list->edict == EDICT_TITLE && !had_title)
7192a6b7db3Sskrll {
7202a6b7db3Sskrll had_title = 1;
7212a6b7db3Sskrll title = list->edict_arg;
7222a6b7db3Sskrll }
7232a6b7db3Sskrll list = list->next;
7242a6b7db3Sskrll c--;
7252a6b7db3Sskrll }
7262a6b7db3Sskrll
7272a6b7db3Sskrll if (page > 1)
7282a6b7db3Sskrll {
7292a6b7db3Sskrll fprintf (list_file, "\f");
7302a6b7db3Sskrll }
7312a6b7db3Sskrll
7322a6b7db3Sskrll fprintf (list_file, "%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page);
7332a6b7db3Sskrll fprintf (list_file, "%s\n", title);
7342a6b7db3Sskrll fprintf (list_file, "%s\n", subtitle);
7352a6b7db3Sskrll on_page = 3;
7362a6b7db3Sskrll eject = 0;
7372a6b7db3Sskrll }
7382a6b7db3Sskrll }
7392a6b7db3Sskrll
740b075ecf2Schristos /* Print a line into the list_file. Update the line count
741b075ecf2Schristos and if necessary start a new page. */
742b075ecf2Schristos
743b075ecf2Schristos static void
emit_line(list_info_type * list,const char * format,...)744b075ecf2Schristos emit_line (list_info_type * list, const char * format, ...)
745b075ecf2Schristos {
746b075ecf2Schristos va_list args;
747b075ecf2Schristos
748b075ecf2Schristos va_start (args, format);
749b075ecf2Schristos
750b075ecf2Schristos vfprintf (list_file, format, args);
751b075ecf2Schristos on_page++;
752b075ecf2Schristos listing_page (list);
753b075ecf2Schristos
754b075ecf2Schristos va_end (args);
755b075ecf2Schristos }
756b075ecf2Schristos
7572a6b7db3Sskrll static unsigned int
calc_hex(list_info_type * list)7582a6b7db3Sskrll calc_hex (list_info_type *list)
7592a6b7db3Sskrll {
7602a6b7db3Sskrll int data_buffer_size;
7612a6b7db3Sskrll list_info_type *first = list;
7622a6b7db3Sskrll unsigned int address = ~(unsigned int) 0;
7632a6b7db3Sskrll fragS *frag;
7642a6b7db3Sskrll fragS *frag_ptr;
7652a6b7db3Sskrll unsigned int octet_in_frag;
7662a6b7db3Sskrll
7672a6b7db3Sskrll /* Find first frag which says it belongs to this line. */
7682a6b7db3Sskrll frag = list->frag;
7692a6b7db3Sskrll while (frag && frag->line != list)
7702a6b7db3Sskrll frag = frag->fr_next;
7712a6b7db3Sskrll
7722a6b7db3Sskrll frag_ptr = frag;
7732a6b7db3Sskrll
7742a6b7db3Sskrll data_buffer_size = 0;
7752a6b7db3Sskrll
7762a6b7db3Sskrll /* Dump all the frags which belong to this line. */
7772a6b7db3Sskrll while (frag_ptr != (fragS *) NULL && frag_ptr->line == first)
7782a6b7db3Sskrll {
7792a6b7db3Sskrll /* Print as many bytes from the fixed part as is sensible. */
7802a6b7db3Sskrll octet_in_frag = 0;
781f7172901Schristos while (octet_in_frag < frag_ptr->fr_fix
7822a6b7db3Sskrll && data_buffer_size < MAX_BYTES - 3)
7832a6b7db3Sskrll {
7842a6b7db3Sskrll if (address == ~(unsigned int) 0)
7852a6b7db3Sskrll address = frag_ptr->fr_address / OCTETS_PER_BYTE;
7862a6b7db3Sskrll
7872a6b7db3Sskrll sprintf (data_buffer + data_buffer_size,
7882a6b7db3Sskrll "%02X",
7892a6b7db3Sskrll (frag_ptr->fr_literal[octet_in_frag]) & 0xff);
7902a6b7db3Sskrll data_buffer_size += 2;
7912a6b7db3Sskrll octet_in_frag++;
7922a6b7db3Sskrll }
7932a6b7db3Sskrll if (frag_ptr->fr_type == rs_fill)
7942a6b7db3Sskrll {
7952a6b7db3Sskrll unsigned int var_rep_max = octet_in_frag;
7962a6b7db3Sskrll unsigned int var_rep_idx = octet_in_frag;
7972a6b7db3Sskrll
7982a6b7db3Sskrll /* Print as many bytes from the variable part as is sensible. */
799f7172901Schristos while ((octet_in_frag
800f7172901Schristos < frag_ptr->fr_fix + frag_ptr->fr_var * frag_ptr->fr_offset)
8012a6b7db3Sskrll && data_buffer_size < MAX_BYTES - 3)
8022a6b7db3Sskrll {
8032a6b7db3Sskrll if (address == ~(unsigned int) 0)
8042a6b7db3Sskrll address = frag_ptr->fr_address / OCTETS_PER_BYTE;
8052a6b7db3Sskrll
8062a6b7db3Sskrll sprintf (data_buffer + data_buffer_size,
8072a6b7db3Sskrll "%02X",
8082a6b7db3Sskrll (frag_ptr->fr_literal[var_rep_idx]) & 0xff);
8092a6b7db3Sskrll data_buffer_size += 2;
8102a6b7db3Sskrll
8112a6b7db3Sskrll var_rep_idx++;
8122a6b7db3Sskrll octet_in_frag++;
8132a6b7db3Sskrll
814f7172901Schristos if (var_rep_idx >= frag_ptr->fr_fix + frag_ptr->fr_var)
8152a6b7db3Sskrll var_rep_idx = var_rep_max;
8162a6b7db3Sskrll }
8172a6b7db3Sskrll }
8182a6b7db3Sskrll
8192a6b7db3Sskrll frag_ptr = frag_ptr->fr_next;
8202a6b7db3Sskrll }
8212a6b7db3Sskrll data_buffer[data_buffer_size] = '\0';
8222a6b7db3Sskrll return address;
8232a6b7db3Sskrll }
8242a6b7db3Sskrll
8252a6b7db3Sskrll static void
print_lines(list_info_type * list,unsigned int lineno,const char * string,unsigned int address)8262a6b7db3Sskrll print_lines (list_info_type *list, unsigned int lineno,
82775f9f1baSchristos const char *string, unsigned int address)
8282a6b7db3Sskrll {
8292a6b7db3Sskrll unsigned int idx;
8302a6b7db3Sskrll unsigned int nchars;
8312a6b7db3Sskrll unsigned int lines;
8322a6b7db3Sskrll unsigned int octet_in_word = 0;
8332a6b7db3Sskrll char *src = data_buffer;
8342a6b7db3Sskrll int cur;
83505caefcfSchristos struct list_message *msg;
8362a6b7db3Sskrll
8372a6b7db3Sskrll /* Print the stuff on the first line. */
8382a6b7db3Sskrll listing_page (list);
8392a6b7db3Sskrll nchars = (LISTING_WORD_SIZE * 2 + 1) * listing_lhs_width;
8402a6b7db3Sskrll
8412a6b7db3Sskrll /* Print the hex for the first line. */
8422a6b7db3Sskrll if (address == ~(unsigned int) 0)
8432a6b7db3Sskrll {
8442a6b7db3Sskrll fprintf (list_file, "% 4d ", lineno);
8452a6b7db3Sskrll for (idx = 0; idx < nchars; idx++)
8462a6b7db3Sskrll fprintf (list_file, " ");
8472a6b7db3Sskrll
848b075ecf2Schristos emit_line (NULL, "\t%s\n", string ? string : "");
8492a6b7db3Sskrll return;
8502a6b7db3Sskrll }
8512a6b7db3Sskrll
8522a6b7db3Sskrll if (had_errors ())
8532a6b7db3Sskrll fprintf (list_file, "% 4d ???? ", lineno);
8542a6b7db3Sskrll else
8552a6b7db3Sskrll fprintf (list_file, "% 4d %04x ", lineno, address);
8562a6b7db3Sskrll
8572a6b7db3Sskrll /* And the data to go along with it. */
8582a6b7db3Sskrll idx = 0;
8592a6b7db3Sskrll cur = 0;
8602a6b7db3Sskrll while (src[cur] && idx < nchars)
8612a6b7db3Sskrll {
8622a6b7db3Sskrll int offset;
8632a6b7db3Sskrll offset = cur;
8642a6b7db3Sskrll fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
8652a6b7db3Sskrll cur += 2;
8662a6b7db3Sskrll octet_in_word++;
8672a6b7db3Sskrll
8682a6b7db3Sskrll if (octet_in_word == LISTING_WORD_SIZE)
8692a6b7db3Sskrll {
8702a6b7db3Sskrll fprintf (list_file, " ");
8712a6b7db3Sskrll idx++;
8722a6b7db3Sskrll octet_in_word = 0;
8732a6b7db3Sskrll }
8742a6b7db3Sskrll
8752a6b7db3Sskrll idx += 2;
8762a6b7db3Sskrll }
8772a6b7db3Sskrll
8782a6b7db3Sskrll for (; idx < nchars; idx++)
8792a6b7db3Sskrll fprintf (list_file, " ");
8802a6b7db3Sskrll
881b075ecf2Schristos emit_line (list, "\t%s\n", string ? string : "");
8822a6b7db3Sskrll
88305caefcfSchristos for (msg = list->messages; msg; msg = msg->next)
88405caefcfSchristos emit_line (list, "**** %s\n", msg->message);
8852a6b7db3Sskrll
8862a6b7db3Sskrll for (lines = 0;
8872a6b7db3Sskrll lines < (unsigned int) listing_lhs_cont_lines
8882a6b7db3Sskrll && src[cur];
8892a6b7db3Sskrll lines++)
8902a6b7db3Sskrll {
8912a6b7db3Sskrll nchars = ((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second - 1;
8922a6b7db3Sskrll idx = 0;
8932a6b7db3Sskrll
8942a6b7db3Sskrll /* Print any more lines of data, but more compactly. */
8952a6b7db3Sskrll fprintf (list_file, "% 4d ", lineno);
8962a6b7db3Sskrll
8972a6b7db3Sskrll while (src[cur] && idx < nchars)
8982a6b7db3Sskrll {
8992a6b7db3Sskrll int offset;
9002a6b7db3Sskrll offset = cur;
9012a6b7db3Sskrll fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
9022a6b7db3Sskrll cur += 2;
9032a6b7db3Sskrll idx += 2;
9042a6b7db3Sskrll octet_in_word++;
9052a6b7db3Sskrll
9062a6b7db3Sskrll if (octet_in_word == LISTING_WORD_SIZE)
9072a6b7db3Sskrll {
9082a6b7db3Sskrll fprintf (list_file, " ");
9092a6b7db3Sskrll idx++;
9102a6b7db3Sskrll octet_in_word = 0;
9112a6b7db3Sskrll }
9122a6b7db3Sskrll }
9132a6b7db3Sskrll
914b075ecf2Schristos emit_line (list, "\n");
9152a6b7db3Sskrll }
9162a6b7db3Sskrll }
9172a6b7db3Sskrll
9182a6b7db3Sskrll static void
list_symbol_table(void)9192a6b7db3Sskrll list_symbol_table (void)
9202a6b7db3Sskrll {
9212a6b7db3Sskrll extern symbolS *symbol_rootP;
9222a6b7db3Sskrll int got_some = 0;
9232a6b7db3Sskrll
9242a6b7db3Sskrll symbolS *ptr;
9252a6b7db3Sskrll eject = 1;
926b075ecf2Schristos listing_page (NULL);
9272a6b7db3Sskrll
9282a6b7db3Sskrll for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
9292a6b7db3Sskrll {
9302a6b7db3Sskrll if (SEG_NORMAL (S_GET_SEGMENT (ptr))
9312a6b7db3Sskrll || S_GET_SEGMENT (ptr) == absolute_section)
9322a6b7db3Sskrll {
9332a6b7db3Sskrll /* Don't report section symbols. They are not interesting. */
9342a6b7db3Sskrll if (symbol_section_p (ptr))
9352a6b7db3Sskrll continue;
9362a6b7db3Sskrll
9372a6b7db3Sskrll if (S_GET_NAME (ptr))
9382a6b7db3Sskrll {
9392a6b7db3Sskrll char buf[30], fmt[8];
9402a6b7db3Sskrll valueT val = S_GET_VALUE (ptr);
9412a6b7db3Sskrll
9422a6b7db3Sskrll /* @@ Note that this is dependent on the compilation options,
9432a6b7db3Sskrll not solely on the target characteristics. */
9442a6b7db3Sskrll if (sizeof (val) == 4 && sizeof (int) == 4)
9452a6b7db3Sskrll sprintf (buf, "%08lx", (unsigned long) val);
9462a6b7db3Sskrll else if (sizeof (val) <= sizeof (unsigned long))
9472a6b7db3Sskrll {
9482a6b7db3Sskrll sprintf (fmt, "%%0%lulx",
9492a6b7db3Sskrll (unsigned long) (sizeof (val) * 2));
9502a6b7db3Sskrll sprintf (buf, fmt, (unsigned long) val);
9512a6b7db3Sskrll }
9522a6b7db3Sskrll #if defined (BFD64)
9532a6b7db3Sskrll else if (sizeof (val) > 4)
9542a6b7db3Sskrll sprintf_vma (buf, val);
9552a6b7db3Sskrll #endif
9562a6b7db3Sskrll else
9572a6b7db3Sskrll abort ();
9582a6b7db3Sskrll
9592a6b7db3Sskrll if (!got_some)
9602a6b7db3Sskrll {
9612a6b7db3Sskrll fprintf (list_file, "DEFINED SYMBOLS\n");
9622a6b7db3Sskrll on_page++;
9632a6b7db3Sskrll got_some = 1;
9642a6b7db3Sskrll }
9652a6b7db3Sskrll
9662a6b7db3Sskrll if (symbol_get_frag (ptr) && symbol_get_frag (ptr)->line)
9672a6b7db3Sskrll {
9682a6b7db3Sskrll fprintf (list_file, "%20s:%-5d %s:%s %s\n",
9692a6b7db3Sskrll symbol_get_frag (ptr)->line->file->filename,
9702a6b7db3Sskrll symbol_get_frag (ptr)->line->line,
9712a6b7db3Sskrll segment_name (S_GET_SEGMENT (ptr)),
9722a6b7db3Sskrll buf, S_GET_NAME (ptr));
9732a6b7db3Sskrll }
9742a6b7db3Sskrll else
9752a6b7db3Sskrll {
9762a6b7db3Sskrll fprintf (list_file, "%33s:%s %s\n",
9772a6b7db3Sskrll segment_name (S_GET_SEGMENT (ptr)),
9782a6b7db3Sskrll buf, S_GET_NAME (ptr));
9792a6b7db3Sskrll }
9802a6b7db3Sskrll
9812a6b7db3Sskrll on_page++;
982b075ecf2Schristos listing_page (NULL);
9832a6b7db3Sskrll }
9842a6b7db3Sskrll }
9852a6b7db3Sskrll
9862a6b7db3Sskrll }
9872a6b7db3Sskrll if (!got_some)
9882a6b7db3Sskrll {
9892a6b7db3Sskrll fprintf (list_file, "NO DEFINED SYMBOLS\n");
9902a6b7db3Sskrll on_page++;
9912a6b7db3Sskrll }
992b075ecf2Schristos emit_line (NULL, "\n");
9932a6b7db3Sskrll
9942a6b7db3Sskrll got_some = 0;
9952a6b7db3Sskrll
9962a6b7db3Sskrll for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
9972a6b7db3Sskrll {
9982a6b7db3Sskrll if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0)
9992a6b7db3Sskrll {
10002a6b7db3Sskrll if (S_GET_SEGMENT (ptr) == undefined_section)
10012a6b7db3Sskrll {
10022a6b7db3Sskrll if (!got_some)
10032a6b7db3Sskrll {
10042a6b7db3Sskrll got_some = 1;
1005b075ecf2Schristos
1006b075ecf2Schristos emit_line (NULL, "UNDEFINED SYMBOLS\n");
10072a6b7db3Sskrll }
1008b075ecf2Schristos
1009b075ecf2Schristos emit_line (NULL, "%s\n", S_GET_NAME (ptr));
10102a6b7db3Sskrll }
10112a6b7db3Sskrll }
10122a6b7db3Sskrll }
10132a6b7db3Sskrll
1014b075ecf2Schristos if (!got_some)
1015b075ecf2Schristos emit_line (NULL, "NO UNDEFINED SYMBOLS\n");
1016b075ecf2Schristos }
1017b075ecf2Schristos
1018b075ecf2Schristos typedef struct cached_line
10192a6b7db3Sskrll {
1020b075ecf2Schristos file_info_type * file;
1021b075ecf2Schristos unsigned int line;
1022b075ecf2Schristos char buffer [LISTING_RHS_WIDTH];
1023b075ecf2Schristos } cached_line;
1024b075ecf2Schristos
1025b075ecf2Schristos static void
print_source(file_info_type * current_file,list_info_type * list,unsigned int width)1026b075ecf2Schristos print_source (file_info_type * current_file,
1027b075ecf2Schristos list_info_type * list,
1028b075ecf2Schristos unsigned int width)
1029b075ecf2Schristos {
1030b075ecf2Schristos #define NUM_CACHE_LINES 3
1031b075ecf2Schristos static cached_line cached_lines[NUM_CACHE_LINES];
1032b075ecf2Schristos static int next_free_line = 0;
1033b075ecf2Schristos cached_line * cache = NULL;
1034b075ecf2Schristos
1035b075ecf2Schristos if (current_file->linenum > list->hll_line
1036b075ecf2Schristos && list->hll_line > 0)
1037b075ecf2Schristos {
1038b075ecf2Schristos /* This can happen with modern optimizing compilers. The source
1039b075ecf2Schristos lines from the high level language input program are split up
1040b075ecf2Schristos and interleaved, meaning the line number we want to display
1041b075ecf2Schristos (list->hll_line) can have already been displayed. We have
1042b075ecf2Schristos three choices:
1043b075ecf2Schristos
1044b075ecf2Schristos a. Do nothing, since we have already displayed the source
1045b075ecf2Schristos line. This was the old behaviour.
1046b075ecf2Schristos
1047b075ecf2Schristos b. Display the particular line requested again, but only
1048b075ecf2Schristos that line. This is the new behaviour.
1049b075ecf2Schristos
1050b075ecf2Schristos c. Display the particular line requested again and reset
1051b075ecf2Schristos the current_file->line_num value so that we redisplay
1052b075ecf2Schristos all the following lines as well the next time we
1053b075ecf2Schristos encounter a larger line number. */
1054b075ecf2Schristos int i;
1055b075ecf2Schristos
1056b075ecf2Schristos /* Check the cache, maybe we already have the line saved. */
1057b075ecf2Schristos for (i = 0; i < NUM_CACHE_LINES; i++)
1058b075ecf2Schristos if (cached_lines[i].file == current_file
1059b075ecf2Schristos && cached_lines[i].line == list->hll_line)
1060b075ecf2Schristos {
1061b075ecf2Schristos cache = cached_lines + i;
1062b075ecf2Schristos break;
1063b075ecf2Schristos }
1064b075ecf2Schristos
1065b075ecf2Schristos if (i == NUM_CACHE_LINES)
1066b075ecf2Schristos {
1067b075ecf2Schristos cache = cached_lines + next_free_line;
1068b075ecf2Schristos next_free_line ++;
1069b075ecf2Schristos if (next_free_line == NUM_CACHE_LINES)
1070b075ecf2Schristos next_free_line = 0;
1071b075ecf2Schristos
1072b075ecf2Schristos cache->file = current_file;
1073b075ecf2Schristos cache->line = list->hll_line;
1074b075ecf2Schristos cache->buffer[0] = 0;
1075b075ecf2Schristos rebuffer_line (current_file, cache->line, cache->buffer, width);
1076b075ecf2Schristos }
1077b075ecf2Schristos
1078b075ecf2Schristos emit_line (list, "%4u:%-13s **** %s\n",
1079b075ecf2Schristos cache->line, cache->file->filename, cache->buffer);
1080b075ecf2Schristos return;
1081b075ecf2Schristos }
1082b075ecf2Schristos
10832a6b7db3Sskrll if (!current_file->at_end)
10842a6b7db3Sskrll {
1085b075ecf2Schristos int num_lines_shown = 0;
1086b075ecf2Schristos
10872a6b7db3Sskrll while (current_file->linenum < list->hll_line
10882a6b7db3Sskrll && !current_file->at_end)
10892a6b7db3Sskrll {
109075f9f1baSchristos const char *p;
10912a6b7db3Sskrll
1092b075ecf2Schristos cache = cached_lines + next_free_line;
1093b075ecf2Schristos cache->file = current_file;
1094b075ecf2Schristos cache->line = current_file->linenum + 1;
1095b075ecf2Schristos cache->buffer[0] = 0;
1096b075ecf2Schristos p = buffer_line (current_file, cache->buffer, width);
1097b075ecf2Schristos
1098b075ecf2Schristos /* Cache optimization: If printing a group of lines
1099b075ecf2Schristos cache the first and last lines in the group. */
1100b075ecf2Schristos if (num_lines_shown == 0)
1101b075ecf2Schristos {
1102b075ecf2Schristos next_free_line ++;
1103b075ecf2Schristos if (next_free_line == NUM_CACHE_LINES)
1104b075ecf2Schristos next_free_line = 0;
1105b075ecf2Schristos }
1106b075ecf2Schristos
1107b075ecf2Schristos emit_line (list, "%4u:%-13s **** %s\n",
1108b075ecf2Schristos cache->line, cache->file->filename, p);
1109b075ecf2Schristos num_lines_shown ++;
11102a6b7db3Sskrll }
11112a6b7db3Sskrll }
11122a6b7db3Sskrll }
11132a6b7db3Sskrll
11142a6b7db3Sskrll /* Sometimes the user doesn't want to be bothered by the debugging
11152a6b7db3Sskrll records inserted by the compiler, see if the line is suspicious. */
11162a6b7db3Sskrll
11172a6b7db3Sskrll static int
debugging_pseudo(list_info_type * list,const char * line)11182a6b7db3Sskrll debugging_pseudo (list_info_type *list, const char *line)
11192a6b7db3Sskrll {
1120b075ecf2Schristos #ifdef OBJ_ELF
11212a6b7db3Sskrll static int in_debug;
11222a6b7db3Sskrll int was_debug;
1123b075ecf2Schristos #endif
11242a6b7db3Sskrll
11252a6b7db3Sskrll if (list->debugging)
11262a6b7db3Sskrll {
1127b075ecf2Schristos #ifdef OBJ_ELF
11282a6b7db3Sskrll in_debug = 1;
1129b075ecf2Schristos #endif
11302a6b7db3Sskrll return 1;
11312a6b7db3Sskrll }
1132b075ecf2Schristos #ifdef OBJ_ELF
11332a6b7db3Sskrll was_debug = in_debug;
11342a6b7db3Sskrll in_debug = 0;
1135b075ecf2Schristos #endif
11362a6b7db3Sskrll
11372a6b7db3Sskrll while (ISSPACE (*line))
11382a6b7db3Sskrll line++;
11392a6b7db3Sskrll
11402a6b7db3Sskrll if (*line != '.')
11412a6b7db3Sskrll {
11422a6b7db3Sskrll #ifdef OBJ_ELF
11432a6b7db3Sskrll /* The ELF compiler sometimes emits blank lines after switching
11442a6b7db3Sskrll out of a debugging section. If the next line drops us back
11452a6b7db3Sskrll into debugging information, then don't print the blank line.
11462a6b7db3Sskrll This is a hack for a particular compiler behaviour, not a
11472a6b7db3Sskrll general case. */
11482a6b7db3Sskrll if (was_debug
11492a6b7db3Sskrll && *line == '\0'
11502a6b7db3Sskrll && list->next != NULL
11512a6b7db3Sskrll && list->next->debugging)
11522a6b7db3Sskrll {
11532a6b7db3Sskrll in_debug = 1;
11542a6b7db3Sskrll return 1;
11552a6b7db3Sskrll }
11562a6b7db3Sskrll #endif
11572a6b7db3Sskrll
11582a6b7db3Sskrll return 0;
11592a6b7db3Sskrll }
11602a6b7db3Sskrll
11612a6b7db3Sskrll line++;
11622a6b7db3Sskrll
1163*f22f0ef4Schristos if (startswith (line, "def"))
11642a6b7db3Sskrll return 1;
1165*f22f0ef4Schristos if (startswith (line, "val"))
11662a6b7db3Sskrll return 1;
1167*f22f0ef4Schristos if (startswith (line, "scl"))
11682a6b7db3Sskrll return 1;
1169*f22f0ef4Schristos if (startswith (line, "line"))
11702a6b7db3Sskrll return 1;
1171*f22f0ef4Schristos if (startswith (line, "endef"))
11722a6b7db3Sskrll return 1;
1173*f22f0ef4Schristos if (startswith (line, "ln"))
11742a6b7db3Sskrll return 1;
1175*f22f0ef4Schristos if (startswith (line, "type"))
11762a6b7db3Sskrll return 1;
1177*f22f0ef4Schristos if (startswith (line, "size"))
11782a6b7db3Sskrll return 1;
1179*f22f0ef4Schristos if (startswith (line, "dim"))
11802a6b7db3Sskrll return 1;
1181*f22f0ef4Schristos if (startswith (line, "tag"))
11822a6b7db3Sskrll return 1;
1183*f22f0ef4Schristos if (startswith (line, "stabs"))
11842a6b7db3Sskrll return 1;
1185*f22f0ef4Schristos if (startswith (line, "stabn"))
11862a6b7db3Sskrll return 1;
11872a6b7db3Sskrll
11882a6b7db3Sskrll return 0;
11892a6b7db3Sskrll }
11902a6b7db3Sskrll
11912a6b7db3Sskrll static void
listing_listing(char * name ATTRIBUTE_UNUSED)11922a6b7db3Sskrll listing_listing (char *name ATTRIBUTE_UNUSED)
11932a6b7db3Sskrll {
11942a6b7db3Sskrll list_info_type *list = head;
11952a6b7db3Sskrll file_info_type *current_hll_file = (file_info_type *) NULL;
11962a6b7db3Sskrll char *buffer;
119775f9f1baSchristos const char *p;
11982a6b7db3Sskrll int show_listing = 1;
11992a6b7db3Sskrll unsigned int width;
12002a6b7db3Sskrll
120175f9f1baSchristos buffer = XNEWVEC (char, listing_rhs_width);
120275f9f1baSchristos data_buffer = XNEWVEC (char, MAX_BYTES);
12032a6b7db3Sskrll eject = 1;
12042a6b7db3Sskrll list = head->next;
12052a6b7db3Sskrll
12062a6b7db3Sskrll while (list)
12072a6b7db3Sskrll {
12082a6b7db3Sskrll unsigned int list_line;
12092a6b7db3Sskrll
12102a6b7db3Sskrll width = listing_rhs_width > paper_width ? paper_width :
12112a6b7db3Sskrll listing_rhs_width;
12122a6b7db3Sskrll
12132a6b7db3Sskrll list_line = list->line;
12142a6b7db3Sskrll switch (list->edict)
12152a6b7db3Sskrll {
12162a6b7db3Sskrll case EDICT_LIST:
12172a6b7db3Sskrll /* Skip all lines up to the current. */
12182a6b7db3Sskrll list_line--;
12192a6b7db3Sskrll break;
12202a6b7db3Sskrll case EDICT_NOLIST:
12212a6b7db3Sskrll show_listing--;
12222a6b7db3Sskrll break;
12232a6b7db3Sskrll case EDICT_NOLIST_NEXT:
12242a6b7db3Sskrll if (show_listing == 0)
12252a6b7db3Sskrll list_line--;
12262a6b7db3Sskrll break;
12272a6b7db3Sskrll case EDICT_EJECT:
12282a6b7db3Sskrll break;
12292a6b7db3Sskrll case EDICT_NONE:
12302a6b7db3Sskrll break;
12312a6b7db3Sskrll case EDICT_TITLE:
12322a6b7db3Sskrll title = list->edict_arg;
12332a6b7db3Sskrll break;
12342a6b7db3Sskrll case EDICT_SBTTL:
12352a6b7db3Sskrll subtitle = list->edict_arg;
12362a6b7db3Sskrll break;
12372a6b7db3Sskrll default:
12382a6b7db3Sskrll abort ();
12392a6b7db3Sskrll }
12402a6b7db3Sskrll
12412a6b7db3Sskrll if (show_listing <= 0)
12422a6b7db3Sskrll {
12432a6b7db3Sskrll while (list->file->linenum < list_line
12442a6b7db3Sskrll && !list->file->at_end)
12452a6b7db3Sskrll p = buffer_line (list->file, buffer, width);
12462a6b7db3Sskrll }
12472a6b7db3Sskrll
12482a6b7db3Sskrll if (list->edict == EDICT_LIST
12492a6b7db3Sskrll || (list->edict == EDICT_NOLIST_NEXT && show_listing == 0))
12502a6b7db3Sskrll {
12512a6b7db3Sskrll /* Enable listing for the single line that caused the enable. */
12522a6b7db3Sskrll list_line++;
12532a6b7db3Sskrll show_listing++;
12542a6b7db3Sskrll }
12552a6b7db3Sskrll
12562a6b7db3Sskrll if (show_listing > 0)
12572a6b7db3Sskrll {
12582a6b7db3Sskrll /* Scan down the list and print all the stuff which can be done
12592a6b7db3Sskrll with this line (or lines). */
12602a6b7db3Sskrll if (list->hll_file)
12612a6b7db3Sskrll current_hll_file = list->hll_file;
12622a6b7db3Sskrll
12632a6b7db3Sskrll if (current_hll_file && list->hll_line && (listing & LISTING_HLL))
1264b075ecf2Schristos print_source (current_hll_file, list, width);
12652a6b7db3Sskrll
12662a6b7db3Sskrll if (list->line_contents)
12672a6b7db3Sskrll {
12682a6b7db3Sskrll if (!((listing & LISTING_NODEBUG)
12692a6b7db3Sskrll && debugging_pseudo (list, list->line_contents)))
12702a6b7db3Sskrll print_lines (list,
12712a6b7db3Sskrll list->file->linenum == 0 ? list->line : list->file->linenum,
12722a6b7db3Sskrll list->line_contents, calc_hex (list));
12732a6b7db3Sskrll
12742a6b7db3Sskrll free (list->line_contents);
12752a6b7db3Sskrll list->line_contents = NULL;
12762a6b7db3Sskrll }
12772a6b7db3Sskrll else
12782a6b7db3Sskrll {
12792a6b7db3Sskrll while (list->file->linenum < list_line
12802a6b7db3Sskrll && !list->file->at_end)
12812a6b7db3Sskrll {
12822a6b7db3Sskrll unsigned int address;
12832a6b7db3Sskrll
12842a6b7db3Sskrll p = buffer_line (list->file, buffer, width);
12852a6b7db3Sskrll
12862a6b7db3Sskrll if (list->file->linenum < list_line)
12872a6b7db3Sskrll address = ~(unsigned int) 0;
12882a6b7db3Sskrll else
12892a6b7db3Sskrll address = calc_hex (list);
12902a6b7db3Sskrll
12912a6b7db3Sskrll if (!((listing & LISTING_NODEBUG)
12922a6b7db3Sskrll && debugging_pseudo (list, p)))
12932a6b7db3Sskrll print_lines (list, list->file->linenum, p, address);
12942a6b7db3Sskrll }
12952a6b7db3Sskrll }
12962a6b7db3Sskrll
12972a6b7db3Sskrll if (list->edict == EDICT_EJECT)
12982a6b7db3Sskrll eject = 1;
12992a6b7db3Sskrll }
13002a6b7db3Sskrll
13012a6b7db3Sskrll if (list->edict == EDICT_NOLIST_NEXT && show_listing == 1)
13022a6b7db3Sskrll --show_listing;
13032a6b7db3Sskrll
13042a6b7db3Sskrll list = list->next;
13052a6b7db3Sskrll }
13062a6b7db3Sskrll
13072a6b7db3Sskrll free (buffer);
13082a6b7db3Sskrll free (data_buffer);
13092a6b7db3Sskrll data_buffer = NULL;
13102a6b7db3Sskrll }
13112a6b7db3Sskrll
13122a6b7db3Sskrll /* Print time stamp in ISO format: yyyy-mm-ddThh:mm:ss.ss+/-zzzz. */
13132a6b7db3Sskrll
13142a6b7db3Sskrll static void
print_timestamp(void)13152a6b7db3Sskrll print_timestamp (void)
13162a6b7db3Sskrll {
13172a6b7db3Sskrll const time_t now = time (NULL);
13182a6b7db3Sskrll struct tm * timestamp;
13192a6b7db3Sskrll char stampstr[MAX_DATELEN];
13202a6b7db3Sskrll
13212a6b7db3Sskrll /* Any portable way to obtain subsecond values??? */
13222a6b7db3Sskrll timestamp = localtime (&now);
13232a6b7db3Sskrll strftime (stampstr, MAX_DATELEN, "%Y-%m-%dT%H:%M:%S.000%z", timestamp);
13242a6b7db3Sskrll fprintf (list_file, _("\n time stamp \t: %s\n\n"), stampstr);
13252a6b7db3Sskrll }
13262a6b7db3Sskrll
13272a6b7db3Sskrll static void
print_single_option(char * opt,int * pos)13282a6b7db3Sskrll print_single_option (char * opt, int *pos)
13292a6b7db3Sskrll {
13302a6b7db3Sskrll int opt_len = strlen (opt);
13312a6b7db3Sskrll
13322a6b7db3Sskrll if ((*pos + opt_len) < paper_width)
13332a6b7db3Sskrll {
13342a6b7db3Sskrll fprintf (list_file, _("%s "), opt);
13352a6b7db3Sskrll *pos = *pos + opt_len;
13362a6b7db3Sskrll }
13372a6b7db3Sskrll else
13382a6b7db3Sskrll {
13392a6b7db3Sskrll fprintf (list_file, _("\n\t%s "), opt);
13402a6b7db3Sskrll *pos = opt_len;
13412a6b7db3Sskrll }
13422a6b7db3Sskrll }
13432a6b7db3Sskrll
13442a6b7db3Sskrll /* Print options passed to as. */
13452a6b7db3Sskrll
13462a6b7db3Sskrll static void
print_options(char ** argv)13472a6b7db3Sskrll print_options (char ** argv)
13482a6b7db3Sskrll {
13492a6b7db3Sskrll const char *field_name = _("\n options passed\t: ");
13502a6b7db3Sskrll int pos = strlen (field_name);
13512a6b7db3Sskrll char **p;
13522a6b7db3Sskrll
13532a6b7db3Sskrll fputs (field_name, list_file);
13542a6b7db3Sskrll for (p = &argv[1]; *p != NULL; p++)
13552a6b7db3Sskrll if (**p == '-')
13562a6b7db3Sskrll {
13572a6b7db3Sskrll /* Ignore these. */
13582a6b7db3Sskrll if (strcmp (*p, "-o") == 0)
13592a6b7db3Sskrll {
13602a6b7db3Sskrll if (p[1] != NULL)
13612a6b7db3Sskrll p++;
13622a6b7db3Sskrll continue;
13632a6b7db3Sskrll }
13642a6b7db3Sskrll if (strcmp (*p, "-v") == 0)
13652a6b7db3Sskrll continue;
13662a6b7db3Sskrll
13672a6b7db3Sskrll print_single_option (*p, &pos);
13682a6b7db3Sskrll }
13692a6b7db3Sskrll }
13702a6b7db3Sskrll
13712a6b7db3Sskrll /* Print a first section with basic info like file names, as version,
13722a6b7db3Sskrll options passed, target, and timestamp.
13732a6b7db3Sskrll The format of this section is as follows:
13742a6b7db3Sskrll
13752a6b7db3Sskrll AS VERSION
13762a6b7db3Sskrll
13772a6b7db3Sskrll fieldname TAB ':' fieldcontents
13782a6b7db3Sskrll { TAB fieldcontents-cont } */
13792a6b7db3Sskrll
13802a6b7db3Sskrll static void
listing_general_info(char ** argv)13812a6b7db3Sskrll listing_general_info (char ** argv)
13822a6b7db3Sskrll {
13832a6b7db3Sskrll /* Print the stuff on the first line. */
13842a6b7db3Sskrll eject = 1;
1385b075ecf2Schristos listing_page (NULL);
13862a6b7db3Sskrll
13872a6b7db3Sskrll fprintf (list_file,
13882a6b7db3Sskrll _(" GNU assembler version %s (%s)\n\t using BFD version %s."),
13892a6b7db3Sskrll VERSION, TARGET_ALIAS, BFD_VERSION_STRING);
13902a6b7db3Sskrll print_options (argv);
13912a6b7db3Sskrll fprintf (list_file, _("\n input file \t: %s"), fn);
13922a6b7db3Sskrll fprintf (list_file, _("\n output file \t: %s"), out_file_name);
13932a6b7db3Sskrll fprintf (list_file, _("\n target \t: %s"), TARGET_CANONICAL);
13942a6b7db3Sskrll print_timestamp ();
13952a6b7db3Sskrll }
13962a6b7db3Sskrll
13972a6b7db3Sskrll void
listing_print(char * name,char ** argv)13982a6b7db3Sskrll listing_print (char *name, char **argv)
13992a6b7db3Sskrll {
14002a6b7db3Sskrll int using_stdout;
14012a6b7db3Sskrll
14022a6b7db3Sskrll title = "";
14032a6b7db3Sskrll subtitle = "";
14042a6b7db3Sskrll
14052a6b7db3Sskrll if (name == NULL)
14062a6b7db3Sskrll {
14072a6b7db3Sskrll list_file = stdout;
14082a6b7db3Sskrll using_stdout = 1;
14092a6b7db3Sskrll }
14102a6b7db3Sskrll else
14112a6b7db3Sskrll {
14122a6b7db3Sskrll list_file = fopen (name, FOPEN_WT);
14132a6b7db3Sskrll if (list_file != NULL)
14142a6b7db3Sskrll using_stdout = 0;
14152a6b7db3Sskrll else
14162a6b7db3Sskrll {
14172a6b7db3Sskrll as_warn (_("can't open %s: %s"), name, xstrerror (errno));
14182a6b7db3Sskrll list_file = stdout;
14192a6b7db3Sskrll using_stdout = 1;
14202a6b7db3Sskrll }
14212a6b7db3Sskrll }
14222a6b7db3Sskrll
14232a6b7db3Sskrll if (listing & LISTING_NOFORM)
14242a6b7db3Sskrll paper_height = 0;
14252a6b7db3Sskrll
14262a6b7db3Sskrll if (listing & LISTING_GENERAL)
14272a6b7db3Sskrll listing_general_info (argv);
14282a6b7db3Sskrll
14292a6b7db3Sskrll if (listing & LISTING_LISTING)
14302a6b7db3Sskrll listing_listing (name);
14312a6b7db3Sskrll
14322a6b7db3Sskrll if (listing & LISTING_SYMBOLS)
14332a6b7db3Sskrll list_symbol_table ();
14342a6b7db3Sskrll
14352a6b7db3Sskrll if (! using_stdout)
14362a6b7db3Sskrll {
14372a6b7db3Sskrll if (fclose (list_file) == EOF)
14382a6b7db3Sskrll as_warn (_("can't close %s: %s"), name, xstrerror (errno));
14392a6b7db3Sskrll }
14402a6b7db3Sskrll
14412a6b7db3Sskrll if (last_open_file)
14422a6b7db3Sskrll fclose (last_open_file);
14432a6b7db3Sskrll }
14442a6b7db3Sskrll
14452a6b7db3Sskrll void
listing_file(const char * name)14462a6b7db3Sskrll listing_file (const char *name)
14472a6b7db3Sskrll {
14482a6b7db3Sskrll fn = name;
14492a6b7db3Sskrll }
14502a6b7db3Sskrll
14512a6b7db3Sskrll void
listing_eject(int ignore ATTRIBUTE_UNUSED)14522a6b7db3Sskrll listing_eject (int ignore ATTRIBUTE_UNUSED)
14532a6b7db3Sskrll {
14542a6b7db3Sskrll if (listing)
14552a6b7db3Sskrll listing_tail->edict = EDICT_EJECT;
14562a6b7db3Sskrll }
14572a6b7db3Sskrll
14582a6b7db3Sskrll /* Turn listing on or off. An argument of 0 means to turn off
14592a6b7db3Sskrll listing. An argument of 1 means to turn on listing. An argument
14602a6b7db3Sskrll of 2 means to turn off listing, but as of the next line; that is,
14612a6b7db3Sskrll the current line should be listed, but the next line should not. */
14622a6b7db3Sskrll
14632a6b7db3Sskrll void
listing_list(int on)14642a6b7db3Sskrll listing_list (int on)
14652a6b7db3Sskrll {
14662a6b7db3Sskrll if (listing)
14672a6b7db3Sskrll {
14682a6b7db3Sskrll switch (on)
14692a6b7db3Sskrll {
14702a6b7db3Sskrll case 0:
14712a6b7db3Sskrll if (listing_tail->edict == EDICT_LIST)
14722a6b7db3Sskrll listing_tail->edict = EDICT_NONE;
14732a6b7db3Sskrll else
14742a6b7db3Sskrll listing_tail->edict = EDICT_NOLIST;
14752a6b7db3Sskrll break;
14762a6b7db3Sskrll case 1:
14772a6b7db3Sskrll if (listing_tail->edict == EDICT_NOLIST
14782a6b7db3Sskrll || listing_tail->edict == EDICT_NOLIST_NEXT)
14792a6b7db3Sskrll listing_tail->edict = EDICT_NONE;
14802a6b7db3Sskrll else
14812a6b7db3Sskrll listing_tail->edict = EDICT_LIST;
14822a6b7db3Sskrll break;
14832a6b7db3Sskrll case 2:
14842a6b7db3Sskrll listing_tail->edict = EDICT_NOLIST_NEXT;
14852a6b7db3Sskrll break;
14862a6b7db3Sskrll default:
14872a6b7db3Sskrll abort ();
14882a6b7db3Sskrll }
14892a6b7db3Sskrll }
14902a6b7db3Sskrll }
14912a6b7db3Sskrll
14922a6b7db3Sskrll void
listing_psize(int width_only)14932a6b7db3Sskrll listing_psize (int width_only)
14942a6b7db3Sskrll {
14952a6b7db3Sskrll if (! width_only)
14962a6b7db3Sskrll {
14972a6b7db3Sskrll paper_height = get_absolute_expression ();
14982a6b7db3Sskrll
14992a6b7db3Sskrll if (paper_height < 0 || paper_height > 1000)
15002a6b7db3Sskrll {
15012a6b7db3Sskrll paper_height = 0;
15022a6b7db3Sskrll as_warn (_("strange paper height, set to no form"));
15032a6b7db3Sskrll }
15042a6b7db3Sskrll
15052a6b7db3Sskrll if (*input_line_pointer != ',')
15062a6b7db3Sskrll {
15072a6b7db3Sskrll demand_empty_rest_of_line ();
15082a6b7db3Sskrll return;
15092a6b7db3Sskrll }
15102a6b7db3Sskrll
15112a6b7db3Sskrll ++input_line_pointer;
15122a6b7db3Sskrll }
15132a6b7db3Sskrll
1514*f22f0ef4Schristos {
1515*f22f0ef4Schristos expressionS exp;
1516*f22f0ef4Schristos
1517*f22f0ef4Schristos (void) expression_and_evaluate (& exp);
1518*f22f0ef4Schristos
1519*f22f0ef4Schristos if (exp.X_op == O_constant)
1520*f22f0ef4Schristos {
1521*f22f0ef4Schristos offsetT new_width = exp.X_add_number;
1522*f22f0ef4Schristos
1523*f22f0ef4Schristos if (new_width > 7)
1524*f22f0ef4Schristos paper_width = new_width;
1525*f22f0ef4Schristos else
1526*f22f0ef4Schristos as_bad (_("new paper width is too small"));
1527*f22f0ef4Schristos }
1528*f22f0ef4Schristos else if (exp.X_op != O_absent)
1529*f22f0ef4Schristos as_bad (_("bad or irreducible expression for paper width"));
1530*f22f0ef4Schristos else
1531*f22f0ef4Schristos as_bad (_("missing expression for paper width"));
1532*f22f0ef4Schristos }
15332a6b7db3Sskrll
15342a6b7db3Sskrll demand_empty_rest_of_line ();
15352a6b7db3Sskrll }
15362a6b7db3Sskrll
15372a6b7db3Sskrll void
listing_nopage(int ignore ATTRIBUTE_UNUSED)15382a6b7db3Sskrll listing_nopage (int ignore ATTRIBUTE_UNUSED)
15392a6b7db3Sskrll {
15402a6b7db3Sskrll paper_height = 0;
15412a6b7db3Sskrll }
15422a6b7db3Sskrll
15432a6b7db3Sskrll void
listing_title(int depth)15442a6b7db3Sskrll listing_title (int depth)
15452a6b7db3Sskrll {
15462a6b7db3Sskrll int quoted;
15472a6b7db3Sskrll char *start;
15482a6b7db3Sskrll char *ttl;
15492a6b7db3Sskrll unsigned int length;
15502a6b7db3Sskrll
15512a6b7db3Sskrll SKIP_WHITESPACE ();
15522a6b7db3Sskrll if (*input_line_pointer != '\"')
15532a6b7db3Sskrll quoted = 0;
15542a6b7db3Sskrll else
15552a6b7db3Sskrll {
15562a6b7db3Sskrll quoted = 1;
15572a6b7db3Sskrll ++input_line_pointer;
15582a6b7db3Sskrll }
15592a6b7db3Sskrll
15602a6b7db3Sskrll start = input_line_pointer;
15612a6b7db3Sskrll
15622a6b7db3Sskrll while (*input_line_pointer)
15632a6b7db3Sskrll {
15642a6b7db3Sskrll if (quoted
15652a6b7db3Sskrll ? *input_line_pointer == '\"'
15662a6b7db3Sskrll : is_end_of_line[(unsigned char) *input_line_pointer])
15672a6b7db3Sskrll {
15682a6b7db3Sskrll if (listing)
15692a6b7db3Sskrll {
15702a6b7db3Sskrll length = input_line_pointer - start;
157175f9f1baSchristos ttl = xmemdup0 (start, length);
15722a6b7db3Sskrll listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE;
15732a6b7db3Sskrll listing_tail->edict_arg = ttl;
15742a6b7db3Sskrll }
15752a6b7db3Sskrll if (quoted)
15762a6b7db3Sskrll input_line_pointer++;
15772a6b7db3Sskrll demand_empty_rest_of_line ();
15782a6b7db3Sskrll return;
15792a6b7db3Sskrll }
15802a6b7db3Sskrll else if (*input_line_pointer == '\n')
15812a6b7db3Sskrll {
15822a6b7db3Sskrll as_bad (_("new line in title"));
15832a6b7db3Sskrll demand_empty_rest_of_line ();
15842a6b7db3Sskrll return;
15852a6b7db3Sskrll }
15862a6b7db3Sskrll else
15872a6b7db3Sskrll {
15882a6b7db3Sskrll input_line_pointer++;
15892a6b7db3Sskrll }
15902a6b7db3Sskrll }
15912a6b7db3Sskrll }
15922a6b7db3Sskrll
15932a6b7db3Sskrll void
listing_source_line(unsigned int line)15942a6b7db3Sskrll listing_source_line (unsigned int line)
15952a6b7db3Sskrll {
15962a6b7db3Sskrll if (listing)
15972a6b7db3Sskrll {
15982a6b7db3Sskrll new_frag ();
15992a6b7db3Sskrll listing_tail->hll_line = line;
16002a6b7db3Sskrll new_frag ();
16012a6b7db3Sskrll }
16022a6b7db3Sskrll }
16032a6b7db3Sskrll
16042a6b7db3Sskrll void
listing_source_file(const char * file)16052a6b7db3Sskrll listing_source_file (const char *file)
16062a6b7db3Sskrll {
16072a6b7db3Sskrll if (listing)
16082a6b7db3Sskrll listing_tail->hll_file = file_info (file);
16092a6b7db3Sskrll }
16102a6b7db3Sskrll
16112a6b7db3Sskrll #else
16122a6b7db3Sskrll
16132a6b7db3Sskrll /* Dummy functions for when compiled without listing enabled. */
16142a6b7db3Sskrll
16152a6b7db3Sskrll void
listing_list(int on)16162a6b7db3Sskrll listing_list (int on)
16172a6b7db3Sskrll {
16182a6b7db3Sskrll s_ignore (0);
16192a6b7db3Sskrll }
16202a6b7db3Sskrll
16212a6b7db3Sskrll void
listing_eject(int ignore)16222a6b7db3Sskrll listing_eject (int ignore)
16232a6b7db3Sskrll {
16242a6b7db3Sskrll s_ignore (0);
16252a6b7db3Sskrll }
16262a6b7db3Sskrll
16272a6b7db3Sskrll void
listing_psize(int ignore)16282a6b7db3Sskrll listing_psize (int ignore)
16292a6b7db3Sskrll {
16302a6b7db3Sskrll s_ignore (0);
16312a6b7db3Sskrll }
16322a6b7db3Sskrll
16332a6b7db3Sskrll void
listing_nopage(int ignore)16342a6b7db3Sskrll listing_nopage (int ignore)
16352a6b7db3Sskrll {
16362a6b7db3Sskrll s_ignore (0);
16372a6b7db3Sskrll }
16382a6b7db3Sskrll
16392a6b7db3Sskrll void
listing_title(int depth)16402a6b7db3Sskrll listing_title (int depth)
16412a6b7db3Sskrll {
16422a6b7db3Sskrll s_ignore (0);
16432a6b7db3Sskrll }
16442a6b7db3Sskrll
16452a6b7db3Sskrll void
listing_file(const char * name)16462a6b7db3Sskrll listing_file (const char *name)
16472a6b7db3Sskrll {
16482a6b7db3Sskrll }
16492a6b7db3Sskrll
16502a6b7db3Sskrll void
listing_newline(char * name)16512a6b7db3Sskrll listing_newline (char *name)
16522a6b7db3Sskrll {
16532a6b7db3Sskrll }
16542a6b7db3Sskrll
16552a6b7db3Sskrll void
listing_source_line(unsigned int n)16562a6b7db3Sskrll listing_source_line (unsigned int n)
16572a6b7db3Sskrll {
16582a6b7db3Sskrll }
16592a6b7db3Sskrll
16602a6b7db3Sskrll void
listing_source_file(const char * n)16612a6b7db3Sskrll listing_source_file (const char *n)
16622a6b7db3Sskrll {
16632a6b7db3Sskrll }
16642a6b7db3Sskrll
16652a6b7db3Sskrll #endif
1666