Merge branch 'master' of https://git.maemo.org/projects/erwise
[erwise] / erwise / Print.c
1 /*
2  * Print.c --
3  *
4  * Author: Teemu Rantanen <tvr@cs.hut.fi> Copyright (c) 1992 Teemu Rantanen All
5  * rights reserved
6  *
7  * Created: Sun Apr 26 21:30:47 1992 tvr Last modified: Mon May 11 22:56:41 1992
8  * tvr
9  *
10  */
11
12 #include "Includes.h"
13
14 #include <fcntl.h>
15
16 int PrintTopMargin = 0;
17 int PrintBottomMargin = 0;
18 int PrintLeftMargin = 0;
19 int PrintWidth = 80;
20 int PrintToFile = 0;
21
22 char PrintCommand[1024] = "lpr";
23 char PrintFileName[1024] = "foobar.www";
24
25
26 /*
27  * One object on a line
28  */
29 typedef struct PrintObject_s {
30
31     HTextObject_t *HtObject;
32
33     struct PrintObject_s *Next;
34 } PrintObject_t;
35
36
37 /*
38  * All line objects and info on line
39  */
40 typedef struct PrintLine_s {
41
42     int LineY;
43
44     PrintObject_t *Objects;
45
46     struct PrintLine_s *Next;
47
48 } PrintLine_t;
49
50
51
52 /*
53  * Allocate new PrintObject.
54  */
55 PrintObject_t *
56  new_print_object()
57 {
58     PrintObject_t *p;
59
60     p = (PrintObject_t *) malloc(sizeof(*p));
61
62     if (!p)
63         return p;
64
65     memset(p, 0, sizeof(*p));
66
67     return p;
68 }
69
70
71 /*
72  * Allocate new PrintLine.
73  */
74 PrintLine_t *
75  new_print_line()
76 {
77     PrintLine_t *p;
78
79     p = (PrintLine_t *) malloc(sizeof(*p));
80
81     if (!p)
82         return p;
83
84     memset(p, 0, sizeof(*p));
85
86     return p;
87 }
88
89
90 /*
91  * Append object to a line. Sort objects according to x position
92  */
93 int printobject_append(line, htobject)
94 PrintLine_t *line;
95 HTextObject_t *htobject;
96 {
97     PrintObject_t *object = line->Objects;
98     PrintObject_t *prev = 0;
99
100     /*
101      * First object on a line
102      */
103     if (!object) {
104         if (!(line->Objects = new_print_object()))
105             return 0;
106
107         line->Objects->HtObject = htobject;
108
109         return 1;
110     }
111     /*
112      * Check on which place do we put this ?
113      */
114     while (object && (htobject->x > object->HtObject->x)) {
115
116         prev = object;
117
118         object = object->Next;
119     }
120
121     /*
122      * Set object to line-list
123      */
124
125     {
126         PrintObject_t *new_object = new_print_object();
127
128         if (!new_object)
129             return 0;
130
131         new_object->Next = object;
132
133         new_object->HtObject = htobject;
134
135         if (prev) {
136
137             prev->Next = new_object;
138
139         } else {
140
141             line->Objects = new_object;
142
143         }
144     }
145 }
146
147
148 /*
149  * Check on which line object should be appended
150  */
151 PrintLine_t *
152  print_check_line_append(first, object)
153 PrintLine_t *first;
154 HTextObject_t *object;
155 {
156     PrintLine_t *p;
157     PrintLine_t *new_line;
158     PrintLine_t *prev;
159
160     /*
161      * If this is first line, no problemo ...
162      */
163     if (!first) {
164
165         p = new_print_line();
166
167         if (!p)
168             return 0;
169
170         p->LineY = object->y;
171
172         if (!printobject_append(p, object))
173             return 0;
174
175         return p;
176     }
177     /*
178      * Find a line
179      */
180     p = first;
181     prev = 0;
182
183     while (p && (p->LineY < object->y)) {
184
185         prev = p;
186
187         p = p->Next;
188     }
189
190     /*
191      * Line already exists ?
192      */
193     if (p && (p->LineY == object->y)) {
194
195         if (!printobject_append(p, object))
196             return 0;
197
198         return first;
199     }
200     /*
201      * Line does not exist ... make one
202      */
203
204     new_line = new_print_line();
205
206     if (!new_line)
207         return 0;
208
209     new_line->LineY = object->y;
210
211     if (prev) {
212         /*
213          * Append to middle of the list
214          */
215         prev->Next = new_line;
216
217         new_line->Next = p;
218
219         if (!printobject_append(new_line, object))
220             return 0;
221
222         return first;
223     } else {
224         /*
225          * Append to first
226          */
227         new_line->Next = p;
228
229         if (!printobject_append(new_line, object))
230             return 0;
231
232         return new_line;
233     }
234
235     /*
236      * Should not get here
237      */
238     return 0;
239 }
240
241
242 /*
243  * Print using this command
244  */
245 int erwise_popen(command)
246 char *command;
247 {
248     int fd[2];
249
250     int ppid;
251
252     if (pipe(fd)) {
253
254         printf("erwise_popen: cannot make pipe\n");
255
256         return -1;
257     }
258     switch (ppid = fork()) {
259     case 0:
260
261         dup2(fd[0], 0);
262
263         close(fd[1]);
264         close(fd[0]);
265
266         system(command);
267
268         close(0);
269
270         exit(0);
271
272         break;
273
274     case -1:
275
276         printf("cannot fork\n");
277
278         return -1;
279
280         break;
281
282     default:
283
284         close(fd[0]);
285
286         return (fd[1]);
287     }
288
289     /*
290      * should not get here ...
291      */
292     return -1;
293 }
294
295
296
297 /*
298  * Open files, handle commands, call DoPrint
299  */
300 int Print(htext)
301 HText_t *htext;
302 {
303     int fd;
304
305     if ((PrintWidth <= 0) || (PrintTopMargin < 0) || (PrintBottomMargin < 0) ||
306         (PrintLeftMargin < 0)) {
307
308         printf("Print: parameters insane\n");
309
310         return 1;
311     }
312     if (PrintToFile) {
313
314         fd = open(PrintFileName, O_WRONLY | O_CREAT, 0666);
315
316         if (fd < 0) {
317
318             printf("Print: cannot create file %s\n", PrintFileName);
319
320             return 1;
321         }
322         DoPrint(htext, fd, PrintWidth, PrintLeftMargin, PrintTopMargin,
323                 PrintBottomMargin);
324
325         close(fd);
326
327     } else {
328
329         fd = erwise_popen(PrintCommand);
330
331         if (fd < 0) {
332
333             printf("Print: failed printing to command %s\n", PrintCommand);
334
335             return 1;
336         }
337         DoPrint(htext, fd, PrintWidth, PrintLeftMargin, PrintTopMargin,
338                 PrintBottomMargin);
339
340         close(fd);
341     }
342
343     return 0;
344 }
345
346
347 /*
348  * Handle printing. Format text (ascii) and put it to wanted fd
349  */
350 int DoPrint(old_htext, fd, width, lmargin, top, bottom)
351 HText_t *old_htext;
352 int fd;
353 int width;
354 int lmargin;
355 int top;
356 int bottom;
357 {
358     PrintLine_t *first_line = 0;
359
360     HText_t *htext = 0;
361
362     htext = (HText_t *) HtDuplicate(old_htext);
363
364     if (!htext)
365         return 0;
366
367     /*
368      * Format text using fixed width. After this call every object is
369      * positioned correctly.
370      */
371     XlFormatTextForPrinting(htext, lmargin, lmargin + width);
372
373     /*
374      * Because some objects may not be in x,y order, contruct list of lines
375      * so that lines are in order 0->j and for every line objects are in
376      * order 0->i.
377      *
378      * Because of allmost all objects are in order by default, contruct lists
379      * from last to first. Now most objects can be inserted as the first
380      * object of the first line.
381      */
382     {
383         HTextObject_t *p;
384
385         p = htext->last;
386
387         while (p) {
388
389             /*
390              * XXXXX free allocated on error
391              */
392             first_line = print_check_line_append(first_line, p);
393
394             p = p->prev;
395         }
396     }
397
398     /*
399      * Now, print line by line
400      */
401
402     {
403         PrintLine_t *line = first_line;
404
405         char newline[1];
406
407         int y = 0;
408         int max_x;
409
410         *newline = 10;
411
412         /*
413          * Write top margin
414          */
415         for (; top > 0; top--)
416             write(fd, newline, 1);
417
418         while (line) {
419             /*
420              * Print empty lines
421              */
422
423             while (y < line->LineY) {
424                 y++;
425
426                 write(fd, newline, 1);
427             }
428
429             /*
430              * Get maximum x on a line
431              */
432             {
433                 PrintObject_t *p;
434
435                 p = line->Objects;
436
437                 max_x = 0;
438
439                 while (p) {
440
441                     if (max_x < (p->HtObject->x + p->HtObject->width))
442                         max_x = p->HtObject->x + p->HtObject->width;
443
444                     p = p->Next;
445                 }
446             }
447
448             /*
449              * Collect data on a line and print it
450              */
451             {
452                 PrintObject_t *p;
453
454                 char *d = malloc(max_x + 1);
455
456                 p = line->Objects;
457
458                 /*
459                  * XXXXXX free
460                  */
461                 if (!d)
462                     return;
463
464                 memset(d, ' ', max_x + 1);
465
466                 while (p) {
467                     if (p->HtObject->data) {
468
469                         memcpy(d + p->HtObject->x, p->HtObject->data,
470                                p->HtObject->length);
471                     }
472                     p = p->Next;
473                 }
474
475                 write(fd, d, max_x + 1);
476
477                 free(d);
478             }
479
480             line = line->Next;
481
482         }
483
484         write(fd, newline, 1);
485
486         /*
487          * Write bottom margin
488          */
489         for (; bottom > 0; bottom--)
490             write(fd, newline, 1);
491
492     }
493
494     /*
495      * Free objects allocated here
496      */
497
498     {
499         PrintLine_t *l;
500         PrintObject_t *p;
501
502         l = first_line;
503
504         while (l) {
505
506             p = l->Objects;
507
508             while (p) {
509
510                 free(p);
511
512                 p = p->Next;
513             }
514
515             free(l);
516
517             l = l->Next;
518         }
519     }
520
521     /*
522      * Delete extra page
523      */
524
525     HText_free(htext);
526 }