diff --git a/char_str_fmt.c b/char_str_fmt.c index 1e90fc2..0330a2f 100644 --- a/char_str_fmt.c +++ b/char_str_fmt.c @@ -10,11 +10,85 @@ * After we get it, we pass it to putchar which simply prints * the value of the character * + * We check if it was successful before returning 1 + * else we return 0 + * */ int handle_char(va_list args) { char x = va_arg(args, int); - return (_putchar(x)); + if (_putchar(x)) + return (1); + + return (0); +} + +/** + * handle_str - A function to print out strings + * to the stdout + * + * @args: The arguments to be passed into our function + * Return: 0 if empty, null if NULL and the number of + * characters printed if successful + * + * The "array" or pointer to the location of the first character + * is retrieved from va_list using va_arg. This enables us to now + * be able to start its manipulation. + * + * The counter is initialized for tracking how many characters are + * printed. It is initialized to 0 to make sure that if nothing + * prints then the functions using it will get 0 instead of + * undefined behaviour. + * + * If our string is NULL, we change its value to "(null)", this ensures that + * our program doesn't produce undesired behaviour. The loop is true + * in all non zero values (check ASCII, man ascii for more), + * this means that if it is equal to null ('\0') it evaluates to false + * effectively terminating the loop and returning the umber of characters + * printed + * +*/ + +int handle_str(va_list args) +{ + char *str = va_arg(args, char *); + size_t i = 0; + + if (str == NULL) + str = "(null)"; + + while (str[i]) + { + _putchar(str[i]); + i++; + } + + return (i); +} + +/** + * handle_pc - A function that handles extra percentage + * @args: Not applicable + * Return: 0 if nothing is printed or an error, and 1 if + * successful + * + * The __attribute__((unused)) is used to silence GCC + * whenever there is an attribute that is unused. This is + * the case here since we don't need to get any value from + * va_list args. + * + * Resources: + * https://lms.fun-mooc.fr/asset-v1:inria+41020+session01+type@asset+block/forum-unused-parameters-attribute-unused-2181.html + * https://developer.arm.com/documentation/dui0491/i/Compiler-specific-Features/--attribute----unused---variable-attribute + * https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Variable-Attributes.html +*/ + +int handle_pc(__attribute__((unused)) va_list args) +{ + if (_putchar('%')) + return (1); + + return (0); } diff --git a/helper_func.c b/helper_func.c index f3bebb5..1866c7c 100644 --- a/helper_func.c +++ b/helper_func.c @@ -16,7 +16,8 @@ * to the stdout (the terminal for most cases but can be redirected * elsewhere or be printed in an entirely separate location) * - * Look up for use cases of write in "man write(2)" + * Resources: + * man write(2) */ int _putchar(char x) @@ -58,8 +59,8 @@ int _strlen(const char *str) { if (i < (INT_MAX - 1)) { - dprintf(2, "%s::%s: The string exceeds %d characters", - __FILE__, _F_NAME__, INT_MAX); + dprintf(2, "%s: The string exceeds %d characters", + __FILE__, INT_MAX); _exit(-1); } i++; diff --git a/main.h b/main.h index d0df97b..82fcaf7 100644 --- a/main.h +++ b/main.h @@ -1,6 +1,49 @@ #ifndef MAIN_H_ #define MAIN_H_ +/* + *======--------- main.h - _printf header file ---------------------------=== + * + * This header file is part of the Codetrybe project to simplify the + * implementation of the printf function. + * It utilizes the concepts taught at ALX. + * Please refrain from directly copying and pasting this code into + * your project, as doing so violates academic integrity + * and risks your standing in the ALX program. + * + * It is important to have a some understanding of the concepts + * taught in ALX for easier comprehension of this code. + * + * Please note that this "documentation" does not replace official + * documentation, man pages, or online resources. + * For doubts or questions about specific concepts or functions, + * refer to the authoritative sources, such as man pages. + * Relevant resources are mentioned where necessary, + * but the list is not comprehensive and may vary depending + * on the author of the function or feature. + * Reading all provided resources is not mandatory; + * they serve as guides for specific concepts. + * + * The author(s) of this project, either in part or as a whole, + * shall not be liable for any damages caused. + * Efforts have been made to provide accurate information. + * + * This project should be compiled on LINUX x86_64 architecture, + * preferably Ubuntu 22.04 LTS, using the -std=gnu89 flag. + * Refer to the link + * https://gcc.gnu.org/gcc-5/porting_to.html + * for more information on why this flag is necessary. + * + * This project is released under the copyleft license GNU GPL v3. + * Visit: https://www.fsf.org/ + * for more information on free software (as in freedom). + * + *======--------------------------------------------------------------------=== + */ + + + +/* Standard Libraries */ #include /* For variadic functions*/ #include /* For useful limits that should not be reached*/ @@ -34,6 +77,22 @@ int _printf(const char *format, ...); * * Exceptions include _putchar(char x) and family * + * Resources: + * man stdarg(3) + * https://www.gnu.org/software/libc/manual/html_node/Variadic-Functions.html + * https://en.wikipedia.org/wiki/Variadic_function + * https://youtu.be/oDC208zvsdg + * https://youtu.be/3iX9a_l9W9Y + * + * https://publications.gbdirect.co.uk//c_book/chapter8/typedef.html + * https://en.wikipedia.org/wiki/Struct_(C_programming_language) + * https://www.geeksforgeeks.org/structures-c/ + * https://www.educative.io/answers/how-to-use-structures-in-c + * https://youtu.be/oKXP1HZ8xIs + * https://youtu.be/dqa0KMSMx2w + * https://youtu.be/LpHnHRI6gLc?t=134 + * https://youtu.be/6Z-silgul48 + * */ typedef struct fmt_specifiers @@ -46,20 +105,39 @@ typedef struct fmt_specifiers #define BUFFER_S 1024 -/** - * _F_NAME_ - Get function name - * If __func__ is available use it (Recommended by Betty) - * Else use __FUNCTION__ (Available for gcc only) - * This operation causes Betty to raise a Warning - * You can remove the operation and replace it with - * #define _F_NAME_ __func__ and everything will work just fine - * and as an added bonus no Betty to deal with -*/ -#ifdef __func__ - #define _F_NAME__ __func__ -#else - #define _F_NAME__ __FUNCTION__ -#endif +/* + *===---- predefined identifier (function name)----------=== + * + * In previous iteration of this project there was a + * preprocessor _F_NAME__ that was either defined to + * __FUNCTION__ or __func__ but it has proved challenging + * to keep it. At first it is not portable to C90 and below + * apparently it was introduced in 1992 (__FUNCTION__) so + * it is not available. This was of course only for GCC. + * https://stackoverflow.com/questions/7008485/ + * https://github.com/grpc/grpc/issues/1739 + * And __func__ was added in ISO C 1999 so its availability is + * not available for most compilers. + * You can easily silence this warnings as explained here + * https://stackoverflow.com/questions/52962812/ but it is not + * worth the hassle. + * You can check out the official bug report about the issue + * https://bugzilla.gnome.org/show_bug.cgi?id=758541 + * + * But if you want to recreate what was here then: + * + * #ifdef __func__ + * #define _F_NAME__ __func__ + * #else + * #define _F_NAME__ __FUNCTION__ + * #endif + * + * The if's are not necessary since the identifier was later + * standardized to use __func__, but __FUNCTION__ can be used + * when compiling with GCC (kept for backward compatibility) + * + *===-------------------------------------------------------=== + */ /* Helper Functions */ @@ -69,5 +147,7 @@ int _strlen(const char *str); /* Format specifiers */ int handle_char(va_list args); +int handle_str(va_list args); +int handle_pc(__attribute__((unused)) va_list args); #endif /* End of MAIN_H_ */ diff --git a/printf.c b/printf.c index 1d298e9..0904770 100644 --- a/printf.c +++ b/printf.c @@ -29,6 +29,8 @@ int _printf(const char *format, ...) fmt_specifier fmt[] = { {"c", handle_char}, + {"s", handle_str}, + {"%", handle_pc}, {NULL, NULL} };