summaryrefslogtreecommitdiff
path: root/snprintfv/stream.c
blob: a979f3384c39db515f55ce6f0922e6bdfff94655 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*  -*- Mode: C -*-  */

/* stream.c ---  customizable stream routines
 * Copyright (C) 1998, 1999, 2000, 2002, 2003 Gary V. Vaughan
 * Originally by Gary V. Vaughan, 1998
 * This file is part of Snprintfv
 *
 * Snprintfv is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * Snprintfv program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * As a special exception to the GNU General Public License, if you
 * distribute this file as part of a program that also links with and
 * uses the libopts library from AutoGen, you may include it under
 * the same distribution terms used by the libopts library.
 */

/* Code: */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#ifdef WITH_DMALLOC
#  include <dmalloc.h>
#endif

#include "compat.h"
#include "stream.h"
#include "mem.h"

struct stream
{
  snv_pointer stream;
  unsigned long limit;

  StreamGet get_func;
  StreamPut put_func;
};

static int
stream_not_readable (STREAM *stream)
{
  (void)stream;
  return -1;
}

static int
stream_not_writable (int ch, STREAM *stream)
{
  (void)stream;
  (void)ch;
  return -1;
}

/**
 * stream_new: constructor
 * @dets: user supplied stream details to be passed into the various funcs.
 * @limit: the maximum number of consecutive bytes to fit in @dets.
 * @get_func: function to get a character from @dets stream.
 * @put_func: function to put a character in @dets stream.
 *
 * Allocate and initialize a new %STREAM data type.  The @get_func
 * and @put_func can be NULL if you intend to create a non-readable
 * or non-writable stream, respectively.
 *
 * Return value:
 * The address of the newly allocated and initialised stream is returned.
 **/
STREAM *
stream_new (snv_pointer dets, unsigned long limit, StreamGet get_func, StreamPut put_func)
{
  STREAM *new = snv_new (STREAM, 1);

  new->stream = dets;
  new->limit = limit;

  new->get_func = get_func ? get_func : stream_not_readable;
  new->put_func = put_func ? put_func : stream_not_writable;

  return new;
}


/**
 * stream_delete: destructor
 * @stream: The stream pending deletion
 *
 * The memory associated with @stream is recycled.

 * Return value:
 * The %dets supplied by the user when the stream was created are
 * returned for handling by the calling function.
 **/
snv_pointer
stream_delete (STREAM *stream)
{
  snv_pointer dets = stream->stream;
  snv_delete (stream);
  return dets;
}

/**
 * stream_details:
 * @stream: the stream being queried.
 *
 * The finalization function specified when @stream was created (if any)
 * is called, and then the memory associated with @stream is recycled.
 * It is the responsibility of the finalization function to recycle, or
 * otherwise manage, any memory associated with the user supplied %dets.
 * Return value:
 * This function returns the stream details associated with @stream
 * when it was originally created.
 **/
snv_pointer
stream_details (STREAM *stream)
{
  return stream ? stream->stream : NULL;
}

/**
 * stream_put:
 * @ch: A single character to be placed in @stream.
 * @stream: The stream to be written to.
 *
 * This function will @ch in @stream if that stream's output limit will
 * not be exceeded.
 *
 * Return value:
 * If @stream is full, return 1.  Otherwise, if any other error occurs,
 * that error code is returned unchanged.  This is of course dependant
 * on what the handler function uses to indicate an error.  If the stream
 * is not full and the stream's writing function succeeds, 1 (the number of
 * characters emitted!) is returned.
 **/
int
stream_put (int ch, STREAM *stream)
{
  int ch_or_errorcode;

  if (!stream)
    return -1;

  if (stream->limit < 1)
    return 1;

  stream->limit -= 1;
  ch_or_errorcode = (*stream->put_func) ((unsigned char) ch, stream);

  return (ch_or_errorcode < 0) ? ch_or_errorcode : 1;
}

/**
 * stream_puts:
 * @s: A string to be placed in @stream.
 * @stream: The stream to be written to.
 *
 * This function will @ch in @stream if that stream's output limit will
 * not be exceeded.
 *
 * Return value:
 * If any other error occurs, that error code is returned unchanged.
 * This is of course dependant on what the handler function uses to
 * indicate an error.  If the stream becomes full, the remaining
 * characters are not printed.  If the stream's writing function
 * always succeeds, the number of characters emitted or skipped is
 * returned.
 **/
int
stream_puts (char *s, STREAM *stream)
{
  int ch_or_errorcode;
  int num;

  if (!stream)
    return -1;

  for (num = 0; *s; num++, s++)
    {
      if (stream->limit < 1)
        return num + strlen (s);

      stream->limit -= 1;
      ch_or_errorcode = (*stream->put_func) ((unsigned char) *s, stream);

      if (ch_or_errorcode < 0)
	return ch_or_errorcode;
    }

  return num;
}

/**
 * stream_get:
 * @stream: The stream to be read from.
 *
 * This function will try to read a single character from @stream.
 *
 * Return value:
 * If an error occurs or the end of @stream is reached, -1 is returned.
 * Under normal circumstances the value if the character read (cast to
 * an int) is returned.
 **/
int
stream_get (STREAM *stream)
{
  return (*stream->get_func) (stream);
}

/*
 * Local Variables:
 * mode: C
 * c-file-style: "gnu"
 * indent-tabs-mode: nil
 * End:
 * end of snprintfv/stream.c */