dd.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       dd.c (11559B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 
            4 #define        BIG        2147483647
            5 #define        LCASE        (1<<0)
            6 #define        UCASE        (1<<1)
            7 #define        SWAB        (1<<2)
            8 #define NERR        (1<<3)
            9 #define SYNC        (1<<4)
           10 int        cflag;
           11 int        fflag;
           12 char        *string;
           13 char        *ifile;
           14 char        *ofile;
           15 char        *ibuf;
           16 char        *obuf;
           17 vlong        skip;
           18 vlong        oseekn;
           19 vlong        iseekn;
           20 vlong        count;
           21 long        files        = 1;
           22 long        ibs        = 512;
           23 long        obs        = 512;
           24 long        bs;
           25 long        cbs;
           26 long        ibc;
           27 long        obc;
           28 long        cbc;
           29 long        nifr;
           30 long        nipr;
           31 long        nofr;
           32 long        nopr;
           33 long        ntrunc;
           34 int dotrunc = 1;
           35 int        ibf;
           36 int        obf;
           37 char        *op;
           38 int        nspace;
           39 uchar        etoa[256];
           40 uchar        atoe[256];
           41 uchar        atoibm[256];
           42 
           43 void        flsh(void);
           44 int        match(char *s);
           45 vlong        number(long big);
           46 void        cnull(int cc);
           47 void        null(int c);
           48 void        ascii(int cc);
           49 void        unblock(int cc);
           50 void        ebcdic(int cc);
           51 void        ibm(int cc);
           52 void        block(int cc);
           53 void        term(void);
           54 void        stats(void);
           55 
           56 #define        iskey(s)        ((key[0] == '-') && (strcmp(key+1, s) == 0))
           57 
           58 void
           59 main(int argc, char *argv[])
           60 {
           61         void (*conv)(int);
           62         char *ip;
           63         char *key;
           64         int a, c;
           65 
           66         conv = null;
           67         for(c=1; c<argc; c++) {
           68                 key = argv[c++];
           69                 if(c >= argc){
           70                         fprint(2, "dd: arg %s needs a value\n", key);
           71                         exits("arg");
           72                 }
           73                 string = argv[c];
           74                 if(iskey("ibs")) {
           75                         ibs = number(BIG);
           76                         continue;
           77                 }
           78                 if(iskey("obs")) {
           79                         obs = number(BIG);
           80                         continue;
           81                 }
           82                 if(iskey("cbs")) {
           83                         cbs = number(BIG);
           84                         continue;
           85                 }
           86                 if(iskey("bs")) {
           87                         bs = number(BIG);
           88                         continue;
           89                 }
           90                 if(iskey("if")) {
           91                         ifile = string;
           92                         continue;
           93                 }
           94                 if(iskey("of")) {
           95                         ofile = string;
           96                         continue;
           97                 }
           98                 if(iskey("trunc")) {
           99                         dotrunc = number(BIG);
          100                         continue;
          101                 }
          102                 if(iskey("skip")) {
          103                         skip = number(BIG);
          104                         continue;
          105                 }
          106                 if(iskey("seek") || iskey("oseek")) {
          107                         oseekn = number(BIG);
          108                         continue;
          109                 }
          110                 if(iskey("iseek")) {
          111                         iseekn = number(BIG);
          112                         continue;
          113                 }
          114                 if(iskey("count")) {
          115                         count = number(BIG);
          116                         continue;
          117                 }
          118                 if(iskey("files")) {
          119                         files = number(BIG);
          120                         continue;
          121                 }
          122                 if(iskey("conv")) {
          123                 cloop:
          124                         if(match(","))
          125                                 goto cloop;
          126                         if(*string == '\0')
          127                                 continue;
          128                         if(match("ebcdic")) {
          129                                 conv = ebcdic;
          130                                 goto cloop;
          131                         }
          132                         if(match("ibm")) {
          133                                 conv = ibm;
          134                                 goto cloop;
          135                         }
          136                         if(match("ascii")) {
          137                                 conv = ascii;
          138                                 goto cloop;
          139                         }
          140                         if(match("block")) {
          141                                 conv = block;
          142                                 goto cloop;
          143                         }
          144                         if(match("unblock")) {
          145                                 conv = unblock;
          146                                 goto cloop;
          147                         }
          148                         if(match("lcase")) {
          149                                 cflag |= LCASE;
          150                                 goto cloop;
          151                         }
          152                         if(match("ucase")) {
          153                                 cflag |= UCASE;
          154                                 goto cloop;
          155                         }
          156                         if(match("swab")) {
          157                                 cflag |= SWAB;
          158                                 goto cloop;
          159                         }
          160                         if(match("noerror")) {
          161                                 cflag |= NERR;
          162                                 goto cloop;
          163                         }
          164                         if(match("sync")) {
          165                                 cflag |= SYNC;
          166                                 goto cloop;
          167                         }
          168                 }
          169                 fprint(2, "dd: bad arg: %s\n", key);
          170                 exits("arg");
          171         }
          172         if(conv == null && cflag&(LCASE|UCASE))
          173                 conv = cnull;
          174         if(ifile)
          175                 ibf = open(ifile, 0);
          176         else
          177                 ibf = dup(0, -1);
          178         if(ibf < 0) {
          179                 fprint(2, "dd: open %s: %r\n", ifile);
          180                 exits("open");
          181         }
          182         if(ofile){
          183                 if(dotrunc)
          184                         obf = create(ofile, 1, 0664);
          185                 else
          186                         obf = open(ofile, 1);
          187                 if(obf < 0) {
          188                         fprint(2, "dd: create %s: %r\n", ofile);
          189                         exits("create");
          190                 }
          191         }else{
          192                 obf = dup(1, -1);
          193                 if(obf < 0) {
          194                         fprint(2, "dd: can't dup file descriptor: %s: %r\n", ofile);
          195                         exits("dup");
          196                 }
          197         }
          198         if(bs)
          199                 ibs = obs = bs;
          200         if(ibs == obs && conv == null)
          201                 fflag++;
          202         if(ibs == 0 || obs == 0) {
          203                 fprint(2, "dd: counts: cannot be zero\n");
          204                 exits("counts");
          205         }
          206         ibuf = malloc(ibs);
          207         if(fflag)
          208                 obuf = ibuf;
          209         else
          210                 obuf = malloc(obs);
          211         if(ibuf == NULL || obuf == NULL) {
          212                 fprint(2, "dd: not enough memory: %r\n");
          213                 exits("memory");
          214         }
          215         ibc = 0;
          216         obc = 0;
          217         cbc = 0;
          218         op = obuf;
          219 
          220 /*
          221         if(signal(SIGINT, SIG_IGN) != SIG_IGN)
          222                 signal(SIGINT, term);
          223 */
          224         seek(obf, obs*oseekn, 1);
          225         seek(ibf, ibs*iseekn, 1);
          226         while(skip) {
          227                 read(ibf, ibuf, ibs);
          228                 skip--;
          229         }
          230 
          231         ip = 0;
          232 loop:
          233         if(ibc-- == 0) {
          234                 ibc = 0;
          235                 if(count==0 || nifr+nipr!=count) {
          236                         if(cflag&(NERR|SYNC))
          237                         for(ip=ibuf+ibs; ip>ibuf;)
          238                                 *--ip = 0;
          239                         ibc = read(ibf, ibuf, ibs);
          240                 }
          241                 if(ibc == -1) {
          242                         perror("read");
          243                         if((cflag&NERR) == 0) {
          244                                 flsh();
          245                                 term();
          246                         }
          247                         ibc = 0;
          248                         for(c=0; c<ibs; c++)
          249                                 if(ibuf[c] != 0)
          250                                         ibc = c;
          251                         stats();
          252                 }
          253                 if(ibc == 0 && --files<=0) {
          254                         flsh();
          255                         term();
          256                 }
          257                 if(ibc != ibs) {
          258                         nipr++;
          259                         if(cflag&SYNC)
          260                                 ibc = ibs;
          261                 } else
          262                         nifr++;
          263                 ip = ibuf;
          264                 c = (ibc>>1) & ~1;
          265                 if(cflag&SWAB && c)
          266                 do {
          267                         a = *ip++;
          268                         ip[-1] = *ip;
          269                         *ip++ = a;
          270                 } while(--c);
          271                 ip = ibuf;
          272                 if(fflag) {
          273                         obc = ibc;
          274                         flsh();
          275                         ibc = 0;
          276                 }
          277                 goto loop;
          278         }
          279         c = 0;
          280         c |= *ip++;
          281         c &= 0377;
          282         (*conv)(c);
          283         goto loop;
          284 }
          285 
          286 void
          287 flsh(void)
          288 {
          289         int c;
          290 
          291         if(obc) {
          292                 c = write(obf, obuf, obc);
          293                 if(c != obc) {
          294                         if(c > 0)
          295                                 ++nopr;
          296                         perror("write");
          297                         term();
          298                 }
          299                 if(obc == obs)
          300                         nofr++;
          301                 else
          302                         nopr++;
          303                 obc = 0;
          304         }
          305 }
          306 
          307 int
          308 match(char *s)
          309 {
          310         char *cs;
          311 
          312         cs = string;
          313         while(*cs++ == *s)
          314                 if(*s++ == '\0')
          315                         goto true;
          316         if(*s != '\0')
          317                 return 0;
          318 
          319 true:
          320         cs--;
          321         string = cs;
          322         return 1;
          323 }
          324 
          325 vlong
          326 number(long big)
          327 {
          328         char *cs;
          329         vlong n;
          330 
          331         cs = string;
          332         n = 0;
          333         while(*cs >= '0' && *cs <= '9')
          334                 n = n*10 + *cs++ - '0';
          335         for(;;)
          336         switch(*cs++) {
          337 
          338         case 'k':
          339                 n *= 1024;
          340                 continue;
          341 
          342 /*        case 'w':
          343                 n *= sizeof(int);
          344                 continue;
          345 */
          346 
          347         case 'b':
          348                 n *= 512;
          349                 continue;
          350 
          351 /*        case '*':*/
          352         case 'x':
          353                 string = cs;
          354                 n *= number(BIG);
          355 
          356         case '\0':
          357                 if(n>=big || n<0) {
          358                         fprint(2, "dd: argument %lld out of range\n", n);
          359                         exits("range");
          360                 }
          361                 return n;
          362         }
          363         /* never gets here */
          364 }
          365 
          366 void
          367 cnull(int cc)
          368 {
          369         int c;
          370 
          371         c = cc;
          372         if((cflag&UCASE) && c>='a' && c<='z')
          373                 c += 'A'-'a';
          374         if((cflag&LCASE) && c>='A' && c<='Z')
          375                 c += 'a'-'A';
          376         null(c);
          377 }
          378 
          379 void
          380 null(int c)
          381 {
          382 
          383         *op = c;
          384         op++;
          385         if(++obc >= obs) {
          386                 flsh();
          387                 op = obuf;
          388         }
          389 }
          390 
          391 void
          392 ascii(int cc)
          393 {
          394         int c;
          395 
          396         c = etoa[cc];
          397         if(cbs == 0) {
          398                 cnull(c);
          399                 return;
          400         }
          401         if(c == ' ') {
          402                 nspace++;
          403                 goto out;
          404         }
          405         while(nspace > 0) {
          406                 null(' ');
          407                 nspace--;
          408         }
          409         cnull(c);
          410 
          411 out:
          412         if(++cbc >= cbs) {
          413                 null('\n');
          414                 cbc = 0;
          415                 nspace = 0;
          416         }
          417 }
          418 
          419 void
          420 unblock(int cc)
          421 {
          422         int c;
          423 
          424         c = cc & 0377;
          425         if(cbs == 0) {
          426                 cnull(c);
          427                 return;
          428         }
          429         if(c == ' ') {
          430                 nspace++;
          431                 goto out;
          432         }
          433         while(nspace > 0) {
          434                 null(' ');
          435                 nspace--;
          436         }
          437         cnull(c);
          438 
          439 out:
          440         if(++cbc >= cbs) {
          441                 null('\n');
          442                 cbc = 0;
          443                 nspace = 0;
          444         }
          445 }
          446 
          447 void
          448 ebcdic(int cc)
          449 {
          450         int c;
          451 
          452         c = cc;
          453         if(cflag&UCASE && c>='a' && c<='z')
          454                 c += 'A'-'a';
          455         if(cflag&LCASE && c>='A' && c<='Z')
          456                 c += 'a'-'A';
          457         c = atoe[c];
          458         if(cbs == 0) {
          459                 null(c);
          460                 return;
          461         }
          462         if(cc == '\n') {
          463                 while(cbc < cbs) {
          464                         null(atoe[' ']);
          465                         cbc++;
          466                 }
          467                 cbc = 0;
          468                 return;
          469         }
          470         if(cbc == cbs)
          471                 ntrunc++;
          472         cbc++;
          473         if(cbc <= cbs)
          474                 null(c);
          475 }
          476 
          477 void
          478 ibm(int cc)
          479 {
          480         int c;
          481 
          482         c = cc;
          483         if(cflag&UCASE && c>='a' && c<='z')
          484                 c += 'A'-'a';
          485         if(cflag&LCASE && c>='A' && c<='Z')
          486                 c += 'a'-'A';
          487         c = atoibm[c] & 0377;
          488         if(cbs == 0) {
          489                 null(c);
          490                 return;
          491         }
          492         if(cc == '\n') {
          493                 while(cbc < cbs) {
          494                         null(atoibm[' ']);
          495                         cbc++;
          496                 }
          497                 cbc = 0;
          498                 return;
          499         }
          500         if(cbc == cbs)
          501                 ntrunc++;
          502         cbc++;
          503         if(cbc <= cbs)
          504                 null(c);
          505 }
          506 
          507 void
          508 block(int cc)
          509 {
          510         int c;
          511 
          512         c = cc;
          513         if(cflag&UCASE && c>='a' && c<='z')
          514                 c += 'A'-'a';
          515         if(cflag&LCASE && c>='A' && c<='Z')
          516                 c += 'a'-'A';
          517         c &= 0377;
          518         if(cbs == 0) {
          519                 null(c);
          520                 return;
          521         }
          522         if(cc == '\n') {
          523                 while(cbc < cbs) {
          524                         null(' ');
          525                         cbc++;
          526                 }
          527                 cbc = 0;
          528                 return;
          529         }
          530         if(cbc == cbs)
          531                 ntrunc++;
          532         cbc++;
          533         if(cbc <= cbs)
          534                 null(c);
          535 }
          536 
          537 void
          538 term(void)
          539 {
          540 
          541         stats();
          542         exits(0);
          543 }
          544 
          545 void
          546 stats(void)
          547 {
          548 
          549         fprint(2, "%lud+%lud records in\n", nifr, nipr);
          550         fprint(2, "%lud+%lud records out\n", nofr, nopr);
          551         if(ntrunc)
          552                 fprint(2, "%lud truncated records\n", ntrunc);
          553 }
          554 
          555 uchar        etoa[] =
          556 {
          557         0000,0001,0002,0003,0234,0011,0206,0177,
          558         0227,0215,0216,0013,0014,0015,0016,0017,
          559         0020,0021,0022,0023,0235,0205,0010,0207,
          560         0030,0031,0222,0217,0034,0035,0036,0037,
          561         0200,0201,0202,0203,0204,0012,0027,0033,
          562         0210,0211,0212,0213,0214,0005,0006,0007,
          563         0220,0221,0026,0223,0224,0225,0226,0004,
          564         0230,0231,0232,0233,0024,0025,0236,0032,
          565         0040,0240,0241,0242,0243,0244,0245,0246,
          566         0247,0250,0133,0056,0074,0050,0053,0041,
          567         0046,0251,0252,0253,0254,0255,0256,0257,
          568         0260,0261,0135,0044,0052,0051,0073,0136,
          569         0055,0057,0262,0263,0264,0265,0266,0267,
          570         0270,0271,0174,0054,0045,0137,0076,0077,
          571         0272,0273,0274,0275,0276,0277,0300,0301,
          572         0302,0140,0072,0043,0100,0047,0075,0042,
          573         0303,0141,0142,0143,0144,0145,0146,0147,
          574         0150,0151,0304,0305,0306,0307,0310,0311,
          575         0312,0152,0153,0154,0155,0156,0157,0160,
          576         0161,0162,0313,0314,0315,0316,0317,0320,
          577         0321,0176,0163,0164,0165,0166,0167,0170,
          578         0171,0172,0322,0323,0324,0325,0326,0327,
          579         0330,0331,0332,0333,0334,0335,0336,0337,
          580         0340,0341,0342,0343,0344,0345,0346,0347,
          581         0173,0101,0102,0103,0104,0105,0106,0107,
          582         0110,0111,0350,0351,0352,0353,0354,0355,
          583         0175,0112,0113,0114,0115,0116,0117,0120,
          584         0121,0122,0356,0357,0360,0361,0362,0363,
          585         0134,0237,0123,0124,0125,0126,0127,0130,
          586         0131,0132,0364,0365,0366,0367,0370,0371,
          587         0060,0061,0062,0063,0064,0065,0066,0067,
          588         0070,0071,0372,0373,0374,0375,0376,0377,
          589 };
          590 uchar        atoe[] =
          591 {
          592         0000,0001,0002,0003,0067,0055,0056,0057,
          593         0026,0005,0045,0013,0014,0015,0016,0017,
          594         0020,0021,0022,0023,0074,0075,0062,0046,
          595         0030,0031,0077,0047,0034,0035,0036,0037,
          596         0100,0117,0177,0173,0133,0154,0120,0175,
          597         0115,0135,0134,0116,0153,0140,0113,0141,
          598         0360,0361,0362,0363,0364,0365,0366,0367,
          599         0370,0371,0172,0136,0114,0176,0156,0157,
          600         0174,0301,0302,0303,0304,0305,0306,0307,
          601         0310,0311,0321,0322,0323,0324,0325,0326,
          602         0327,0330,0331,0342,0343,0344,0345,0346,
          603         0347,0350,0351,0112,0340,0132,0137,0155,
          604         0171,0201,0202,0203,0204,0205,0206,0207,
          605         0210,0211,0221,0222,0223,0224,0225,0226,
          606         0227,0230,0231,0242,0243,0244,0245,0246,
          607         0247,0250,0251,0300,0152,0320,0241,0007,
          608         0040,0041,0042,0043,0044,0025,0006,0027,
          609         0050,0051,0052,0053,0054,0011,0012,0033,
          610         0060,0061,0032,0063,0064,0065,0066,0010,
          611         0070,0071,0072,0073,0004,0024,0076,0341,
          612         0101,0102,0103,0104,0105,0106,0107,0110,
          613         0111,0121,0122,0123,0124,0125,0126,0127,
          614         0130,0131,0142,0143,0144,0145,0146,0147,
          615         0150,0151,0160,0161,0162,0163,0164,0165,
          616         0166,0167,0170,0200,0212,0213,0214,0215,
          617         0216,0217,0220,0232,0233,0234,0235,0236,
          618         0237,0240,0252,0253,0254,0255,0256,0257,
          619         0260,0261,0262,0263,0264,0265,0266,0267,
          620         0270,0271,0272,0273,0274,0275,0276,0277,
          621         0312,0313,0314,0315,0316,0317,0332,0333,
          622         0334,0335,0336,0337,0352,0353,0354,0355,
          623         0356,0357,0372,0373,0374,0375,0376,0377,
          624 };
          625 uchar        atoibm[] =
          626 {
          627         0000,0001,0002,0003,0067,0055,0056,0057,
          628         0026,0005,0045,0013,0014,0015,0016,0017,
          629         0020,0021,0022,0023,0074,0075,0062,0046,
          630         0030,0031,0077,0047,0034,0035,0036,0037,
          631         0100,0132,0177,0173,0133,0154,0120,0175,
          632         0115,0135,0134,0116,0153,0140,0113,0141,
          633         0360,0361,0362,0363,0364,0365,0366,0367,
          634         0370,0371,0172,0136,0114,0176,0156,0157,
          635         0174,0301,0302,0303,0304,0305,0306,0307,
          636         0310,0311,0321,0322,0323,0324,0325,0326,
          637         0327,0330,0331,0342,0343,0344,0345,0346,
          638         0347,0350,0351,0255,0340,0275,0137,0155,
          639         0171,0201,0202,0203,0204,0205,0206,0207,
          640         0210,0211,0221,0222,0223,0224,0225,0226,
          641         0227,0230,0231,0242,0243,0244,0245,0246,
          642         0247,0250,0251,0300,0117,0320,0241,0007,
          643         0040,0041,0042,0043,0044,0025,0006,0027,
          644         0050,0051,0052,0053,0054,0011,0012,0033,
          645         0060,0061,0032,0063,0064,0065,0066,0010,
          646         0070,0071,0072,0073,0004,0024,0076,0341,
          647         0101,0102,0103,0104,0105,0106,0107,0110,
          648         0111,0121,0122,0123,0124,0125,0126,0127,
          649         0130,0131,0142,0143,0144,0145,0146,0147,
          650         0150,0151,0160,0161,0162,0163,0164,0165,
          651         0166,0167,0170,0200,0212,0213,0214,0215,
          652         0216,0217,0220,0232,0233,0234,0235,0236,
          653         0237,0240,0252,0253,0254,0255,0256,0257,
          654         0260,0261,0262,0263,0264,0265,0266,0267,
          655         0270,0271,0272,0273,0274,0275,0276,0277,
          656         0312,0313,0314,0315,0316,0317,0332,0333,
          657         0334,0335,0336,0337,0352,0353,0354,0355,
          658         0356,0357,0372,0373,0374,0375,0376,0377,
          659 };