1 | /* |
---|
2 | * $Id$ |
---|
3 | */ |
---|
4 | |
---|
5 | #include <stdio.h> |
---|
6 | #include <string.h> |
---|
7 | #include <process.h> |
---|
8 | |
---|
9 | #include <io.h> |
---|
10 | |
---|
11 | void * xmalloc( int size ) |
---|
12 | { |
---|
13 | void * p = (void *)malloc( size ); |
---|
14 | if ( !p ) { |
---|
15 | fprintf( stderr, "out of memory\n" ); |
---|
16 | exit( 1 ); |
---|
17 | } |
---|
18 | return p; |
---|
19 | } |
---|
20 | void * xrealloc( void * old, int size ) |
---|
21 | { |
---|
22 | void * p = (void *)realloc( old, size ); |
---|
23 | if ( !p ) { |
---|
24 | fprintf( stderr, "out of memory\n" ); |
---|
25 | exit( 1 ); |
---|
26 | } |
---|
27 | return p; |
---|
28 | } |
---|
29 | |
---|
30 | char ** argv_fix( int * argc, char ** argv ) |
---|
31 | { |
---|
32 | char ** new = NULL; |
---|
33 | int max = 20; |
---|
34 | int cnt = 0; |
---|
35 | int j; |
---|
36 | |
---|
37 | for ( j = 1; argv[j]; ++j ) |
---|
38 | if ( argv[j][0] == '@' && access(argv[j]+1,0)==0 ) |
---|
39 | break; |
---|
40 | if ( argv[j] == NULL ) |
---|
41 | return argv; |
---|
42 | |
---|
43 | new = (char **)xmalloc( max * sizeof *new ); |
---|
44 | new[cnt++] = *argv++; |
---|
45 | for ( ; *argv; ++argv ) { |
---|
46 | if ( cnt >= max ) |
---|
47 | new = (char **)realloc( new, (max*=2) * sizeof *new ); |
---|
48 | |
---|
49 | if ( argv[0][0] != '@' || access(argv[0]+1,0) ) { |
---|
50 | new[cnt++] = *argv; |
---|
51 | } else { |
---|
52 | char line[ 1000 ]; |
---|
53 | FILE * f = fopen( argv[0]+1, "r" ); |
---|
54 | if ( !f ) { |
---|
55 | perror( argv[0]+1 ); |
---|
56 | exit( 2 ); |
---|
57 | } |
---|
58 | while ( fgets( line, sizeof line, f ) ) { |
---|
59 | int len = strlen( line ); |
---|
60 | /* delete trailing newlines */ |
---|
61 | while ( line[len-1] == '\n' || line[len-1] == '\r' ) |
---|
62 | line[--len] = '\0'; |
---|
63 | if ( cnt >= max ) |
---|
64 | new = (char **)xrealloc( new, (max*=2) * sizeof *new ); |
---|
65 | new[cnt] = (char *)xmalloc( len+1 ); |
---|
66 | strcpy( new[cnt], line ); |
---|
67 | ++cnt; |
---|
68 | } |
---|
69 | fclose( f ); |
---|
70 | } |
---|
71 | } |
---|
72 | if ( cnt >= max ) |
---|
73 | new = (char **)xrealloc( new, (max+1) * sizeof *new ); |
---|
74 | new[cnt] = NULL; |
---|
75 | *argc = cnt; |
---|
76 | return new; |
---|
77 | } |
---|
78 | |
---|
79 | |
---|
80 | const char * USAGE = |
---|
81 | "usage: $progname [ -cNvmV ] file [ file ... ] dest-directory-or-file\n" |
---|
82 | " -v -- verbose\n" |
---|
83 | " -V suffix -- suffix to append to targets (before any . suffix)\n" |
---|
84 | " eg: -V _g would change 'foo' to 'foo_g' and\n" |
---|
85 | " 'libfoo.a' to 'libfoo_g.a'\n" |
---|
86 | " -m mode -- mode for new file(s)\n" |
---|
87 | " -c -- copy instead of move (always on)\n" |
---|
88 | " -N -- copy only if source is newer than target\n" |
---|
89 | ; |
---|
90 | |
---|
91 | void fatal( char * msg ) |
---|
92 | { |
---|
93 | if ( msg ) |
---|
94 | fprintf( stderr, "%s\n", msg ); |
---|
95 | fprintf( stderr, "%s", USAGE ); |
---|
96 | exit( 1 ); |
---|
97 | } |
---|
98 | |
---|
99 | char * basename( char * f ) |
---|
100 | { |
---|
101 | char * b = strrchr( f, '/' ); |
---|
102 | if ( b ) ++b; |
---|
103 | else b = f; |
---|
104 | return b; |
---|
105 | } |
---|
106 | |
---|
107 | #include <sys/stat.h> |
---|
108 | int is_dir( char * path ) |
---|
109 | { |
---|
110 | struct stat buf; |
---|
111 | if ( stat( path, &buf ) ) |
---|
112 | return 0; |
---|
113 | return buf.st_mode & S_IFDIR; |
---|
114 | } |
---|
115 | int is_file( char * path ) |
---|
116 | { |
---|
117 | struct stat buf; |
---|
118 | if ( stat( path, &buf ) ) |
---|
119 | return 0; |
---|
120 | return buf.st_mode & S_IFREG; |
---|
121 | } |
---|
122 | int newer( char * p1, char * p2 ) |
---|
123 | { |
---|
124 | struct stat buf1; |
---|
125 | struct stat buf2; |
---|
126 | if ( stat( p1, &buf1 ) ) |
---|
127 | return 0; |
---|
128 | if ( stat( p2, &buf2 ) ) |
---|
129 | return 0; |
---|
130 | return buf1.st_mtime > buf2.st_mtime; |
---|
131 | } |
---|
132 | |
---|
133 | int filecopy( char * d, char * s, int preserve_time ) |
---|
134 | { |
---|
135 | #if 0 |
---|
136 | int status; |
---|
137 | char * argv[ 5 ]; |
---|
138 | argv[0] = "cp"; |
---|
139 | argv[1] = "-p"; |
---|
140 | argv[2] = s; |
---|
141 | argv[3] = d; |
---|
142 | argv[4] = NULL; |
---|
143 | status = spawnvp( P_WAIT, argv[0], argv ); |
---|
144 | if ( status ) |
---|
145 | perror( "cp" ); |
---|
146 | return status; |
---|
147 | #else |
---|
148 | FILE * fs; |
---|
149 | FILE * fd; |
---|
150 | char buffer[ 8192 ]; |
---|
151 | int n; |
---|
152 | struct ftime When; |
---|
153 | struct stat Stat; |
---|
154 | |
---|
155 | fs = fopen( s, "rb" ); |
---|
156 | if ( fs == NULL ) { |
---|
157 | perror( s ); |
---|
158 | return 1; |
---|
159 | } |
---|
160 | fd = fopen( d, "wb" ); |
---|
161 | if ( fd == NULL ) { |
---|
162 | perror( d ); |
---|
163 | fclose( fs ); |
---|
164 | return 2; |
---|
165 | } |
---|
166 | |
---|
167 | if ( preserve_time ) |
---|
168 | if ( getftime( fileno(fs), &When ) ) { |
---|
169 | perror( s ); |
---|
170 | preserve_time = 0; |
---|
171 | } |
---|
172 | |
---|
173 | do { |
---|
174 | n = fread( buffer, 1, sizeof buffer, fs ); |
---|
175 | if ( n > 0 ) |
---|
176 | if ( fwrite( buffer, 1, n, fd ) < 0 ) { |
---|
177 | perror( d ); |
---|
178 | return 3; |
---|
179 | } |
---|
180 | } while ( n > 0 ); |
---|
181 | |
---|
182 | fclose( fs ); |
---|
183 | |
---|
184 | /* Fix time stamp */ |
---|
185 | if ( preserve_time ) |
---|
186 | if ( setftime( fileno(fd), &When ) ) { |
---|
187 | perror( s ); |
---|
188 | preserve_time = 0; |
---|
189 | } |
---|
190 | fclose( fd ); |
---|
191 | |
---|
192 | /* Fix access rights */ |
---|
193 | if ( stat( s, &Stat ) ) |
---|
194 | perror( s ); |
---|
195 | else if ( chmod( d, Stat.st_mode ) ) |
---|
196 | perror( d ); |
---|
197 | |
---|
198 | return 0; |
---|
199 | #endif |
---|
200 | } |
---|
201 | |
---|
202 | |
---|
203 | |
---|
204 | |
---|
205 | |
---|
206 | int main( int argc, char * argv[] ) |
---|
207 | { |
---|
208 | char * progname; |
---|
209 | int verbose = 0; |
---|
210 | int only_if_newer= 0; |
---|
211 | char * suffix = NULL; |
---|
212 | char * mode = NULL; |
---|
213 | char * dest; |
---|
214 | char ** pp; |
---|
215 | |
---|
216 | argv = argv_fix( &argc, argv ); |
---|
217 | |
---|
218 | progname = basename( *argv++ ); |
---|
219 | |
---|
220 | /* process the options */ |
---|
221 | while ( argv[0] && argv[0][0] == '-' ) { |
---|
222 | switch ( argv[0][1] ) { |
---|
223 | case 'N': |
---|
224 | ++argv; |
---|
225 | only_if_newer = 1; |
---|
226 | break; |
---|
227 | case 'c': |
---|
228 | ++argv; |
---|
229 | /* We always copy, regardless */ |
---|
230 | break; |
---|
231 | case 'v': |
---|
232 | ++argv; |
---|
233 | verbose = 1; |
---|
234 | break; |
---|
235 | case 'V': |
---|
236 | ++argv; |
---|
237 | suffix = *argv; |
---|
238 | ++argv; |
---|
239 | break; |
---|
240 | case 'm': |
---|
241 | ++argv; |
---|
242 | mode = *argv; |
---|
243 | ++argv; |
---|
244 | break; |
---|
245 | default: |
---|
246 | fatal( NULL ); |
---|
247 | } |
---|
248 | } |
---|
249 | |
---|
250 | /* Separate source file(s) from dest directory or file */ |
---|
251 | #if 0 |
---|
252 | if ( !argv[0] || !argv[1] ) |
---|
253 | fatal( "missing files or invalid destination" ); |
---|
254 | #else |
---|
255 | /* We used to require at least one file; not any more */ |
---|
256 | if ( !argv[0] ) |
---|
257 | fatal( "missing files or invalid destination" ); |
---|
258 | if ( !argv[1] ) |
---|
259 | return 0; |
---|
260 | #endif |
---|
261 | for ( pp = argv; *pp; ++pp ) |
---|
262 | continue; |
---|
263 | --pp; |
---|
264 | dest = *pp; |
---|
265 | *pp = NULL; |
---|
266 | |
---|
267 | /* Process the arguments */ |
---|
268 | for (; *argv; ++argv ) { |
---|
269 | char * f = *argv; |
---|
270 | char * leaf = basename( f ); |
---|
271 | char target[ 128 ]; |
---|
272 | |
---|
273 | strcpy( target, dest ); |
---|
274 | |
---|
275 | if ( is_dir( target ) ) { |
---|
276 | strcat( target, "/" ); |
---|
277 | /* if we were given a suffix, then add it as appropriate */ |
---|
278 | if ( suffix ) { |
---|
279 | char * dot = strchr( leaf, '.' ); |
---|
280 | if ( dot ) { |
---|
281 | strncat( target, leaf, dot-leaf ); |
---|
282 | strcat( target, suffix ); |
---|
283 | strcat( target, dot ); |
---|
284 | if ( verbose ) |
---|
285 | printf( "%s: %s will be installed as %s", |
---|
286 | progname, f, strrchr(target,'/')+1 ); |
---|
287 | } else { |
---|
288 | strcat( target, leaf ); |
---|
289 | strcat( target, suffix ); |
---|
290 | } |
---|
291 | } else { |
---|
292 | strcat( target, leaf ); |
---|
293 | } |
---|
294 | } |
---|
295 | |
---|
296 | if ( access( f, 0 ) ) { |
---|
297 | char buf[200]; |
---|
298 | sprintf( buf, "cannot read %s", f ); |
---|
299 | fatal( buf ); |
---|
300 | } |
---|
301 | |
---|
302 | if ( only_if_newer && is_file( target ) && !newer( f, target ) ) { |
---|
303 | if ( verbose ) |
---|
304 | printf( "'%s' not newer than '%s'\n", f, target ); |
---|
305 | continue; |
---|
306 | } |
---|
307 | |
---|
308 | if ( verbose ) |
---|
309 | printf( "rm -f %s\n", target ); |
---|
310 | if ( chmod( target, 0777 ) ) |
---|
311 | if ( verbose ) |
---|
312 | perror( target ); |
---|
313 | if ( unlink( target ) ) |
---|
314 | if ( verbose ) |
---|
315 | perror( target ); |
---|
316 | if ( verbose ) |
---|
317 | printf( "cp -p %s %s\n", f, target ); |
---|
318 | if ( filecopy( target, f, 1 ) ) |
---|
319 | return 1; |
---|
320 | if ( mode ) { |
---|
321 | char buf[ 255 ]; |
---|
322 | sprintf( buf, "chmod %s %s\n", mode, target ); |
---|
323 | if ( verbose ) |
---|
324 | printf( "%s\n", buf ); |
---|
325 | system( buf ); |
---|
326 | } |
---|
327 | } |
---|
328 | |
---|
329 | return 0; |
---|
330 | } |
---|
331 | |
---|