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 57static u_char psbuf[ 8192 ]; 58static struct psinfo_st psinfo; 59static int orderflag, forceflag; 60 61static void 62filecleanup( 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 83static void 84filesetup( 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 141static 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 156static int 157handletok(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 244static void 245readps(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 344static void 345temp2out(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 375static void 376writelable(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 402static void 403writeps(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 497static int 498psorder(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 519int 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 556