root/lib-src/hexl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. output_error
  2. hexchar
  3. main

     1 /* Convert files for Emacs Hexl mode.
     2    Copyright (C) 1989, 2001-2023 Free Software Foundation, Inc.
     3 
     4 Author: Keith Gabryelski (according to authors.el)
     5 
     6 This file is not considered part of GNU Emacs.
     7 
     8 This program is free software: you can redistribute it and/or modify
     9 it under the terms of the GNU General Public License as published by
    10 the Free Software Foundation, either version 3 of the License, or (at
    11 your option) any later version.
    12 
    13 This program is distributed in the hope that it will be useful,
    14 but WITHOUT ANY WARRANTY; without even the implied warranty of
    15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16 GNU General Public License for more details.
    17 
    18 You should have received a copy of the GNU General Public License
    19 along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
    20 
    21 
    22 #include <config.h>
    23 
    24 #include <inttypes.h>
    25 #include <stdlib.h>
    26 #include <string.h>
    27 
    28 #include <binary-io.h>
    29 #include <unlocked-io.h>
    30 
    31 static char *progname;
    32 
    33 static _Noreturn void
    34 output_error (void)
    35 {
    36   fprintf (stderr, "%s: write error\n", progname);
    37   exit (EXIT_FAILURE);
    38 }
    39 
    40 static int
    41 hexchar (int c)
    42 {
    43   return c - ('0' <= c && c <= '9' ? '0' : 'a' - 10);
    44 }
    45 
    46 int
    47 main (int argc, char **argv)
    48 {
    49   int status = EXIT_SUCCESS;
    50   int DEFAULT_GROUPING = 0x01;
    51   int group_by = DEFAULT_GROUPING;
    52   bool un_flag = false, iso_flag = false;
    53   progname = *argv++;
    54 
    55   /*
    56    ** -hex              hex dump
    57    ** -group-by-8-bits
    58    ** -group-by-16-bits
    59    ** -group-by-32-bits
    60    ** -group-by-64-bits
    61    ** -iso              iso character set.
    62    ** -un || -de        from hexl format to binary.
    63    ** --                End switch list.
    64    ** <filename>        dump filename
    65    ** -         (as filename == stdin)
    66    */
    67 
    68   for (; *argv && *argv[0] == '-' && (*argv)[1]; argv++)
    69     {
    70       /* A switch! */
    71       if (!strcmp (*argv, "--"))
    72         {
    73           argv++;
    74           break;
    75         }
    76       else if (!strcmp (*argv, "-un") || !strcmp (*argv, "-de"))
    77         {
    78           un_flag = true;
    79           set_binary_mode (fileno (stdout), O_BINARY);
    80         }
    81       else if (!strcmp (*argv, "-hex"))
    82         /* Hex is the default and is only base supported.  */;
    83       else if (!strcmp (*argv, "-iso"))
    84         iso_flag = true;
    85       else if (!strcmp (*argv, "-group-by-8-bits"))
    86         group_by = 0x00;
    87       else if (!strcmp (*argv, "-group-by-16-bits"))
    88         group_by = 0x01;
    89       else if (!strcmp (*argv, "-group-by-32-bits"))
    90         group_by = 0x03;
    91       else if (!strcmp (*argv, "-group-by-64-bits"))
    92         group_by = 0x07;
    93       else
    94         {
    95           fprintf (stderr, "%s: invalid switch: \"%s\".\n", progname,
    96                    *argv);
    97           fprintf (stderr, "usage: %s [-de] [-iso]\n", progname);
    98           return EXIT_FAILURE;
    99         }
   100     }
   101 
   102   char const *filename = *argv ? *argv++ : "-";
   103 
   104   do
   105     {
   106       FILE *fp;
   107 
   108       if (!strcmp (filename, "-"))
   109         {
   110           fp = stdin;
   111           if (!un_flag)
   112             set_binary_mode (fileno (stdin), O_BINARY);
   113         }
   114       else
   115         {
   116           fp = fopen (filename, un_flag ? "r" : "rb");
   117           if (!fp)
   118             {
   119               perror (filename);
   120               status = EXIT_FAILURE;
   121               continue;
   122             }
   123         }
   124 
   125       if (un_flag)
   126         {
   127           for (int c; 0 <= (c = getc (fp)); )
   128             {
   129               /* Skip address at start of line.  */
   130               if (c != ' ')
   131                 continue;
   132 
   133               for (int i = 0; i < 16; i++)
   134                 {
   135                   c = getc (fp);
   136                   if (c < 0 || c == ' ')
   137                     break;
   138 
   139                   int hc = hexchar (c);
   140                   c = getc (fp);
   141                   if (c < 0)
   142                     break;
   143                   putchar (hc * 0x10 + hexchar (c));
   144 
   145                   if ((i & group_by) == group_by)
   146                     {
   147                       c = getc (fp);
   148                       if (c < 0)
   149                         break;
   150                     }
   151                 }
   152 
   153               while (0 <= c && c != '\n')
   154                 c = getc (fp);
   155               if (c < 0)
   156                 break;
   157               if (ferror (stdout))
   158                 output_error ();
   159             }
   160         }
   161       else
   162         {
   163           int c = 0;
   164           char string[18];
   165           string[0] = ' ';
   166           string[17] = '\0';
   167           for (uintmax_t address = 0; 0 <= c; address += 0x10)
   168             {
   169               int i;
   170               for (i = 0; i < 16; i++)
   171                 {
   172                   if (0 <= c)
   173                     c = getc (fp);
   174                   if (c < 0)
   175                     {
   176                       if (!i)
   177                         break;
   178 
   179                       fputs ("  ", stdout);
   180                       string[i + 1] = '\0';
   181                     }
   182                   else
   183                     {
   184                       if (!i)
   185                         printf ("%08"PRIxMAX": ", address);
   186 
   187                       string[i + 1]
   188                         = (c < 0x20 || (0x7F <= c && (!iso_flag || c < 0xa0))
   189                            ? '.' : c);
   190 
   191                       printf ("%02x", c + 0u);
   192                     }
   193 
   194                   if ((i & group_by) == group_by)
   195                     putchar (' ');
   196                 }
   197 
   198               if (i)
   199                 puts (string);
   200 
   201               if (ferror (stdout))
   202                 output_error ();
   203             }
   204         }
   205 
   206       bool trouble = ferror (fp) != 0;
   207       trouble |= fp != stdin && fclose (fp) != 0;
   208       if (trouble)
   209         {
   210           fprintf (stderr, "%s: read error\n", progname);
   211           status = EXIT_FAILURE;
   212         }
   213 
   214       filename = *argv++;
   215     }
   216   while (filename);
   217 
   218   if (ferror (stdout) || fclose (stdout) != 0)
   219     output_error ();
   220   return status;
   221 }

/* [<][>][^][v][top][bottom][index][help] */