#include "textcommon.h"
char *Glyphs[65536];
int NumFonts;
char *Fonts[256][4];
unsigned short Chars[65536];
unsigned short Codes[65536];
int Widths[256];
int Directions[256];
static void write_line(int row, lchar_t *line);
static void write_string(int col, int row, int len, lchar_t *s);
static void write_text(const char *s);
int
main(int argc,
char *argv[])
{
return (TextMain("texttops", argc, argv));
}
void
WriteEpilogue(void)
{
puts("%%Trailer");
printf("%%%%Pages: %d\n", NumPages);
puts("%%EOF");
free(Page[0]);
free(Page);
}
void
WritePage(void)
{
int line;
NumPages ++;
printf("%%%%Page: %d %d\n", NumPages, NumPages);
puts("gsave");
if (PrettyPrint)
printf("%d H\n", NumPages);
for (line = 0; line < SizeLines; line ++)
write_line(line, Page[line]);
puts("grestore");
puts("showpage");
memset(Page[0], 0, sizeof(lchar_t) * SizeColumns * SizeLines);
}
void
WriteProlog(const char *title,
const char *user,
const char *classification,
const char *label,
ppd_file_t *ppd)
{
int i, j, k;
char *charset;
char filename[1024];
FILE *fp;
const char *datadir;
char line[1024],
*lineptr,
*valptr;
int ch, unicode;
int start, end;
char glyph[64];
time_t curtime;
struct tm *curtm;
char curdate[255];
int num_fonts;
char *fonts[1024];
static char *names[] =
{
"cupsNormal",
"cupsBold",
"cupsItalic"
};
if ((datadir = getenv("CUPS_DATADIR")) == NULL)
datadir = CUPS_DATADIR;
if (classification || label)
{
PageBottom += 36;
PageTop -= 36;
}
SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch;
SizeLines = (PageTop - PageBottom) / 72.0 * LinesPerInch;
Page = calloc(sizeof(lchar_t *), SizeLines);
Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines);
for (i = 1; i < SizeLines; i ++)
Page[i] = Page[0] + i * SizeColumns;
if (PageColumns > 1)
{
ColumnGutter = CharsPerInch / 2;
ColumnWidth = (SizeColumns - ColumnGutter * (PageColumns - 1)) /
PageColumns;
}
else
ColumnWidth = SizeColumns;
curtime = time(NULL);
curtm = localtime(&curtime);
strftime(curdate, sizeof(curdate), CUPS_STRFTIME_FORMAT, curtm);
puts("%!PS-Adobe-3.0");
printf("%%%%BoundingBox: 0 0 %.0f %.0f\n", PageWidth, PageLength);
printf("%%cupsRotation: %d\n", (Orientation & 3) * 90);
puts("%%Creator: texttops/" CUPS_SVERSION);
printf("%%%%CreationDate: %s\n", curdate);
printf("%%%%Title: %s\n", title);
printf("%%%%For: %s\n", user);
puts("%%Pages: (atend)");
NumFonts = 0;
memset(Fonts, 0, sizeof(Fonts));
memset(Glyphs, 0, sizeof(Glyphs));
memset(Chars, 0, sizeof(Chars));
memset(Codes, 0, sizeof(Codes));
snprintf(filename, sizeof(filename), "%s/data/psglyphs", datadir);
if ((fp = fopen(filename, "r")) != NULL)
{
while (fscanf(fp, "%x%63s", &unicode, glyph) == 2)
Glyphs[unicode] = strdup(glyph);
fclose(fp);
}
else
{
fprintf(stderr, "ERROR: Unable to open \"%s\" - %s\n", filename,
strerror(errno));
exit(1);
}
charset = getenv("CHARSET");
if (charset != NULL && strcmp(charset, "us-ascii") != 0)
{
snprintf(filename, sizeof(filename), "%s/charsets/%s", datadir, charset);
if ((fp = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "ERROR: Unable to open %s: %s\n", filename,
strerror(errno));
exit(1);
}
if (fgets(line, sizeof(line), fp) == NULL)
{
fclose(fp);
fprintf(stderr, "ERROR: Bad/empty charset file %s\n", filename);
exit(1);
}
if (strncmp(line, "charset", 7) != 0)
{
fclose(fp);
fprintf(stderr, "ERROR: Bad charset file %s\n", filename);
exit(1);
}
line[strlen(line) - 1] = '\0';
for (lineptr = line + 7; isspace(*lineptr); lineptr ++);
if (strcmp(lineptr, "8bit") == 0)
{
UTF8 = 0;
NumFonts = 0;
while (fgets(line, sizeof(line), fp) != NULL)
{
if (line[0] == '#' || line[0] == '\n')
continue;
lineptr = line;
start = strtol(lineptr, &lineptr, 16);
end = strtol(lineptr, &lineptr, 16);
while (isspace(*lineptr))
lineptr ++;
if (!*lineptr)
break;
valptr = lineptr;
while (!isspace(*lineptr) && *lineptr)
lineptr ++;
if (!*lineptr)
{
fprintf(stderr, "ERROR: bad font description line: %s\n", valptr);
fclose(fp);
exit(1);
}
*lineptr++ = '\0';
if (strcmp(valptr, "ltor") == 0)
Directions[NumFonts] = 1;
else if (strcmp(valptr, "rtol") == 0)
Directions[NumFonts] = -1;
else
{
fprintf(stderr, "ERROR: Bad text direction %s\n", valptr);
fclose(fp);
exit(1);
}
while (isspace(*lineptr))
lineptr ++;
valptr = lineptr;
while (!isspace(*lineptr) && *lineptr)
lineptr ++;
if (!*lineptr)
{
fprintf(stderr, "ERROR: bad font description line: %s\n", valptr);
fclose(fp);
exit(1);
}
*lineptr++ = '\0';
if (strcmp(valptr, "single") == 0)
Widths[NumFonts] = 1;
else if (strcmp(valptr, "double") == 0)
Widths[NumFonts] = 2;
else
{
fprintf(stderr, "ERROR: Bad text width %s\n", valptr);
fclose(fp);
exit(1);
}
for (i = 0; *lineptr && i < 4; i ++)
{
while (isspace(*lineptr))
lineptr ++;
valptr = lineptr;
while (!isspace(*lineptr) && *lineptr)
lineptr ++;
if (*lineptr)
*lineptr++ = '\0';
if (lineptr > valptr)
Fonts[NumFonts][i] = strdup(valptr);
}
for (j = i; j < 4; j ++)
Fonts[NumFonts][j] = strdup(Fonts[NumFonts][0]);
for (i = start, j = NumFonts * 256; i <= end; i ++, j ++)
Chars[i] = j;
NumFonts ++;
}
do
{
if (line[0] == '#' || line[0] == '\n')
continue;
if (sscanf(line, "%x%x", &ch, &unicode) == 2 && ch < 256)
Codes[Chars[ch]] = unicode;
}
while (fgets(line, sizeof(line), fp) != NULL);
fclose(fp);
}
else if (strcmp(lineptr, "utf8") == 0)
{
UTF8 = 1;
NumFonts = 0;
while (fgets(line, sizeof(line), fp) != NULL)
{
if (line[0] == '#' || line[0] == '\n')
continue;
lineptr = line;
start = strtol(lineptr, &lineptr, 16);
end = strtol(lineptr, &lineptr, 16);
while (isspace(*lineptr))
lineptr ++;
valptr = lineptr;
while (!isspace(*lineptr) && *lineptr)
lineptr ++;
if (!*lineptr)
{
fprintf(stderr, "ERROR: bad font description line: %s\n", valptr);
fclose(fp);
exit(1);
}
*lineptr++ = '\0';
if (strcmp(valptr, "ltor") == 0)
Directions[NumFonts] = 1;
else if (strcmp(valptr, "rtol") == 0)
Directions[NumFonts] = -1;
else
{
fprintf(stderr, "ERROR: Bad text direction %s\n", valptr);
fclose(fp);
exit(1);
}
while (isspace(*lineptr))
lineptr ++;
valptr = lineptr;
while (!isspace(*lineptr) && *lineptr)
lineptr ++;
if (!*lineptr)
{
fprintf(stderr, "ERROR: bad font description line: %s\n", valptr);
fclose(fp);
exit(1);
}
*lineptr++ = '\0';
if (strcmp(valptr, "single") == 0)
Widths[NumFonts] = 1;
else if (strcmp(valptr, "double") == 0)
Widths[NumFonts] = 2;
else
{
fprintf(stderr, "ERROR: Bad text width %s\n", valptr);
fclose(fp);
exit(1);
}
for (i = 0; *lineptr && i < 4; i ++)
{
while (isspace(*lineptr))
lineptr ++;
valptr = lineptr;
while (!isspace(*lineptr) && *lineptr)
lineptr ++;
if (*lineptr)
*lineptr++ = '\0';
if (lineptr > valptr)
Fonts[NumFonts][i] = strdup(valptr);
}
for (j = i; j < 4; j ++)
Fonts[NumFonts][j] = strdup(Fonts[NumFonts][0]);
for (i = start, j = NumFonts * 256; i <= end; i ++, j ++)
{
Chars[i] = j;
Codes[j] = i;
}
NumFonts ++;
if (NumFonts >= 256)
break;
}
fclose(fp);
}
else
{
fprintf(stderr, "ERROR: Bad charset type %s\n", lineptr);
fclose(fp);
exit(1);
}
}
else
{
NumFonts = 1;
Fonts[0][ATTR_NORMAL] = strdup("Courier");
Fonts[0][ATTR_BOLD] = strdup("Courier-Bold");
Fonts[0][ATTR_ITALIC] = strdup("Courier-Oblique");
Fonts[0][ATTR_BOLDITALIC] = strdup("Courier-BoldOblique");
Widths[0] = 1;
Directions[0] = 1;
for (i = 32; i < 127; i ++)
{
Chars[i] = i;
Codes[i] = i;
}
}
for (i = 0, num_fonts = 0; i < NumFonts; i ++)
for (j = PrettyPrint ? 2 : 1; j >= 0; j --)
{
for (k = 0; k < num_fonts; k ++)
if (strcmp(Fonts[i][j], fonts[k]) == 0)
break;
if (k >= num_fonts)
{
fonts[num_fonts] = Fonts[i][j];
num_fonts ++;
}
}
for (i = 0; i < num_fonts; i ++)
if (i == 0)
printf("%%%%DocumentNeededResources: font %s\n", fonts[i]);
else
printf("%%%%+ font %s\n", fonts[i]);
puts("%%DocumentSuppliedResources: procset texttops 1.1 0");
for (i = 0; i < num_fonts; i ++)
{
if (ppd != NULL)
{
fprintf(stderr, "DEBUG: ppd->num_fonts = %d\n", ppd->num_fonts);
for (j = 0; j < ppd->num_fonts; j ++)
{
fprintf(stderr, "DEBUG: ppd->fonts[%d] = %s\n", j, ppd->fonts[j]);
if (strcmp(fonts[i], ppd->fonts[j]) == 0)
break;
}
}
else
j = 0;
if ((ppd != NULL && j >= ppd->num_fonts) ||
strncmp(fonts[i], "Courier", 7) == 0 ||
strcmp(fonts[i], "Symbol") == 0)
{
printf("%%%%+ font %s\n", fonts[i]);
}
}
puts("%%EndComments");
puts("%%BeginProlog");
for (i = 0; i < num_fonts; i ++)
{
if (ppd != NULL)
{
for (j = 0; j < ppd->num_fonts; j ++)
if (strcmp(fonts[i], ppd->fonts[j]) == 0)
break;
}
else
j = 0;
if ((ppd != NULL && j >= ppd->num_fonts) ||
strncmp(fonts[i], "Courier", 7) == 0 ||
strcmp(fonts[i], "Symbol") == 0)
{
printf("%%%%BeginResource: font %s\n", fonts[i]);
snprintf(filename, sizeof(filename), "%s/fonts/%s", datadir, fonts[i]);
if ((fp = fopen(filename, "rb")) != NULL)
{
while ((j = fread(line, 1, sizeof(line), fp)) > 0)
fwrite(line, 1, j, stdout);
fclose(fp);
}
puts("\n%%EndResource");
}
}
puts("% character encoding(s)");
for (i = 0; i < NumFonts; i ++)
{
printf("/cupsEncoding%02x [\n", i);
for (ch = 0; ch < 256; ch ++)
{
if (Glyphs[Codes[i * 256 + ch]])
printf("/%s", Glyphs[Codes[i * 256 + ch]]);
else if (Codes[i * 256 + ch] > 255)
printf("/uni%04X", Codes[i * 256 + ch]);
else
printf("/.notdef");
if ((ch & 7) == 7)
putchar('\n');
}
puts("] def");
}
if (NumFonts == 1)
{
puts("% Reencode fonts");
for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
{
printf("/%s findfont\n", Fonts[0][i]);
puts("dup length 1 add dict begin\n"
" { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
" /Encoding cupsEncoding00 def\n"
" currentdict\n"
"end");
printf("/%s exch definefont pop\n", names[i]);
}
}
else
{
puts("% Reencode base fonts");
for (i = 1 + PrettyPrint; i >= 0; i --)
for (j = 0; j < NumFonts; j ++)
{
printf("/%s findfont\n", Fonts[j][i]);
printf("dup length 1 add dict begin\n"
" { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
" /Encoding cupsEncoding%02x def\n"
" currentdict\n"
"end\n", j);
printf("/%s%02x exch definefont /%s%02x exch def\n", names[i], j,
names[i], j);
}
puts("% Create composite fonts...");
for (i = 1 + PrettyPrint; i >= 0; i --)
{
puts("8 dict begin");
puts("/FontType 0 def/FontMatrix[1.0 0 0 1.0 0 0]def/FMapType 2 def/Encoding[");
for (j = 0; j < NumFonts; j ++)
if (j == (NumFonts - 1))
printf("%d", j);
else if ((j & 15) == 15)
printf("%d\n", j);
else
printf("%d ", j);
puts("]def/FDepVector[");
for (j = 0; j < NumFonts; j ++)
if (j == (NumFonts - 1))
printf("%s%02x", names[i], j);
else if ((j & 3) == 3)
printf("%s%02x\n", names[i], j);
else
printf("%s%02x ", names[i], j);
puts("]def currentdict end");
printf("/%s exch definefont pop\n", names[i]);
}
}
puts("%%BeginResource: procset texttops 1.1 0");
puts("% Define fonts");
printf("/FN /cupsNormal findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
120.0 / CharsPerInch, 68.0 / LinesPerInch);
printf("/FB /cupsBold findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
120.0 / CharsPerInch, 68.0 / LinesPerInch);
if (PrettyPrint)
printf("/FI /cupsItalic findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
120.0 / CharsPerInch, 68.0 / LinesPerInch);
puts("% Common procedures");
puts("/N { FN setfont moveto } bind def");
puts("/B { FB setfont moveto } bind def");
printf("/U { gsave 0.5 setlinewidth 0 %.3f rmoveto "
"0 rlineto stroke grestore } bind def\n", -6.8 / LinesPerInch);
if (PrettyPrint)
{
if (ColorDevice)
{
puts("/S { 0.0 setgray show } bind def");
puts("/r { 0.5 0.0 0.0 setrgbcolor show } bind def");
puts("/g { 0.0 0.5 0.0 setrgbcolor show } bind def");
puts("/b { 0.0 0.0 0.5 setrgbcolor show } bind def");
}
else
{
puts("/S { 0.0 setgray show } bind def");
puts("/r { 0.2 setgray show } bind def");
puts("/g { 0.2 setgray show } bind def");
puts("/b { 0.2 setgray show } bind def");
}
puts("/I { FI setfont moveto } bind def");
puts("/n {");
puts("\t20 string cvs % convert page number to string");
if (NumFonts > 1)
{
puts("\tdup length % get length");
puts("\tdup 2 mul string /P exch def % P = string twice as long");
puts("\t0 1 2 index 1 sub { % loop through each character in the page number");
puts("\t\tdup 3 index exch get % get character N from the page number");
puts("\t\texch 2 mul dup % compute offset in P");
puts("\t\tP exch 0 put % font 0");
puts("\t\t1 add P exch 2 index put % character");
puts("\t\tpop % discard character");
puts("\t} for % do for loop");
puts("\tpop pop % discard string and length");
puts("\tP % put string on stack");
}
puts("} bind def");
printf("/T");
write_text(title);
puts("def");
printf("/D");
write_text(curdate);
puts("def");
puts("/H {");
puts("\tgsave");
puts("\t0.9 setgray");
if (Duplex)
{
puts("\tdup 2 mod 0 eq {");
printf("\t\t%.3f %.3f translate } {\n",
PageWidth - PageRight, PageTop + 72.0f / LinesPerInch);
printf("\t\t%.3f %.3f translate } ifelse\n",
PageLeft, PageTop + 72.0f / LinesPerInch);
}
else
printf("\t%.3f %.3f translate\n",
PageLeft, PageTop + 72.0f / LinesPerInch);
printf("\t0 0 %.3f %.3f rectfill\n", PageRight - PageLeft,
144.0f / LinesPerInch);
puts("\tFB setfont");
puts("\t0 setgray");
if (Duplex)
{
puts("\tdup 2 mod 0 eq {");
printf("\t\tT stringwidth pop neg %.3f add %.3f } {\n",
PageRight - PageLeft - 36.0f / LinesPerInch,
(0.5f + 0.157f) * 72.0f / LinesPerInch);
printf("\t\t%.3f %.3f } ifelse\n", 36.0f / LinesPerInch,
(0.5f + 0.157f) * 72.0f / LinesPerInch);
}
else
printf("\t%.3f %.3f\n", 36.0f / LinesPerInch,
(0.5f + 0.157f) * 72.0f / LinesPerInch);
puts("\tmoveto T show");
printf("\tD dup stringwidth pop neg 2 div %.3f add %.3f\n",
(PageRight - PageLeft) * 0.5,
(0.5f + 0.157f) * 72.0f / LinesPerInch);
puts("\tmoveto show");
if (Duplex)
{
puts("\tdup n exch 2 mod 0 eq {");
printf("\t\t%.3f %.3f } {\n", 36.0f / LinesPerInch,
(0.5f + 0.157f) * 72.0f / LinesPerInch);
printf("\t\tdup stringwidth pop neg %.3f add %.3f } ifelse\n",
PageRight - PageLeft - 36.0f / LinesPerInch,
(0.5f + 0.157f) * 72.0f / LinesPerInch);
}
else
printf("\tn dup stringwidth pop neg %.3f add %.3f\n",
PageRight - PageLeft - 36.0f / LinesPerInch,
(0.5f + 0.157f) * 72.0f / LinesPerInch);
puts("\tmoveto show");
puts("\tgrestore");
puts("} bind def");
}
else
puts("/S { show } bind def");
puts("%%EndResource");
puts("%%EndProlog");
}
static void
write_line(int row,
lchar_t *line)
{
int i;
int col;
int attr;
int font,
lastfont,
mono;
lchar_t *start;
for (col = 0, start = line; col < SizeColumns;)
{
while (col < SizeColumns && (line->ch == ' ' || line->ch == 0))
{
col ++;
line ++;
}
if (col >= SizeColumns)
break;
if (NumFonts == 1)
{
attr = line->attr;
start = line;
while (col < SizeColumns && line->ch != 0 && attr == line->attr)
{
col ++;
line ++;
}
write_string(col - (line - start), row, line - start, start);
}
else
{
attr = line->attr;
start = line;
lastfont = Chars[line->ch] / 256;
mono = strncmp(Fonts[lastfont][0], "Courier", 7) == 0;
col ++;
line ++;
if (mono)
{
while (col < SizeColumns && line->ch != 0 && attr == line->attr)
{
font = Chars[line->ch] / 256;
if (strncmp(Fonts[font][0], "Courier", 7) != 0 ||
font != lastfont)
break;
col ++;
line ++;
}
}
if (Directions[lastfont] > 0)
write_string(col - (line - start), row, line - start, start);
else
{
while (col < SizeColumns && line->ch != 0 && attr == line->attr)
{
if (Directions[Chars[line->ch] / 256] > 0 &&
!ispunct(line->ch) && !isspace(line->ch))
break;
col ++;
line ++;
}
for (i = 1; start < line; i ++, start ++)
if (!isspace(start->ch))
write_string(col - i, row, 1, start);
}
}
}
}
static void
write_string(int col,
int row,
int len,
lchar_t *s)
{
int ch;
float x, y;
unsigned attr;
if (Duplex && (NumPages & 1) == 0)
{
x = PageWidth - PageRight;
y = PageTop;
}
else
{
x = PageLeft;
y = PageTop;
}
x += (float)col * 72.0f / (float)CharsPerInch;
y -= (float)(row + 0.843) * 72.0f / (float)LinesPerInch;
attr = s->attr;
if (attr & ATTR_RAISED)
y += 36.0 / (float)LinesPerInch;
else if (attr & ATTR_LOWERED)
y -= 36.0 / (float)LinesPerInch;
if (x == (int)x)
printf("%.0f ", x);
else
printf("%.3f ", x);
if (y == (int)y)
printf("%.0f ", y);
else
printf("%.3f ", y);
if (attr & ATTR_BOLD)
putchar('B');
else if (attr & ATTR_ITALIC)
putchar('I');
else
putchar('N');
if (attr & ATTR_UNDERLINE)
printf(" %.3f U", (float)len * 72.0 / (float)CharsPerInch);
if (NumFonts > 1)
{
putchar('<');
while (len > 0)
{
printf("%04x", Chars[s->ch]);
len --;
s ++;
}
putchar('>');
}
else
{
putchar('(');
while (len > 0)
{
ch = Chars[s->ch];
if (ch < 32 || ch > 126)
{
printf("\\%03o", ch);
}
else
{
if (ch == '(' || ch == ')' || ch == '\\')
putchar('\\');
putchar(ch);
}
len --;
s ++;
}
putchar(')');
}
if (PrettyPrint)
{
if (attr & ATTR_RED)
puts("r");
else if (attr & ATTR_GREEN)
puts("g");
else if (attr & ATTR_BLUE)
puts("b");
else
puts("S");
}
else
puts("S");
}
static void
write_text(const char *s)
{
int ch;
const unsigned char *utf8;
if (NumFonts > 1)
{
putchar('<');
utf8 = (const unsigned char *)s;
while (*utf8)
{
if (*utf8 < 0xc0 || !UTF8)
ch = *utf8 ++;
else if ((*utf8 & 0xe0) == 0xc0)
{
ch = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f);
utf8 += 2;
}
else
{
ch = ((((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)) << 6) |
(utf8[2] & 0x3f);
utf8 += 3;
}
printf("%04x", Chars[ch]);
}
putchar('>');
}
else
{
putchar('(');
while (*s)
{
if (*s < 32 || *s > 126)
printf("\\%03o", *s);
else
{
if (*s == '(' || *s == ')' || *s == '\\')
putchar('\\');
putchar(*s);
}
s ++;
}
putchar(')');
}
}