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