diff options
author | Jim Meyering <jim@meyering.net> | 1998-01-22 08:55:13 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 1998-01-22 08:55:13 +0000 |
commit | d82fadf3653a507b9ca79a5884920fc0b3fdeb15 (patch) | |
tree | e2245fd7acccd350e3857f7bceb39e8f8f17a312 /src | |
parent | ef63ce007d9bc2ced67f452c29c0a404ea508f1f (diff) | |
download | coreutils-d82fadf3653a507b9ca79a5884920fc0b3fdeb15.tar.xz |
Reorder functions to obviate forward dcls.
Diffstat (limited to 'src')
-rw-r--r-- | src/dd.c | 1074 |
1 files changed, 531 insertions, 543 deletions
@@ -65,23 +65,6 @@ int safe_read (); int full_write (); -static RETSIGTYPE interrupt_handler PARAMS ((int)); -static int bit_count PARAMS ((register unsigned int i)); -static uintmax_t parse_integer PARAMS ((char *str, int *)); -static void apply_translations PARAMS ((void)); -static void copy PARAMS ((void)); -static void copy_simple PARAMS ((unsigned char *buf, int nread)); -static void copy_with_block PARAMS ((unsigned char *buf, int nread)); -static void copy_with_unblock PARAMS ((unsigned char *buf, int nread)); -static void parse_conversion PARAMS ((char *str)); -static void translate_charset PARAMS ((const unsigned char *new_trans)); -static void quit PARAMS ((int code)); -static void scanargs PARAMS ((int argc, char **argv)); -static void skip PARAMS ((int fdesc, char *file, uintmax_t records, - size_t blocksize, unsigned char *buf)); -static void usage PARAMS ((int status)); -static void write_output PARAMS ((void)); - /* The name this program was run with. */ char *program_name; @@ -141,6 +124,15 @@ static uintmax_t r_truncate = 0; static unsigned char newline_character = '\n'; static unsigned char space_character = ' '; +/* Output buffer. */ +static unsigned char *obuf; + +/* Current index into `obuf'. */ +static size_t oc = 0; + +/* Index into current line, for `conv=block' and `conv=unblock'. */ +static size_t col = 0; + struct conversion { char *convname; @@ -288,6 +280,74 @@ static struct option const long_options[] = }; static void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]...\n"), program_name); + printf (_("\ +Copy a file, converting and formatting according to the options.\n\ +\n\ + bs=BYTES force ibs=BYTES and obs=BYTES\n\ + cbs=BYTES convert BYTES bytes at a time\n\ + conv=KEYWORDS convert the file as per the comma separated keyword list\n\ + count=BLOCKS copy only BLOCKS input blocks\n\ + ibs=BYTES read BYTES bytes at a time\n\ + if=FILE read from FILE instead of stdin\n\ + obs=BYTES write BYTES bytes at a time\n\ + of=FILE write to FILE instead of stdout\n\ + seek=BLOCKS skip BLOCKS obs-sized blocks at start of output\n\ + skip=BLOCKS skip BLOCKS ibs-sized blocks at start of input\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +BYTES may be suffixed: by xM for multiplication by M, by c for x1,\n\ +by w for x2, by b for x512, by k for x1024. Each KEYWORD may be:\n\ +\n\ + ascii from EBCDIC to ASCII\n\ + ebcdic from ASCII to EBCDIC\n\ + ibm from ASCII to alternated EBCDIC\n\ + block pad newline-terminated records with spaces to cbs-size\n\ + unblock replace trailing spaces in cbs-size records with newline\n\ + lcase change upper case to lower case\n\ + notrunc do not truncate the output file\n\ + ucase change lower case to upper case\n\ + swab swap every pair of input bytes\n\ + noerror continue after read errors\n\ + sync pad every input block with NULs to ibs-size\n\ +")); + puts (_("\nReport bugs to <fileutils-bugs@gnu.org>.")); + close_stdout (); + } + exit (status); +} + +static void +translate_charset (const unsigned char *new_trans) +{ + int i; + + for (i = 0; i < 256; i++) + trans_table[i] = new_trans[trans_table[i]]; + translation_needed = 1; +} + +/* Return the number of 1 bits in `i'. */ + +static int +bit_count (register unsigned int i) +{ + register int set_bits; + + for (set_bits = 0; i != 0; set_bits++) + i &= i - 1; + return set_bits; +} + +static void print_stats (void) { char buf[2][LONGEST_HUMAN_READABLE + 1]; @@ -298,11 +358,47 @@ print_stats (void) human_readable (w_full, buf[0], 1, 1, 0), human_readable (w_partial, buf[1], 1, 1, 0)); if (r_truncate > 0) - fprintf (stderr, "%s %s\n", - human_readable (r_truncate, buf[0], 1, 1, 0), - (r_truncate == 1 - ? _("truncated record") - : _("truncated records"))); + { + fprintf (stderr, "%s %s\n", + human_readable (r_truncate, buf[0], 1, 1, 0), + (r_truncate == 1 + ? _("truncated record") + : _("truncated records"))); + } +} + +static void +cleanup (void) +{ + print_stats (); + if (close (input_fd) < 0) + error (1, errno, "%s", input_file); + if (close (output_fd) < 0) + error (1, errno, "%s", output_file); +} + +static void +quit (int code) +{ + cleanup (); + exit (code); +} + +static RETSIGTYPE +interrupt_handler (int sig) +{ +#ifdef SA_INTERRUPT + struct sigaction sigact; + + sigact.sa_handler = SIG_DFL; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig, &sigact, NULL); +#else /* !SA_INTERRUPT */ + signal (sig, SIG_DFL); +#endif /* SA_INTERRUPT */ + cleanup (); + kill (getpid (), sig); } static RETSIGTYPE @@ -332,125 +428,260 @@ install_handler (int sig_num, RETSIGTYPE (*sig_handler) (int sig)) #endif } -int -main (int argc, char **argv) +/* Write, then empty, the output buffer `obuf'. */ + +static void +write_output (void) { + int nwritten = full_write (output_fd, obuf, output_blocksize); + if (nwritten != output_blocksize) + { + error (0, errno, "%s", output_file); + if (nwritten > 0) + w_partial++; + quit (1); + } + else + w_full++; + oc = 0; +} + +/* Interpret one "conv=..." option. */ + +static void +parse_conversion (char *str) +{ + char *new; int i; - program_name = argv[0]; - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + do + { + new = strchr (str, ','); + if (new != NULL) + *new++ = '\0'; + for (i = 0; conversions[i].convname != NULL; i++) + if (STREQ (conversions[i].convname, str)) + { + conversions_mask |= conversions[i].conversion; + break; + } + if (conversions[i].convname == NULL) + { + error (0, 0, _("%s: invalid conversion"), str); + usage (1); + } + str = new; + } while (new != NULL); +} - /* Initialize translation table to identity translation. */ - for (i = 0; i < 256; i++) - trans_table[i] = i; +/* Return the value of STR, interpreted as a non-negative decimal integer, + optionally multiplied by various values. + Assign nonzero to *INVALID if STR does not represent a number in + this format. */ - /* Decode arguments. */ - scanargs (argc, argv); +/* FIXME: use xstrtou?[lq] */ - if (show_version) +static uintmax_t +parse_integer (char *str, int *invalid) +{ + register uintmax_t n = 0; + register char *p = str; + + while (ISDIGIT (*p)) { - printf ("dd (%s) %s\n", GNU_PACKAGE, VERSION); - close_stdout (); - exit (0); + uintmax_t n10 = n * 10; + int digit = *p - '0'; + if (! (n10 / 10 == n && n10 <= n10 + digit)) + { + *invalid = 1; + return 0; + } + n = n10 + digit; + p++; } - if (show_help) - usage (0); + for (;;) + { + uintmax_t multiplier; - apply_translations (); + switch (*p++) + { + case '\0': + return n; + case 'b': + multiplier = 512; + break; + case 'c': + continue; + case 'k': + multiplier = 1024; + break; + case 'w': + multiplier = 2; + break; + case 'x': + multiplier = parse_integer (p, invalid); + p = ""; + break; + default: + { + *invalid = 1; + return 0; + } + } - if (input_file != NULL) - { - input_fd = open (input_file, O_RDONLY); - if (input_fd < 0) - error (1, errno, "%s", input_file); + if (multiplier != 0 && n * multiplier / multiplier != n) + { + *invalid = 1; + return 0; + } + + n *= multiplier; } - else - input_file = _("standard input"); +} - if (input_fd == output_fd) - error (1, 0, _("%s is closed"), (input_fd == 0 - ? _("standard input") - : _("standard output"))); +static void +scanargs (int argc, char **argv) +{ + int i; + int c; - if (output_file != NULL) + while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1) { - int omode = O_RDWR | O_CREAT; - - if (seek_record == 0 && !(conversions_mask & C_NOTRUNC)) - omode |= O_TRUNC; - output_fd = open (output_file, omode, 0666); - if (output_fd < 0) - error (1, errno, "%s", output_file); -#ifdef HAVE_FTRUNCATE - if (seek_record != 0 && !(conversions_mask & C_NOTRUNC)) + switch (c) { - off_t o = seek_record * output_blocksize; - if (o / output_blocksize != seek_record) - error (1, 0, _("file offset out of range")); - if (ftruncate (output_fd, o) < 0) - error (0, errno, "%s", output_file); + case 0: + break; + + default: + usage (1); } -#endif } - else + + for (i = optind; i < argc; i++) { - output_file = _("standard output"); - } + char *name, *val; - install_handler (SIGINT, interrupt_handler); - install_handler (SIGQUIT, interrupt_handler); - install_handler (SIGPIPE, interrupt_handler); - install_handler (SIGINFO, siginfo_handler); + name = argv[i]; + val = strchr (name, '='); + if (val == NULL) + { + error (0, 0, _("unrecognized option `%s'"), name); + usage (1); + } + *val++ = '\0'; + + if (STREQ (name, "if")) + input_file = val; + else if (STREQ (name, "of")) + output_file = val; + else if (STREQ (name, "conv")) + parse_conversion (val); + else + { + int invalid = 0; + uintmax_t n = parse_integer (val, &invalid); - copy (); + if (STREQ (name, "ibs")) + { + input_blocksize = n; + invalid |= input_blocksize != n || input_blocksize == 0; + conversions_mask |= C_TWOBUFS; + } + else if (STREQ (name, "obs")) + { + output_blocksize = n; + invalid |= output_blocksize != n || output_blocksize == 0; + conversions_mask |= C_TWOBUFS; + } + else if (STREQ (name, "bs")) + { + output_blocksize = input_blocksize = n; + invalid |= output_blocksize != n || output_blocksize == 0; + } + else if (STREQ (name, "cbs")) + { + conversion_blocksize = n; + invalid |= (conversion_blocksize != n + || conversion_blocksize == 0); + } + else if (STREQ (name, "skip")) + skip_records = n; + else if (STREQ (name, "seek")) + seek_record = n; + else if (STREQ (name, "count")) + max_records = n; + else + { + error (0, 0, _("unrecognized option `%s=%s'"), name, val); + usage (1); + } + + if (invalid) + error (1, 0, _("invalid number `%s'"), val); + } + } + + /* If bs= was given, both `input_blocksize' and `output_blocksize' will + have been set to positive values. If either has not been set, + bs= was not given, so make sure two buffers are used. */ + if (input_blocksize == 0 || output_blocksize == 0) + conversions_mask |= C_TWOBUFS; + if (input_blocksize == 0) + input_blocksize = DEFAULT_BLOCKSIZE; + if (output_blocksize == 0) + output_blocksize = DEFAULT_BLOCKSIZE; + if (conversion_blocksize == 0) + conversions_mask &= ~(C_BLOCK | C_UNBLOCK); } -/* Throw away RECORDS blocks of BLOCKSIZE bytes on file descriptor FDESC, - which is open with read permission for FILE. Store up to BLOCKSIZE - bytes of the data at a time in BUF, if necessary. */ +/* Fix up translation table. */ static void -skip (int fdesc, char *file, uintmax_t records, size_t blocksize, - unsigned char *buf) +apply_translations (void) { - struct stat stats; - off_t o; + int i; - /* Use fstat instead of checking for errno == ESPIPE because - lseek doesn't work on some special files but doesn't return an - error, either. */ - /* FIXME: can this really happen? What system? */ - if (fstat (fdesc, &stats)) +#define MX(a) (bit_count (conversions_mask & (a))) + if ((MX (C_ASCII | C_EBCDIC | C_IBM) > 1) + || (MX (C_BLOCK | C_UNBLOCK) > 1) + || (MX (C_LCASE | C_UCASE) > 1) + || (MX (C_UNBLOCK | C_SYNC) > 1)) { - error (0, errno, "%s", file); - quit (1); + error (1, 0, _("\ +only one conv in {ascii,ebcdic,ibm}, {lcase,ucase}, {block,unblock}, {unblock,sync}")); } +#undef MX - /* Try lseek and if an error indicates it was an inappropriate - operation, fall back on using read. */ - o = records * blocksize; - if (o / blocksize != records - || lseek (fdesc, o, SEEK_SET) == -1) + if (conversions_mask & C_ASCII) + translate_charset (ebcdic_to_ascii); + + if (conversions_mask & C_UCASE) { - while (records-- > 0) - { - int nread; + for (i = 0; i < 256; i++) + if (ISLOWER (trans_table[i])) + trans_table[i] = toupper (trans_table[i]); + translation_needed = 1; + } + else if (conversions_mask & C_LCASE) + { + for (i = 0; i < 256; i++) + if (ISUPPER (trans_table[i])) + trans_table[i] = tolower (trans_table[i]); + translation_needed = 1; + } - nread = safe_read (fdesc, buf, blocksize); - if (nread < 0) - { - error (0, errno, "%s", file); - quit (1); - } - /* POSIX doesn't say what to do when dd detects it has been - asked to skip past EOF, so I assume it's non-fatal. - FIXME: maybe give a warning. */ - if (nread == 0) - break; - } + if (conversions_mask & C_EBCDIC) + { + translate_charset (ascii_to_ebcdic); + newline_character = ascii_to_ebcdic['\n']; + space_character = ascii_to_ebcdic[' ']; + } + else if (conversions_mask & C_IBM) + { + translate_charset (ascii_to_ibm); + newline_character = ascii_to_ibm['\n']; + space_character = ascii_to_ibm[' ']; } } @@ -511,18 +742,149 @@ swab_buffer (unsigned char *buf, int *nread) return ++bufstart; } -/* Output buffer. */ -static unsigned char *obuf; +/* Throw away RECORDS blocks of BLOCKSIZE bytes on file descriptor FDESC, + which is open with read permission for FILE. Store up to BLOCKSIZE + bytes of the data at a time in BUF, if necessary. */ -/* Current index into `obuf'. */ -static size_t oc = 0; +static void +skip (int fdesc, char *file, uintmax_t records, size_t blocksize, + unsigned char *buf) +{ + struct stat stats; + off_t o; -/* Index into current line, for `conv=block' and `conv=unblock'. */ -static size_t col = 0; + /* Use fstat instead of checking for errno == ESPIPE because + lseek doesn't work on some special files but doesn't return an + error, either. */ + /* FIXME: can this really happen? What system? */ + if (fstat (fdesc, &stats)) + { + error (0, errno, "%s", file); + quit (1); + } -/* The main loop. */ + /* Try lseek and if an error indicates it was an inappropriate + operation, fall back on using read. */ + o = records * blocksize; + if (o / blocksize != records + || lseek (fdesc, o, SEEK_SET) == -1) + { + while (records-- > 0) + { + int nread; + + nread = safe_read (fdesc, buf, blocksize); + if (nread < 0) + { + error (0, errno, "%s", file); + quit (1); + } + /* POSIX doesn't say what to do when dd detects it has been + asked to skip past EOF, so I assume it's non-fatal. + FIXME: maybe give a warning. */ + if (nread == 0) + break; + } + } +} + +/* Copy NREAD bytes of BUF, with no conversions. */ + +static void +copy_simple (unsigned char *buf, int nread) +{ + int nfree; /* Number of unused bytes in `obuf'. */ + unsigned char *start = buf; /* First uncopied char in BUF. */ + + do + { + nfree = output_blocksize - oc; + if (nfree > nread) + nfree = nread; + + memcpy ((char *) (obuf + oc), (char *) start, nfree); + + nread -= nfree; /* Update the number of bytes left to copy. */ + start += nfree; + oc += nfree; + if (oc >= output_blocksize) + write_output (); + } + while (nread > 0); +} + +/* Copy NREAD bytes of BUF, doing conv=block + (pad newline-terminated records to `conversion_blocksize', + replacing the newline with trailing spaces). */ + +static void +copy_with_block (unsigned char *buf, int nread) +{ + register int i; + + for (i = nread; i; i--, buf++) + { + if (*buf == newline_character) + { + if (col < conversion_blocksize) + { + size_t j; + for (j = col; j < conversion_blocksize; j++) + output_char (space_character); + } + col = 0; + } + else + { + if (col == conversion_blocksize) + r_truncate++; + else if (col < conversion_blocksize) + output_char (*buf); + col++; + } + } +} + +/* Copy NREAD bytes of BUF, doing conv=unblock + (replace trailing spaces in `conversion_blocksize'-sized records + with a newline). */ static void +copy_with_unblock (unsigned char *buf, int nread) +{ + register int i; + register unsigned char c; + static int pending_spaces = 0; + + for (i = 0; i < nread; i++) + { + c = buf[i]; + + if (col++ >= conversion_blocksize) + { + col = pending_spaces = 0; /* Wipe out any pending spaces. */ + i--; /* Push the char back; get it later. */ + output_char (newline_character); + } + else if (c == space_character) + pending_spaces++; + else + { + /* `c' is the character after a run of spaces that were not + at the end of the conversion buffer. Output them. */ + while (pending_spaces) + { + output_char (space_character); + --pending_spaces; + } + output_char (c); + } + } +} + +/* The main loop. */ + +static int copy (void) { unsigned char *ibuf, *bufstart; /* Input buffer. */ @@ -688,458 +1050,84 @@ copy (void) if (obuf != ibuf) free (obuf); - quit (exit_status); + return exit_status; } -/* Copy NREAD bytes of BUF, with no conversions. */ - -static void -copy_simple (unsigned char *buf, int nread) +int +main (int argc, char **argv) { - int nfree; /* Number of unused bytes in `obuf'. */ - unsigned char *start = buf; /* First uncopied char in BUF. */ - - do - { - nfree = output_blocksize - oc; - if (nfree > nread) - nfree = nread; - - memcpy ((char *) (obuf + oc), (char *) start, nfree); + int i; + int exit_status; - nread -= nfree; /* Update the number of bytes left to copy. */ - start += nfree; - oc += nfree; - if (oc >= output_blocksize) - write_output (); - } - while (nread > 0); -} + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); -/* Copy NREAD bytes of BUF, doing conv=block - (pad newline-terminated records to `conversion_blocksize', - replacing the newline with trailing spaces). */ + /* Initialize translation table to identity translation. */ + for (i = 0; i < 256; i++) + trans_table[i] = i; -static void -copy_with_block (unsigned char *buf, int nread) -{ - register int i; + /* Decode arguments. */ + scanargs (argc, argv); - for (i = nread; i; i--, buf++) + if (show_version) { - if (*buf == newline_character) - { - if (col < conversion_blocksize) - { - size_t j; - for (j = col; j < conversion_blocksize; j++) - output_char (space_character); - } - col = 0; - } - else - { - if (col == conversion_blocksize) - r_truncate++; - else if (col < conversion_blocksize) - output_char (*buf); - col++; - } + printf ("dd (%s) %s\n", GNU_PACKAGE, VERSION); + close_stdout (); + exit (0); } -} - -/* Copy NREAD bytes of BUF, doing conv=unblock - (replace trailing spaces in `conversion_blocksize'-sized records - with a newline). */ -static void -copy_with_unblock (unsigned char *buf, int nread) -{ - register int i; - register unsigned char c; - static int pending_spaces = 0; - - for (i = 0; i < nread; i++) - { - c = buf[i]; - - if (col++ >= conversion_blocksize) - { - col = pending_spaces = 0; /* Wipe out any pending spaces. */ - i--; /* Push the char back; get it later. */ - output_char (newline_character); - } - else if (c == space_character) - pending_spaces++; - else - { - /* `c' is the character after a run of spaces that were not - at the end of the conversion buffer. Output them. */ - while (pending_spaces) - { - output_char (space_character); - --pending_spaces; - } - output_char (c); - } - } -} + if (show_help) + usage (0); -/* Write, then empty, the output buffer `obuf'. */ + apply_translations (); -static void -write_output (void) -{ - int nwritten = full_write (output_fd, obuf, output_blocksize); - if (nwritten != output_blocksize) + if (input_file != NULL) { - error (0, errno, "%s", output_file); - if (nwritten > 0) - w_partial++; - quit (1); + input_fd = open (input_file, O_RDONLY); + if (input_fd < 0) + error (1, errno, "%s", input_file); } else - w_full++; - oc = 0; -} - -static void -scanargs (int argc, char **argv) -{ - int i; - int c; - - while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1) - { - switch (c) - { - case 0: - break; - - default: - usage (1); - } - } - - for (i = optind; i < argc; i++) - { - char *name, *val; - - name = argv[i]; - val = strchr (name, '='); - if (val == NULL) - { - error (0, 0, _("unrecognized option `%s'"), name); - usage (1); - } - *val++ = '\0'; - - if (STREQ (name, "if")) - input_file = val; - else if (STREQ (name, "of")) - output_file = val; - else if (STREQ (name, "conv")) - parse_conversion (val); - else - { - int invalid = 0; - uintmax_t n = parse_integer (val, &invalid); - - if (STREQ (name, "ibs")) - { - input_blocksize = n; - invalid |= input_blocksize != n || input_blocksize == 0; - conversions_mask |= C_TWOBUFS; - } - else if (STREQ (name, "obs")) - { - output_blocksize = n; - invalid |= output_blocksize != n || output_blocksize == 0; - conversions_mask |= C_TWOBUFS; - } - else if (STREQ (name, "bs")) - { - output_blocksize = input_blocksize = n; - invalid |= output_blocksize != n || output_blocksize == 0; - } - else if (STREQ (name, "cbs")) - { - conversion_blocksize = n; - invalid |= (conversion_blocksize != n - || conversion_blocksize == 0); - } - else if (STREQ (name, "skip")) - skip_records = n; - else if (STREQ (name, "seek")) - seek_record = n; - else if (STREQ (name, "count")) - max_records = n; - else - { - error (0, 0, _("unrecognized option `%s=%s'"), name, val); - usage (1); - } - - if (invalid) - error (1, 0, _("invalid number `%s'"), val); - } - } - - /* If bs= was given, both `input_blocksize' and `output_blocksize' will - have been set to positive values. If either has not been set, - bs= was not given, so make sure two buffers are used. */ - if (input_blocksize == 0 || output_blocksize == 0) - conversions_mask |= C_TWOBUFS; - if (input_blocksize == 0) - input_blocksize = DEFAULT_BLOCKSIZE; - if (output_blocksize == 0) - output_blocksize = DEFAULT_BLOCKSIZE; - if (conversion_blocksize == 0) - conversions_mask &= ~(C_BLOCK | C_UNBLOCK); -} - -/* Return the value of STR, interpreted as a non-negative decimal integer, - optionally multiplied by various values. - Assign nonzero to *INVALID if STR does not represent a number in - this format. */ - -/* FIXME: use xstrtou?[lq] */ - -static uintmax_t -parse_integer (char *str, int *invalid) -{ - register uintmax_t n = 0; - register char *p = str; + input_file = _("standard input"); - while (ISDIGIT (*p)) - { - uintmax_t n10 = n * 10; - int digit = *p - '0'; - if (! (n10 / 10 == n && n10 <= n10 + digit)) - { - *invalid = 1; - return 0; - } - n = n10 + digit; - p++; - } + if (input_fd == output_fd) + error (1, 0, _("%s is closed"), (input_fd == 0 + ? _("standard input") + : _("standard output"))); - for (;;) + if (output_file != NULL) { - uintmax_t multiplier; - - switch (*p++) - { - case '\0': - return n; - case 'b': - multiplier = 512; - break; - case 'c': - continue; - case 'k': - multiplier = 1024; - break; - case 'w': - multiplier = 2; - break; - case 'x': - multiplier = parse_integer (p, invalid); - p = ""; - break; - default: - { - *invalid = 1; - return 0; - } - } - - if (multiplier != 0 && n * multiplier / multiplier != n) - { - *invalid = 1; - return 0; - } - - n *= multiplier; - } -} - -/* Interpret one "conv=..." option. */ - -static void -parse_conversion (char *str) -{ - char *new; - int i; + int omode = O_RDWR | O_CREAT; - do - { - new = strchr (str, ','); - if (new != NULL) - *new++ = '\0'; - for (i = 0; conversions[i].convname != NULL; i++) - if (STREQ (conversions[i].convname, str)) - { - conversions_mask |= conversions[i].conversion; - break; - } - if (conversions[i].convname == NULL) + if (seek_record == 0 && !(conversions_mask & C_NOTRUNC)) + omode |= O_TRUNC; + output_fd = open (output_file, omode, 0666); + if (output_fd < 0) + error (1, errno, "%s", output_file); +#ifdef HAVE_FTRUNCATE + if (seek_record != 0 && !(conversions_mask & C_NOTRUNC)) { - error (0, 0, _("%s: invalid conversion"), str); - usage (1); + off_t o = seek_record * output_blocksize; + if (o / output_blocksize != seek_record) + error (1, 0, _("file offset out of range")); + if (ftruncate (output_fd, o) < 0) + error (0, errno, "%s", output_file); } - str = new; - } while (new != NULL); -} - -/* Fix up translation table. */ - -static void -apply_translations (void) -{ - int i; - -#define MX(a) (bit_count (conversions_mask & (a))) - if ((MX (C_ASCII | C_EBCDIC | C_IBM) > 1) - || (MX (C_BLOCK | C_UNBLOCK) > 1) - || (MX (C_LCASE | C_UCASE) > 1) - || (MX (C_UNBLOCK | C_SYNC) > 1)) - { - error (1, 0, _("\ -only one conv in {ascii,ebcdic,ibm}, {lcase,ucase}, {block,unblock}, {unblock,sync}")); - } -#undef MX - - if (conversions_mask & C_ASCII) - translate_charset (ebcdic_to_ascii); - - if (conversions_mask & C_UCASE) - { - for (i = 0; i < 256; i++) - if (ISLOWER (trans_table[i])) - trans_table[i] = toupper (trans_table[i]); - translation_needed = 1; - } - else if (conversions_mask & C_LCASE) - { - for (i = 0; i < 256; i++) - if (ISUPPER (trans_table[i])) - trans_table[i] = tolower (trans_table[i]); - translation_needed = 1; - } - - if (conversions_mask & C_EBCDIC) - { - translate_charset (ascii_to_ebcdic); - newline_character = ascii_to_ebcdic['\n']; - space_character = ascii_to_ebcdic[' ']; +#endif } - else if (conversions_mask & C_IBM) + else { - translate_charset (ascii_to_ibm); - newline_character = ascii_to_ibm['\n']; - space_character = ascii_to_ibm[' ']; + output_file = _("standard output"); } -} - -static void -translate_charset (const unsigned char *new_trans) -{ - int i; - - for (i = 0; i < 256; i++) - trans_table[i] = new_trans[trans_table[i]]; - translation_needed = 1; -} - -/* Return the number of 1 bits in `i'. */ - -static int -bit_count (register unsigned int i) -{ - register int set_bits; - - for (set_bits = 0; i != 0; set_bits++) - i &= i - 1; - return set_bits; -} - -static void -cleanup (void) -{ - print_stats (); - if (close (input_fd) < 0) - error (1, errno, "%s", input_file); - if (close (output_fd) < 0) - error (1, errno, "%s", output_file); -} - -static void -quit (int code) -{ - cleanup (); - exit (code); -} -static RETSIGTYPE -interrupt_handler (int sig) -{ -#ifdef SA_INTERRUPT - struct sigaction sigact; + install_handler (SIGINT, interrupt_handler); + install_handler (SIGQUIT, interrupt_handler); + install_handler (SIGPIPE, interrupt_handler); + install_handler (SIGINFO, siginfo_handler); - sigact.sa_handler = SIG_DFL; - sigemptyset (&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction (sig, &sigact, NULL); -#else /* !SA_INTERRUPT */ - signal (sig, SIG_DFL); -#endif /* SA_INTERRUPT */ - cleanup (); - kill (getpid (), sig); -} + exit_status = copy (); -static void -usage (int status) -{ - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); - else - { - printf (_("Usage: %s [OPTION]...\n"), program_name); - printf (_("\ -Copy a file, converting and formatting according to the options.\n\ -\n\ - bs=BYTES force ibs=BYTES and obs=BYTES\n\ - cbs=BYTES convert BYTES bytes at a time\n\ - conv=KEYWORDS convert the file as per the comma separated keyword list\n\ - count=BLOCKS copy only BLOCKS input blocks\n\ - ibs=BYTES read BYTES bytes at a time\n\ - if=FILE read from FILE instead of stdin\n\ - obs=BYTES write BYTES bytes at a time\n\ - of=FILE write to FILE instead of stdout\n\ - seek=BLOCKS skip BLOCKS obs-sized blocks at start of output\n\ - skip=BLOCKS skip BLOCKS ibs-sized blocks at start of input\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -\n\ -BYTES may be suffixed: by xM for multiplication by M, by c for x1,\n\ -by w for x2, by b for x512, by k for x1024. Each KEYWORD may be:\n\ -\n\ - ascii from EBCDIC to ASCII\n\ - ebcdic from ASCII to EBCDIC\n\ - ibm from ASCII to alternated EBCDIC\n\ - block pad newline-terminated records with spaces to cbs-size\n\ - unblock replace trailing spaces in cbs-size records with newline\n\ - lcase change upper case to lower case\n\ - notrunc do not truncate the output file\n\ - ucase change lower case to upper case\n\ - swab swap every pair of input bytes\n\ - noerror continue after read errors\n\ - sync pad every input block with NULs to ibs-size\n\ -")); - puts (_("\nReport bugs to <fileutils-bugs@gnu.org>.")); - close_stdout (); - } - exit (status); + quit (exit_status); } |