]> arthur.barton.de Git - netatalk.git/blob - bin/psorder/psorder.c
Remove bdb env on exit
[netatalk.git] / bin / psorder / psorder.c
1 /*
2  * $Id: psorder.c,v 1.10 2010-04-12 14:28:47 franklahm Exp $
3  *
4  * Copyright (c) 1990,1991 Regents of The University of Michigan.
5  * All Rights Reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software and
8  * its documentation for any purpose and without fee is hereby granted,
9  * provided that the above copyright notice appears in all copies and
10  * that both that copyright notice and this permission notice appear
11  * in supporting documentation, and that the name of The University
12  * of Michigan not be used in advertising or publicity pertaining to
13  * distribution of the software without specific, written prior
14  * permission. This software is supplied as is without expressed or
15  * implied warranties of any kind.
16  *
17  *      Research Systems Unix Group
18  *      The University of Michigan
19  *      c/o Mike Clark
20  *      535 W. William Street
21  *      Ann Arbor, Michigan
22  *      +1-313-763-0525
23  *      netatalk@itd.umich.edu
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29
30 #include <stdlib.h>
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/stat.h>
35 #include <sys/uio.h>
36 #include <sys/file.h>
37 #include <ctype.h>
38 #include <limits.h>
39 #ifdef HAVE_FCNTL_H
40 #include <fcntl.h>
41 #endif /* HAVE_FCNTL_H */
42 #include <stdio.h>
43 #include <string.h>
44 #include <dirent.h>
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif /* HAVE_UNISTD_H */
48 #include "pa.h"
49 #include "psorder.h"
50
51 #include <atalk/paths.h>
52
53 /*
54  *                      Global Variables
55  */
56
57 static u_char                   psbuf[ 8192 ];
58 static struct psinfo_st         psinfo;
59 static int                      orderflag, forceflag;
60
61 static void
62 filecleanup( int errorcode, int tfd, char *tfile)
63 {
64
65 /*
66         Close and unlink the temporary file.
67  */
68
69     if ( tfd != 0 ) {
70         if ( close( tfd ) != 0 ) {
71             perror( tfile );
72             exit( errorcode );
73         }
74         if ( unlink( tfile ) != 0 ) {
75             perror( tfile );
76             exit( errorcode );
77         }
78     }
79
80     exit( errorcode );
81 }
82
83 static void
84 filesetup( char *inputfile, int *infd, char *tfile, int *tfd)
85 {
86     struct stat         st;
87     char                *template = _PATH_TMPPAGEORDER;
88
89     if ( strcmp( inputfile, STDIN ) != 0 ) {
90         if ( stat( inputfile, &st ) < 0 ) {
91             perror( inputfile );
92             filecleanup( -1, -1, "" );
93         }
94         if ( st.st_mode & S_IFMT & S_IFDIR ) {
95             fprintf( stderr, "%s is a directory.\n", inputfile );
96             filecleanup( 0, -1, "" );
97         }
98         if (( *infd = open( inputfile, O_RDONLY, 0600 )) < 0 ) {
99             perror( inputfile );
100             filecleanup( -1, -1, "" );
101         }
102     } else {
103         *infd = 0;
104     }
105
106 #if DEBUG
107     fprintf( stderr, "Input file or stdin and stdout opened.\n" );
108     fprintf( stderr, "Input file descriptor is %d .\n", *infd );
109 #endif /* DEBUG */
110
111 /*
112         make temporary file
113  */
114
115 #if defined(NAME_MAX)
116     (void *)strncpy( tfile, template, NAME_MAX );
117 #else
118     (void *)strncpy( tfile, template, MAXNAMLEN );
119 #endif
120     if (( *tfd = mkstemp( tfile )) == -1 ) {
121         fprintf( stderr, "can't create temporary file %s\n", tfile );
122         filecleanup( -1, -1, "" );
123     }
124
125 #if DEBUG
126     fprintf( stderr, "Temporary file %s created and opened.\n", tfile );
127     fprintf( stderr, "Temporary file descriptor is %d .\n", *tfd );
128 #endif /* DEBUG */
129
130     psinfo.firstpage = NULL;
131     psinfo.lastpage = NULL;
132     psinfo.trailer = 0;
133     psinfo.pages.offset = 0;
134     psinfo.pages.end = 0;
135     psinfo.pages.num[0] = '\0';
136     psinfo.pages.order[0] = '\0';
137
138     return;
139 }
140
141 static struct pspage_st
142 *getpspage(off_t off)
143 {
144     struct pspage_st    *newpspage;
145
146     newpspage = (struct pspage_st *)malloc( sizeof( struct pspage_st )); 
147     if ( newpspage != NULL ) {
148         newpspage->offset = off;
149         newpspage->nextpage = NULL;
150         *newpspage->lable = '\0';
151         *newpspage->ord = '\0';
152     }
153     return( newpspage );
154 }
155
156 static int
157 handletok(off_t count, char *token)
158 {
159     int                 incdoc = 0;
160     struct pspage_st    *newpage;
161     char                *tmp;
162
163     if (( strncmp( PENDDOC, token, strlen( PENDDOC )) == 0 ) && incdoc ) {
164         incdoc--;
165 #if DEBUG
166         fprintf( stderr, "found an EndDoc\n" );
167 #endif /* DEBUG */
168
169     } else if ( strncmp( PBEGINDOC, token, strlen( PBEGINDOC )) == 0 ) {
170         incdoc++;
171 #if DEBUG
172         fprintf( stderr, "found a BeginDoc\n" );
173 #endif /* DEBUG */
174
175     } else if ( !incdoc && 
176             ( strncmp( PPAGE, token, strlen( PPAGE )) == 0 )) {
177 #if DEBUG
178         fprintf( stderr, "found a Page\n" );
179 #endif /* DEBUG */
180         if (( newpage = getpspage( count )) == NULL ) {
181             return( -1 );
182         }
183         if ( psinfo.firstpage == NULL ) {
184             newpage->prevpage = NULL;
185             psinfo.firstpage = newpage;
186         } else {
187             newpage->prevpage = psinfo.lastpage;
188             psinfo.lastpage->nextpage = newpage;
189         }
190         psinfo.lastpage = newpage;
191         while ( *token++ != ':' );
192         if (( tmp = strtok( token, WHITESPACE )) != NULL ) {
193             (void)strncpy( newpage->lable, tmp, NUMLEN );
194             if (( tmp = strtok( NULL, WHITESPACE )) != NULL ) {
195                 (void)strncpy( newpage->ord, tmp, ORDLEN );
196             }
197         }
198 #if DEBUG
199         fprintf( stderr, "page lable %s, page ord %s\n", newpage->lable,
200                 newpage->ord );
201 #endif /* DEBUG */
202
203     } else if ( !incdoc && 
204             ( strncmp( PPAGES, token, strlen( PPAGES )) == 0 )) {
205 #if DEBUG
206         fprintf( stderr, "found a Pages\n" );
207 #endif /* DEBUG */
208         psinfo.pages.offset = count;
209         psinfo.pages.end = strlen( token ) + count;
210         while ( *token++ != ':' );
211         while ( isspace( *token )) token++;
212         if ( strncmp( ATEND, token, strlen( ATEND )) == 0 ) {
213 #if DEBUG
214             fprintf( stderr, "it is a Pages: (atend)\n" );
215 #endif /* DEBUG */
216             psinfo.pages.offset = 0;
217             psinfo.pages.end = 0;
218         } else {
219             if (( tmp = strtok( token, WHITESPACE )) != NULL ) {
220                 (void)strncpy( psinfo.pages.num, tmp, NUMLEN );
221                 if (( tmp = strtok( NULL, WHITESPACE )) != NULL ) {
222                     (void)strncpy( psinfo.pages.order, tmp, ORDERLEN );
223                 }
224             }
225 #if DEBUG
226             fprintf( stderr, "number of pages %s\n", psinfo.pages.num );
227             fprintf( stderr, "order control number %s\n", psinfo.pages.order );
228 #endif /* DEBUG */
229         }
230
231     } else if ( !incdoc && 
232             ( strncmp( PTRAILER, token, strlen( PTRAILER )) == 0 )) {
233 #if DEBUG
234         fprintf( stderr, "found the Trailer\n" );
235 #endif /* DEBUG */
236         if  ( psinfo.trailer == 0 ) {
237             psinfo.trailer = count;
238         }
239     }
240
241     return( 0 );
242 }
243
244 static void
245 readps(int inputfd, int tempfd, char *tempfile)
246 {
247     off_t               ccread = 0;
248     off_t               ccmatch;
249     char                *curtok = NULL;
250     FILE                *tempstream;
251     pa_buf_t            *pb;
252     int                 n;
253     char                c = -1;
254     char                pc, cc = 0;
255
256     pb = pa_init( inputfd );
257     if (( tempstream = fdopen( tempfd, "w" )) == NULL ) {
258         perror( "fdopen fails for tempfile" );
259         filecleanup( -1, tempfd, tempfile );
260     }
261
262     if (( c = pa_getchar( pb )) != 0 ) {
263         ccread++;
264         (void)putc( c, tempstream );
265         pc = 0;
266         cc = c;
267         pa_match( pb );
268         n = strlen( PPSADOBE );
269         for ( ; ( n > 0 ) && (( c = pa_getchar( pb )) != 0 ) ; n-- ) {
270             ccread++ ;
271             (void)putc( c, tempstream );
272             pc = cc;
273             cc = c;
274         }
275         curtok = pa_gettok( pb );
276     }
277 #if DEBUG
278     fprintf( stderr, "%s\n", curtok );
279 #endif /* DEBUG */
280
281 /*
282  * not postscript
283  */
284     if ( strcmp( curtok, PPSADOBE ) != 0 ) {
285 #if DEBUG
286     fprintf( stderr, "in the not postscript section of readps\n" );
287 #endif /* DEBUG */
288         while (( c = pa_getchar( pb )) != 0 ) {
289             ccread++;
290             (void)putc( c, tempstream );
291             pc = cc;
292             cc = c;
293         }
294
295         (void)fflush( tempstream );
296         return;
297     }
298
299 /*
300  * postscript
301  */
302 #if DEBUG
303     fprintf( stderr, "in the postscript section of readps\n" );
304 #endif /* DEBUG */
305     while (( c = pa_getchar( pb )) != 0 ) {
306         ccread++;
307         (void)putc( c, tempstream );
308         pc = cc;
309         cc = c;
310         if ((( pc == '\r' ) || ( pc == '\n' )) && ( cc == '%' )) {
311 #if DEBUG
312             fprintf( stderr, "supposed start of match, cc = %c\n", cc );
313 #endif /* DEBUG */
314             pa_match( pb );
315             ccmatch = ccread - 1;
316             while ( ( c = pa_getchar( pb ) ) ) {
317                 if ( c != 0 ) {
318                     ccread++;
319                     (void)putc( c, tempstream );
320                     pc = cc;
321                     cc = c;
322                 }
323                 if (( c == '\r' ) || ( c == '\n' ) || ( cc == '\0' )) {
324                     curtok = pa_gettok( pb );
325 #if DEBUG
326                     fprintf( stderr, "%s\n", curtok );
327 #endif /* DEBUG */
328                     if ( handletok( ccmatch, curtok ) < 0 ) {
329                         perror( "malloc died" );
330                         filecleanup( -1, tempfd, tempfile );
331                     }
332                     break;
333                 }
334                 if ( c == 0 ) break;
335             }
336             if ( c == 0 ) break;
337         }
338     }
339
340     (void)fflush( tempstream );
341     return;
342 }
343
344 static void
345 temp2out(int tempfd, char *tempfile, off_t length)
346 {
347     int                 ccread;
348     int                 ccwrite;
349     int                 size;
350
351     while ( length > 0 ) {
352         if ( length > sizeof( psbuf )) {
353             size = sizeof( psbuf );
354         } else size = length;
355         if (( ccread = read( tempfd, psbuf, size )) > 0 ) {
356             size = ccread;
357             while ( ccread > 0 ) {
358                 ccwrite = write( 1, psbuf, ccread );
359                 if ( ccwrite < 0 ) {
360                     perror( "stdout" );
361                     filecleanup( ccwrite, tempfd, tempfile );
362                 } else {
363                     ccread -= ccwrite;
364                 }
365             }
366         }
367         if ( ccread < 0 ) {
368             perror( "temporary file" );
369             filecleanup( ccread, tempfd, tempfile );
370         }
371         length -= size;
372     }
373 }
374
375 static void
376 writelable(int tempfd, char *tempfile, char *lable)
377 {
378     char                line[256];
379     int                 ccwrite;
380     int                 linelen;
381     char                *argone;
382     char                *argtwo;
383
384     if ( strcmp( lable, PPAGES ) == 0 ) {
385         argone = psinfo.pages.num;
386         argtwo = psinfo.pages.order;
387     } else {
388         argone = argtwo = NULL;
389     }
390     (void)sprintf( line, "%s %s %s", lable, argone, argtwo );
391     linelen = strlen( line );
392
393     ccwrite = write( 1, line, linelen );
394     if ( ccwrite < 0 ) {
395         perror( "stdout" );
396         filecleanup( ccwrite, tempfd, tempfile );
397     } else {
398         linelen -= ccwrite;
399     }
400 }
401
402 static void
403 writeps(int tempfd, char *tempfile)
404 {
405     struct stat         st;
406     off_t               endofpage;
407     int                 order;
408
409     if ( stat( tempfile, &st ) < 0 ) {
410         perror( "stat failed" );
411         filecleanup( -1, tempfd, tempfile );
412     }
413     if ( psinfo.trailer == 0 ) {
414         endofpage = st.st_size;
415     } else endofpage = psinfo.trailer;
416
417     if (( psinfo.firstpage == NULL ) || 
418             ( psinfo.firstpage == psinfo.lastpage )) {
419         order = FORWARD;
420     } else if ( psinfo.pages.offset == 0 ) {
421         order = orderflag;
422     } else if (( strncmp( psinfo.pages.order, "", ORDERLEN ) == 0 ) ||
423             ( strncmp( psinfo.pages.order, "1", ORDERLEN ) == 0 )) {
424         order = orderflag;
425         if ( order == REVERSE ) strcpy( psinfo.pages.order, "-1" );
426     } else if ( strncmp( psinfo.pages.order, "-1", ORDERLEN ) == 0 ) {
427         if ( orderflag == FORWARD ) {
428             order = REVERSE;
429             strcpy( psinfo.pages.order, "1" );
430         } else order = FORWARD;
431     } else if (( strncmp( psinfo.pages.order, "0", ORDERLEN ) == 0 ) &&
432             forceflag ) {
433         order = orderflag;
434     } else order = FORWARD;
435
436     if ( order == FORWARD ) {
437         temp2out( tempfd, tempfile, st.st_size );
438     } else {
439 /*
440  *      output the header stuff and rewrite the $$Pages line
441  *      if it is in the header and not %%Pages: (atend)
442  */
443         if ( psinfo.firstpage->offset > 0 ) {
444             if (( psinfo.firstpage->offset > psinfo.pages.offset ) &&
445                     ( psinfo.pages.offset != 0 )) {
446                 temp2out( tempfd, tempfile, psinfo.pages.offset );
447                 writelable( tempfd, tempfile, PPAGES );
448                 if ( lseek( tempfd, psinfo.pages.end, SEEK_SET ) < 0 ) {
449                     perror( tempfile );
450                     filecleanup( -1, tempfd, tempfile );
451                 }
452                 temp2out( tempfd, tempfile, 
453                         psinfo.firstpage->offset - psinfo.pages.end );
454             } else temp2out( tempfd, tempfile, psinfo.firstpage->offset );
455         }
456 /*
457  *      output the pages, last to first
458  */
459         while ( psinfo.lastpage != NULL ) {
460             if ( lseek( tempfd, psinfo.lastpage->offset, SEEK_SET ) < 0 ) {
461                 perror( tempfile );
462                 filecleanup( -1, tempfd, tempfile );
463             }
464             temp2out( tempfd, tempfile, endofpage - psinfo.lastpage->offset );
465             endofpage = psinfo.lastpage->offset;
466             psinfo.lastpage = psinfo.lastpage->prevpage;
467             if ( psinfo.lastpage != NULL ) {
468                 (void)free( psinfo.lastpage->nextpage );
469                 psinfo.lastpage->nextpage = NULL;
470             }
471         }
472 /*
473  *      output the trailer stuff and rewrite the $$Pages line
474  *      if it is in the trailer
475  */
476         if ( psinfo.trailer != 0 ) {
477             if ( lseek( tempfd, psinfo.trailer, SEEK_SET ) < 0 ) {
478                 perror( tempfile );
479                 filecleanup( -1, tempfd, tempfile );
480             }
481             if ( psinfo.trailer < psinfo.pages.offset ) {
482                 temp2out( tempfd, tempfile,
483                         psinfo.pages.offset - psinfo.trailer );
484                 writelable( tempfd, tempfile, PPAGES );
485                 if ( lseek( tempfd, psinfo.pages.end, SEEK_SET ) < 0 ) {
486                     perror( tempfile );
487                     filecleanup( -1, tempfd, tempfile );
488                 }
489                 temp2out( tempfd, tempfile, st.st_size - psinfo.pages.end );
490             } else temp2out( tempfd, tempfile, st.st_size - psinfo.trailer );
491         }
492     }
493
494     return;
495 }
496
497 static int
498 psorder(char *path)
499 {
500     int                 tempfd;
501     int                 inputfd;
502 #if defined(NAME_MAX)
503     char                tempfile[NAME_MAX];
504 #else
505     char                tempfile[MAXNAMLEN];
506 #endif
507
508     filesetup( path, &inputfd, tempfile, &tempfd );
509     readps( inputfd, tempfd, tempfile );
510     if ( lseek( tempfd, REWIND, SEEK_SET ) < 0 ) {
511         perror( tempfile );
512         filecleanup( -1, tempfd, tempfile );
513     }
514     writeps( tempfd, tempfile );
515     filecleanup( 0, tempfd, tempfile );
516     return( 0 );
517 }
518
519 int main(int argc, char **argv)
520 {
521     extern int  optind;
522     char        *progname;
523     int         errflag = 0;
524     int         c;
525
526     while (( c = getopt( argc, argv, OPTSTR )) != -1 ) {
527         switch ( c ) {
528         case REVCHAR:
529             if ( orderflag ) errflag++;
530             else orderflag = REVERSE;
531             break;
532         case FORWCHAR:
533             if ( orderflag ) errflag++;
534             else orderflag = FORWARD;
535             break;
536         case FORCECHAR:
537             if ( forceflag ) errflag++;
538             else forceflag++;
539             break;
540         }
541     }
542     if ( errflag ) {
543         if (( progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
544             progname = argv[ 0 ];
545         } else progname++;
546         fprintf( stderr, "usage: %s [-duf] [sourcefile]\n", progname );
547         return( -1 );
548     } else if ( !orderflag ) orderflag = FORWARD;
549
550     if ( optind >= argc ) {
551         return( psorder( STDIN ));
552     }
553     return( psorder( argv[ optind ] ));
554 }
555