Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/std/dd.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1989-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* posix dd
26
*/
27
28
static const char usage1[] =
29
"[-1p0?\n@(#)$Id: dd (AT&T Research) 2011-04-21 $\n]"
30
USAGE_LICENSE
31
"[+NAME?dd - convert and copy a file]"
32
"[+DESCRIPTION?\bdd\b copies an input file to an output file with optional"
33
" conversions. The standard input and output are used by default."
34
" Input and output block sizes can be specified to take advantage of"
35
" physical io limitations. Options are of the form \aname=value\a"
36
" and may be specified with 0, 1, or 2 leading `-' characters.]"
37
"[+?A \anumber\a argument may be a scaled number with optional trailing"
38
" multipliers of the form `* \anumber\a', `x \anumber\a' or `X \anumber\a'."
39
" Scale suffixes may be one of:]{"
40
" [+b|B?512]"
41
" [+k|K?1000]"
42
" [+ki|Ki?1024]"
43
" [+m|M?1000000]"
44
" [+mi|Mi?1048576]"
45
" [+g|G?1000000000]"
46
" [+gi|Gi?1073741824]"
47
" [+t|T?1000000000000]"
48
" [+ti|Ti?1099511627776]"
49
" [+p|P?1000000000000000]"
50
" [+pi|Pi?1125899906842624]"
51
" [+e|E?1000000000000000000]"
52
" [+ei|Ei?1152921504606846976]"
53
"}"
54
;
55
56
static const char usage2[] =
57
"[+SEE ALSO?\bcp\b(1), \biconv\b(1), \bpax\b(1), \btr\b(1), \bseek\b(2)]"
58
;
59
60
#include <ast.h>
61
#include <ctype.h>
62
#include <ccode.h>
63
#include <error.h>
64
#include <iconv.h>
65
#include <ls.h>
66
#include <sig.h>
67
#include <swap.h>
68
69
#define CODE 0
70
#define CONV 1
71
#define FLAG 2
72
#define NUMBER 3
73
#define STRING 4
74
75
#define A2E (1<<0)
76
#define A2I (1<<1)
77
#define A2N (1<<2)
78
#define A2O (1<<3)
79
#define BLOCK (1<<4)
80
#define E2A (1<<5)
81
#define IGNERROR (1<<6)
82
#define I2A (1<<7)
83
#define ISPECIAL (1<<8)
84
#define LCASE (1<<9)
85
#define N2A (1<<10)
86
#define NOERROR (1<<11)
87
#define NOTRUNC (1<<12)
88
#define O2A (1<<13)
89
#define OSPECIAL (1<<14)
90
#define SILENT (1L<<15)
91
#define SWAP (1L<<16)
92
#define SYNC (1L<<17)
93
#define UCASE (1L<<18)
94
#define UNBLOCK (1L<<19)
95
96
#define BS 512
97
98
#define operand_begin bs
99
#define operand_end to
100
101
#define conv_begin a2e
102
#define conv_end unblock
103
104
typedef struct
105
{
106
const char* name;
107
const char* help;
108
} Desc_t;
109
110
typedef struct
111
{
112
char* string;
113
Sflong_t number;
114
} Value_t;
115
116
typedef struct
117
{
118
const char* name;
119
long type;
120
const char* help;
121
Value_t value;
122
} Operand_t;
123
124
typedef struct
125
{
126
Sfio_t* fp;
127
Sfulong_t complete;
128
Sfulong_t partial;
129
Sfulong_t truncated;
130
Sfulong_t remains;
131
int special;
132
} Io_t;
133
134
typedef struct
135
{
136
Operand_t bs;
137
Operand_t cbs;
138
Operand_t conv;
139
Operand_t count;
140
Operand_t from;
141
Operand_t ibs;
142
Operand_t ifn;
143
Operand_t iseek;
144
Operand_t obs;
145
Operand_t ofn;
146
Operand_t oseek;
147
Operand_t silent;
148
Operand_t skip;
149
Operand_t swap;
150
Operand_t to;
151
152
Operand_t a2e;
153
Operand_t a2i;
154
Operand_t a2n;
155
Operand_t a2o;
156
Operand_t ascii;
157
Operand_t block;
158
Operand_t e2a;
159
Operand_t ebcdic;
160
Operand_t i2a;
161
Operand_t ibm;
162
Operand_t ifix;
163
Operand_t ignerror;
164
Operand_t lcase;
165
Operand_t n2a;
166
Operand_t noerror;
167
Operand_t notrunc;
168
Operand_t o2a;
169
Operand_t ofix;
170
Operand_t swab;
171
Operand_t sync;
172
Operand_t ucase;
173
Operand_t unblock;
174
175
Iconv_disc_t iconv;
176
Io_t in;
177
Io_t out;
178
char* buffer;
179
int pad;
180
iconv_t cvt;
181
Sfio_t* tmp;
182
} State_t;
183
184
static State_t state =
185
{
186
{
187
"bs",
188
NUMBER,
189
"Input and output block size.",
190
},
191
{
192
"cbs",
193
NUMBER,
194
"Conversion buffer size (logical record length)."
195
},
196
{
197
"conv",
198
CONV,
199
"Convert input.",
200
},
201
{
202
"count",
203
NUMBER,
204
"Copy only \anumber\a input blocks.",
205
},
206
{
207
"from",
208
CODE,
209
"Convert from \acodeset\a to the \bto\b=\acodeset\a"
210
" or the local default. \acodeset\a names are matched"
211
" by left-anchored case-insensitive \bksh\b(1) patterns.",
212
},
213
{
214
"ibs",
215
NUMBER,
216
"Input block size.",
217
0, BS,
218
},
219
{
220
"if",
221
STRING,
222
"The input file name; standard input is the default.",
223
},
224
{
225
"iseek",
226
NUMBER,
227
"Seek \anumber\a blocks from the beginning of the input"
228
" file before copying.",
229
},
230
{
231
"obs",
232
NUMBER,
233
"Output block size.",
234
0, BS,
235
},
236
{
237
"of",
238
STRING,
239
"The output file name; standard output is the default.",
240
},
241
{
242
"oseek|seek",
243
NUMBER,
244
"Seek \anumber\a blocks from the beginning of the output"
245
" file before copying.",
246
},
247
{
248
"silent",
249
FLAG,
250
"\bsilent\b does not print the total number of io blocks"
251
" on exit.",
252
},
253
{
254
"skip",
255
NUMBER,
256
"Skip \anumber\a blocks before reading. Seek is used if"
257
" possible, otherwise the blocks are read and discarded.",
258
},
259
{
260
"swap",
261
NUMBER,
262
"Swap bytes acording to the inclusive or of: 1-byte,"
263
" 2-short, 4-long, 8-quad, etc.",
264
},
265
{
266
"to",
267
CODE,
268
"Convert to \acodeset\a from the \bfrom\b=\acodeset\a"
269
" or the local default. See \bfrom\b for \acodeset\a names.",
270
},
271
272
{
273
"a2e",
274
A2E,
275
"ascii to ebcdic",
276
},
277
{
278
"a2i",
279
A2I,
280
"ascii to ibm",
281
},
282
{
283
"a2n",
284
A2N,
285
"ascii to native",
286
},
287
{
288
"a2o",
289
A2O,
290
"ascii to open edition ebcdic",
291
},
292
{
293
"ascii",
294
E2A,
295
"ebcdic to ascii",
296
},
297
{
298
"block",
299
BLOCK,
300
"newline-terminated ascii to fixed record length",
301
},
302
{
303
"e2a",
304
E2A,
305
"ebcdic to ascii",
306
},
307
{
308
"ebcdic",
309
A2E,
310
"equivalent to \ba2e\b",
311
},
312
{
313
"i2a",
314
I2A,
315
"ibm to ascii",
316
},
317
{
318
"ibm",
319
A2I,
320
"ascii to ibm ebcdic",
321
},
322
{
323
"ignerror",
324
IGNERROR,
325
"continue processing after errors",
326
},
327
{
328
"ispecial",
329
ISPECIAL,
330
"currently ignored",
331
},
332
{
333
"lcase",
334
LCASE,
335
"to lower case",
336
},
337
{
338
"n2a",
339
N2A,
340
"native to ascii",
341
},
342
{
343
"noerror",
344
NOERROR,
345
"stop processing only after 5 consecutive errors",
346
},
347
{
348
"notrunc",
349
NOTRUNC,
350
"do not truncate pre-existing output files",
351
},
352
{
353
"o2a",
354
O2A,
355
"open edition ibm to ascii",
356
},
357
{
358
"ospecial",
359
OSPECIAL,
360
"currently ignored"
361
},
362
{
363
"swab",
364
SWAP,
365
"swap byte pairs",
366
},
367
{
368
"sync",
369
SYNC,
370
"Pad each input block to \bibs\b. Pad with spaces if"
371
" \bconv=block\b or \bconv=unblock\b, otherwise pad"
372
" with nulls.",
373
},
374
{
375
"ucase",
376
UCASE,
377
"to upper case",
378
},
379
{
380
"unblock",
381
UNBLOCK,
382
"fixed-length records to newline-terminated records",
383
},
384
};
385
386
static Desc_t desc[] =
387
{
388
"codeset", "",
389
"conversion", "",
390
0, 0,
391
"number", 0,
392
"file", 0,
393
};
394
395
static void
396
fini(int code)
397
{
398
if (state.in.fp != sfstdin)
399
sfclose(state.in.fp);
400
if (state.out.fp == sfstdout)
401
sfsync(state.out.fp);
402
else
403
sfclose(state.out.fp);
404
if (!state.silent.value.number)
405
{
406
sfprintf(sfstderr, "%I*u+%I*u records in\n", sizeof(Sfulong_t), (Sfulong_t)state.in.complete, sizeof(Sfulong_t), (Sfulong_t)(state.in.partial + (state.in.remains > 0)));
407
sfprintf(sfstderr, "%I*u+%I*u records out\n", sizeof(Sfulong_t), (Sfulong_t)state.out.complete, sizeof(Sfulong_t), (Sfulong_t)(state.out.partial + (state.out.remains > 0)));
408
if (state.in.truncated)
409
sfprintf(sfstderr, "%I*u truncated record%s\n", sizeof(Sfulong_t), (Sfulong_t)state.in.truncated, state.in.truncated == 1 ? "" : "s");
410
}
411
exit(code);
412
}
413
414
static void
415
interrupt(int sig)
416
{
417
signal(sig, SIG_DFL);
418
fini(EXIT_TERM(sig));
419
}
420
421
static ssize_t
422
output(Sfio_t* sp, const Void_t* buf, size_t n, Sfdisc_t* disc)
423
{
424
register ssize_t r;
425
register size_t x;
426
427
if ((r = sfwr(sp, buf, n, disc)) > 0)
428
{
429
x = r / state.obs.value.number;
430
state.out.complete += x;
431
if (x = r - x * state.obs.value.number)
432
{
433
if (state.out.special)
434
state.out.partial++;
435
else if ((state.out.remains += x) >= state.obs.value.number)
436
{
437
state.out.remains -= state.obs.value.number;
438
state.out.complete++;
439
}
440
}
441
}
442
return r;
443
}
444
445
int
446
main(int argc, char** argv)
447
{
448
register char* s;
449
register char* v;
450
register char* b;
451
register Operand_t* op;
452
register Operand_t* vp;
453
register int f;
454
char* usage;
455
char* e;
456
int i;
457
char* cb;
458
size_t cc;
459
Sfio_t* sp;
460
Sflong_t c;
461
Sflong_t d;
462
Sflong_t m;
463
Sflong_t n;
464
Sflong_t r;
465
Sflong_t partial;
466
struct stat st;
467
Sfdisc_t disc;
468
469
setlocale(LC_ALL, "");
470
error_info.id = "dd";
471
iconv_init(&state.iconv, errorf);
472
state.from.value.string = state.to.value.string = "";
473
if (!(sp = sfstropen()))
474
error(ERROR_SYSTEM|3, "out of space");
475
sfputr(sp, usage1, '\n');
476
for (op = &state.operand_begin; op <= &state.operand_end; op++)
477
{
478
sfprintf(sp, "[%d:%s?%s", op - &state.operand_begin + 10, op->name, op->help);
479
i = ']';
480
if (desc[op->type].name)
481
{
482
if (desc[op->type].help)
483
{
484
if (*desc[op->type].help)
485
sfprintf(sp, " %s", desc[op->type].help);
486
else
487
sfprintf(sp, " \a%s\a may be one of:", desc[op->type].name);
488
sfprintf(sp, "]:[%s", desc[op->type].name);
489
desc[op->type].help = 0;
490
if (op->type == CONV)
491
{
492
i = '}';
493
sfprintf(sp, "]{\n");
494
for (vp = &state.conv_begin; vp <= &state.conv_end; vp++)
495
sfprintf(sp, "\t[+%s?%s]\n", vp->name, vp->help);
496
}
497
else if (op->type == CODE)
498
{
499
register iconv_list_t* ic;
500
501
sfputc(sp, ']');
502
sfputc(sp, '{');
503
for (ic = iconv_list(NiL); ic; ic = iconv_list(ic))
504
{
505
sfputc(sp, '[');
506
sfputc(sp, '+');
507
sfputc(sp, '\b');
508
optesc(sp, ic->match, '?');
509
sfputc(sp, '?');
510
optesc(sp, ic->desc, 0);
511
sfputc(sp, ']');
512
sfputc(sp, '\n');
513
}
514
i = '}';
515
}
516
}
517
else
518
sfprintf(sp, "]:[%s", desc[op->type].name);
519
}
520
sfputc(sp, i);
521
sfputc(sp, '\n');
522
}
523
sfputr(sp, usage2, '\n');
524
if (!(usage = sfstruse(sp)))
525
error(ERROR_SYSTEM|3, "out of space");
526
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
527
signal(SIGINT, interrupt);
528
while (f = optget(argv, usage))
529
{
530
531
if (f > 0)
532
{
533
if (f == '?')
534
error(ERROR_USAGE|4, "%s", opt_info.arg);
535
if (f = ':')
536
error(2, "%s", opt_info.arg);
537
continue;
538
}
539
op = &state.operand_begin - (f + 10);
540
v = opt_info.arg;
541
switch (op->type)
542
{
543
case CODE:
544
case STRING:
545
op->value.string = v;
546
break;
547
case CONV:
548
do
549
{
550
if (e = strchr(v, ','))
551
*e = 0;
552
vp = (Operand_t*)strsearch(&state.conv_begin, &state.conv_end - &state.conv_begin + 1, sizeof(Operand_t), stracmp, v, NiL);
553
if (e)
554
*e++ = ',';
555
if (!vp)
556
error(3, "%s: unknown %s value", v, op->name);
557
op->value.number |= vp->type;
558
} while (v = e);
559
break;
560
case FLAG:
561
op->value.number = opt_info.number;
562
break;
563
case NUMBER:
564
c = 0;
565
for (;;)
566
{
567
n = strtonll(v, &e, NiL, 0);
568
if (n < 0)
569
error(3, "%s: %s must be >= 0", v, op->name);
570
if (!c)
571
{
572
c = 1;
573
op->value.number = n;
574
}
575
else
576
op->value.number *= n;
577
for (v = e; isspace(*v); v++);
578
if (*v != 'x' && *v != 'X' && *v != '*')
579
break;
580
while (isspace(*++v));
581
if (!*v)
582
{
583
v = e;
584
break;
585
}
586
}
587
if (*v)
588
error(3, "%s: %s: invalid numeric expression", op->name, opt_info.arg);
589
break;
590
}
591
}
592
if (error_info.errors)
593
error(ERROR_USAGE|4, "%s", optusage(NiL));
594
error_info.exit = fini;
595
switch ((long)(state.conv.value.number & (A2E|A2I|A2N|A2O|E2A|I2A|N2A|O2A)))
596
{
597
case 0:
598
break;
599
case A2E:
600
state.from.value.string = "ascii";
601
state.to.value.string = "ebcdic-e";
602
break;
603
case A2I:
604
state.from.value.string = "ascii";
605
state.to.value.string = "ebcdic-i";
606
break;
607
case A2N:
608
state.from.value.string = "ascii";
609
state.to.value.string = "";
610
break;
611
case A2O:
612
state.from.value.string = "ascii";
613
state.to.value.string = "ebcdic-o";
614
break;
615
case E2A:
616
state.from.value.string = "ebcdic-e";
617
state.to.value.string = "ascii";
618
break;
619
case I2A:
620
state.from.value.string = "ebcdic-i";
621
state.to.value.string = "ascii";
622
break;
623
case N2A:
624
state.from.value.string = "";
625
state.to.value.string = "ascii";
626
break;
627
case O2A:
628
state.from.value.string = "ebcdic-o";
629
state.to.value.string = "ascii";
630
break;
631
default:
632
error(3, "only one of %s={%s,%s,%s} may be specified", state.conv.name, state.ascii.value.string, state.ebcdic.value.string, state.ibm.value.string);
633
}
634
if (streq(state.from.value.string, state.to.value.string))
635
state.cvt = (iconv_t)(-1);
636
else if ((state.cvt = iconv_open(state.to.value.string, state.from.value.string)) == (iconv_t)(-1))
637
error(3, "cannot convert from %s to %s", *state.from.value.string ? state.from.value.string : ccmapname(CC_NATIVE), *state.to.value.string ? state.to.value.string : ccmapname(CC_NATIVE));
638
else if (state.cvt == (iconv_t)(0)) /* ast iconv identity */
639
state.cvt = (iconv_t)(-1);
640
else if (!(state.tmp = sfstropen()))
641
error(ERROR_SYSTEM|3, "out of space");
642
if ((state.conv.value.number & (BLOCK|UNBLOCK)) == (BLOCK|UNBLOCK))
643
error(3, "only one of %s=%s and %s=%s may be specified", state.conv.name, state.block.value.string, state.conv.name, state.unblock.value.string);
644
if ((state.conv.value.number & (SYNC|UNBLOCK)) == (SYNC|UNBLOCK))
645
{
646
state.conv.value.number &= ~SYNC;
647
error(1, "%s=%s ignored for %s=%s", state.conv.name, state.sync.value.string, state.conv.name, state.unblock.value.string);
648
}
649
if (state.conv.value.number & SWAP)
650
state.swap.value.number = 1;
651
else if (state.swap.value.number)
652
state.conv.value.number |= SWAP;
653
if (state.oseek.value.number && (state.conv.value.number & NOTRUNC))
654
{
655
state.oseek.value.number = 0;
656
error(1, "%s ignored for %s=%s", state.oseek.name, state.conv.name, state.notrunc.value.string);
657
}
658
if ((state.conv.value.number & (LCASE|UCASE)) == (LCASE|UCASE))
659
error(3, "only one of %s=%s and %s=%s may be specified", state.conv.name, state.lcase.value.string, state.conv.name, state.ucase.value.string);
660
if (state.conv.value.number & (BLOCK|UNBLOCK))
661
{
662
if (!state.cbs.value.number)
663
error(3, "%s must be specified for %s=%s", state.cbs.name, state.conv.name, (state.conv.value.number & BLOCK) ? state.block.value.string : state.unblock.value.string);
664
state.pad = ' ';
665
if (state.conv.value.number & UNBLOCK)
666
{
667
state.ibs.value.number = state.cbs.value.number;
668
if (state.bs.value.number)
669
{
670
state.obs.value.number = state.bs.value.number;
671
state.bs.value.number = 0;
672
}
673
}
674
}
675
else if (state.cbs.value.number)
676
{
677
state.cbs.value.number = 0;
678
error(1, "%s ignored", state.cbs.name);
679
}
680
if (n = state.bs.value.number)
681
state.ibs.value.number = state.obs.value.number = n;
682
if (n = state.iseek.value.number)
683
{
684
if (state.skip.value.number)
685
error(3, "only on of %s and %s may be specified", state.skip.name, state.iseek.name);
686
if (!state.ibs.value.number)
687
error(3, "%s requires %s or %s", state.iseek.name, state.bs.name, state.ibs.name);
688
state.skip.value.number = n;
689
}
690
if (state.oseek.value.number && !state.obs.value.number)
691
error(3, "%s requires %s or %s", state.oseek.name, state.bs.name, state.obs.name);
692
if (!(s = state.ifn.value.string))
693
{
694
state.ifn.value.string = "/dev/stdin";
695
state.in.fp = sfstdin;
696
#if O_NONBLOCK
697
if ((i = fcntl(sffileno(sfstdin), F_GETFL)) > 0 && (i & O_NONBLOCK))
698
fcntl(sffileno(sfstdin), F_SETFL, i & ~O_NONBLOCK);
699
#endif
700
}
701
else if (!(state.in.fp = sfopen(NiL, s, "rb")))
702
error(ERROR_SYSTEM|3, "%s: cannot read", s);
703
if (!(s = state.ofn.value.string))
704
{
705
state.ofn.value.string = "/dev/stdout";
706
state.out.fp = sfstdout;
707
}
708
else if (!(state.out.fp = sfopen(NiL, s, (state.conv.value.number & NOTRUNC) ? "a+b" : state.oseek.value.number ? "w+b" : "wb")))
709
error(ERROR_SYSTEM|3, "%s: cannot write", s);
710
if ((state.conv.value.number & ISPECIAL) || fstat(sffileno(state.in.fp), &st) || !S_ISREG(st.st_mode))
711
state.in.special = 1;
712
if (state.in.special && !(state.conv.value.number & BLOCK) && (n = state.ibs.value.number))
713
sfsetbuf(state.in.fp, NiL, n);
714
if ((state.conv.value.number & OSPECIAL) || fstat(sffileno(state.out.fp), &st) || !S_ISREG(st.st_mode))
715
state.out.special = 1;
716
if (state.out.special && !(state.conv.value.number & UNBLOCK) && (n = state.obs.value.number))
717
sfsetbuf(state.out.fp, NiL, n);
718
state.bs.value.number = state.ibs.value.number;
719
if (state.obs.value.number > state.bs.value.number)
720
state.bs.value.number = state.obs.value.number;
721
if (state.cbs.value.number > state.bs.value.number)
722
state.bs.value.number = state.cbs.value.number;
723
if (!(state.buffer = newof(0, char, state.bs.value.number, 0)))
724
error(ERROR_SYSTEM|3, "out of space");
725
if (n = state.skip.value.number)
726
{
727
if (!state.ibs.value.number)
728
error(3, "%s requires %s or %s", state.skip.name, state.bs.name, state.ibs.name);
729
n *= state.ibs.value.number;
730
if (sfseek(state.in.fp, n, SEEK_SET) != n)
731
{
732
do
733
{
734
if (!sfreserve(state.in.fp, state.in.special && state.ibs.value.number < n ? state.ibs.value.number : n, 0))
735
{
736
if (sfvalue(state.in.fp) > 0)
737
error(ERROR_SYSTEM|3, "%s: seek read error", state.ifn.value.string);
738
break;
739
}
740
} while ((n -= sfvalue(state.in.fp)) > 0);
741
if (n > 0)
742
error(3, "%s: cannot seek past end of file", state.ifn.value.string);
743
}
744
}
745
if (n = state.oseek.value.number)
746
{
747
n *= state.obs.value.number;
748
if (sfseek(state.out.fp, n, SEEK_SET) != n)
749
{
750
do
751
{
752
if (!sfreserve(state.out.fp, state.out.special && state.obs.value.number < n ? state.obs.value.number : n, 0))
753
{
754
if (sfvalue(state.out.fp) > 0)
755
error(ERROR_SYSTEM|3, "%s: seek read error", state.ofn.value.string);
756
break;
757
}
758
} while ((n -= sfvalue(state.out.fp)) > 0);
759
while (n > 0 && (c = sfwrite(state.out.fp, state.buffer, state.out.special && state.obs.value.number < n ? state.obs.value.number : n)) > 0)
760
n -= c;
761
if (c < 0)
762
error(ERROR_SYSTEM|3, "%s: seek 0 fill write error", state.ofn.value.string);
763
}
764
}
765
if (state.silent.value.number)
766
state.iconv.errorf = 0;
767
if (state.conv.value.number & NOERROR)
768
{
769
state.iconv.errorf = 0;
770
if (state.conv.value.number & SYNC)
771
state.iconv.fill = 0;
772
else
773
state.iconv.flags |= ICONV_OMIT;
774
}
775
else
776
state.iconv.flags |= ICONV_FATAL;
777
memset(&disc, 0, sizeof(disc));
778
disc.writef = output;
779
sfdisc(state.out.fp, &disc);
780
if (!state.obs.value.number)
781
state.obs.value.number = BS;
782
if (state.conv.value.number & BLOCK)
783
{
784
c = state.cbs.value.number;
785
memset(state.buffer, state.pad, c);
786
while ((s = sfgetr(state.in.fp, '\n', 0)) || (s = sfgetr(state.in.fp, '\n', -1)))
787
{
788
state.in.complete++;
789
n = sfvalue(state.in.fp) - 1;
790
if (n > c)
791
{
792
if (sfwrite(state.out.fp, s, c) != c)
793
error(ERROR_SYSTEM|3, "%s: write error", state.ofn.value.string);
794
state.in.truncated++;
795
}
796
else
797
{
798
if (sfwrite(state.out.fp, s, n) != n)
799
error(ERROR_SYSTEM|3, "%s: write error", state.ofn.value.string);
800
n = c - n;
801
if (sfwrite(state.out.fp, state.buffer, n) != n)
802
error(ERROR_SYSTEM|3, "%s: write error", state.ofn.value.string);
803
}
804
}
805
}
806
else
807
{
808
if (!(c = state.ibs.value.number))
809
c = BS;
810
f = state.conv.value.number;
811
if (!state.in.special)
812
f &= ~NOERROR;
813
if (!(r = state.count.value.number))
814
r = -1;
815
partial = 0;
816
while (state.in.complete != r)
817
{
818
b = sfreserve(state.in.fp, SF_UNBOUND, 0);
819
m = sfvalue(state.in.fp);
820
if (!b)
821
{
822
if (!m)
823
break;
824
error(ERROR_SYSTEM|((f & NOERROR) ? 2 : 3), "%s: read error", state.ifn.value.string);
825
memset(b = state.buffer, state.pad, m = c);
826
}
827
while (state.in.complete != r)
828
{
829
s = b;
830
831
/*
832
* m is the amount actually read
833
* c is the specified (or default) block size
834
*/
835
836
if (m >= c)
837
{
838
/*
839
* the read gave us at least a complete block
840
*/
841
842
state.in.complete++;
843
844
/*
845
* set n (the # of bytes to write) to the block size
846
*/
847
848
n = c;
849
850
/*
851
* if we've hit the block count, check to see if the
852
* previous write was in the middle of an output block, and
853
* adjust the # of bytes to write accordingly; don't bother
854
* adjusting the remains, since we're done
855
*/
856
857
if (state.in.complete >= r && (state.in.remains + n) >= c)
858
n -= state.in.remains;
859
}
860
else
861
{
862
/*
863
* read gave us less than a complete block
864
*/
865
866
n = m;
867
if (state.in.special)
868
state.in.partial++;
869
870
/*
871
* see if writing the amount read in will cross an (output) block boundry
872
*/
873
874
if ((state.in.remains + n) >= c)
875
{
876
state.in.complete++;
877
878
/*
879
* see above comment on block count, but also adjust
880
* partial block byte count (remains)
881
*/
882
883
if (state.in.complete >= r)
884
{
885
n = c - state.in.remains;
886
state.in.remains += m - c;
887
}
888
else
889
{
890
partial++;
891
state.in.remains += m - c;
892
}
893
}
894
else
895
state.in.remains += n;
896
if (f & SYNC)
897
{
898
s = memcpy(state.buffer, s, n);
899
memset(s + n, state.pad, c - n);
900
n = c;
901
}
902
}
903
if (f & SWAP)
904
swapmem(state.swap.value.number, s, s, n);
905
if (state.cvt != (iconv_t)(-1))
906
{
907
cb = s;
908
cc = n;
909
state.iconv.errors = 0;
910
if ((d = iconv_write(state.cvt, state.tmp, &cb, &cc, &state.iconv)) < 0)
911
d = 0;
912
if (!(s = sfstruse(state.tmp)))
913
error(ERROR_SYSTEM|3, "out of space");
914
m -= n - d;
915
if (state.iconv.errors && (state.iconv.flags & ICONV_FATAL))
916
{
917
m -= n;
918
n = 0;
919
}
920
}
921
switch (f & (LCASE|UCASE))
922
{
923
case LCASE:
924
for (v = (e = s) + n; s < v; s++)
925
if (isupper(*s))
926
*s = tolower(*s);
927
s = e;
928
break;
929
case UCASE:
930
for (v = (e = s) + n; s < v; s++)
931
if (islower(*s))
932
*s = toupper(*s);
933
s = e;
934
break;
935
}
936
if (f & UNBLOCK)
937
{
938
for (v = s + n; v > s && *(v - 1) == ' '; v--);
939
if (sfwrite(state.out.fp, s, v - s) != (v - s) || sfputc(state.out.fp, '\n') != '\n')
940
error(ERROR_SYSTEM|3, "%s: write error", state.ofn.value.string);
941
}
942
else if (sfwrite(state.out.fp, s, n) != n)
943
error(ERROR_SYSTEM|3, "%s: write error", state.ofn.value.string);
944
if ((m -= n) <= 0)
945
break;
946
b += n;
947
}
948
}
949
if (state.in.partial)
950
{
951
state.in.complete -= partial;
952
state.in.remains = 0;
953
}
954
if (sfsync(state.out.fp))
955
error(ERROR_SYSTEM|3, "%s: write error", state.ofn.value.string);
956
}
957
fini(error_info.errors != 0);
958
}
959
960