Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add format specifiers #2

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion char_str_fmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
7 changes: 4 additions & 3 deletions helper_func.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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++;
Expand Down
108 changes: 94 additions & 14 deletions main.h
Original file line number Diff line number Diff line change
@@ -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 <stdarg.h> /* For variadic functions*/
#include <limits.h> /* For useful limits that should not be reached*/
Expand Down Expand Up @@ -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
Expand All @@ -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 */

Expand All @@ -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_ */
2 changes: 2 additions & 0 deletions printf.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ int _printf(const char *format, ...)

fmt_specifier fmt[] = {
{"c", handle_char},
{"s", handle_str},
{"%", handle_pc},
{NULL, NULL}
};

Expand Down