1 /* -*- Mode: C -*- */
2
3 /* custom.c --- printf clone for argv arrays
4 * Copyright (C) 2003 Gary V. Vaughan
5 * Originally by Paolo Bonzini, 2002
6 * This file is part of Snprintfv
7 *
8 * Snprintfv is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * Snprintfv 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 GNU
16 * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 *
22 * As a special exception to the GNU General Public License, if you
23 * distribute this file as part of a program that also links with and
24 * uses the libopts library from AutoGen, you may include it under
25 * the same distribution terms used by the libopts library.
26 */
27
28 /* Code: */
29
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #ifdef WITH_DMALLOC
35 # include <dmalloc.h>
36 #endif
37
38 #include <stddef.h>
39
40 #ifdef HAVE_WCHAR_H
41 # include <wchar.h>
42 #endif
43
44 #include "printf.h"
45
46
47
48 /**
49 * printf_generic_info:
50 * @pinfo: the current state information for the format
51 * string parser.
52 * @n: the number of available slots in the @argtypes array
53 * @argtypes: the pointer to the first slot to be filled by the
54 * function
55 *
56 * An example implementation of a %printf_arginfo_function, which
57 * takes the basic type from the type given in the %spec_entry
58 * and adds flags depending on what was parsed (e.g. %PA_FLAG_SHORT
59 * is %pparser->is_short and so on).
60 *
61 * Return value:
62 * Always 1.
63 */
64 int
printf_generic_info(struct printf_info * const pinfo,size_t n,int * argtypes)65 printf_generic_info (struct printf_info *const pinfo, size_t n, int *argtypes)
66 {
67 int type = pinfo->type;
68
69 if (!n)
70 return 1;
71
72 if ((type & PA_TYPE_MASK) == PA_POINTER)
73 type |= PA_FLAG_UNSIGNED;
74
75 if (pinfo->is_char)
76 type = PA_CHAR;
77
78 if (pinfo->is_short)
79 type |= PA_FLAG_SHORT;
80
81 if (pinfo->is_long)
82 type |= PA_FLAG_LONG;
83
84 if (pinfo->is_long_double)
85 type |= PA_FLAG_LONG_LONG;
86
87 argtypes[0] = type;
88 return 1;
89 }
90
91
92 /**
93 * printf_generic:
94 * @stream: the stream (possibly a struct printfv_stream appropriately
95 * cast) on which to write output.
96 * @pinfo: the current state information for the format string parser.
97 * @args: the pointer to the first argument to be read by the handler
98 *
99 * An example implementation of a %printf_function, used to provide easy
100 * access to justification, width and precision options.
101 *
102 * Return value:
103 * The number of characters output.
104 **/
105 int
printf_generic(STREAM * stream,struct printf_info * const pinfo,union printf_arg const * args)106 printf_generic (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args)
107 {
108 int len = 0, count_or_errorcode = SNV_OK;
109 char *p = NULL;
110
111 /* Used to interface to the custom function. */
112 STREAM *out;
113 Filament *fil;
114 printf_function *user_func = (printf_function *) pinfo->extra;
115
116 return_val_if_fail (pinfo != NULL, SNV_ERROR);
117
118 /* Read these now to advance the argument pointer appropriately */
119 if (pinfo->prec == -1)
120 pinfo->prec = 0;
121
122 /* Check for valid pre-state. */
123 if (pinfo->prec <= -1)
124 {
125 PRINTF_ERROR (pinfo, "invalid flags");
126 return -1;
127 }
128
129 /* Print to a stream using a user-supplied function. */
130 fil = filnew (NULL, 0);
131 out = stream_new (fil, SNV_UNLIMITED, NULL, snv_filputc);
132 user_func (out, pinfo, args);
133 stream_delete (out);
134 len = fillen (fil);
135 p = fildelete (fil);
136
137 /* Left pad to the width if the supplied argument is less than
138 the width specifier. */
139 if (p != NULL && pinfo->prec && pinfo->prec < len)
140 len = pinfo->prec;
141
142 if ((len < pinfo->width) && !pinfo->left)
143 {
144 int padwidth = pinfo->width - len;
145 while ((count_or_errorcode >= 0) && (count_or_errorcode < padwidth))
146 SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
147 }
148
149 /* Fill the buffer with as many characters from the format argument
150 * as possible without overflowing or exceeding the precision.
151 */
152 if ((count_or_errorcode >= 0) && (p != NULL))
153 {
154 int mark = count_or_errorcode;
155 while ((count_or_errorcode >= 0) && *p != '\0'
156 && ((pinfo->prec == 0) || (count_or_errorcode - mark < len)))
157 SNV_EMIT (*p++, stream, count_or_errorcode);
158 }
159
160 /* Right pad to the width if we still didn't reach the specified
161 * width and the left justify flag was set.
162 */
163 if ((count_or_errorcode < pinfo->width) && pinfo->left)
164 while ((count_or_errorcode >= 0)
165 && (count_or_errorcode < pinfo->width))
166 SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
167
168 /* Return the number of characters emitted. */
169 return count_or_errorcode;
170 }
171
172