Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/pack/pack.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1993-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
* David Korn <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* pack [-] [-f] file ...
23
*
24
* pack files using Huffman coding
25
*
26
* David Korn
27
* AT&T Research
28
*
29
*/
30
31
static const char usage[] =
32
"[-?\n@(#)$Id: pack (AT&T Research) 2003-04-28 $\n]"
33
USAGE_LICENSE
34
"[+NAME?pack - pack files using Huffman coding]"
35
"[+DESCRIPTION?\bpack\b attempts to store the specified files in a compressed "
36
"form using static Huffman coding. Wherever possible each \afile\a "
37
"is replaced by a packed file named \afile\a\b.z\b with the same "
38
"access modes, access and modified dates, and owner as those of "
39
"\afile\a. The \b-f\b option forces packing of \afile\a even when "
40
"there is no space benefit for packing the file.]"
41
"[+?If \bpack\b is successful, \afile\a will be removed. Packed files "
42
"can be restored to their original form using \bunpack\b or \bpcat\b.]"
43
"[+?\bpack\b uses Huffman (minimum redundancy) codes on a byte-by-byte basis. "
44
"Ordinarily, for each file that is packed, a line is written to "
45
"standard output containing \afile\a\b.z\b and the percent "
46
"compression. If the \b-v\b options is specified, or if the \b-\b "
47
"argument is specified, an internal flag is set that causes the "
48
"number of times each byte is used, its relative frequency, and the "
49
"code for the byte to be written to the standard output. Additional "
50
"occurrences of \b-\b in place of name cause the internal flag to be "
51
"set and reset.]"
52
"[+?No packing occurs if:]{"
53
"[+-?\afile\a appears to be already packed.]"
54
"[+-?\afile\a has links.]"
55
"[+-?\afile\a is a directory.]"
56
"[+-?\afile\a cannot be opened.]"
57
"[+-?No disk storage blocks will be saved by packing unless \b-f\b "
58
"is specified.]"
59
"[+-?A file called \afile\a\b.z\b already exists.]"
60
"[+-?The \b.z\b file cannot be created.]"
61
"[+-?An I/O error occurred during processing.]"
62
"}"
63
"[f:force?Pack the file even if the packed size is larger than the original.]"
64
"[v:verbose?Causes additional information to be written to standard ouput.]"
65
"\n"
66
"\nfile ...\n"
67
"\n"
68
"[+EXIT STATUS]{"
69
"[+0?All files packed successfully.]"
70
"[+\an\a?\an\a files failed to pack, where \an\a is less than 125.]"
71
"[+125?125 or more files failed to pack.]"
72
"}"
73
"[+SEE ALSO?\bunpack\b(1), \bpcat\b(1), \bcompress\b(1), \bgzip\b(1)]"
74
;
75
76
77
#include "huffman.h"
78
#include <error.h>
79
#include <ls.h>
80
81
#define BLKSIZE 512
82
#define block(size) (((size) + BLKSIZE-1) & ~(BLKSIZE-1))
83
#define PERM(m) ((m)&(S_IRWXU|S_IRWXG|S_IRWXO))
84
85
static void vprint(Huff_t*, int);
86
static char *outname(char*);
87
static const char suffix[] = ".z";
88
89
int
90
main(int argc, register char *argv[])
91
{
92
static char command[] = "pack";
93
register Huff_t *hp;
94
register char *infile,*outfile;
95
Sfio_t *fpin,*fpout;
96
int nfile=0, npack=0, force=0, verbose=0;
97
int out, deleted, dsize, n;
98
struct stat statb;
99
100
NOT_USED(argc);
101
error_info.id = command;
102
while(n = optget(argv,usage)) switch(n)
103
{
104
case 'f':
105
force++;
106
break;
107
case 'v':
108
verbose = !verbose;
109
break;
110
case ':':
111
error(2, opt_info.arg);
112
break;
113
case '?':
114
error(ERROR_usage(2), "%s", opt_info.arg);
115
break;
116
}
117
argv += opt_info.index;
118
if(error_info.errors || !*argv)
119
error(ERROR_usage(2), "%s", optusage((char*)0));
120
121
while (infile = *argv++)
122
{
123
if(*infile == '-')
124
{
125
/* awful way to handle options, but preserves SVID */
126
switch(infile[1])
127
{
128
case 'f':
129
force++;
130
continue;
131
case 0:
132
verbose = !verbose;
133
continue;
134
}
135
}
136
nfile++;
137
fpin = fpout = (Sfio_t*)0;
138
hp = (Huff_t*)0;
139
deleted = 0;
140
if(!(outfile = outname(infile)))
141
continue;
142
if (!(fpin=sfopen((Sfio_t*)0,infile,"r")))
143
error(ERROR_system(0), "%s: cannot open", infile);
144
else if(fstat(sffileno(fpin),&statb) < 0)
145
error(ERROR_system(0), "%s: cannot stat", infile);
146
else if(S_ISDIR(statb.st_mode))
147
error(2, "%s: cannot pack a directory", infile);
148
else if(statb.st_nlink > 1)
149
error(2, "%s: has links", infile);
150
else if(statb.st_size ==0)
151
error(2, "%s: cannot pack a zero length file", infile);
152
else if(access(outfile,F_OK) ==0)
153
error(ERROR_system(0), "%s: already exists", outfile);
154
else if(((out=open(outfile,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,PERM(statb.st_mode))) < 0) ||
155
!(fpout = sfnew((Sfio_t*)0,(char*)0,SF_UNBOUND,out,SF_WRITE)))
156
error(ERROR_system(0), "%s: cannot create", outfile);
157
else if((deleted++,chmod(outfile,statb.st_mode)) < 0)
158
error(ERROR_system(0), "%s: cannot change mode to %o",outfile,statb.st_mode);
159
else
160
{
161
chown(outfile,statb.st_uid,statb.st_gid);
162
if(!(hp = huffinit(fpin,(Sfoff_t)-1)))
163
error(2, "%s: read error", infile);
164
else if(sfseek(fpin,(Sfoff_t)0,0) < 0)
165
error(ERROR_system(0),"%s: seek error", infile);
166
else if((dsize = huffputhdr(hp,fpout)) < 0)
167
error(2, "%s: write error", infile);
168
else if(!force && block(huffisize(hp)) <= block(huffosize(hp)+dsize))
169
error(2, "%s:no savings - file unchanged", infile);
170
else if(huffencode(hp,fpin,fpout,SF_UNBOUND)<0)
171
error(2, "%s: read error", infile);
172
else
173
{
174
double diff;
175
if(remove(infile) < 0)
176
error(ERROR_system(0), "%s: cannot remove", infile);
177
diff = huffisize(hp) - (dsize+huffosize(hp));
178
sfprintf(sfstdout,"%s: %s : %.1f%% Compression\n",command,
179
infile,(100*diff)/((double)huffisize(hp)));
180
if(verbose)
181
vprint(hp,dsize);
182
npack++;
183
deleted = 0;
184
}
185
}
186
if(hp)
187
huffend(hp);
188
if(fpin)
189
sfclose(fpin);
190
if(fpout)
191
sfclose(fpout);
192
if(deleted)
193
remove(outfile);
194
if(outfile)
195
free(outfile);
196
}
197
nfile -= npack;
198
if(nfile > 125)
199
nfile = 125;
200
exit(nfile);
201
}
202
203
204
static char *outname(char *infile)
205
{
206
register int n = strlen(infile);
207
register int sufflen = strlen(suffix);
208
register char *cp;
209
if(streq(suffix,infile+n-sufflen))
210
{
211
error(ERROR_exit(1), "%s: already packed", infile);
212
return((char*)0);
213
}
214
if(cp = (char*)malloc(n+sufflen+1))
215
{
216
strcpy(cp,infile);
217
strcat(cp+n,suffix);
218
}
219
return(cp);
220
}
221
222
static void vprint(Huff_t *hp,int dsize)
223
{
224
sfprintf(sfstdout," from %lld to %lld bytes\n", huffisize(hp), huffosize(hp));
225
sfprintf(sfstdout," Huffman tree has %d levels below root\n", hp->maxlev);
226
sfprintf(sfstdout," %d distinct bytes in input\n", hp->nchars);
227
sfprintf(sfstdout," dictionary overhead = %ld bytes\n", dsize);
228
sfprintf(sfstdout," effective entropy = %.2f bits/byte\n",
229
((double)(huffosize(hp))/(double)huffisize(hp))*CHAR_BIT);
230
sfprintf(sfstdout," asymptotic entropy = %.2f bits/byte\n",
231
((double)(huffosize(hp)-dsize)/(double)huffisize(hp))*CHAR_BIT);
232
}
233
234