#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include "postreverse.h"
static void *
nmalloc(size_t size)
{
void *ret = malloc(size);
if (!ret) {
(void) fprintf(stderr,
"postreverse : malloc() failed : Out of memory\n");
exit(2);
}
return (ret);
}
static void *
nrealloc(void *ptr, size_t size)
{
void *ret = realloc(ptr, size);
if (!ret) {
(void) fprintf(stderr,
"postreverse : realloc() failed - Out of memory\n");
exit(2);
}
return (ret);
}
static size_t
nstrlen(const char *s, char *bptr)
{
const char *s0 = s;
while (s < bptr && *s != '\0')
s++;
return (s - s0);
}
static char *
nstrstr(const char *as1, const char *as2, char *bptr)
{
const char *s1, *s2;
const char *tptr;
char c;
s1 = as1;
s2 = as2;
if (s2 == NULL || *s2 == '\0')
return ((char *)s1);
c = *s2;
while (s1 < bptr && *s1)
if (*s1++ == c) {
tptr = s1;
while ((s1 < bptr) &&
(c = *++s2) == *s1++ && c);
if (c == 0)
return ((char *)tptr - 1);
s1 = tptr;
s2 = as2;
c = *s2;
}
return (NULL);
}
caddr_t
strrstr(caddr_t s1, caddr_t s2, char *bptr)
{
char *t1, *t2;
char c;
t1 = s1 + nstrlen(s1, bptr) - 1;
t2 = s2 + nstrlen(s2, bptr) - 1;
if (t2 == NULL || *t2 == '\0')
return ((char *)t1);
c = *t2;
while (s1 <= t1)
if (*t1-- == c) {
while ((c = *--t2) == *t1-- && t2 > s2);
if (t2 <= s2)
return ((char *)t1 + 1);
t2 = s2 + nstrlen(s2, bptr) - 1;
c = *t2;
}
return (NULL);
}
char *
StdinToFile()
{
char *fileName = tmpnam(NULL);
int fd;
int count;
char buf[BUFSIZ];
if ((fd = open(fileName, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {
fprintf(stderr, "open(%s): %s\n", fileName,
strerror(errno));
return (NULL);
}
while ((count = read(0, buf, sizeof (buf))) > 0)
if (write(fd, buf, count) != count) {
fprintf(stderr, "write(%d, 0x%x, %d): %s\n", fd, buf,
count, strerror(errno));
close(fd);
unlink(fileName);
return (NULL);
}
return (fileName);
}
void
Usage(char *name)
{
fprintf(stderr, "Usage: %s [ -o list ] [ -r ] [ filename ]\n", name);
exit(1);
}
int **
ParsePageList(char *list)
{
int **pageList = NULL;
int pass = 0;
if (list == NULL)
return (NULL);
while (pass++ < 2) {
char *page;
char *tmplist;
int size = 0;
tmplist = strdup(list);
page = strtok(tmplist, ",");
do {
int start, end;
char *s1 = page, *s2;
if (s2 = strchr(page, '-')) {
*s2++ = '\0';
start = atoi(s1);
end = atoi(s2);
if (end < start) {
int tmp = end;
end = start;
start = tmp;
}
} else
start = end = atoi(s1);
while (start <= end)
if (pass == 1)
size++, start++;
else {
int *tmp = (int *)nmalloc(sizeof (int));
*tmp = start++;
pageList[size++] = tmp;
}
} while (page = strtok(NULL, ","));
free(tmplist);
if (pass == 1)
pageList = (int **)calloc(sizeof (int *), (size + 1));
}
return (pageList);
}
int
PageIsListed(int page, int **pageList)
{
int count = 0;
if (!pageList)
return (1);
for (count = 0; pageList[count] != NULL; count++)
if (*pageList[count] == page)
return (1);
return (0);
}
int
WriteDocumentHeader(int fd, DOCUMENT * d)
{
if (d) {
HEADER *h = d->header;
if (h)
return (write(fd, h->start, h->size));
}
errno = EINVAL;
return (-1);
}
int
WriteGlobal(int fd, GLOBAL * g)
{
if (g)
return (write(fd, g->start, g->size));
errno = EINVAL;
return (-1);
}
int
WriteDocumentTrailer(int fd, DOCUMENT * d)
{
if (d) {
TRAILER *t = d->trailer;
if (t)
return (write(fd, t->start, t->size));
}
errno = EINVAL;
return (-1);
}
int
WritePage(int fd, PAGE * p, int global, char *bptr)
{
if (p) {
caddr_t ptr1;
if (((ptr1 = nstrstr(p->start, PS_BEGIN_GLOBAL, bptr))
!= NULL) && (ptr1 < p->start + p->size) &&
(global != 0)) {
write(fd, p->start, ptr1 - p->start);
ptr1 = nstrstr(ptr1, PS_END_GLOBAL, bptr);
ptr1 += nstrlen(PS_END_GLOBAL, bptr);
return (write(fd, ptr1, (p->size - (ptr1 - p->start))));
} else
return (write(fd, p->start, p->size));
}
errno = EINVAL;
return (-1);
}
void
WriteDocument(DOCUMENT * document, int reverse, int **pageList)
{
int count = 0;
int prnindex;
if (document->header && document->trailer && document->page) {
WriteDocumentHeader(1, document);
if (document->global != NULL) {
while (document->global[count] != NULL) {
GLOBAL *global = document->global[count++];
if (global)
WriteGlobal(1, global);
}
}
count = reverse ? (document->pages-1) : 0;
for (prnindex = 0; prnindex < document->pages; prnindex++) {
PAGE *page = document->page[count];
if (page && PageIsListed(page->number, pageList))
WritePage(1, page, document->global != NULL,
document->start + document->size);
count = reverse ? count - 1 : count + 1;
}
WriteDocumentTrailer(1, document);
} else {
write(1, document->start, document->size);
}
}
HEADER *
DocumentHeader(DOCUMENT * document)
{
HEADER *header;
caddr_t start;
header = (HEADER *) nmalloc(sizeof (*header));
memset(header, 0, sizeof (*header));
if (start = nstrstr(document->start, PS_PAGE,
document->start + document->size)) {
header->label = "Document Header";
header->start = document->start;
header->size = (start - document->start + 1);
} else {
free(header);
header = NULL;
}
return (header);
}
TRAILER *
DocumentTrailer(DOCUMENT * document)
{
TRAILER *trailer;
trailer = (TRAILER *) nmalloc(sizeof (*trailer));
memset(trailer, 0, sizeof (trailer));
if (trailer->start = strrstr(document->start, PS_TRAILER,
document->start + document->size)) {
trailer->label = "Document Trailer";
trailer->start += 1;
trailer->size = nstrlen(trailer->start,
document->start + document->size);
} else {
free(trailer);
trailer = NULL;
}
return (trailer);
}
GLOBAL **
DocumentGlobals(DOCUMENT * document)
{
GLOBAL **globals = NULL, *global;
caddr_t start, ptr1;
int count = 0;
char *bptr = document->start + document->size;
long allocated_slots = 0;
caddr_t global_end;
start = nstrstr(document->start, PS_PAGE, bptr);
if (start != NULL) {
for (ptr1 = nstrstr(start, PS_BEGIN_GLOBAL, bptr); ptr1 != NULL;
ptr1 = nstrstr(++ptr1, PS_BEGIN_GLOBAL, bptr)) {
count++;
global = (GLOBAL *) nmalloc(sizeof (GLOBAL));
if ((global_end = nstrstr(++ptr1, PS_END_GLOBAL, bptr))
== NULL) {
fprintf(stderr,
"DSC violation: %%%%BeginGlobal "
"with no %%%%EndGlobal\n");
exit(-1);
}
memset(global, 0, sizeof (GLOBAL));
global->start = ptr1;
global->size = strchr(++global_end, '\n') - ptr1 + 1;
if (count > allocated_slots) {
globals = (GLOBAL **) nrealloc(globals,
(allocated_slots + BLOCKSIZE) *
sizeof (GLOBAL *));
memset(globals +
allocated_slots * sizeof (GLOBAL *), 0,
BLOCKSIZE *
sizeof (GLOBAL *));
allocated_slots += BLOCKSIZE;
}
globals[count - 1] = global;
ptr1 = global->start + global->size;
}
}
return (globals);
}
PAGE **
DocumentPages(DOCUMENT * document)
{
PAGE **pages = NULL, *page;
caddr_t ptr1, page_end;
char *bptr = document->start + document->size;
long allocated_slots = 0;
long no_pages = 0;
long number;
char *label, *tmp, *tmp_end;
for (ptr1 = nstrstr(document->start, PS_PAGE, bptr); ptr1 != NULL;
ptr1 = nstrstr(++ptr1, PS_PAGE, bptr)) {
no_pages++;
if (no_pages > allocated_slots) {
pages = (PAGE **) nrealloc(pages,
(allocated_slots + BLOCKSIZE) * sizeof (PAGE *));
memset(pages + allocated_slots, 0,
BLOCKSIZE * sizeof (PAGE *));
allocated_slots += BLOCKSIZE;
}
page = (PAGE *) nmalloc(sizeof (PAGE));
label = NULL;
number = -1;
if ((page_end = nstrstr(++ptr1, PS_PAGE, bptr)) == NULL)
if (document->trailer)
page_end = document->trailer->start - 1;
else
page_end = document->start + document->size;
if (tmp = strchr(ptr1, ' ')) {
if (tmp_end = strchr(++tmp, ' ')) {
label = (char *)nmalloc((tmp_end - tmp) + 1);
memset(label, 0, (tmp_end - tmp) + 1);
strncpy(label, tmp, (tmp_end - tmp));
number = atol(++tmp_end);
}
}
memset(page, 0, sizeof (PAGE));
page->label = label;
page->number = number;
page->start = ptr1;
page->size = page_end - ptr1 + 1;
pages[document->pages++] = page;
}
return (pages);
}
DOCUMENT *
DocumentParse(char *name)
{
DOCUMENT *document = NULL;
int fd;
struct stat st;
if (stat(name, &st) < 0) {
fprintf(stderr, "stat(%s): %s\n", name, strerror(errno));
return (NULL);
}
if (st.st_size == 0) {
fprintf(stderr, "%s: empty file\n", name);
return (NULL);
}
if ((fd = open(name, O_RDONLY)) < 0) {
fprintf(stderr, "open(%s, O_RDONLY): %s\n", name,
strerror(errno));
return (NULL);
}
document = (DOCUMENT *) nmalloc(sizeof (DOCUMENT));
memset(document, 0, sizeof (DOCUMENT));
if ((document->start = mmap((void *)0, (size_t)st.st_size, PROT_READ,
MAP_SHARED, fd, (off_t)0)) == MAP_FAILED) {
fprintf(stderr, "mmap(0, %ld, PROT_READ,"
" MAP_SHARED, %d, 0): %s\n",
st.st_size, fd, strerror(errno));
free(document);
document = NULL;
} else {
document->name = strdup(name);
document->size = nstrlen(document->start,
document->start + st.st_size);
document->header = DocumentHeader(document);
document->trailer = DocumentTrailer(document);
document->page = DocumentPages(document);
document->global = DocumentGlobals(document);
}
close(fd);
return (document);
}
#if defined(DEBUG)
void
PrintDocumentInfo(DOCUMENT * d)
{
if (d) {
printf("Document:\n\tname: %s\n\tstart: 0x%x\n\tsize: %ld\n",
d->name, d->start, d->size);
if (d->header) {
HEADER *h = d->header;
printf("\tHeader: %s (0x%x, %ld)\n",
h->label, h->start, h->size);
}
if (d->global) {
int count = 0;
while (d->global[count++] != NULL);
printf("\tDSC violating BeginGlobals: %d\n", count);
}
if (d->page) {
PAGE *p;
int count = 0;
printf("\tPages: (%d)\n", d->pages);
for (p = d->page[0]; p != NULL; p = d->page[++count])
printf("\t\t %4d (%s) - (0x%x, %ld)\n",
p->number,
(p->label ? p->label : "Page"),
p->start, p->size);
}
if (d->trailer) {
TRAILER *t = d->trailer;
printf("\tTrailer: %s (0x%x, %ld)\n",
t->label, t->start, t->size);
}
}
}
#endif
int
main(int ac, char *av[])
{
DOCUMENT *document;
char *fileName = NULL;
char *programName = NULL;
char *unlinkFile = NULL;
int reversePages = 1;
int **pageList = NULL;
int option;
if (programName = strrchr(av[0], '/'))
programName++;
else
programName = av[0];
while ((option = getopt(ac, av, "o:r")) != EOF)
switch (option) {
case 'o':
pageList = ParsePageList(optarg);
break;
case 'r':
reversePages = 0;
break;
case '?':
Usage(programName);
break;
default:
fprintf(stderr, "missing case for option %c\n", option);
Usage(programName);
break;
}
ac -= optind;
av += optind;
switch (ac) {
case 0:
unlinkFile = fileName = StdinToFile();
break;
case 1:
fileName = av[0];
break;
default:
Usage(programName);
}
if ((document = DocumentParse(fileName)) == NULL) {
fprintf(stderr, "Unable to parse document (%s)\n", fileName);
exit(0);
}
#if defined(DEBUG) && defined(NOTDEF)
PrintDocumentInfo(document);
#endif
WriteDocument(document, reversePages, pageList);
if (unlinkFile)
unlink(unlinkFile);
return (0);
}