blob: ad0c72ff687ebc8a50949dce185de400ab656e63 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* xxd: my hexdump facility. jw
2 *
3 * 2.10.90 changed to word output
4 * 3.03.93 new indent style, dumb bug inserted and fixed.
5 * -c option, mls
6 * 26.04.94 better option parser, -ps, -l, -s added.
7 * 1.07.94 -r badly needs - as input file. Per default autoskip over
Bram Moolenaar82038d72007-05-10 17:15:45 +00008 * consecutive lines of zeroes, as unix od does.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009 * -a shows them too.
10 * -i dump as c-style #include "file.h"
11 * 1.11.95 if "xxd -i" knows the filename, an 'unsigned char filename_bits[]'
12 * array is written in correct c-syntax.
13 * -s improved, now defaults to absolute seek, relative requires a '+'.
14 * -r improved, now -r -s -0x... is supported.
15 * change/suppress leading '\0' bytes.
16 * -l n improved: stops exactly after n bytes.
17 * -r improved, better handling of partial lines with trailing garbage.
18 * -r improved, now -r -p works again!
19 * -r improved, less flushing, much faster now! (that was silly)
20 * 3.04.96 Per repeated request of a single person: autoskip defaults to off.
21 * 15.05.96 -v added. They want to know the version.
22 * -a fixed, to show last line inf file ends in all zeros.
23 * -u added: Print upper case hex-letters, as preferred by unix bc.
24 * -h added to usage message. Usage message extended.
25 * Now using outfile if specified even in normal mode, aehem.
26 * No longer mixing of ints and longs. May help doze people.
27 * Added binify ioctl for same reason. (Enough Doze stress for 1996!)
28 * 16.05.96 -p improved, removed occasional superfluous linefeed.
29 * 20.05.96 -l 0 fixed. tried to read anyway.
30 * 21.05.96 -i fixed. now honours -u, and prepends __ to numeric filenames.
31 * compile -DWIN32 for NT or W95. George V. Reilly, * -v improved :-)
32 * support --gnuish-longhorn-options
33 * 25.05.96 MAC support added: CodeWarrior already uses ``outline'' in Types.h
34 * which is included by MacHeaders (Axel Kielhorn). Renamed to
35 * xxdline().
36 * 7.06.96 -i printed 'int' instead of 'char'. *blush*
37 * added Bram's OS2 ifdefs...
Bram Moolenaar4b96df52020-01-26 22:00:26 +010038 * 18.07.96 gcc -Wall @ SunOS4 is now silent.
Bram Moolenaar071d4272004-06-13 20:20:40 +000039 * Added osver for MSDOS/DJGPP/WIN32.
40 * 29.08.96 Added size_t to strncmp() for Amiga.
41 * 24.03.97 Windows NT support (Phil Hanna). Clean exit for Amiga WB (Bram)
42 * 02.04.97 Added -E option, to have EBCDIC translation instead of ASCII
Bram Moolenaar4317d9b2005-03-18 20:25:31 +000043 * (azc10@yahoo.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000044 * 22.05.97 added -g (group octets) option (jcook@namerica.kla.com).
45 * 23.09.98 nasty -p -r misfeature fixed: slightly wrong output, when -c was
46 * missing or wrong.
47 * 26.09.98 Fixed: 'xxd -i infile outfile' did not truncate outfile.
48 * 27.10.98 Fixed: -g option parser required blank.
49 * option -b added: 01000101 binary output in normal format.
50 * 16.05.00 Added VAXC changes by Stephen P. Wall
Bram Moolenaar82038d72007-05-10 17:15:45 +000051 * 16.05.00 Improved MMS file and merge for VMS by Zoltan Arpadffy
Bram Moolenaare0659a62011-04-01 19:14:40 +020052 * 2011 March Better error handling by Florian Zumbiehl.
53 * 2011 April Formatting by Bram Moolenaar
Bram Moolenaar4dcdf292015-03-05 17:51:15 +010054 * 08.06.2013 Little-endian hexdump (-e) and offset (-o) by Vadim Vygonets.
Bram Moolenaard8c56a02019-01-30 23:02:25 +010055 * 11.01.2019 Add full 64/32 bit range to -o and output by Christer Jensen.
Bram Moolenaar363d6142020-05-30 20:50:25 +020056 * 04.02.2020 Add -d for decimal offsets by Aapo Rantalainen
Bram Moolenaar071d4272004-06-13 20:20:40 +000057 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020058 * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000059 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020060 * I hereby grant permission to distribute and use xxd
61 * under X11-MIT or GPL-2.0 (at the user's choice).
62 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020063 * Contributions by Bram Moolenaar et al.
Bram Moolenaar071d4272004-06-13 20:20:40 +000064 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000065
66/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
67#if _MSC_VER >= 1400
68# define _CRT_SECURE_NO_DEPRECATE
69# define _CRT_NONSTDC_NO_DEPRECATE
70#endif
Bram Moolenaar6ef8f9e2019-03-02 07:15:28 +010071#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000072# define CYGWIN
73#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000074
Bram Moolenaar071d4272004-06-13 20:20:40 +000075#include <stdio.h>
76#ifdef VAXC
77# include <file.h>
78#else
79# include <fcntl.h>
80#endif
Bram Moolenaareae1b912019-05-09 15:12:55 +020081#if defined(WIN32) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000082# include <io.h> /* for setmode() */
83#else
84# ifdef UNIX
85# include <unistd.h>
86# endif
87#endif
88#include <stdlib.h>
89#include <string.h> /* for strncmp() */
90#include <ctype.h> /* for isalnum() */
Bram Moolenaard8c56a02019-01-30 23:02:25 +010091#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000092#if __MWERKS__ && !defined(BEBOX)
93# include <unix.h> /* for fdopen() on MAC */
94#endif
95
Bram Moolenaar071d4272004-06-13 20:20:40 +000096
97/* This corrects the problem of missing prototypes for certain functions
98 * in some GNU installations (e.g. SunOS 4.1.x).
99 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
100 */
101#if defined(__GNUC__) && defined(__STDC__)
102# ifndef __USE_FIXED_PROTOTYPES__
103# define __USE_FIXED_PROTOTYPES__
104# endif
105#endif
106
107#ifndef __USE_FIXED_PROTOTYPES__
108/*
109 * This is historic and works only if the compiler really has no prototypes:
110 *
111 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
112 * FILE is defined on OS 4.x, not on 5.x (Solaris).
113 * if __SVR4 is defined (some Solaris versions), don't include this.
114 */
115#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
116# define __P(a) a
117/* excerpt from my sun_stdlib.h */
118extern int fprintf __P((FILE *, char *, ...));
119extern int fputs __P((char *, FILE *));
120extern int _flsbuf __P((unsigned char, FILE *));
121extern int _filbuf __P((FILE *));
122extern int fflush __P((FILE *));
123extern int fclose __P((FILE *));
124extern int fseek __P((FILE *, long, int));
125extern int rewind __P((FILE *));
126
127extern void perror __P((char *));
128# endif
129#endif
130
131extern long int strtol();
132extern long int ftell();
133
DungSaga47810462021-10-22 12:55:42 +0100134char version[] = "xxd 2021-10-22 by Juergen Weigert et al.";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000135#ifdef WIN32
136char osver[] = " (Win32)";
137#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139#endif
140
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200141#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000142# define BIN_READ(yes) ((yes) ? "rb" : "rt")
143# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
144# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
145# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000146# define PATH_SEP '\\'
147#elif defined(CYGWIN)
148# define BIN_READ(yes) ((yes) ? "rb" : "rt")
149# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
150# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
151# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
152# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153#else
154# ifdef VMS
155# define BIN_READ(dummy) "r"
156# define BIN_WRITE(dummy) "w"
157# define BIN_CREAT(dummy) O_CREAT
158# define BIN_ASSIGN(fp, dummy) fp
159# define PATH_SEP ']'
160# define FILE_SEP '.'
161# else
162# define BIN_READ(dummy) "r"
163# define BIN_WRITE(dummy) "w"
164# define BIN_CREAT(dummy) O_CREAT
165# define BIN_ASSIGN(fp, dummy) fp
166# define PATH_SEP '/'
167# endif
168#endif
169
170/* open has only to arguments on the Mac */
171#if __MWERKS__
172# define OPEN(name, mode, umask) open(name, mode)
173#else
174# define OPEN(name, mode, umask) open(name, mode, umask)
175#endif
176
177#ifdef AMIGA
178# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
179#else
180# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
181#endif
182
183#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200184# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000185# define __P(a) a
186# else
187# define __P(a) ()
188# endif
189#endif
190
Bram Moolenaar071d4272004-06-13 20:20:40 +0000191#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
192#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100193#define LLEN ((2*(int)sizeof(unsigned long)) + 4 + (9*COLS-1) + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194
195char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
196
197/* the different hextypes known by this program: */
198#define HEX_NORMAL 0
199#define HEX_POSTSCRIPT 1
200#define HEX_CINCLUDE 2
201#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100202#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200204#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c)
205
Bram Moolenaare0659a62011-04-01 19:14:40 +0200206static char *pname;
207
208 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100209exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210{
211 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
212 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
213 fprintf(stderr, "Options:\n");
214 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100215 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200216 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
218 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100219 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
Atsushi SUGAWARA34a36482021-10-17 16:09:08 +0100220 fprintf(stderr, " -g bytes number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000221 fprintf(stderr, " -h print this summary.\n");
222 fprintf(stderr, " -i output in C include file style.\n");
223 fprintf(stderr, " -l len stop after <len> octets.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100224 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000225 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
226 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
227 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
Bram Moolenaar363d6142020-05-30 20:50:25 +0200228 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000229 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
230#ifdef TRY_SEEK
231 "[+][-]", "(or +: rel.) ");
232#else
233 "", "");
234#endif
235 fprintf(stderr, " -u use upper case hex letters.\n");
236 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
237 exit(1);
238}
239
Bram Moolenaare0659a62011-04-01 19:14:40 +0200240 static void
DungSagaa2ffb432021-10-22 15:55:31 +0100241perror_exit(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200242{
243 fprintf(stderr, "%s: ", pname);
244 perror(NULL);
245 exit(ret);
246}
247
DungSagaa2ffb432021-10-22 15:55:31 +0100248 static void
249error_exit(int ret, char *msg)
250{
251 fprintf(stderr, "%s: %s\n", pname, msg);
252 exit(ret);
253}
254
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000255 static void
Bram Moolenaar71b36202021-11-25 13:26:19 +0000256exit_on_ferror(int c, FILE *fpi)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000257{
258 if (c == EOF && ferror(fpi))
259 perror_exit(2);
260}
261
262 static void
Bram Moolenaar71b36202021-11-25 13:26:19 +0000263putc_or_die(int c, FILE *fpo)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000264{
265 if (putc(c, fpo) == EOF)
266 perror_exit(3);
267}
268
269 static void
270fputs_or_die(char *s, FILE *fpo)
271{
272 if (fputs(s, fpo) == EOF)
273 perror_exit(3);
274}
275
276 static void
277fprintf_or_die(FILE *fpo, char *format, char *s, int d)
278{
279 if (fprintf(fpo, format, s, d) < 0)
280 perror_exit(3);
281}
282
283 static void
284fclose_or_die(FILE *fpi, FILE *fpo)
285{
286 if (fclose(fpo) != 0)
287 perror_exit(3);
288 if (fclose(fpi) != 0)
289 perror_exit(2);
290}
291
Bram Moolenaar071d4272004-06-13 20:20:40 +0000292/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000293 * If "c" is a hex digit, return the value.
294 * Otherwise return -1.
295 */
296 static int
297parse_hex_digit(int c)
298{
299 return (c >= '0' && c <= '9') ? c - '0'
300 : (c >= 'a' && c <= 'f') ? c - 'a' + 10
301 : (c >= 'A' && c <= 'F') ? c - 'A' + 10
302 : -1;
303}
304
305/*
306 * Ignore text on "fpi" until end-of-line or end-of-file.
307 * Return the '\n' or EOF character.
308 * When an error is encountered exit with an error message.
309 */
310 static int
311skip_to_eol(FILE *fpi, int c)
312{
313 while (c != '\n' && c != EOF)
314 c = getc(fpi);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000315 exit_on_ferror(c, fpi);
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000316 return c;
317}
318
319/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000320 * Max. cols binary characters are decoded from the input stream per line.
321 * Two adjacent garbage characters after evaluated data delimit valid data.
322 * Everything up to the next newline is discarded.
323 *
324 * The name is historic and came from 'undo type opt h'.
325 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200326 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100327huntype(
328 FILE *fpi,
329 FILE *fpo,
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100330 int cols,
331 int hextype,
332 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000333{
334 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
335 long have_off = 0, want_off = 0;
336
337 rewind(fpi);
338
339 while ((c = getc(fpi)) != EOF)
340 {
341 if (c == '\r') /* Doze style input file? */
342 continue;
343
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100344 /* Allow multiple spaces. This doesn't work when there is normal text
345 * after the hex codes in the last line that looks like hex, thus only
346 * use it for PostScript format. */
347 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000348 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000349
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 n3 = n2;
351 n2 = n1;
352
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000353 n1 = parse_hex_digit(c);
354 if (n1 == -1 && ign_garb)
355 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356
357 ign_garb = 0;
358
DungSaga375c35a2021-10-18 13:16:03 +0100359 if (!hextype && (p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000360 {
DungSaga375c35a2021-10-18 13:16:03 +0100361 if (n1 < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000362 {
DungSaga375c35a2021-10-18 13:16:03 +0100363 p = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000364 continue;
365 }
DungSaga375c35a2021-10-18 13:16:03 +0100366 want_off = (want_off << 4) | n1;
367 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368 }
369
370 if (base_off + want_off != have_off)
371 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200372 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100373 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000375 if (fseek(fpo, base_off + want_off - have_off, SEEK_CUR) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376 have_off = base_off + want_off;
377#endif
378 if (base_off + want_off < have_off)
DungSagaa2ffb432021-10-22 15:55:31 +0100379 error_exit(5, "sorry, cannot seek backwards.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000380 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000381 putc_or_die(0, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000382 }
383
384 if (n2 >= 0 && n1 >= 0)
385 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000386 putc_or_die((n2 << 4) | n1, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387 have_off++;
388 want_off++;
389 n1 = -1;
DungSaga375c35a2021-10-18 13:16:03 +0100390 if (!hextype && (++p >= cols))
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000391 /* skip the rest of the line as garbage */
392 c = skip_to_eol(fpi, c);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000393 }
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000394 else if (n1 < 0 && n2 < 0 && n3 < 0)
395 /* already stumbled into garbage, skip line, wait and see */
396 c = skip_to_eol(fpi, c);
397
DungSaga47810462021-10-22 12:55:42 +0100398 if (c == '\n')
399 {
400 if (!hextype)
401 want_off = 0;
402 p = cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000403 ign_garb = 1;
404 }
405 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200406 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100407 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000409 fseek(fpo, 0L, SEEK_END);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410#endif
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000411 fclose_or_die(fpi, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412 return 0;
413}
414
415/*
416 * Print line l. If nz is false, xxdline regards the line a line of
417 * zeroes. If there are three or more consecutive lines of zeroes,
418 * they are replaced by a single '*' character.
419 *
420 * If the output ends with more than two lines of zeroes, you
421 * should call xxdline again with l being the last line and nz
422 * negative. This ensures that the last line is shown even when
423 * it is all zeroes.
424 *
425 * If nz is always positive, lines are never suppressed.
426 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200427 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100428xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000429{
430 static char z[LLEN+1];
431 static int zero_seen = 0;
432
433 if (!nz && zero_seen == 1)
434 strcpy(z, l);
435
436 if (nz || !zero_seen++)
437 {
438 if (nz)
439 {
440 if (nz < 0)
441 zero_seen--;
442 if (zero_seen == 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000443 fputs_or_die(z, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000444 if (zero_seen > 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000445 fputs_or_die("*\n", fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 }
447 if (nz >= 0 || zero_seen > 0)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000448 fputs_or_die(l, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000449 if (nz)
450 zero_seen = 0;
451 }
452}
453
454/* This is an EBCDIC to ASCII conversion table */
455/* from a proposed BTL standard April 16, 1979 */
456static unsigned char etoa64[] =
457{
458 0040,0240,0241,0242,0243,0244,0245,0246,
459 0247,0250,0325,0056,0074,0050,0053,0174,
460 0046,0251,0252,0253,0254,0255,0256,0257,
461 0260,0261,0041,0044,0052,0051,0073,0176,
462 0055,0057,0262,0263,0264,0265,0266,0267,
463 0270,0271,0313,0054,0045,0137,0076,0077,
464 0272,0273,0274,0275,0276,0277,0300,0301,
465 0302,0140,0072,0043,0100,0047,0075,0042,
466 0303,0141,0142,0143,0144,0145,0146,0147,
467 0150,0151,0304,0305,0306,0307,0310,0311,
468 0312,0152,0153,0154,0155,0156,0157,0160,
469 0161,0162,0136,0314,0315,0316,0317,0320,
470 0321,0345,0163,0164,0165,0166,0167,0170,
471 0171,0172,0322,0323,0324,0133,0326,0327,
472 0330,0331,0332,0333,0334,0335,0336,0337,
473 0340,0341,0342,0343,0344,0135,0346,0347,
474 0173,0101,0102,0103,0104,0105,0106,0107,
475 0110,0111,0350,0351,0352,0353,0354,0355,
476 0175,0112,0113,0114,0115,0116,0117,0120,
477 0121,0122,0356,0357,0360,0361,0362,0363,
478 0134,0237,0123,0124,0125,0126,0127,0130,
479 0131,0132,0364,0365,0366,0367,0370,0371,
480 0060,0061,0062,0063,0064,0065,0066,0067,
481 0070,0071,0372,0373,0374,0375,0376,0377
482};
483
Bram Moolenaare0659a62011-04-01 19:14:40 +0200484 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100485main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000486{
487 FILE *fp, *fpo;
488 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200489 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
490 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 int ebcdic = 0;
492 int octspergrp = -1; /* number of octets grouped in output */
493 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100494 long length = -1, n = 0, seekoff = 0;
495 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200496 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200497 char *pp;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100498 int addrlen = 9;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000499
500#ifdef AMIGA
501 /* This program doesn't work when started from the Workbench */
502 if (argc == 0)
503 exit(1);
504#endif
505
506 pname = argv[0];
507 for (pp = pname; *pp; )
508 if (*pp++ == PATH_SEP)
509 pname = pp;
510#ifdef FILE_SEP
511 for (pp = pname; *pp; pp++)
512 if (*pp == FILE_SEP)
513 {
514 *pp = '\0';
515 break;
516 }
517#endif
518
519 while (argc >= 2)
520 {
521 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
522 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
523 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100524 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000525 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
526 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
527 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200528 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200529 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530 else if (!STRNCMP(pp, "-r", 2)) revert++;
531 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
532 else if (!STRNCMP(pp, "-v", 2))
533 {
534 fprintf(stderr, "%s%s\n", version, osver);
535 exit(0);
536 }
537 else if (!STRNCMP(pp, "-c", 2))
538 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100539 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200540 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100541 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
542 cols = (int)strtol(pp + 2, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543 else
544 {
545 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200546 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547 cols = (int)strtol(argv[2], NULL, 0);
548 argv++;
549 argc--;
550 }
551 }
552 else if (!STRNCMP(pp, "-g", 2))
553 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100554 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 octspergrp = (int)strtol(pp + 2, NULL, 0);
556 else
557 {
558 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200559 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560 octspergrp = (int)strtol(argv[2], NULL, 0);
561 argv++;
562 argc--;
563 }
564 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100565 else if (!STRNCMP(pp, "-o", 2))
566 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100567 int reloffset = 0;
568 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100569 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100570 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100571 else
572 {
573 if (!argv[2])
574 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100575
576 if (argv[2][0] == '+')
577 reloffset++;
578 if (argv[2][reloffset] == '-')
579 negoffset++;
580
581 if (negoffset)
582 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
583 else
584 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
585
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100586 argv++;
587 argc--;
588 }
589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590 else if (!STRNCMP(pp, "-s", 2))
591 {
592 relseek = 0;
593 negseek = 0;
594 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
595 {
596#ifdef TRY_SEEK
597 if (pp[2] == '+')
598 relseek++;
599 if (pp[2+relseek] == '-')
600 negseek++;
601#endif
602 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
603 }
604 else
605 {
606 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200607 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608#ifdef TRY_SEEK
609 if (argv[2][0] == '+')
610 relseek++;
611 if (argv[2][relseek] == '-')
612 negseek++;
613#endif
614 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
615 argv++;
616 argc--;
617 }
618 }
619 else if (!STRNCMP(pp, "-l", 2))
620 {
621 if (pp[2] && STRNCMP("en", pp + 2, 2))
622 length = strtol(pp + 2, (char **)NULL, 0);
623 else
624 {
625 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200626 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627 length = strtol(argv[2], (char **)NULL, 0);
628 argv++;
629 argc--;
630 }
631 }
632 else if (!strcmp(pp, "--")) /* end of options */
633 {
634 argv++;
635 argc--;
636 break;
637 }
638 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200639 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640 else
641 break; /* not an option */
642
643 argv++; /* advance to next argument */
644 argc--;
645 }
646
647 if (!cols)
648 switch (hextype)
649 {
650 case HEX_POSTSCRIPT: cols = 30; break;
651 case HEX_CINCLUDE: cols = 12; break;
652 case HEX_BITS: cols = 6; break;
653 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100654 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000655 default: cols = 16; break;
656 }
657
658 if (octspergrp < 0)
659 switch (hextype)
660 {
661 case HEX_BITS: octspergrp = 1; break;
662 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100663 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664 case HEX_POSTSCRIPT:
665 case HEX_CINCLUDE:
666 default: octspergrp = 0; break;
667 }
668
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100669 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000670 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000671 {
672 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
673 exit(1);
674 }
675
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100676 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100678 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
DungSagaa2ffb432021-10-22 15:55:31 +0100679 error_exit(1, "number of octets per group must be a power of 2 with -e.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680
681 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200682 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683
684 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
685 BIN_ASSIGN(fp = stdin, !revert);
686 else
687 {
688 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
689 {
690 fprintf(stderr,"%s: ", pname);
691 perror(argv[1]);
692 return 2;
693 }
694 }
695
696 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
697 BIN_ASSIGN(fpo = stdout, revert);
698 else
699 {
700 int fd;
701 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
702
703 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
704 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
705 {
706 fprintf(stderr, "%s: ", pname);
707 perror(argv[2]);
708 return 3;
709 }
710 rewind(fpo);
711 }
712
713 if (revert)
714 {
715 if (hextype && (hextype != HEX_POSTSCRIPT))
DungSagaa2ffb432021-10-22 15:55:31 +0100716 error_exit(-1, "sorry, cannot revert this type of hexdump");
717 return huntype(fp, fpo, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 negseek ? -seekoff : seekoff);
719 }
720
721 if (seekoff || negseek || !relseek)
722 {
723#ifdef TRY_SEEK
724 if (relseek)
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000725 e = fseek(fp, negseek ? -seekoff : seekoff, SEEK_CUR);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726 else
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000727 e = fseek(fp, negseek ? -seekoff : seekoff,
728 negseek ? SEEK_END : SEEK_SET);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000729 if (e < 0 && negseek)
DungSagaa2ffb432021-10-22 15:55:31 +0100730 error_exit(4, "sorry cannot seek.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731 if (e >= 0)
732 seekoff = ftell(fp);
733 else
734#endif
735 {
736 long s = seekoff;
737
738 while (s--)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000739 if ((c = getc(fp)) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200740 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000741 exit_on_ferror(c, fp);
742 error_exit(4, "sorry cannot seek.");
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200743 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000744 }
745 }
746
747 if (hextype == HEX_CINCLUDE)
748 {
749 if (fp != stdin)
750 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000751 fprintf_or_die(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000753 putc_or_die(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
754 fputs_or_die("[] = {\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755 }
756
757 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200758 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
760 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000761 fprintf_or_die(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
762 (p % cols) ? ", " : &",\n "[2*!p], c);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763 p++;
764 }
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000765 exit_on_ferror(c, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000767 if (p)
768 fputs_or_die("\n", fpo);
769 fputs_or_die(&"};\n"[3 * (fp == stdin)], fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000770
771 if (fp != stdin)
772 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000773 fprintf_or_die(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000775 putc_or_die(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
776 fprintf_or_die(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777 }
778
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000779 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 return 0;
781 }
782
783 if (hextype == HEX_POSTSCRIPT)
784 {
785 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200786 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
788 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000789 putc_or_die(hexx[(e >> 4) & 0xf], fpo);
790 putc_or_die(hexx[e & 0xf], fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791 n++;
792 if (!--p)
793 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000794 putc_or_die('\n', fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795 p = cols;
796 }
797 }
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000798 exit_on_ferror(e, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000799 if (p < cols)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000800 putc_or_die('\n', fpo);
801 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802 return 0;
803 }
804
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100805 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100807 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
809 else /* hextype == HEX_BITS */
810 grplen = 8 * octspergrp + 1;
811
Bram Moolenaare0659a62011-04-01 19:14:40 +0200812 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
814 {
DungSaga48608b42021-11-24 11:18:07 +0000815 int x;
816
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817 if (p == 0)
818 {
DungSaga581f41a2021-11-22 11:57:31 +0000819 addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
Bram Moolenaar363d6142020-05-30 20:50:25 +0200820 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100821 for (c = addrlen; c < LLEN; l[c++] = ' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 }
DungSaga48608b42021-11-24 11:18:07 +0000823 x = hextype == HEX_LITTLEENDIAN ? p ^ (octspergrp-1) : p;
824 c = addrlen + 1 + (grplen * x) / octspergrp;
DungSaga581f41a2021-11-22 11:57:31 +0000825 if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826 {
DungSaga48608b42021-11-24 11:18:07 +0000827 l[c] = hexx[(e >> 4) & 0xf];
DungSaga581f41a2021-11-22 11:57:31 +0000828 l[++c] = hexx[e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829 }
830 else /* hextype == HEX_BITS */
831 {
832 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000833 for (i = 7; i >= 0; i--)
DungSaga48608b42021-11-24 11:18:07 +0000834 l[c++] = (e & (1 << i)) ? '1' : '0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100836 if (e)
837 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838 if (ebcdic)
839 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000840 /* When changing this update definition of LLEN above. */
DungSaga48608b42021-11-24 11:18:07 +0000841 c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p;
842 l[c++] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843#ifdef __MVS__
844 (e >= 64)
845#else
846 (e > 31 && e < 127)
847#endif
848 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000849 n++;
850 if (++p == cols)
851 {
DungSaga48608b42021-11-24 11:18:07 +0000852 l[c] = '\n';
853 l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854 xxdline(fpo, l, autoskip ? nonzero : 1);
855 nonzero = 0;
856 p = 0;
857 }
858 }
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000859 exit_on_ferror(e, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860 if (p)
861 {
DungSaga48608b42021-11-24 11:18:07 +0000862 l[c] = '\n';
863 l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000864 xxdline(fpo, l, 1);
865 }
866 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000867 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000868
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000869 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870 return 0;
871}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200872
873/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */