blob: cf2a3569f52e50eb7a58b866c0d18585bb8fcfdd [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
DungSagad1d8a592021-11-26 13:59:27 +0000255 static int
256getc_or_die(FILE *fpi)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000257{
DungSagad1d8a592021-11-26 13:59:27 +0000258 int c = getc(fpi);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000259 if (c == EOF && ferror(fpi))
260 perror_exit(2);
DungSagad1d8a592021-11-26 13:59:27 +0000261 return c;
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000262}
263
264 static void
Bram Moolenaar71b36202021-11-25 13:26:19 +0000265putc_or_die(int c, FILE *fpo)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000266{
267 if (putc(c, fpo) == EOF)
268 perror_exit(3);
269}
270
271 static void
272fputs_or_die(char *s, FILE *fpo)
273{
274 if (fputs(s, fpo) == EOF)
275 perror_exit(3);
276}
277
DungSaga7e5503c2021-12-01 11:24:52 +0000278/* Use a macro to allow for different arguments. */
279#define FPRINTF_OR_DIE(args) if (fprintf args < 0) perror_exit(3)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000280
281 static void
282fclose_or_die(FILE *fpi, FILE *fpo)
283{
284 if (fclose(fpo) != 0)
285 perror_exit(3);
286 if (fclose(fpi) != 0)
287 perror_exit(2);
288}
289
Bram Moolenaar071d4272004-06-13 20:20:40 +0000290/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000291 * If "c" is a hex digit, return the value.
292 * Otherwise return -1.
293 */
294 static int
295parse_hex_digit(int c)
296{
297 return (c >= '0' && c <= '9') ? c - '0'
298 : (c >= 'a' && c <= 'f') ? c - 'a' + 10
299 : (c >= 'A' && c <= 'F') ? c - 'A' + 10
300 : -1;
301}
302
303/*
304 * Ignore text on "fpi" until end-of-line or end-of-file.
305 * Return the '\n' or EOF character.
306 * When an error is encountered exit with an error message.
307 */
308 static int
309skip_to_eol(FILE *fpi, int c)
310{
311 while (c != '\n' && c != EOF)
DungSagad1d8a592021-11-26 13:59:27 +0000312 c = getc_or_die(fpi);
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000313 return c;
314}
315
316/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000317 * Max. cols binary characters are decoded from the input stream per line.
318 * Two adjacent garbage characters after evaluated data delimit valid data.
319 * Everything up to the next newline is discarded.
320 *
321 * The name is historic and came from 'undo type opt h'.
322 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200323 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100324huntype(
325 FILE *fpi,
326 FILE *fpo,
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100327 int cols,
328 int hextype,
329 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000330{
331 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
332 long have_off = 0, want_off = 0;
333
334 rewind(fpi);
335
336 while ((c = getc(fpi)) != EOF)
337 {
338 if (c == '\r') /* Doze style input file? */
339 continue;
340
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100341 /* Allow multiple spaces. This doesn't work when there is normal text
342 * after the hex codes in the last line that looks like hex, thus only
343 * use it for PostScript format. */
344 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000345 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000346
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 n3 = n2;
348 n2 = n1;
349
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000350 n1 = parse_hex_digit(c);
351 if (n1 == -1 && ign_garb)
352 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353
354 ign_garb = 0;
355
DungSaga375c35a2021-10-18 13:16:03 +0100356 if (!hextype && (p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000357 {
DungSaga375c35a2021-10-18 13:16:03 +0100358 if (n1 < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000359 {
DungSaga375c35a2021-10-18 13:16:03 +0100360 p = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000361 continue;
362 }
DungSaga375c35a2021-10-18 13:16:03 +0100363 want_off = (want_off << 4) | n1;
364 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000365 }
366
367 if (base_off + want_off != have_off)
368 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200369 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100370 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000371#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000372 if (fseek(fpo, base_off + want_off - have_off, SEEK_CUR) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373 have_off = base_off + want_off;
374#endif
375 if (base_off + want_off < have_off)
DungSaga7e5503c2021-12-01 11:24:52 +0000376 error_exit(5, "Sorry, cannot seek backwards.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000378 putc_or_die(0, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000379 }
380
381 if (n2 >= 0 && n1 >= 0)
382 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000383 putc_or_die((n2 << 4) | n1, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000384 have_off++;
385 want_off++;
386 n1 = -1;
DungSaga375c35a2021-10-18 13:16:03 +0100387 if (!hextype && (++p >= cols))
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000388 /* skip the rest of the line as garbage */
389 c = skip_to_eol(fpi, c);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390 }
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000391 else if (n1 < 0 && n2 < 0 && n3 < 0)
392 /* already stumbled into garbage, skip line, wait and see */
393 c = skip_to_eol(fpi, c);
394
DungSaga47810462021-10-22 12:55:42 +0100395 if (c == '\n')
396 {
397 if (!hextype)
398 want_off = 0;
399 p = cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000400 ign_garb = 1;
401 }
402 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200403 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100404 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000406 fseek(fpo, 0L, SEEK_END);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407#endif
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000408 fclose_or_die(fpi, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000409 return 0;
410}
411
412/*
413 * Print line l. If nz is false, xxdline regards the line a line of
414 * zeroes. If there are three or more consecutive lines of zeroes,
415 * they are replaced by a single '*' character.
416 *
417 * If the output ends with more than two lines of zeroes, you
418 * should call xxdline again with l being the last line and nz
419 * negative. This ensures that the last line is shown even when
420 * it is all zeroes.
421 *
422 * If nz is always positive, lines are never suppressed.
423 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200424 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100425xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000426{
427 static char z[LLEN+1];
428 static int zero_seen = 0;
429
430 if (!nz && zero_seen == 1)
431 strcpy(z, l);
432
433 if (nz || !zero_seen++)
434 {
435 if (nz)
436 {
437 if (nz < 0)
438 zero_seen--;
439 if (zero_seen == 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000440 fputs_or_die(z, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 if (zero_seen > 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000442 fputs_or_die("*\n", fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443 }
444 if (nz >= 0 || zero_seen > 0)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000445 fputs_or_die(l, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 if (nz)
447 zero_seen = 0;
448 }
449}
450
451/* This is an EBCDIC to ASCII conversion table */
452/* from a proposed BTL standard April 16, 1979 */
453static unsigned char etoa64[] =
454{
455 0040,0240,0241,0242,0243,0244,0245,0246,
456 0247,0250,0325,0056,0074,0050,0053,0174,
457 0046,0251,0252,0253,0254,0255,0256,0257,
458 0260,0261,0041,0044,0052,0051,0073,0176,
459 0055,0057,0262,0263,0264,0265,0266,0267,
460 0270,0271,0313,0054,0045,0137,0076,0077,
461 0272,0273,0274,0275,0276,0277,0300,0301,
462 0302,0140,0072,0043,0100,0047,0075,0042,
463 0303,0141,0142,0143,0144,0145,0146,0147,
464 0150,0151,0304,0305,0306,0307,0310,0311,
465 0312,0152,0153,0154,0155,0156,0157,0160,
466 0161,0162,0136,0314,0315,0316,0317,0320,
467 0321,0345,0163,0164,0165,0166,0167,0170,
468 0171,0172,0322,0323,0324,0133,0326,0327,
469 0330,0331,0332,0333,0334,0335,0336,0337,
470 0340,0341,0342,0343,0344,0135,0346,0347,
471 0173,0101,0102,0103,0104,0105,0106,0107,
472 0110,0111,0350,0351,0352,0353,0354,0355,
473 0175,0112,0113,0114,0115,0116,0117,0120,
474 0121,0122,0356,0357,0360,0361,0362,0363,
475 0134,0237,0123,0124,0125,0126,0127,0130,
476 0131,0132,0364,0365,0366,0367,0370,0371,
477 0060,0061,0062,0063,0064,0065,0066,0067,
478 0070,0071,0372,0373,0374,0375,0376,0377
479};
480
Bram Moolenaare0659a62011-04-01 19:14:40 +0200481 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100482main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000483{
484 FILE *fp, *fpo;
485 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200486 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
487 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 int ebcdic = 0;
489 int octspergrp = -1; /* number of octets grouped in output */
490 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100491 long length = -1, n = 0, seekoff = 0;
492 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200493 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200494 char *pp;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100495 int addrlen = 9;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496
497#ifdef AMIGA
498 /* This program doesn't work when started from the Workbench */
499 if (argc == 0)
500 exit(1);
501#endif
502
503 pname = argv[0];
504 for (pp = pname; *pp; )
505 if (*pp++ == PATH_SEP)
506 pname = pp;
507#ifdef FILE_SEP
508 for (pp = pname; *pp; pp++)
509 if (*pp == FILE_SEP)
510 {
511 *pp = '\0';
512 break;
513 }
514#endif
515
516 while (argc >= 2)
517 {
518 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
519 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
520 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100521 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000522 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
523 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
524 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200525 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200526 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000527 else if (!STRNCMP(pp, "-r", 2)) revert++;
528 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
529 else if (!STRNCMP(pp, "-v", 2))
530 {
531 fprintf(stderr, "%s%s\n", version, osver);
532 exit(0);
533 }
534 else if (!STRNCMP(pp, "-c", 2))
535 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100536 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200537 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100538 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
539 cols = (int)strtol(pp + 2, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540 else
541 {
542 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200543 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544 cols = (int)strtol(argv[2], NULL, 0);
545 argv++;
546 argc--;
547 }
548 }
549 else if (!STRNCMP(pp, "-g", 2))
550 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100551 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000552 octspergrp = (int)strtol(pp + 2, NULL, 0);
553 else
554 {
555 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200556 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 octspergrp = (int)strtol(argv[2], NULL, 0);
558 argv++;
559 argc--;
560 }
561 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100562 else if (!STRNCMP(pp, "-o", 2))
563 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100564 int reloffset = 0;
565 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100566 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100567 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100568 else
569 {
570 if (!argv[2])
571 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100572
573 if (argv[2][0] == '+')
574 reloffset++;
575 if (argv[2][reloffset] == '-')
576 negoffset++;
577
578 if (negoffset)
579 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
580 else
581 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
582
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100583 argv++;
584 argc--;
585 }
586 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000587 else if (!STRNCMP(pp, "-s", 2))
588 {
589 relseek = 0;
590 negseek = 0;
591 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
592 {
593#ifdef TRY_SEEK
594 if (pp[2] == '+')
595 relseek++;
596 if (pp[2+relseek] == '-')
597 negseek++;
598#endif
599 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
600 }
601 else
602 {
603 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200604 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605#ifdef TRY_SEEK
606 if (argv[2][0] == '+')
607 relseek++;
608 if (argv[2][relseek] == '-')
609 negseek++;
610#endif
611 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
612 argv++;
613 argc--;
614 }
615 }
616 else if (!STRNCMP(pp, "-l", 2))
617 {
618 if (pp[2] && STRNCMP("en", pp + 2, 2))
619 length = strtol(pp + 2, (char **)NULL, 0);
620 else
621 {
622 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200623 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 length = strtol(argv[2], (char **)NULL, 0);
625 argv++;
626 argc--;
627 }
628 }
629 else if (!strcmp(pp, "--")) /* end of options */
630 {
631 argv++;
632 argc--;
633 break;
634 }
635 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200636 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 else
638 break; /* not an option */
639
640 argv++; /* advance to next argument */
641 argc--;
642 }
643
644 if (!cols)
645 switch (hextype)
646 {
647 case HEX_POSTSCRIPT: cols = 30; break;
648 case HEX_CINCLUDE: cols = 12; break;
649 case HEX_BITS: cols = 6; break;
650 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100651 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000652 default: cols = 16; break;
653 }
654
655 if (octspergrp < 0)
656 switch (hextype)
657 {
658 case HEX_BITS: octspergrp = 1; break;
659 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100660 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661 case HEX_POSTSCRIPT:
662 case HEX_CINCLUDE:
663 default: octspergrp = 0; break;
664 }
665
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100666 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000667 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 {
669 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
670 exit(1);
671 }
672
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100673 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000674 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100675 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
DungSagaa2ffb432021-10-22 15:55:31 +0100676 error_exit(1, "number of octets per group must be a power of 2 with -e.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677
678 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200679 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680
681 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
682 BIN_ASSIGN(fp = stdin, !revert);
683 else
684 {
685 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
686 {
687 fprintf(stderr,"%s: ", pname);
688 perror(argv[1]);
689 return 2;
690 }
691 }
692
693 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
694 BIN_ASSIGN(fpo = stdout, revert);
695 else
696 {
697 int fd;
698 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
699
700 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
701 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
702 {
703 fprintf(stderr, "%s: ", pname);
704 perror(argv[2]);
705 return 3;
706 }
707 rewind(fpo);
708 }
709
710 if (revert)
711 {
712 if (hextype && (hextype != HEX_POSTSCRIPT))
DungSaga7e5503c2021-12-01 11:24:52 +0000713 error_exit(-1, "Sorry, cannot revert this type of hexdump");
DungSagaa2ffb432021-10-22 15:55:31 +0100714 return huntype(fp, fpo, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000715 negseek ? -seekoff : seekoff);
716 }
717
718 if (seekoff || negseek || !relseek)
719 {
720#ifdef TRY_SEEK
721 if (relseek)
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000722 e = fseek(fp, negseek ? -seekoff : seekoff, SEEK_CUR);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000723 else
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000724 e = fseek(fp, negseek ? -seekoff : seekoff,
725 negseek ? SEEK_END : SEEK_SET);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726 if (e < 0 && negseek)
DungSaga7e5503c2021-12-01 11:24:52 +0000727 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000728 if (e >= 0)
729 seekoff = ftell(fp);
730 else
731#endif
732 {
733 long s = seekoff;
734
735 while (s--)
DungSaga7e5503c2021-12-01 11:24:52 +0000736 if (getc_or_die(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200737 {
DungSaga7e5503c2021-12-01 11:24:52 +0000738 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200739 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740 }
741 }
742
743 if (hextype == HEX_CINCLUDE)
744 {
745 if (fp != stdin)
746 {
DungSaga7e5503c2021-12-01 11:24:52 +0000747 FPRINTF_OR_DIE((fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000749 putc_or_die(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
750 fputs_or_die("[] = {\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000751 }
752
753 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200754 c = 0;
DungSagad1d8a592021-11-26 13:59:27 +0000755 while ((length < 0 || p < length) && (c = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 {
DungSaga7e5503c2021-12-01 11:24:52 +0000757 FPRINTF_OR_DIE((fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
758 (p % cols) ? ", " : (!p ? " " : ",\n "), c));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 p++;
760 }
761
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000762 if (p)
763 fputs_or_die("\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764
765 if (fp != stdin)
766 {
DungSagad1d8a592021-11-26 13:59:27 +0000767 fputs_or_die("};\n", fpo);
DungSaga7e5503c2021-12-01 11:24:52 +0000768 FPRINTF_OR_DIE((fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000770 putc_or_die(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
DungSaga7e5503c2021-12-01 11:24:52 +0000771 FPRINTF_OR_DIE((fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000772 }
773
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000774 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 return 0;
776 }
777
778 if (hextype == HEX_POSTSCRIPT)
779 {
780 p = cols;
DungSagad1d8a592021-11-26 13:59:27 +0000781 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000783 putc_or_die(hexx[(e >> 4) & 0xf], fpo);
784 putc_or_die(hexx[e & 0xf], fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 n++;
786 if (!--p)
787 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000788 putc_or_die('\n', fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789 p = cols;
790 }
791 }
792 if (p < cols)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000793 putc_or_die('\n', fpo);
794 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795 return 0;
796 }
797
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100798 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000799
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100800 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
802 else /* hextype == HEX_BITS */
803 grplen = 8 * octspergrp + 1;
804
DungSagad1d8a592021-11-26 13:59:27 +0000805 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806 {
DungSaga48608b42021-11-24 11:18:07 +0000807 int x;
808
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809 if (p == 0)
810 {
DungSaga581f41a2021-11-22 11:57:31 +0000811 addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
Bram Moolenaar363d6142020-05-30 20:50:25 +0200812 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100813 for (c = addrlen; c < LLEN; l[c++] = ' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814 }
DungSaga48608b42021-11-24 11:18:07 +0000815 x = hextype == HEX_LITTLEENDIAN ? p ^ (octspergrp-1) : p;
816 c = addrlen + 1 + (grplen * x) / octspergrp;
DungSaga581f41a2021-11-22 11:57:31 +0000817 if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818 {
DungSaga48608b42021-11-24 11:18:07 +0000819 l[c] = hexx[(e >> 4) & 0xf];
DungSaga581f41a2021-11-22 11:57:31 +0000820 l[++c] = hexx[e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 }
822 else /* hextype == HEX_BITS */
823 {
824 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000825 for (i = 7; i >= 0; i--)
DungSaga48608b42021-11-24 11:18:07 +0000826 l[c++] = (e & (1 << i)) ? '1' : '0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100828 if (e)
829 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 if (ebcdic)
831 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000832 /* When changing this update definition of LLEN above. */
DungSaga48608b42021-11-24 11:18:07 +0000833 c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p;
834 l[c++] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835#ifdef __MVS__
836 (e >= 64)
837#else
838 (e > 31 && e < 127)
839#endif
840 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 n++;
842 if (++p == cols)
843 {
DungSaga48608b42021-11-24 11:18:07 +0000844 l[c] = '\n';
845 l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 xxdline(fpo, l, autoskip ? nonzero : 1);
847 nonzero = 0;
848 p = 0;
849 }
850 }
851 if (p)
852 {
DungSaga48608b42021-11-24 11:18:07 +0000853 l[c] = '\n';
854 l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855 xxdline(fpo, l, 1);
856 }
857 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000858 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000859
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000860 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000861 return 0;
862}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200863
864/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */