]> www.fi.muni.cz Git - evince.git/blob - backend/ps/gsio.c
15c7f388733259c4da025988ec2d0fe5f494570c
[evince.git] / backend / ps / gsio.c
1 /*
2  * gsio.c: an IO abstraction
3  *
4  * Copyright 2002 - 2005 the Free Software Foundation
5  *
6  * Author: Jaka Mocnik  <jaka@gnu.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #include <string.h>
24
25 #include <gsio.h>
26
27 #define CHUNK_SIZE 32768
28
29 typedef struct _GtkGSDocChunk GtkGSDocChunk;
30 struct _GtkGSDocChunk {
31   gchar *buf, *ptr;
32   guint len, max_len;
33 };
34
35 struct _GtkGSDocSink {
36   GSList *chunks;
37   GtkGSDocChunk *tail;
38 };
39
40 static GtkGSDocChunk *
41 gtk_gs_doc_chunk_new(guint size)
42 {
43   GtkGSDocChunk *c;
44
45   c = g_new0(GtkGSDocChunk, 1);
46   if((c->buf = g_malloc(sizeof(gchar) * size)) == NULL) {
47     g_free(c);
48     return NULL;
49   }
50   c->ptr = c->buf;
51   *c->ptr = '\0';
52   c->max_len = size;
53   c->len = 0;
54   return c;
55 }
56
57 static void
58 gtk_gs_doc_chunk_free(GtkGSDocChunk * c)
59 {
60   if(c->buf)
61     g_free(c->buf);
62   g_free(c);
63 }
64
65 GtkGSDocSink *
66 gtk_gs_doc_sink_new()
67 {
68   GtkGSDocSink *sink;
69
70   sink = g_new0(GtkGSDocSink, 1);
71   return sink;
72 }
73
74 void
75 gtk_gs_doc_sink_free(GtkGSDocSink * sink)
76 {
77   GSList *node;
78
79   node = sink->chunks;
80   while(node) {
81     gtk_gs_doc_chunk_free((GtkGSDocChunk *) node->data);
82     node = node->next;
83   }
84   g_slist_free(sink->chunks);
85 }
86
87 void
88 gtk_gs_doc_sink_write(GtkGSDocSink * sink, const gchar * buf, int len)
89 {
90   gint real_len;
91
92   if(sink->tail == NULL) {
93     sink->tail = gtk_gs_doc_chunk_new(CHUNK_SIZE);
94     sink->chunks = g_slist_append(sink->chunks, sink->tail);
95   }
96
97   real_len = MIN(sink->tail->max_len - sink->tail->len, len);
98   if(real_len > 0) {
99     strncpy(sink->tail->ptr, buf, real_len);
100     sink->tail->ptr += real_len;
101     sink->tail->len += real_len;
102   }
103   len -= real_len;
104   if(len > 0) {
105     sink->tail = NULL;
106     gtk_gs_doc_sink_write(sink, buf + real_len, len);
107   }
108 }
109
110 void
111 gtk_gs_doc_sink_printf_v(GtkGSDocSink * sink, const gchar * fmt, va_list ap)
112 {
113   gint max_len, len;
114
115   if(sink->tail == NULL) {
116     sink->tail = gtk_gs_doc_chunk_new(CHUNK_SIZE);
117     sink->chunks = g_slist_append(sink->chunks, sink->tail);
118   }
119
120   max_len = sink->tail->max_len - sink->tail->len;
121   if(max_len > 0) {
122     len = g_vsnprintf(sink->tail->ptr, max_len, fmt, ap);
123     if(len >= max_len - 1) {
124       /* force printf in the next chunk later on */
125       max_len = 0;
126       sink->tail = NULL;
127     }
128     else {
129       sink->tail->ptr += len;
130       sink->tail->len += len;
131     }
132   }
133   if(max_len <= 0) {
134     gtk_gs_doc_sink_printf(sink, fmt, ap);
135   }
136 }
137
138 void
139 gtk_gs_doc_sink_printf(GtkGSDocSink * sink, const gchar * fmt, ...)
140 {
141   va_list ap;
142
143   va_start(ap, fmt);
144   gtk_gs_doc_sink_printf_v(sink, fmt, ap);
145   va_end(ap);
146 }
147
148 gchar *
149 gtk_gs_doc_sink_get_buffer(GtkGSDocSink * sink)
150 {
151   guint total;
152   GSList *node;
153
154   for(total = 0, node = sink->chunks; node; node = node->next) {
155     total += ((GtkGSDocChunk *) node->data)->len;
156   }
157   if(total) {
158     gchar *buf = g_malloc(sizeof(gchar) * (total + 1)), *ptr;
159     if(!buf)
160       return NULL;
161     for(ptr = buf, node = sink->chunks; node; node = node->next) {
162       memcpy(ptr,
163              ((GtkGSDocChunk *) node->data)->buf,
164              ((GtkGSDocChunk *) node->data)->len);
165       ptr += ((GtkGSDocChunk *) node->data)->len;
166     }
167     buf[total] = '\0';
168     return buf;
169   }
170   else
171     return NULL;
172 }