#include "ppd.h"
#include <stdlib.h>
#include "string.h"
#include <errno.h>
#include "debug.h"
#if defined(WIN32) || defined(__EMX__)
# include <io.h>
#else
# include <unistd.h>
#endif
static void ppd_handle_media(ppd_file_t *ppd);
static int ppd_sort(ppd_choice_t **c1, ppd_choice_t **c2);
static const char ppd_custom_code[] =
"pop pop pop\n"
"<</PageSize[5 -2 roll]/ImagingBBox null>>setpagedevice\n";
int
ppdCollect(ppd_file_t *ppd,
ppd_section_t section,
ppd_choice_t ***choices)
{
return (ppdCollect2(ppd, section, 0.0, choices));
}
int
ppdCollect2(ppd_file_t *ppd,
ppd_section_t section,
float min_order,
ppd_choice_t ***choices)
{
int i, j, k, m;
ppd_group_t *g,
*sg;
ppd_option_t *o;
ppd_choice_t *c;
int count;
ppd_choice_t **collect;
DEBUG_printf(("ppdCollect2(ppd=%p, section=%d, min_order=%f, choices=%p)\n",
ppd, section, min_order, choices));
if (ppd == NULL)
return (0);
count = 0;
collect = calloc(sizeof(ppd_choice_t *), 1000);
for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
{
for (j = g->num_options, o = g->options; j > 0; j --, o ++)
if (o->section == section && o->order >= min_order)
for (k = o->num_choices, c = o->choices; k > 0; k --, c ++)
if (c->marked && count < 1000)
{
DEBUG_printf(("ppdCollect2: %s=%s marked...\n", o->keyword,
c->choice));
collect[count] = c;
count ++;
}
for (j = g->num_subgroups, sg = g->subgroups; j > 0; j --, sg ++)
for (k = sg->num_options, o = sg->options; k > 0; k --, o ++)
if (o->section == section && o->order >= min_order)
for (m = o->num_choices, c = o->choices; m > 0; m --, c ++)
if (c->marked && count < 1000)
{
DEBUG_printf(("ppdCollect2: %s=%s marked...\n", o->keyword,
c->choice));
collect[count] = c;
count ++;
}
}
if (count > 1)
qsort(collect, count, sizeof(ppd_choice_t *),
(int (*)(const void *, const void *))ppd_sort);
DEBUG_printf(("ppdCollect2: %d marked choices...\n", count));
if (count > 0)
{
*choices = collect;
return (count);
}
else
{
*choices = NULL;
free(collect);
return (0);
}
}
int
ppdEmit(ppd_file_t *ppd,
FILE *fp,
ppd_section_t section)
{
return (ppdEmitAfterOrder(ppd, fp, section, 0, 0.0));
}
int
ppdEmitAfterOrder(
ppd_file_t *ppd,
FILE *fp,
ppd_section_t section,
int limit,
float min_order)
{
char *buffer;
int status;
if (!ppd || !fp)
return (-1);
buffer = ppdEmitString(ppd, section, min_order);
if (buffer)
{
status = fputs(buffer, fp) < 0 ? -1 : 0;
free(buffer);
}
else
status = 0;
return (status);
}
int
ppdEmitFd(ppd_file_t *ppd,
int fd,
ppd_section_t section)
{
char *buffer,
*bufptr;
size_t buflength;
ssize_t bytes;
int status;
if (!ppd || fd < 0)
return (-1);
buffer = ppdEmitString(ppd, section, 0.0);
if (buffer)
{
buflength = strlen(buffer);
bufptr = buffer;
bytes = 0;
while (buflength > 0)
{
#ifdef WIN32
if ((bytes = (ssize_t)write(fd, bufptr, (unsigned)buflength)) < 0)
#else
if ((bytes = write(fd, bufptr, buflength)) < 0)
#endif
{
if (errno == EAGAIN || errno == EINTR)
continue;
break;
}
buflength -= bytes;
bufptr += bytes;
}
status = bytes < 0 ? -1 : 0;
free(buffer);
}
else
status = 0;
return (status);
}
int
ppdEmitJCL(ppd_file_t *ppd,
FILE *fp,
int job_id,
const char *user,
const char *title)
{
char *ptr;
char temp[81];
if (!ppd || !ppd->jcl_begin || !ppd->jcl_ps)
return (0);
if (!strncmp(ppd->jcl_begin, "\033%-12345X@", 10))
{
ppd_attr_t *charset;
if ((charset = ppdFindAttr(ppd, "cupsPJLCharset", NULL)) != NULL)
{
if (!charset->value || strcasecmp(charset->value, "UTF-8"))
charset = NULL;
}
fputs("\033%-12345X@PJL\n", fp);
for (ptr = ppd->jcl_begin + 9; *ptr;)
if (!strncmp(ptr, "@PJL JOB", 8))
{
for (;*ptr; ptr ++)
if (*ptr == '\n')
break;
if (*ptr)
ptr ++;
}
else
{
for (;*ptr; ptr ++)
{
putc(*ptr, fp);
if (*ptr == '\n')
break;
}
if (*ptr)
ptr ++;
}
if ((ptr = strrchr(title, '/')) != NULL)
title = ptr + 1;
strlcpy(temp, title, sizeof(temp));
for (ptr = temp; *ptr; ptr ++)
if (*ptr == '\"')
*ptr = '\'';
else if (charset && (*ptr & 128))
*ptr = '?';
fprintf(fp, "@PJL JOB NAME = \"%s\" DISPLAY = \"%d %s %s\"\n", temp,
job_id, user, temp);
fprintf(fp, "@PJL RDYMSG DISPLAY = \"%d %s %s\"\n", job_id, user, temp);
}
else
fputs(ppd->jcl_begin, fp);
ppdEmit(ppd, fp, PPD_ORDER_JCL);
fputs(ppd->jcl_ps, fp);
return (0);
}
int
ppdEmitJCLEnd(ppd_file_t *ppd,
FILE *fp)
{
if (!ppd)
return (0);
if (!ppd->jcl_end)
{
if (ppd->num_filters == 0)
putc(0x04, fp);
return (0);
}
if (!strncmp(ppd->jcl_end, "\033%-12345X@", 10))
{
fputs("\033%-12345X@PJL\n", fp);
fputs("@PJL RDYMSG DISPLAY = \"READY\"\n", fp);
fputs(ppd->jcl_end + 9, fp);
}
else
fputs(ppd->jcl_end, fp);
return (0);
}
char *
ppdEmitString(ppd_file_t *ppd,
ppd_section_t section,
float min_order)
{
int i, j,
count;
ppd_choice_t **choices;
ppd_size_t *size;
ppd_coption_t *coption;
ppd_cparam_t *cparam;
size_t bufsize;
char *buffer,
*bufptr,
*bufend;
struct lconv *loc;
DEBUG_printf(("ppdEmitString(ppd=%p, section=%d, min_order=%f)\n",
ppd, section, min_order));
if (!ppd)
return (NULL);
ppd_handle_media(ppd);
if ((count = ppdCollect2(ppd, section, min_order, &choices)) == 0)
return (NULL);
for (i = 0, bufsize = 1; i < count; i ++)
{
if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
{
bufsize += 3;
if ((!strcasecmp(choices[i]->option->keyword, "PageSize") ||
!strcasecmp(choices[i]->option->keyword, "PageRegion")) &&
!strcasecmp(choices[i]->choice, "Custom"))
{
DEBUG_puts("ppdEmitString: Custom size set!");
bufsize += 37;
bufsize += 50;
}
else if (!strcasecmp(choices[i]->choice, "Custom") &&
(coption = ppdFindCustomOption(ppd,
choices[i]->option->keyword))
!= NULL)
{
bufsize += 17 + strlen(choices[i]->option->keyword) + 6;
for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
cparam;
cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
{
switch (cparam->type)
{
case PPD_CUSTOM_CURVE :
case PPD_CUSTOM_INVCURVE :
case PPD_CUSTOM_POINTS :
case PPD_CUSTOM_REAL :
case PPD_CUSTOM_INT :
bufsize += 10;
break;
case PPD_CUSTOM_PASSCODE :
case PPD_CUSTOM_PASSWORD :
case PPD_CUSTOM_STRING :
bufsize += 3 + 4 * strlen(cparam->current.custom_string);
break;
}
}
}
else
bufsize += 17 + strlen(choices[i]->option->keyword) + 1 +
strlen(choices[i]->choice) + 1;
bufsize += 13;
bufsize += 22;
}
if (choices[i]->code)
bufsize += strlen(choices[i]->code) + 1;
else
bufsize += strlen(ppd_custom_code);
}
DEBUG_printf(("ppdEmitString: Allocating %d bytes for string...\n", bufsize));
if ((buffer = calloc(1, bufsize)) == NULL)
{
free(choices);
return (NULL);
}
bufend = buffer + bufsize - 1;
loc = localeconv();
for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr))
if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
{
strlcpy(bufptr, "[{\n", bufend - bufptr + 1);
bufptr += 3;
DEBUG_printf(("Adding code for %s=%s...\n", choices[i]->option->keyword,
choices[i]->choice));
if ((!strcasecmp(choices[i]->option->keyword, "PageSize") ||
!strcasecmp(choices[i]->option->keyword, "PageRegion")) &&
!strcasecmp(choices[i]->choice, "Custom"))
{
ppd_attr_t *attr;
int pos,
orientation;
float values[5];
strlcpy(bufptr, "%%BeginFeature: *CustomPageSize True\n",
bufend - bufptr + 1);
bufptr += 37;
size = ppdPageSize(ppd, "Custom");
memset(values, 0, sizeof(values));
if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL)
{
pos = atoi(attr->value) - 1;
if (pos < 0 || pos > 4)
pos = 0;
}
else
pos = 0;
values[pos] = size->width;
if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL)
{
pos = atoi(attr->value) - 1;
if (pos < 0 || pos > 4)
pos = 1;
}
else
pos = 1;
values[pos] = size->length;
orientation = 1;
if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize",
"Orientation")) != NULL)
{
int min_orient, max_orient;
if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient,
&max_orient) != 3)
pos = 4;
else
{
pos --;
if (pos < 0 || pos > 4)
pos = 4;
if (orientation > max_orient)
orientation = max_orient;
else if (orientation < min_orient)
orientation = min_orient;
}
}
else
pos = 4;
values[pos] = (float)orientation;
for (pos = 0; pos < 5; pos ++)
{
bufptr = _cupsStrFormatd(bufptr, bufend, values[pos], loc);
*bufptr++ = '\n';
}
if (!choices[i]->code)
{
strlcpy(bufptr, ppd_custom_code, bufend - bufptr + 1);
bufptr += strlen(bufptr);
}
}
else if (!strcasecmp(choices[i]->choice, "Custom") &&
(coption = ppdFindCustomOption(ppd,
choices[i]->option->keyword))
!= NULL)
{
const char *s;
snprintf(bufptr, bufend - bufptr + 1,
"%%%%BeginFeature: *Custom%s True\n", coption->keyword);
bufptr += strlen(bufptr);
for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
cparam;
cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
{
switch (cparam->type)
{
case PPD_CUSTOM_CURVE :
case PPD_CUSTOM_INVCURVE :
case PPD_CUSTOM_POINTS :
case PPD_CUSTOM_REAL :
bufptr = _cupsStrFormatd(bufptr, bufend,
cparam->current.custom_real, loc);
*bufptr++ = '\n';
break;
case PPD_CUSTOM_INT :
snprintf(bufptr, bufend - bufptr + 1, "%d\n",
cparam->current.custom_int);
bufptr += strlen(bufptr);
break;
case PPD_CUSTOM_PASSCODE :
case PPD_CUSTOM_PASSWORD :
case PPD_CUSTOM_STRING :
*bufptr++ = '(';
for (s = cparam->current.custom_string; *s; s ++)
if (*s < ' ' || *s == '(' || *s == ')' || *s >= 127)
{
snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *s & 255);
bufptr += strlen(bufptr);
}
else
*bufptr++ = *s;
*bufptr++ = ')';
*bufptr++ = '\n';
break;
}
}
}
else
{
snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *%s %s\n",
choices[i]->option->keyword, choices[i]->choice);
bufptr += strlen(bufptr);
}
if (choices[i]->code && choices[i]->code[0])
{
j = (int)strlen(choices[i]->code);
memcpy(bufptr, choices[i]->code, j);
bufptr += j;
if (choices[i]->code[j - 1] != '\n')
*bufptr++ = '\n';
}
strlcpy(bufptr, "%%EndFeature\n"
"} stopped cleartomark\n", bufend - bufptr + 1);
bufptr += strlen(bufptr);
DEBUG_printf(("ppdEmitString: Offset in string is %d...\n",
bufptr - buffer));
}
else
{
strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1);
bufptr += strlen(bufptr);
}
*bufptr = '\0';
free(choices);
return (buffer);
}
static void
ppd_handle_media(ppd_file_t *ppd)
{
ppd_choice_t *manual_feed,
*input_slot,
*page;
ppd_size_t *size;
ppd_attr_t *rpr;
if ((size = ppdPageSize(ppd, NULL)) == NULL)
return;
manual_feed = ppdFindMarkedChoice(ppd, "ManualFeed");
input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
if (input_slot != NULL)
rpr = ppdFindAttr(ppd, "RequiresPageRegion", input_slot->choice);
else
rpr = NULL;
if (!rpr)
rpr = ppdFindAttr(ppd, "RequiresPageRegion", "All");
if (!strcasecmp(size->name, "Custom") || (!manual_feed && !input_slot) ||
!((manual_feed && !strcasecmp(manual_feed->choice, "True")) ||
(input_slot && input_slot->code && input_slot->code[0])))
{
ppdMarkOption(ppd, "PageSize", size->name);
}
else
{
ppdMarkOption(ppd, "PageRegion", size->name);
if (!(manual_feed && !strcasecmp(manual_feed->choice, "True")) &&
((rpr && rpr->value && !strcmp(rpr->value, "False")) ||
(!rpr && !ppd->num_filters)))
{
page = ppdFindMarkedChoice(ppd, "PageRegion");
if (page)
page->marked = 0;
}
}
}
static int
ppd_sort(ppd_choice_t **c1,
ppd_choice_t **c2)
{
if ((*c1)->option->order < (*c2)->option->order)
return (-1);
else if ((*c1)->option->order > (*c2)->option->order)
return (1);
else
return (0);
}