1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-16 17:19:41 +00:00
emacs/lib-src/hexl.c
Paul Eggert f6ef15cf84 Use unlocked stdio more systematically
This can improve performance significantly on stdio-bottlenecked code.
E.g., make-docfile is 3x faster on my Fedora 25 x86-64 desktop.
* admin/merge-gnulib (GNULIB_MODULES): Add unlocked-io.
* lib-src/ebrowse.c, lib-src/emacsclient.c, lib-src/etags.c:
* lib-src/hexl.c, lib-src/make-docfile.c, lib-src/movemail.c:
* lib-src/profile.c, lib-src/update-game-score.c:
Include unlocked-io.h instead of stdio.h, since these programs are
single-threaded.
* lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
* lib/unlocked-io.h, m4/unlocked-io.m4: New files, copied from Gnulib.
* src/charset.c, src/cm.c, src/emacs.c, src/image.c, src/keyboard.c:
* src/lread.c, src/term.c:
Include sysstdio.h, possibly instead of stdio.h, to define
the unlocked functions if the system does not provide them.
* src/charset.c, src/lread.c (getc_unlocked):
Remove, since sysstdio.h now defines it if needed.
* src/cm.c (cmputc, cmcheckmagic):
* src/dispnew.c (update_frame, update_frame_with_menu)
(update_frame_1, Fsend_string_to_terminal, Fding, bitch_at_user):
* src/emacs.c (main, Fdump_emacs):
* src/fileio.c (Fdo_auto_save, Fset_binary_mode):
* src/image.c (slurp_file, png_read_from_file, png_load_body)
(our_stdio_fill_input_buffer):
* src/keyboard.c (record_char, kbd_buffer_get_event, handle_interrupt):
* src/lread.c (readbyte_from_file):
* src/minibuf.c (read_minibuf_noninteractive):
* src/print.c (printchar_to_stream, strout)
(Fredirect_debugging_output):
* src/sysdep.c (reset_sys_modes, procfs_ttyname)
(procfs_get_total_memory):
* src/term.c (tty_ring_bell, tty_send_additional_strings)
(tty_set_terminal_modes, tty_reset_terminal_modes)
(tty_update_end, tty_clear_end_of_line, tty_write_glyphs)
(tty_write_glyphs_with_face, tty_insert_glyphs)
(tty_menu_activate):
* src/xfaces.c (Fx_load_color_file):
Use unlocked stdio when it should be safe.
* src/sysstdio.h (clearerr_unlocked, feof_unlocked, ferror_unlocked)
(fflush_unlocked, fgets_unlocked, fputc_unlocked, fputs_unlocked)
(fread_unlocked, fwrite_unlocked, getc_unlocked, getchar_unlocked)
(putc_unlocked, putchar_unloced): Provide substitutes if not declared.
2017-06-22 11:22:53 -07:00

222 lines
4.5 KiB
C

/* Convert files for Emacs Hexl mode.
Copyright (C) 1989, 2001-2017 Free Software Foundation, Inc.
Author: Keith Gabryelski (according to authors.el)
This file is not considered part of GNU Emacs.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <binary-io.h>
#include <unlocked-io.h>
static char *progname;
static _Noreturn void
output_error (void)
{
fprintf (stderr, "%s: write error\n", progname);
exit (EXIT_FAILURE);
}
static int
hexchar (int c)
{
return c - ('0' <= c && c <= '9' ? '0' : 'a' - 10);
}
int
main (int argc, char **argv)
{
int status = EXIT_SUCCESS;
int DEFAULT_GROUPING = 0x01;
int group_by = DEFAULT_GROUPING;
bool un_flag = false, iso_flag = false;
progname = *argv++;
/*
** -hex hex dump
** -group-by-8-bits
** -group-by-16-bits
** -group-by-32-bits
** -group-by-64-bits
** -iso iso character set.
** -un || -de from hexl format to binary.
** -- End switch list.
** <filename> dump filename
** - (as filename == stdin)
*/
for (; *argv && *argv[0] == '-' && (*argv)[1]; argv++)
{
/* A switch! */
if (!strcmp (*argv, "--"))
{
argv++;
break;
}
else if (!strcmp (*argv, "-un") || !strcmp (*argv, "-de"))
{
un_flag = true;
set_binary_mode (fileno (stdout), O_BINARY);
}
else if (!strcmp (*argv, "-hex"))
/* Hex is the default and is only base supported. */;
else if (!strcmp (*argv, "-iso"))
iso_flag = true;
else if (!strcmp (*argv, "-group-by-8-bits"))
group_by = 0x00;
else if (!strcmp (*argv, "-group-by-16-bits"))
group_by = 0x01;
else if (!strcmp (*argv, "-group-by-32-bits"))
group_by = 0x03;
else if (!strcmp (*argv, "-group-by-64-bits"))
group_by = 0x07;
else
{
fprintf (stderr, "%s: invalid switch: \"%s\".\n", progname,
*argv);
fprintf (stderr, "usage: %s [-de] [-iso]\n", progname);
return EXIT_FAILURE;
}
}
char const *filename = *argv ? *argv++ : "-";
do
{
FILE *fp;
if (!strcmp (filename, "-"))
{
fp = stdin;
if (!un_flag)
set_binary_mode (fileno (stdin), O_BINARY);
}
else
{
fp = fopen (filename, un_flag ? "r" : "rb");
if (!fp)
{
perror (filename);
status = EXIT_FAILURE;
continue;
}
}
if (un_flag)
{
for (int c; 0 <= (c = getc (fp)); )
{
/* Skip address at start of line. */
if (c != ' ')
continue;
for (int i = 0; i < 16; i++)
{
c = getc (fp);
if (c < 0 || c == ' ')
break;
int hc = hexchar (c);
c = getc (fp);
if (c < 0)
break;
putchar (hc * 0x10 + hexchar (c));
if ((i & group_by) == group_by)
{
c = getc (fp);
if (c < 0)
break;
}
}
while (0 <= c && c != '\n')
c = getc (fp);
if (c < 0)
break;
if (ferror (stdout))
output_error ();
}
}
else
{
int c = 0;
char string[18];
string[0] = ' ';
string[17] = '\0';
for (uintmax_t address = 0; 0 <= c; address += 0x10)
{
int i;
for (i = 0; i < 16; i++)
{
if (0 <= c)
c = getc (fp);
if (c < 0)
{
if (!i)
break;
fputs (" ", stdout);
string[i + 1] = '\0';
}
else
{
if (!i)
printf ("%08"PRIxMAX": ", address);
string[i + 1]
= (c < 0x20 || (0x7F <= c && (!iso_flag || c < 0xa0))
? '.' : c);
printf ("%02x", c + 0u);
}
if ((i & group_by) == group_by)
putchar (' ');
}
if (i)
puts (string);
if (ferror (stdout))
output_error ();
}
}
bool trouble = ferror (fp) != 0;
trouble |= fp != stdin && fclose (fp) != 0;
if (trouble)
{
fprintf (stderr, "%s: read error\n", progname);
status = EXIT_FAILURE;
}
filename = *argv++;
}
while (filename);
if (ferror (stdout) || fclose (stdout) != 0)
output_error ();
return status;
}