1
2/*
3    Copyright 2004, Broadcom Corporation
4    All Rights Reserved.
5
6    THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
7    KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
8    SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
9    FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
10*/
11
12
13#include "upnp_dbg.h"
14#include "upnp_osl.h"
15#include "upnp.h"
16
17#define UIO_FILE     (1<<0)
18#define UIO_STRING   (1<<2)
19#define UIO_DYNAMIC  (1<<3)
20
21/*
22
23  Define UIO_TRACE to track the creation and deletion of uio
24  structures when you suspect a leak.  When this symbol is defined,
25  each UFILE structure will be tracked with a unique identifier.  That
26  identifier will br printed when the structure is allocated and when
27  it is freed.  If you see the identifiers grow much beyond 2 or 3,
28  then you probably are leaking UFILE structures.
29
30  #define UIO_TRACE 1
31*/
32
33#ifdef UIO_TRACE
34fd_set uio_fds;
35#endif
36
37struct _ufile {
38#ifdef UIO_TRACE
39    int identifier;
40#endif
41    int flags;
42    int bytes_written;
43    union {
44	FILE *fp;
45	struct {
46	    char *buffer;
47	    int avail;
48	} str;
49    } io;
50};
51
52UFILE *uio_new()
53{
54    UFILE *up;
55#ifdef UIO_TRACE
56    int i;
57#endif
58
59    up = (UFILE *) malloc(sizeof(UFILE));
60    if (up) {
61	memset(up, 0, sizeof(UFILE));
62#ifdef UIO_TRACE
63	for (i = 0; i < 64; i++) {
64	    if (!FD_ISSET(i, &uio_fds)) {
65		up->index = i;
66		FD_SET(up->index, &uio_fds);
67		printf("%s %d\n", __FUNCTION__, up->index);
68		break;
69	    }
70	}
71#endif
72    }
73    return up;
74}
75
76void uio_delete(UFILE *up)
77{
78#ifdef UIO_TRACE
79    printf("%s %d\n", __FUNCTION__, up->index);
80    FD_CLR(up->index, &uio_fds);
81#endif
82
83    free(up);
84}
85
86
87UFILE *udopen(int fd)
88{
89    UFILE *up = NULL;
90    FILE *fp;
91
92    fp = fdopen(fd, "w");
93    if (fp != NULL) {
94	up = uio_new();
95	if (up) {
96	    up->flags |= UIO_FILE;
97	    up->io.fp = fp;
98	} else {
99	    fclose(fp);
100	}
101    }
102
103    return up;
104}
105
106
107UFILE *ufopen(const char *fname)
108{
109    UFILE *up = NULL;
110    FILE *fp;
111
112    fp = fopen(fname, "w");
113    if (fp != NULL) {
114	up = uio_new();
115	if (up) {
116	    up->flags |= UIO_FILE;
117	    up->io.fp = fp;
118	}
119    }
120
121    return up;
122}
123
124
125UFILE *usopen(char *str, int maxlen)
126{
127    UFILE *up;
128
129    up = uio_new();
130    if (up) {
131	up->flags |= UIO_STRING;
132	if (str) {
133	    up->io.str.buffer = str;
134	    up->io.str.avail = maxlen;
135	} else {
136	    if (maxlen <= 0)
137		maxlen = 1024;
138	    up->flags |= UIO_DYNAMIC;
139	    up->io.str.buffer = malloc(maxlen);
140	    up->io.str.avail = maxlen;
141	}
142    }
143
144    return up;
145}
146
147
148int uprintf(UFILE *up, char *fmt, ...)
149{
150    va_list ap;
151    int len, n = 0;
152    char *buf;
153
154    va_start(ap, fmt);
155    if (up->flags & UIO_STRING) {
156	while (TRUE) {
157	    buf = &up->io.str.buffer[up->bytes_written];
158	    len = up->io.str.avail - up->bytes_written;
159	    n = vsnprintf(buf, len, fmt, ap);
160	    if (n < 0 || n > len) {
161		/* we tried to overwrite the end of the buffer */
162		if (up->flags & UIO_DYNAMIC) {
163		    buf = realloc(up->io.str.buffer, up->io.str.avail + 256);
164#ifdef UIO_TRACE
165		    printf("realloc was %d, now %d\n", up->io.str.avail, up->io.str.avail + 256);
166#endif
167		    if (buf) {
168			up->io.str.buffer = buf;
169			up->io.str.avail += 256;
170			continue;
171		    }
172		}
173	    } else {
174		up->bytes_written += n;
175	    }
176	    break;
177	} /* end while */
178    } else if (up->flags & UIO_FILE) {
179	n = vfprintf(up->io.fp, fmt, ap);
180	if (n > 0) {
181	    up->bytes_written += n;
182	}
183    }
184    va_end(ap);
185
186    return n;
187}
188
189
190void uclose(UFILE *up)
191{
192    if (up->flags & UIO_FILE) {
193	fclose(up->io.fp);
194    } else if (up->flags & UIO_DYNAMIC) {
195	free(up->io.str.buffer);
196    }
197    uio_delete(up);
198}
199
200
201int utell(UFILE *up)
202{
203    return up->bytes_written;
204}
205
206
207char *ubuffer(UFILE *up)
208{
209    char *buf = NULL;
210
211    if (up->flags & UIO_STRING) {
212	buf = up->io.str.buffer;
213    } else {
214	UPNP_ERROR(("Called %s on UFILE that does not use buffers.\n", __FUNCTION__));
215    }
216    return buf;
217}
218
219
220int ufileno(UFILE *up)
221{
222    int fd = 0;
223
224    if (up->flags & UIO_FILE) {
225	fd = fileno(up->io.fp);
226    }  else {
227	UPNP_ERROR(("Called %s on UFILE that does not use file descriptors.\n", __FUNCTION__));
228    }
229    return fd;
230}
231
232
233void uflush(UFILE *up)
234{
235    if (up->flags & UIO_FILE) {
236	fflush(up->io.fp);
237    } else if (up->flags & UIO_STRING) {
238	up->bytes_written = 0;
239    }
240}
241