#include <cups/cups-private.h>
static int check_file(const char *filename);
static void usage(void) __attribute__((noreturn));
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;
printf("%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"));
status ++;
_cupsLangPrintf(stdout,
_(" Line %d is longer than 255 characters (%d).\n"
" REF: Page 25, Line Length"),
linenum, (int)bytes);
}
saw_long_line ++;
}
if (linenum == 1)
{
if (strncmp(line, "%!PS-Adobe-", 11))
{
if (!status)
_cupsLangPuts(stdout, _("FAIL"));
_cupsLangPuts(stdout,
_(" Missing %!PS-Adobe-3.0 on first line.\n"
" REF: Page 17, 3.1 Conforming Documents"));
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"));
status ++;
_cupsLangPrintf(stdout,
_(" Bad %%%%Pages: on line %d.\n"
" REF: Page 43, %%%%Pages:"),
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"));
status ++;
_cupsLangPrintf(stdout, _(" Bad %%%%BoundingBox: on line %d.\n"
" REF: Page 39, %%%%BoundingBox:"),
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"));
status ++;
_cupsLangPrintf(stdout, _(" Bad %%%%Pages: on line %d.\n"
" REF: Page 43, %%%%Pages:"),
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"));
status ++;
_cupsLangPrintf(stdout, _(" Bad %%%%BoundingBox: on line %d.\n"
" REF: Page 39, %%%%BoundingBox:"),
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"));
status ++;
_cupsLangPrintf(stdout, _(" Bad %%%%Page: on line %d.\n"
" REF: Page 53, %%%%Page:"),
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"));
status ++;
_cupsLangPuts(stdout, _(" Missing or bad %%BoundingBox: comment.\n"
" REF: Page 39, %%BoundingBox:"));
}
if (saw_pages <= 0)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL"));
status ++;
_cupsLangPuts(stdout, _(" Missing or bad %%Pages: comment.\n"
" REF: Page 43, %%Pages:"));
}
if (!saw_end_comments)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL"));
status ++;
_cupsLangPuts(stdout, _(" Missing %%EndComments comment."
" REF: Page 41, %%EndComments"));
}
if (!saw_page)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL"));
status ++;
_cupsLangPuts(stdout, _(" Missing or bad %%Page: comments.\n"
" REF: Page 53, %%Page:"));
}
if (level < 0)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL"));
status ++;
_cupsLangPuts(stdout, _(" Too many %%EndDocument comments."));
}
else if (level > 0)
{
if (!status)
_cupsLangPuts(stdout, _("FAIL"));
status ++;
_cupsLangPuts(stdout, _(" Too many %%BeginDocument comments."));
}
if (saw_long_line > 1)
_cupsLangPrintf(stderr,
_(" Saw %d lines that exceeded 255 characters."),
saw_long_line);
if (!status)
_cupsLangPuts(stdout, _("PASS"));
if (binary)
_cupsLangPuts(stdout, _(" Warning: file contains binary data."));
if (version < 3.0f)
_cupsLangPrintf(stdout,
_(" Warning: obsolete DSC version %.1f in file."),
version);
if (saw_end_comments < 0)
_cupsLangPuts(stdout, _(" Warning: no %%EndComments comment in file."));
cupsFileClose(fp);
return (status);
}
static void
usage(void)
{
_cupsLangPuts(stdout, _("Usage: cupstestdsc [options] filename.ps [... "
"filename.ps]"));
_cupsLangPuts(stdout, _(" cupstestdsc [options] -"));
_cupsLangPuts(stdout, "");
_cupsLangPuts(stdout, _("Options:"));
_cupsLangPuts(stdout, "");
_cupsLangPuts(stdout, _(" -h Show program usage"));
_cupsLangPuts(stdout, "");
_cupsLangPuts(stdout, _("Note: this program only validates the DSC comments, "
"not the PostScript itself."));
exit(1);
}