1 /*
2 * This is a set of routines for dvips that are used to process color
3 * commands in the TeX file (passed by \special commands). This was
4 * orignally written by J. Hafner, E. Blanz and M. Flickner of IBM
5 * Research, Almaden Research Center. Contact hafner@almaden.ibm.com.
6 * And then it was completely rewritten by Tomas Rokicki to:
7 *
8 * - Be easier on the memory allocator (malloc/free)
9 * - Use less memory overall (by a great deal) and be faster
10 * - Work with the -C, -a, and other options
11 * - Be more adaptable to other drivers and previewers.
12 *
13 * The motivating idea: we want to be able to process 5,000 page
14 * documents using lots of colors on each page on a 640K IBM PC
15 * relatively quickly.
16 */
17 #include "dvips.h" /* The copyright notice in that file is included too! */
18 #include <stdio.h>
19 /*
20 * The external declarations:
21 */
22 #include "protos.h"
23
24 /*
25 * Here we set some limits on some color stuff.
26 */
27 #define COLORHASH (89)
28 #define MAXCOLORLEN (120) /* maximum color length for background */
29 #define INITCOLORLEN (10000) /* initial stack size in chars */
30 /*
31 * This is where we store the color information for a particular page.
32 * If we free all of these, we free all of the allocated color
33 * stuff; we do no allocations (but one) other than when we allocate
34 * these.
35 */
36 static struct colorpage {
37 struct colorpage *next;
38 integer boploc; /* we use the bop loc as a page indicator */
39 char *bg;
40 char colordat[2];
41 } *colorhash[COLORHASH];
42 static char *cstack, *csp, *cend, *bg;
43 /*
44 * This routine sends a color command out. If the command is a
45 * single `word' or starts with a double quote, we send it out
46 * exactly as is (except for any double quote.) If the command
47 * is a word followed by arguments, we send out the arguments and
48 * then the word prefixed by "TeXcolor".
49 */
50 static void
colorcmdout(char * s)51 colorcmdout(char *s)
52 {
53 char *p;
54 char tempword[100];
55
56 while (*s && *s <= ' ')
57 s++;
58 if (*s == '"') {
59 cmdout(s+1);
60 return;
61 }
62 for (p=s; *p && *p > ' '; p++);
63 for (; *p && *p <= ' '; p++);
64 if (*p == 0) {
65 cmdout(s);
66 return;
67 }
68 cmdout(p);
69 strcpy(tempword, "TeXcolor");
70 for (p=tempword + strlen(tempword); *s && *s > ' '; p++, s++)
71 *p = *s;
72 *p = 0;
73 cmdout(tempword);
74 return;
75 }
76 /*
77 * For a new dvi file, call this. Frees all allocated memory.
78 */
79 #define DEFAULTCOLOR "Black"
initcolor(void)80 void initcolor(void) {
81 int i;
82 struct colorpage *p, *q;
83
84 for (i=0; i<COLORHASH; i++) {
85 for (p=colorhash[i]; p; p = q) {
86 q = p->next;
87 free(p);
88 }
89 colorhash[i] = 0;
90 }
91 cstack = (char *)mymalloc(INITCOLORLEN);
92 strcpy(cstack, "\n");
93 strcat(cstack, DEFAULTCOLOR);
94 csp = cstack + strlen(cstack);
95 cend = cstack + INITCOLORLEN - 3; /* for conservativeness */
96 bg = 0;
97 }
98 /*
99 * This takes a call from predospecial to set the background color for
100 * the current page. It is saved in stackdepth and backed down the
101 * stack during popcolors.
102 */
103 void
background(char * bkgrnd)104 background(char *bkgrnd)
105 {
106 if (bkgrnd && *bkgrnd) {
107 if (strlen(bkgrnd) > MAXCOLORLEN)
108 error(" color name too long; ignored");
109 else
110 strcpy(bg, bkgrnd);
111 }
112 }
113 /*
114 * This routine puts a call from \special for color on the colorstack
115 * and sets the color in the PostScript.
116 */
117 void
pushcolor(char * p,Boolean outtops)118 pushcolor(char *p, Boolean outtops)
119 {
120 while (strlen(p) + csp > cend) {
121 int newlen = 3 * (cend - cstack);
122 char *newcs = (char *)mymalloc(newlen);
123 strcpy(newcs, cstack);
124 csp = newcs + (csp - cstack);
125 cend = newcs + newlen - 3;
126 cstack = newcs;
127 }
128 *csp++ = '\n';
129 strcpy(csp, p);
130 csp += strlen(p);
131 if (outtops) {
132 colorcmdout(p);
133 }
134 }
135 /*
136 * This routine removes a color from the colorstack and resets the color
137 * in the PostScript to the previous color.
138 */
139 void
popcolor(Boolean outtops)140 popcolor(Boolean outtops)
141 {
142 char *p = csp - 1;
143
144 while (p >= cstack && *p != '\n')
145 p--;
146 if (p == cstack)
147 return; /* We don't pop the last color as that is global */
148 *p = 0;
149 csp = p;
150 for (p--; p >= cstack && *p != '\n'; p--);
151 p++;
152 if ( outtops ) {
153 colorcmdout(p);
154 }
155 }
156 /*
157 * This routine clears the colorstack, pushes a new color onto the stack
158 * (this is now the root or global color).
159 */
160 void
resetcolorstack(char * p,int outtops)161 resetcolorstack(char * p, int outtops)
162 {
163 char *q = csp - 1;
164
165 while (q > cstack && *q != '\n')
166 q--;
167 if (q > cstack && outtops == 0) {
168 #ifdef SHORTINT
169 fprintf(stderr, "You've mistakenly made a global color change ");
170 fprintf(stderr, "to %s within nested colors\n", p);
171 fprintf(stderr, "on page %ld. Will try to recover.\n", pagenum);
172 #else /* ~SHORTINT */
173 fprintf(stderr, "You've mistakenly made a global color change ");
174 fprintf(stderr, "to %s within nested colors\n", p);
175 fprintf(stderr, "on page %d. Will try to recover.\n", pagenum);
176 #endif /* ~SHORTINT */
177 }
178 csp = cstack;
179 *csp = 0;
180 pushcolor(p, outtops);
181 }
182 /*
183 * This routine is a bit magic. It looks up the page in the current
184 * hash table. If the page is already entered in the hash table, then
185 * it restores the color to what that page had, and sets the last
186 * color. This will occur if this is not the first time that this
187 * page has been encountered.
188 *
189 * If, on the other hand, this is the first time that the page has
190 * been encountered, then it will create a new hash entry and copy the
191 * current color information into it. Since we can only encounter a
192 * new page after having just finished scanning the previous page,
193 * this is safe.
194 */
195 void
bopcolor(int outtops)196 bopcolor(int outtops)
197 {
198 integer pageloc = ftell(dvifile);
199 int h = pageloc % COLORHASH;
200 struct colorpage *p = colorhash[h];
201
202 while (p) {
203 if (p->boploc == pageloc)
204 break;
205 else
206 p = p->next;
207 }
208 if (p) {
209 strcpy(cstack, p->colordat);
210 csp = cstack + strlen(cstack);
211 bg = p->bg;
212 if (outtops && strcmp(bg, "White")!=0 && bg[0]) {
213 cmdout("gsave");
214 colorcmdout(bg);
215 cmdout("clippath fill grestore");
216 }
217 } else {
218 p = (struct colorpage *)mymalloc((integer)
219 (strlen(cstack) + sizeof(struct colorpage) + MAXCOLORLEN));
220 p->next = colorhash[h];
221 p->boploc = pageloc;
222 strcpy(p->colordat, cstack);
223 p->bg = p->colordat + strlen(cstack) + 1;
224 if (bg)
225 strcpy(p->bg, bg);
226 else
227 *(p->bg) = 0;
228 bg = p->bg;
229 colorhash[h] = p;
230 }
231 if (outtops) {
232 char *pp = csp - 1;
233 while (pp >= cstack && *pp != '\n')
234 pp--;
235 pp++;
236 if (strcmp(pp, DEFAULTCOLOR)!=0) {
237 colorcmdout(pp);
238 }
239 }
240 }
241