#include <cups/string.h>
#include <cups/cups.h>
#include <cups/file.h>
#include <cups/i18n.h>
#include <errno.h>
#include <stdlib.h>
static int check_file(const char *filename);
static void usage(void);
int
main(int argc,
char *argv[])
{
int i;
int status;
int num_files;
_cupsSetLocale(argv);
for (i = 1, num_files = 0, status = 0; i < argc; i ++)
if (argv[i][0] == '-')
{
if (argv[i][1])
{
usage();
}
else
{
num_files ++;
status += check_file("(stdin)");
}
}
else
{
num_files ++;
status += check_file(argv[i]);
}
if (!num_files)
usage();
return (status);
}
static int
check_file(const char *filename)
{
int i;
cups_file_t *fp;
char line[1024];
int ch;
size_t bytes;
int status;
int linenum;
int binary;
float version;
int lbrt[4];
char page_label[256];
int page_number;
int last_page_number;
int level;
int saw_bounding_box,
saw_pages,
saw_end_comments,
saw_begin_prolog,
saw_end_prolog,
saw_begin_setup,
saw_end_setup,
saw_page,
saw_trailer,
saw_long_line;
if (!strcmp(filename, "(stdin)"))
fp = cupsFileStdin();
else
fp = cupsFileOpen(filename, "r");
if (!fp)
{
perror(filename);
return (1);
}
binary = 0;
last_page_number = 0;
level = 0;
linenum = 0;
saw_begin_prolog = 0;
saw_begin_setup = 0;
saw_bounding_box = 0;
saw_end_comments = 0;
saw_end_prolog = 0;
saw_end_setup = 0;
saw_long_line = 0;
saw_page = 0;
saw_pages = 0;
saw_trailer = 0;
status = 0;
version = 0.0f;
_cupsLangPrintf(stdout, "%s: ", filename);
fflush(stdout);
while ((bytes = cupsFileGetLine(fp, line, sizeof(line))) > 0)
{
linenum ++;
if (bytes > 255)
{
if (!saw_long_line)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPrintf(stdout,
_(" Line %d is longer than 255 characters (%d)!\n"
" REF: Page 25, Line Length\n"),
linenum, (int)bytes);
}
saw_long_line ++;
}
if (linenum == 1)
{
if (strncmp(line, "%!PS-Adobe-", 11))
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
_cupsLangPuts(stdout,
_(" Missing %!PS-Adobe-3.0 on first line!\n"
" REF: Page 17, 3.1 Conforming Documents\n"));
cupsFileClose(fp);
return (1);
}
else
version = atof(line + 11);
}
else if (level > 0)
{
if (!strncmp(line, "%%BeginDocument:", 16))
level ++;
else if (!strncmp(line, "%%EndDocument", 13))
level --;
}
else if (saw_trailer)
{
if (!strncmp(line, "%%Pages:", 8))
{
if (atoi(line + 8) <= 0)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPrintf(stdout,
_(" Bad %%%%Pages: on line %d!\n"
" REF: Page 43, %%%%Pages:\n"),
linenum);
}
else
saw_pages = 1;
}
else if (!strncmp(line, "%%BoundingBox:", 14))
{
if (sscanf(line + 14, "%d%d%d%d", lbrt + 0, lbrt + 1, lbrt + 2,
lbrt + 3) != 4)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPrintf(stdout, _(" Bad %%%%BoundingBox: on line %d!\n"
" REF: Page 39, %%%%BoundingBox:\n"),
linenum);
}
else
saw_bounding_box = 1;
}
}
else if (!saw_end_comments)
{
if (!strncmp(line, "%%EndComments", 13))
saw_end_comments = 1;
else if (line[0] != '%')
saw_end_comments = -1;
else if (!strncmp(line, "%%Pages:", 8))
{
if (strstr(line + 8, "(atend)"))
saw_pages = -1;
else if (atoi(line + 8) <= 0)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPrintf(stdout, _(" Bad %%%%Pages: on line %d!\n"
" REF: Page 43, %%%%Pages:\n"),
linenum);
}
else
saw_pages = 1;
}
else if (!strncmp(line, "%%BoundingBox:", 14))
{
if (strstr(line, "(atend)"))
saw_bounding_box = -1;
else if (sscanf(line + 14, "%d%d%d%d", lbrt + 0, lbrt + 1, lbrt + 2,
lbrt + 3) != 4)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPrintf(stdout, _(" Bad %%%%BoundingBox: on line %d!\n"
" REF: Page 39, %%%%BoundingBox:\n"),
linenum);
}
else
saw_bounding_box = 1;
}
}
else if (saw_begin_prolog && !saw_end_prolog)
{
if (!strncmp(line, "%%EndProlog", 11))
saw_end_prolog = 1;
}
else if (saw_begin_setup && !saw_end_setup)
{
if (!strncmp(line, "%%EndSetup", 10))
saw_end_setup = 1;
}
else if (saw_end_comments)
{
if (!strncmp(line, "%%Page:", 7))
{
if (sscanf(line + 7, "%255s%d", page_label, &page_number) != 2 ||
page_number != (last_page_number + 1) || page_number < 1)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPrintf(stdout, _(" Bad %%%%Page: on line %d!\n"
" REF: Page 53, %%%%Page:\n"),
linenum);
}
else
{
last_page_number = page_number;
saw_page = 1;
}
}
else if (!strncmp(line, "%%BeginProlog", 13))
saw_begin_prolog = 1;
else if (!strncmp(line, "%%BeginSetup", 12))
saw_begin_setup = 1;
else if (!strncmp(line, "%%BeginDocument:", 16))
level ++;
else if (!strncmp(line, "%%EndDocument", 13))
level --;
else if (!strncmp(line, "%%Trailer", 9))
saw_trailer = 1;
}
for (i = 0; !binary && i < bytes; i ++)
{
ch = line[i];
if ((ch < ' ' || (ch & 0x80)) && ch != '\n' && ch != '\r' && ch != '\t')
binary = 1;
}
}
if (saw_bounding_box <= 0)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPuts(stdout, _(" Missing or bad %%BoundingBox: comment!\n"
" REF: Page 39, %%BoundingBox:\n"));
}
if (saw_pages <= 0)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPuts(stdout, _(" Missing or bad %%Pages: comment!\n"
" REF: Page 43, %%Pages:\n"));
}
if (!saw_end_comments)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPuts(stdout, _(" Missing %%EndComments comment!\n"
" REF: Page 41, %%EndComments\n"));
}
if (!saw_page)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPuts(stdout, _(" Missing or bad %%Page: comments!\n"
" REF: Page 53, %%Page:\n"));
}
if (level < 0)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPuts(stdout, _(" Too many %%EndDocument comments!\n"));
}
else if (level > 0)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL\n"));
status ++;
_cupsLangPuts(stdout, _(" Too many %%BeginDocument comments!\n"));
}
if (saw_long_line > 1)
_cupsLangPrintf(stderr,
_(" Saw %d lines that exceeded 255 characters!\n"),
saw_long_line);
if (!status)
_cupsLangPuts(stdout, _("PASS\n"));
if (binary)
_cupsLangPuts(stdout, _(" Warning: file contains binary data!\n"));
if (version < 3.0f)
_cupsLangPrintf(stdout,
_(" Warning: obsolete DSC version %.1f in file!\n"),
version);
if (saw_end_comments < 0)
_cupsLangPuts(stdout, _(" Warning: no %%EndComments comment in file!\n"));
cupsFileClose(fp);
return (status);
}
static void
usage(void)
{
_cupsLangPuts(stdout,
_("Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
" cupstestdsc [options] -\n"
"\n"
"Options:\n"
"\n"
" -h Show program usage\n"
"\n"
" Note: this program only validates the DSC comments, "
"not the PostScript itself.\n"));
exit(1);
}