Algorithms_in_C 1.0.0
Set of algorithms implemented in C.
Loading...
Searching...
No Matches
min_printf.h
Go to the documentation of this file.
1/**
2 * @file
3 * @brief Implementation of a [function](https://www.geeksforgeeks.org/variable-length-argument-c) similar to `printf`
4 * @details
5 * `printf` statement rewritten (as `min_printf`) in C without using the `stdio.h` library
6 * Syntax of `min_printf` is same as `printf`
7 * Currently min_printf handles:
8 * Integers, Doubles, floats, characters and strings
9 * The format specifiers and escape sequence is the same as for `printf`
10 * User can also specify the width and precision if required, just like in the case of `printf`
11 * How to use it:
12 * - First include min_printf.h in your code
13 * - Then type `min_printf()`, and pass required parameters to it
14 * - As already specified, it's syntax is same as printf
15 * @author [Jaskarn Singh](https://github.com/Jaskarn7)
16*/
17
18#ifndef MIN_PRINTF_H
19#define MIN_PRINTF_H
20
21#include <stdlib.h> /// for `malloc` and `free` functions
22#ifdef _WIN32
23 #include <io.h> /// for `write` function
24#else
25 #include <unistd.h> /// for `write` function
26#endif
27#include <stdarg.h> /// for `va_start` and `va_arg` functions
28
29#define INT_MAX_LENGTH 10 /// used as standard length of string to store integers
30#define PRECISION_FOR_FLOAT 8 /// default precision for float or double if not specified
31
32/**
33 * @brief struct used to store character in certain times
34*/
35typedef struct buffer {
36 char buffr_char; // Character will be stored in this variable
37 int buf_size; // Checks if character is present in buffr_char or not, 0 if no and 1 if yes
39
40/**
41 * @details
42 * This function return ten to the power a(The parameter specified to it) like:
43 * if the parameter specified is 4 i.e. -> power_of_ten(4) is called then
44 * this function will return ten to the power four (10000);
45 * @param a The power of ten which is to be returned
46 * @return Ten to the power a
47 */
48int power_of_ten(int a)
49{
50 int n = 1; ///< This number will be returned as ten to power of a
51 for (int i = 1; i <= a; ++i)
52 n *= 10 ;
53 return n;
54}
55
56/**
57 * @brief Checks if a character is a number
58 * @param c character to be checked if it's a number or not
59 * @return `true`(1) if the character is a number
60 * @return `false`(0) if the character is NOT a number
61*/
62int is_number(char *c)
63{
64 return (*c >= '0' && *c <= '9') ? 1 : 0;
65}
66
67/**
68 * @brief Returns specific required next character
69 * @param p pointer to a format string of `min_printf()`
70 * @param buffer struct for checking if buffr_char character is present or not
71 * @return character inside `buffer->buffr_char`, if `buffer->buf_size` is one
72 * @return character at which p is pointing, if `buffer->buf_size` is zero
73 */
74char get_ch(char *p, Buffer *buffer)
75{
76 if (buffer->buf_size) {
77 buffer->buf_size = 0; ///< Since character is used, this sets `buffer->buf_size` to zero
78 return buffer->buffr_char; // Returns character inside buffer->buffr_char
79 }
80 return *p++;
81}
82
83/**
84 * @brief Stores character to the `buffer->buffr_char`
85 * @param c character to be stored in the `buffer->buffr_char`
86 * @param buffer struct where character will be stored
87*/
88void unget_ch(char *c, Buffer *buffer)
89{
90 buffer->buffr_char = *c; // Character initializes inside buffer->buffr_char
91 buffer->buf_size = 1; // Sets bufsize to one as new character is stored in buffr_char
92}
93
94
95/**
96 * @brief Calculates the number of digits in a number
97 * @param n number whose digits are to be counted
98 * @return number of digits in n
99*/
101{
102 int digits = 0; // Stores encountered number of digits
103 while (n > 0) {
104 ++digits; // Since number still contains a digit, so increment digit variable
105 n /= 10; // Removes last digit from number
106 }
107 return digits;
108}
109
110/**
111 * @brief Prints one character on screen
112 * @param s character to be printed on the screen
113*/
114void put_char(char s)
115{
116 /* buf used for storing character to be printed in an array (+1 for '\0')*/
117 char *buf = (char *) malloc(sizeof(char) + 1);
118 *buf = s;
119 *(buf + 1) = '\0';
120 write(1, buf, 1);
121 free(buf);
122}
123
124/**
125 * @brief Reverses a string using [two pointer algorithm](https://www.geeksforgeeks.org/program-reverse-array-using-pointers/?ref=rp)
126 * @param p pointer to the string which is to be reversed
127*/
128void reverse_str(char *p)
129{
130 char *l = p; // Points to first character of p
131 char *h = p; // Will be used to point to last character of p
132 char temp; // Temporarily stores a character, Used in swapping
133
134 while (*h != '\0')
135 ++h;
136 --h; // Now h point to last valid character of string
137
138 /* Swap character which lower and higher are pointing until lower < higher. At that point string will be reversed.*/
139 while (l < h) {
140 temp = *l;
141 *l = *h;
142 *h = temp;
143 ++l; // Increment lower to next character
144 --h; // Decrement higher to previous character from current character
145 }
146}
147
148/**
149 * @details
150 * The algorithm here is to first convert the number into
151 * string and then reverse it be passing it to reverse_str function
152 * and then printing on the screen
153 * @param n Number to be printed
154 * @param width Total characters to be printed (Prints ' ' if (size < width)
155 * @param precision Total character of number to be printed (prints 0 before number if size of number < precision)
156 *
157*/
158void print_int_value(int n, int width, int precision)
159{
160 char *p = (char *) malloc(INT_MAX_LENGTH * sizeof(char) + 1); /* +1 for '\0' */
161 char *s = p; // Temporary pointer
162 int size = 0; //!< Used to store number of digits in number
163
164 while (n > 0) {
165 *s++ = n % 10 + '0'; // Converts last digit of number to character and store it in p
166 ++size; // Increment size variable as one more digit is occurred
167 n /= 10; // Removes the last digit from the number n as we have successfully stored it in p
168 }
169 *s = '\0';
170
171 s = p; // Again point back s to starting of p
172
173 reverse_str(p);
174
175 /*!
176 * The next two conditions check weather it is required to
177 * add blanks before printing the number (ie: width)and is it specified how many
178 * zeros to be printed before the number is printed (ie: precision)
179 */
180 if (width > 0 && size < width)
181 for (int i = 0; i < (width - precision); ++i)
182 put_char(' ');
183
184 if (precision > 0 && precision > size)
185 for (int i = 0; i < (precision - size); ++i)
186 put_char('0');
187
188 /* Prints the number.*/
189 while (*s != '\0')
190 put_char(*s++);
191
192 free(p);
193}
194
195/**
196* @brief The algorithm here is also the same as the `print_int_value` function
197 *
198 * @details
199 * First, the digits before decimal is printed by converting the double
200 * to int. Then after printed a `.`, the double number is subtracted with
201 * the integer value of the number, leaving us with 0 before the decimal.
202 * Then, we multiply the number with 10 raised to the power precision (
203 * precision means how many digits to be printed after the decimal.)
204 * By default, the precision is 8 if it is not specified.
205 * Then, the remaining number is printed on the screen.
206 * @param dval double number to be printed
207 * @param width similar to width parameter of print_int_value()
208 * @param precision tells the number of digits to be printed after the decimal (By default it is 8)
209 */
210void print_double_value(double dval, int width, int precision)
211{
212 int ndigits = get_number_of_digits((int) dval); // Store number of digits before decimal in dval
213 int reqd_blanks = width - (precision + 1) - ndigits; // Blanks to be printed before printing dval, just to cover the width
214
215 print_int_value((int) dval, reqd_blanks, 0); // Prints the part before decimal
216
217 put_char('.'); // Print decimal
218
219 /*Deletes digits before decimal and makes them zero. For example:
220 if dval = 1923.79022, them this will make dval = 0.79022
221 */
222 dval = dval - (int) dval;
223
224 dval *= power_of_ten(precision); // Brings precision number of digits after decimal to before decimal
225
226 print_int_value((int) dval, 0, precision); // Prints the remaining number
227}
228
229/**
230 * @details
231* First size of the string is calculated to check whether
232* width and precision are to be taken into account or not.
233* Then, the string is printed in accordingly.
234* @param p pointer to string to be printed
235* @param width if (width > sizeof string) then, blanks will be printed before sting to cover up the width
236* @param precision total characters of the string to be printed (prints the whole string if 0 or greater than size of string)
237*/
238void print_string(char *p, int width, int precision)
239{
240 int size = 0; // Stores number of character in string
241 char *s = p; // Temporary pointer
242
243 /* Calculates size of string p*/
244 while (*s != '\0') {
245 ++size;
246 ++s;
247 }
248
249 s = p; // Point s to starting of p
250
251 /* Checks how many characters to be printed.
252 if precision is defined then size variable is changed to precision so that only precision
253 number of characters were printed.
254 */
255 if (precision != 0 && precision < size)
256 size = precision;
257
258 /* Prints blanks to cover the width if required*/
259 for (int i = 0; i < (width - size); ++i)
260 put_char(' ');
261
262 /* Print the string.*/
263 for (int i = 0; i < size; ++i)
264 put_char(*s++);
265
266}
267
268/**
269* @brief Takes width and precision specified from the format of the string
270* @param p pointer of the format string
271* @param width variable in which width will be stored
272* @param precision variable in which precision will be stored
273* @return character pointer to the current pointer of string p (used to update value of p)
274*/
275char *get_width_and_precision(char *p, Buffer *buffer, int *width, int *precision)
276{
277 /* Skip % if p is pointing to it.*/
278 if (*p == '%')
279 ++p;
280
281 /* Calculates the width specified. */
282 while (*p != '.' && is_number(p))
283 *width = *width * 10 + (*p++ - '0');
284
285 /* Calculates the precision specified.*/
286 if (*p == '.' /* Since a precision is always specified after a '.'. */) {
287 while (is_number(++p))
288 *precision = *precision * 10 + (*p - '0');
289 unget_ch(p, buffer); // The non number will be stored in `buffer->buffr`
290 }
291 return p;
292}
293
294/**
295 * min_printf is the function same as printf
296 * @param fmt format of string
297 * @param ... arguments passed according to the format
298*/
299void min_printf(char *fmt, ...)
300{
301 va_list ap; // Points to each unnamed arg in turn
302 char *p, *sval; // p will be used to point to fmt and sval will store string value
303 char cval; // Stores character value
304 int ival; // For integer values
305 double dval; // For double or float values
306 va_start(ap, fmt); // Makes ap points to first unnames argument
307
308 /* Initializing the buffer for storing character. */
309 Buffer *buffer = (Buffer *) malloc(sizeof(Buffer));
310 buffer->buf_size = 0; // Initially set buffer size to zero as no character is inserted
311
312 for (p = fmt; *p != '\0'; ++p) {
313
314 /* If p != '%' then the character is printed to screen. */
315 if (*p != '%') {
316 put_char(*p);
317 continue;
318 }
319
320 int width = 0; // Stores width specified
321 int precision = 0; // Stores precision specified
322
323 /* Updates values of width, precision and p. */
324 p = get_width_and_precision(p, buffer, &width, &precision);
325
326 /* Checks format of next argument.*/
327 switch (get_ch(p, buffer)) {
328 case 'd': // Integer
329 ival = va_arg(ap, int);
330 print_int_value(ival, width, precision);
331 break;
332 case 'c': // Character
333 cval = va_arg(ap, int);
334 put_char(cval);
335 break;
336 case 'f': // Float or Double
337 dval = va_arg(ap, double);
338
339 // If precision is not specified then default value is applied
340 if (precision == 0)
341 precision = PRECISION_FOR_FLOAT;
342 print_double_value(dval, width, precision);
343 break;
344 case 's': // String pointer
345 sval = va_arg(ap, char *);
346 print_string(sval, width, precision);
347 break;
348 default:
349 put_char(*p);
350 break;
351 }
352 }
353 va_end(ap);
354}
355
356#endif /* MIN_PRINTF_H */
#define malloc(bytes)
This macro replace the standard malloc function with malloc_dbg.
Definition malloc_dbg.h:18
#define free(ptr)
This macro replace the standard free function with free_dbg.
Definition malloc_dbg.h:26
void print_int_value(int n, int width, int precision)
Definition min_printf.h:158
void min_printf(char *fmt,...)
min_printf is the function same as printf
Definition min_printf.h:299
char get_ch(char *p, Buffer *buffer)
Returns specific required next character.
Definition min_printf.h:74
void print_double_value(double dval, int width, int precision)
The algorithm here is also the same as the print_int_value function.
Definition min_printf.h:210
int power_of_ten(int a)
Definition min_printf.h:48
void reverse_str(char *p)
Reverses a string using two pointer algorithm
Definition min_printf.h:128
char * get_width_and_precision(char *p, Buffer *buffer, int *width, int *precision)
Takes width and precision specified from the format of the string.
Definition min_printf.h:275
void unget_ch(char *c, Buffer *buffer)
Stores character to the buffer->buffr_char
Definition min_printf.h:88
#define INT_MAX_LENGTH
for malloc and free functions
Definition min_printf.h:29
struct buffer Buffer
struct used to store character in certain times
void put_char(char s)
Prints one character on screen.
Definition min_printf.h:114
int is_number(char *c)
Checks if a character is a number.
Definition min_printf.h:62
int get_number_of_digits(int n)
Calculates the number of digits in a number.
Definition min_printf.h:100
void print_string(char *p, int width, int precision)
Definition min_printf.h:238
struct used to store character in certain times
Definition min_printf.h:35