123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- /*
- * dd.c -- convert and copy files. phr 22-march-85.
- */
- #include <ctype.h>
- #include <stdio.h>
- #define equal(p, q) (strcmp ((p),(q)) == 0)
- #define max(a, b) ((a) > (b) ? (a) : (b))
- #define BLOCKSIZE 512 /* Unix dd uses this so we do too */
- #define C_ASCII 01
- #define C_EBCDIC 02
- #define C_IBM 04
- #define C_BLOCK 010
- #define C_UNBLOCK 020
- #define C_LCASE 040
- #define C_UCASE 0100
- #define C_SWAB 0200
- #define C_NOERROR 0400
- #define C_SYNC 01000
- #define C_DEBUG 02000
- #define C_HARDWAY 04000 /* some conversion is needed during i/o */
- struct info
- {
- char *i_if; /* input filename */
- int i_ifd; /* input file descriptor */
- char *i_of; /* output filename */
- int i_ofd; /* output file descriptor */
- int i_ibs; /* input blocksize */
- int i_obs; /* output blocksize */
- int i_cbs; /* conversion buffer size */
- int i_skip; /* skip this many records on input */
- int i_files; /* skip this many files on input (TODO) */
- int i_seek; /* seek to this record on output */
- int i_count; /* copy only this many records */
- int i_convert; /* bit vector of conversions to apply */
- } info = { NULL, 0, NULL, 1, BLOCKSIZE, BLOCKSIZE, BLOCKSIZE, 0, 0, 0, -1, 0};
- int w_partial = 0; /* number of partial blocks written */
- int w_full = 0; /* numer of full blocks written */
- int r_partial = 0; /* number of partial blocks read */
- int r_full = 0; /* number of full blocks read */
- int r_truncate = 0; /* records truncated by conv=block */
- struct conversion
- {
- char *convname;
- int conversion;
- } conversions[] = {
- "ascii", C_ASCII | C_HARDWAY, /* ebcdic to ascii */
- "ebcdic", C_EBCDIC | C_HARDWAY, /* ascii to ebcdic */
- "ibm", C_IBM | C_HARDWAY, /* slightly different atoe */
- "block", C_BLOCK | C_HARDWAY, /* var to fixed len recs */
- "unblock", C_UNBLOCK | C_HARDWAY, /* fixed to var */
- "lcase", C_LCASE | C_HARDWAY, /* translate upper to lower */
- "ucase", C_UCASE | C_HARDWAY, /* translate lower to upper */
- "swab", C_SWAB | C_HARDWAY, /* swap bytes of input */
- "noerror", C_NOERROR, /* ignore i/o errors */
- "sync", C_SYNC, /* pad input recs to ibs */
- "debug", C_DEBUG, /* debugging output flag */
- NULL, 0,
- };
- char trans_table[256]; /* translation table formed by applying */
- /* successive transformations */
- char ascii_to_ebcdic[] = {
- 0, 01, 02, 03, 067, 055, 056, 057,
- 026, 05, 045, 013, 014, 015, 016, 017,
- 020, 021, 022, 023, 074, 075, 062, 046,
- 030, 031, 077, 047, 034, 035, 036, 037,
- 0100, 0117, 0177, 0173, 0133, 0154, 0120, 0175,
- 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,
- 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
- 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,
- 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
- 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,
- 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,
- 0347, 0350, 0351, 0112, 0340, 0132, 0137, 0155,
- 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
- 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,
- 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,
- 0247, 0250, 0251, 0300, 0152, 0320, 0241, 07,
- 040, 041, 042, 043, 044, 025, 06, 027,
- 050, 051, 052, 053, 054, 011, 012, 033,
- 060, 061, 032, 063, 064, 065, 066, 010,
- 070, 071, 072, 073, 04, 024, 076, 0341,
- 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,
- 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
- 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,
- 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,
- 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,
- 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236,
- 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257,
- 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
- 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
- 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,
- 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,
- 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,
- };
- char ascii_to_ibm[] = {
- 0, 01, 02, 03, 067, 055, 056, 057,
- 026, 05, 045, 013, 014, 015, 016, 017,
- 020, 021, 022, 023, 074, 075, 062, 046,
- 030, 031, 077, 047, 034, 035, 036, 037,
- 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175,
- 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,
- 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
- 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,
- 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
- 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,
- 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,
- 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155,
- 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
- 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,
- 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,
- 0247, 0250, 0251, 0300, 0117, 0320, 0241, 07,
- 040, 041, 042, 043, 044, 025, 06, 027,
- 050, 051, 052, 053, 054, 011, 012, 033,
- 060, 061, 032, 063, 064, 065, 066, 010,
- 070, 071, 072, 073, 04, 024, 076, 0341,
- 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,
- 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
- 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,
- 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,
- 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,
- 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236,
- 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257,
- 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
- 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
- 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,
- 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,
- 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,
- };
- char ebcdic_to_ascii[] = {
- 0, 01, 02, 03, 0234, 011, 0206, 0177,
- 0227, 0215, 0216, 013, 014, 015, 016, 017,
- 020, 021, 022, 023, 0235, 0205, 010, 0207,
- 030, 031, 0222, 0217, 034, 035, 036, 037,
- 0200, 0201, 0202, 0203, 0204, 012, 027, 033,
- 0210, 0211, 0212, 0213, 0214, 05, 06, 07,
- 0220, 0221, 026, 0223, 0224, 0225, 0226, 04,
- 0230, 0231, 0232, 0233, 024, 025, 0236, 032,
- 040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
- 0247, 0250, 0133, 056, 074, 050, 053, 041,
- 046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
- 0260, 0261, 0135, 044, 052, 051, 073, 0136,
- 055, 057, 0262, 0263, 0264, 0265, 0266, 0267,
- 0270, 0271, 0174, 054, 045, 0137, 076, 077,
- 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
- 0302, 0140, 072, 043, 0100, 047, 075, 042,
- 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
- 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
- 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
- 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
- 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
- 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
- 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
- 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
- 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
- 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
- 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
- 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
- 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
- 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
- 060, 061, 062, 063, 064, 065, 066, 067,
- 070, 071, 0372, 0373, 0374, 0375, 0376, 0377,
- };
- main (argc, argv)
- int argc;
- char **argv;
- {
- int i;
- /* initialize translation table to identity translation */
- for (i = 0; i < 256; i++)
- trans_table[i] = (char) i;
- /* decode arguments and fill in info structure */
- scanargs (argc, argv);
- if (info.i_if != NULL)
- {
- if ((info.i_ifd = open (info.i_if, 0)) < 0)
- fatal (info.i_if, 1);
- if (info.i_of != NULL)
- if ((info.i_ofd = creat (info.i_of, 0666)) < 0)
- fatal (info.i_of, 1);
- }
- if (info.i_convert & C_DEBUG)
- {
- printf ("Info: if=%s, of=%s, ibs=%d, obs=%d, cbs=%d, skip=%d,\n",
- info.i_if, info.i_of, info.i_ibs, info.i_obs, info.i_cbs,
- info.i_skip);
- printf ("files=%d, seek=%d, count=%d conv=0%o\n",
- info.i_files, info.i_seek, info.i_count, info.i_convert);
- }
- copy ();
- quit (0);
- }
- copy ()
- {
- register int i, oc = 0;
- int spaces = 0, col = 0;
- char *ibuf, *obuf, *xmalloc ();
- int nread, nwritten;
- ibuf = xmalloc (info.i_ibs);
- if (info.i_ibs != info.i_obs || (info.i_convert & C_HARDWAY))
- obuf = xmalloc (info.i_obs);
- else
- obuf = ibuf;
-
- for (i = 0; i < info.i_skip; i++)
- if (read (info.i_ifd, ibuf, info.i_ibs) < 0)
- fatal (info.i_if, 1);
-
- if (lseek (info.i_ofd, info.i_seek * info.i_obs, 0) < 0)
- fatal (info.i_of, 1);
-
- while ((nread = read (info.i_ifd, ibuf, info.i_ibs)) != 0)
- {
- if (info.i_count >= 0 && r_partial+r_full > info.i_count)
- return;
- if (nread < 0)
- {
- perror (info.i_if);
- if (info.i_convert & C_NOERROR)
- continue;
- else
- quit (2);
- }
- if (nread < info.i_ibs)
- {
- r_partial++;
- if (info.i_convert & C_SYNC)
- while (nread < info.i_ibs)
- ibuf[nread++] = '\0';
- }
- else
- r_full++;
- /* if blocksizes are the same and no conversion, just flush */
- if (ibuf == obuf)
- {
- if ((nwritten = write (info.i_ofd, obuf, nread)) != nread)
- {
- perror (info.i_of);
- w_partial++;
- if (!(info.i_convert & C_NOERROR))
- quit (1);
- }
- else if (nread == info.i_ibs)
- w_full++;
- else
- w_partial++;
- continue;
- }
- /*
- * copy input to output, doing conversion and flushing output
- * as necessary.
- */
- for (i = 0; i < nread; i++)
- {
- register int c = trans_table[ibuf[i] & 0377] & 0377;
- if (info.i_convert & C_BLOCK)
- {
- if (spaces-- > 0)
- {
- i--; /* push back char, get it next time */
- c = trans_table[' '];
- }
- else if (c == '\n')
- {
- spaces = max (0, info.i_cbs - col);
- col = 0;
- continue;
- }
- else if (col++ >= info.i_cbs)
- {
- r_truncate++;
- continue;
- }
- }
- else if (info.i_convert & C_UNBLOCK)
- {
- if (col++ >= info.i_cbs)
- {
- col = spaces = 0;
- c = trans_table['\n'];
- i--; /* get the real c next time */
- }
- else if (c == ' ')
- spaces++;
- else if (spaces > 0)
- {
- i--;
- spaces--;
- c = trans_table[' '];
- }
- }
- if (info.i_convert & C_SWAB)
- obuf[oc++ ^ 1] = c;
- else
- obuf[oc++] = c;
- if (oc >= info.i_obs)
- {
- if ((nwritten = write (info.i_ofd, obuf, info.i_obs)) != info.i_obs)
- {
- perror (info.i_of);
- w_partial++;
- /* maybe it would be better to try to write out the rest of the
- block next time instead of throwing it away */
- if (!(info.i_convert & C_NOERROR))
- quit (1);
- }
- else
- w_full++;
- oc = 0;
- }
- }
- }
- /* flush last block */
- if (oc > 0)
- {
- /* first, fix earlier screw if swapping bytes and n is odd */
- if ((info.i_convert & C_SWAB) && (oc & 1))
- obuf[oc-1] = obuf[oc];
- if ((nwritten = write (info.i_ofd, obuf, oc)) != oc)
- perror (info.i_of);
- if (nwritten > 0)
- w_partial++;
- }
- }
- scanargs (argc, argv)
- int argc;
- char **argv;
- {
- int i, n;
- for (i = 1; i < argc; i++)
- {
- char *name, *val, *index ();
- name = argv[i];
- if ((val = index (name, '=')) == NULL)
- {
- printf ("bad arg: %s\n", name);
- return -1;
- }
- *val++ = '\0';
-
- if (equal (name, "if"))
- info.i_if = val;
- else if (equal (name, "of"))
- info.i_of = val;
- else if (equal (name, "conv"))
- parse_conversion (val);
- else
- {
- n = parse_integer (val);
-
- if (equal (name, "ibs"))
- info.i_ibs = n;
- else if (equal (name, "obs"))
- info.i_obs = n;
- else if (equal (name, "bs"))
- info.i_obs = info.i_ibs = n;
- else if (equal (name, "cbs"))
- info.i_cbs = n;
- else if (equal (name, "skip"))
- info.i_skip = n;
- else if (equal (name, "seek"))
- info.i_seek = n;
- else if (equal (name, "count"))
- info.i_count = n;
- else
- {
- printf ("bad arg: %s=%s\n", name, val);
- exit (1);
- }
- }
- }
- }
- parse_integer (str)
- char *str;
- {
- int n = 0;
- char *p = str;
- while (isdigit (*p))
- {
- n = n * 10 + *p - '0';
- p++;
- }
- loop:
- switch (*p++)
- {
- case '\0':
- return n;
- case 'b':
- n *= 512;
- goto loop;
- case 'k':
- n *= 1024;
- goto loop;
- case 'w':
- n *= 2;
- goto loop;
- case 'x':
- n *= parse_integer (p);
- break;
- default:
- return 0;
- }
- return n;
- }
- parse_conversion (str)
- char *str;
- {
- char *new;
- int i, j;
- char *new_trans;
- do {
- if ((new = index (str, ',')) != NULL)
- *new++ = '\0';
- for (i = 0; conversions[i].convname != NULL; i++)
- if (equal (conversions[i].convname, str))
- {
- info.i_convert |= conversions[i].conversion;
- break;
- }
- if (conversions[i].convname == NULL)
- {
- printf ("%s: bad conversion.\n", str);
- exit (1);
- }
- #define MX(a) (bit_count (info.i_convert & (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))
- {
- printf ("Only one conv in {ascii,ebcdic,ibm}, {lcase,ucase},\n\t%s",
- "{block,unblock}, {unblock,sync}\n");
- exit (1);
- }
- #undef MX
- str = new;
- } while (new != NULL);
- /* I don't know if the following restriction is stupid */
- /* but it's convenient */
- if ((info.i_convert & C_SWAB) && (info.i_ibs % 2 != 0 ||
- info.i_obs % 2 != 0))
- {
- printf ("Ibs and obs must both be even for swab to work.\n");
- exit (1);
- }
- /* fix up translation table */
- /* do upper and lower case if necessary */
- if (info.i_convert & C_UCASE)
- for (j = 'a'; j <= 'z'; j++)
- trans_table[j] = toupper (j);
- else if (info.i_convert & C_LCASE)
- for (j = 'A'; j <= 'Z'; j++)
- trans_table[j] = tolower (j);
- /* now find and apply char set translation */
- if (info.i_convert & C_ASCII)
- new_trans = ebcdic_to_ascii;
- else if (info.i_convert & C_EBCDIC)
- new_trans = ascii_to_ebcdic;
- else if (info.i_convert & C_IBM)
- new_trans = ascii_to_ibm;
- else
- return;
- for (i = 0; i < 256; i++)
- trans_table[i] = new_trans[trans_table[i]];
- }
- /* return number of 1 bits in i. */
- bit_count (i)
- register int i;
- {
- register int n;
- for (n = 0; i != 0; i = (i >> 1) & ~(1<<31))
- n += i & 1;
- return n;
- }
- /* print fatal error for file, then die */
- fatal (filename, code)
- char *filename;
- int code;
- {
- perror (filename);
- quit (code);
- }
- /* print statistics and exit */
- quit (code)
- {
- fprintf (stderr, "%d+%d records in\n", r_full, r_partial);
- fprintf (stderr, "%d+%d records out\n", w_full, w_partial);
- if (r_truncate > 0)
- fprintf (stderr, "%d truncated records\n", r_truncate);
- exit (code);
- }
- /* malloc or die */
- char *
- xmalloc (n)
- int n;
- {
- char *p, *malloc ();
- if ((p = malloc (n)) == NULL)
- {
- printf ("Malloc: not enough memory\n");
- exit (3);
- }
- }
|