[<prev] [next>] [day] [month] [year] [list]
Message-ID: <CAFf+5ziNV4KUT93awVTgipgdQESsi5wJ9tyY9yqiUAXkoWauCw@mail.gmail.com>
Date: Thu, 11 Dec 2025 13:54:19 +0530
From: Amit <amitchoudhary0523@...il.com>
To: linux-kernel@...r.kernel.org
Subject: stdin functions library (Three files: stdin_functions_library.c,
stdin_functions_library.h, and compile_stdin_functions_library.sh).
stdin functions library (Three files: stdin_functions_library.c,
stdin_functions_library.h, and compile_stdin_functions_library.sh).
--------------------------
stdin_functions_library.c
--------------------------
/*
* License:
*
* This file has been released under "unlicense" license
* (https://unlicense.org).
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or distribute
* this software, either in source code form or as a compiled binary, for any
* purpose, commercial or non-commercial, and by any means.
*
* For more information about this license, please visit - https://unlicense.org
*/
/*
* Author: Amit Choudhary
* Email: amitchoudhary0523 AT gmail DOT com
*/
#include "stdin_functions_library.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
const char *sful_convert_err_num_to_err_str(int error_num)
{
switch (error_num) {
case SFUL_SUCCESS:
return ("Everything happened successfully");
case SFUL_FAILURE:
return ("Some error happened");
case SFUL_ARG_STR_IS_NULL:
return ("Argument 'str' is NULL");
case SFUL_ARG_SIZE_IS_OUT_OF_BOUNDS:
return ("Argument 'size' is either less than 1 or greater than"
" SFUL_MAX_INPUT_SIZE_ALLOWED_FROM_STDIN");
case SFUL_USER_GAVE_MORE_INPUT_THAN_ASKED_FOR:
return ("The user gave more input than asked for");
case SFUL_ARG_STR_IS_EMPTY_STRING:
return ("Argument 'str' is an empty string");
case SFUL_LENGTH_OF_ARG_STR_IS_OUT_OF_BOUNDS:
return ("The length of argument 'str' is greater than"
" 'SFUL_INTEGER_STR_SIZE - 1'");
case SFUL_ARG_MSG_FOR_USER_IS_NULL:
return ("Argument 'msg_for_user' is NULL");
case SFUL_ARG_MIN_IS_OUT_OF_BOUNDS:
return ("Argument 'min' is less than SFUL_INT_MIN or greater than"
" SFUL_INT_MAX");
case SFUL_ARG_MAX_IS_OUT_OF_BOUNDS:
return ("Argument 'max' is less than SFUL_INT_MIN or greater than"
" SFUL_INT_MAX");
case SFUL_ARG_MAX_IS_LESS_THAN_ARG_MIN:
return ("Argument 'max' is less than argument 'min'");
} // end of switch (error_num)
return ("Wrong error number given");
} // end of function sful_convert_err_num_to_err_str()
int sful_get_input_from_stdin_and_clear_stdin(char *str, int size,
int clear_stdin)
{
int c = 0;
int num_chars_read = 0;
if (!str) {
if (clear_stdin > 0) {
sful_clear_stdin();
}
return SFUL_ARG_STR_IS_NULL;
}
if ((size < 1) || (size > SFUL_MAX_INPUT_SIZE_ALLOWED_FROM_STDIN)) {
if (clear_stdin > 0) {
sful_clear_stdin();
}
return SFUL_ARG_SIZE_IS_OUT_OF_BOUNDS;
}
while (1) {
c = getchar();
if ((c == '\n') || (c == EOF)) {
str[num_chars_read] = 0;
if (clear_stdin > 0) {
sful_clear_stdin();
}
return SFUL_SUCCESS;
}
str[num_chars_read] = (char)(c);
num_chars_read++;
// The user has given more input than asked for, so we should return
// a negative error number and memset all characters read till now to 0.
if (num_chars_read > (size - 1)) {
memset(str, 0, (size_t)(num_chars_read));
if (clear_stdin > 0) {
sful_clear_stdin();
}
return SFUL_USER_GAVE_MORE_INPUT_THAN_ASKED_FOR;
}
} // end of while (1) loop
} // end of function sful_get_input_from_stdin_and_clear_stdin()
void sful_clear_stdin(void)
{
int c = 0;
fcntl(fileno(stdin), F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
c = getchar();
fcntl(fileno(stdin), F_SETFL, fcntl(0, F_GETFL) ^ O_NONBLOCK);
if ((c == '\n') || (c == EOF)) {
return;
}
while ((c = getchar()) && (c != '\n') && (c != EOF));
return;
} // end of function sful_clear_stdin()
void sful_wait_for_user_to_press_enter(void)
{
printf("Please press the \"ENTER\" key to continue..");
getchar();
sful_clear_stdin();
return;
} // end of function sful_wait_for_user_to_press_enter()
int sful_get_integer_from_user_within_range_inclusive(const char *msg_for_user,
int min, int max, int *error_num_ptr)
{
char str[SFUL_INTEGER_STR_SIZE];
int int_from_user = SFUL_INT_MIN - 1;
int retval = SFUL_FAILURE;
*error_num_ptr = SFUL_SUCCESS;
if (!msg_for_user) {
*error_num_ptr = SFUL_ARG_MSG_FOR_USER_IS_NULL;
return (SFUL_INT_MIN - 1);
}
if ((min < SFUL_INT_MIN) || (min > SFUL_INT_MAX)) {
*error_num_ptr = SFUL_ARG_MIN_IS_OUT_OF_BOUNDS;
return (SFUL_INT_MIN - 1);
}
if ((max < SFUL_INT_MIN) || (max > SFUL_INT_MAX)) {
*error_num_ptr = SFUL_ARG_MAX_IS_OUT_OF_BOUNDS;
return (SFUL_INT_MIN - 1);
}
if (max < min) {
*error_num_ptr = SFUL_ARG_MAX_IS_LESS_THAN_ARG_MIN;
return (SFUL_INT_MIN - 1);
}
// Keep looping until a valid integer is received or some error happens.
while ((int_from_user < min) || (int_from_user > max)) {
printf("\n");
printf("%s", msg_for_user);
memset(str, 0, SFUL_INTEGER_STR_SIZE);
retval = sful_get_input_from_stdin_and_clear_stdin(str,
SFUL_INTEGER_STR_SIZE, SFUL_CLEAR_STDIN);
if (retval == SFUL_USER_GAVE_MORE_INPUT_THAN_ASKED_FOR) {
continue;
}
if (retval != SFUL_SUCCESS) {
*error_num_ptr = retval;
return (SFUL_INT_MIN - 1);
}
retval = sful_is_str_allowed_integer(str);
if (retval != SFUL_SUCCESS) {
continue;
}
int_from_user = atoi(str);
} // end of while loop
return int_from_user;
} // end of function sful_get_integer_from_user_within_range_inclusive()
char sful_get_y_or_n_from_user(const char *msg_for_user, int *error_num_ptr)
{
char str[SFUL_Y_OR_N_STR_SIZE];
int retval = SFUL_FAILURE;
*error_num_ptr = SFUL_SUCCESS;
if (!msg_for_user) {
*error_num_ptr = SFUL_ARG_MSG_FOR_USER_IS_NULL;
return -1;
}
// Keep looping until 'y' or 'n' is received or some error happens.
while (1) {
printf("\n");
printf("%s", msg_for_user);
memset(str, 0, SFUL_Y_OR_N_STR_SIZE);
retval = sful_get_input_from_stdin_and_clear_stdin(str,
SFUL_Y_OR_N_STR_SIZE, SFUL_CLEAR_STDIN);
if (retval == SFUL_USER_GAVE_MORE_INPUT_THAN_ASKED_FOR) {
continue;
}
if (retval != SFUL_SUCCESS) {
*error_num_ptr = retval;
return -1;
}
if (strncmp(str, "y", SFUL_Y_OR_N_STR_SIZE) == 0) {
return 'y';
}
if (strncmp(str, "n", SFUL_Y_OR_N_STR_SIZE) == 0) {
return 'n';
}
} // end of while (1) loop
} // end of function sful_get_y_or_n_from_user()
int sful_is_str_allowed_integer(const char *str)
{
char c = -1;
if (!str) {
return SFUL_ARG_STR_IS_NULL;
}
if (!(str[0])) { // empty string
return SFUL_ARG_STR_IS_EMPTY_STRING;
}
// If length of 'str' is not less than SFUL_INTEGER_STR_SIZE, then it is
// an error, and in this case, return SFUL_FAILURE.
if (strnlen(str, SFUL_INTEGER_STR_SIZE) == SFUL_INTEGER_STR_SIZE) {
return SFUL_LENGTH_OF_ARG_STR_IS_OUT_OF_BOUNDS;
}
if ((*str == '+') || (*str == '-')) {
str++;
}
while ((c = *str)) {
if ((c < '0') || (c > '9')) {
return SFUL_FAILURE;
}
str++;
}
return SFUL_SUCCESS;
} // end of function sful_is_str_allowed_integer()
--------------------------
stdin_functions_library.h
--------------------------
/*
* License:
*
* This file has been released under "unlicense" license
* (https://unlicense.org).
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or distribute
* this software, either in source code form or as a compiled binary, for any
* purpose, commercial or non-commercial, and by any means.
*
* For more information about this license, please visit - https://unlicense.org
*/
/*
* Author: Amit Choudhary
* Email: amitchoudhary0523 AT gmail DOT com
*/
#ifndef _STDIN_FUNCTIONS_H_
#define _STDIN_FUNCTIONS_H_
// SFUL/sful means stdin functions library.
#define SFUL_CLEAR_STDIN 10001 // Arbitrary positive integer which doesn't
// conflict with other constant values.
#define SFUL_DO_NOT_CLEAR_STDIN -99992 // Arbitrary negative integer which
// doesn't conflict with other constant
// values.
/* START OF SUCCESS AND ERROR CODES */
// Everything happened successfully.
#define SFUL_SUCCESS 0
// Some error happened.
#define SFUL_FAILURE -1
// Argument 'str' is NULL.
#define SFUL_ARG_STR_IS_NULL -2
// Argument 'size' is either less than 1 or greater than
// 'SFUL_MAX_INPUT_SIZE_ALLOWED_FROM_STDIN'.
#define SFUL_ARG_SIZE_IS_OUT_OF_BOUNDS -3
// The user gave more input than asked for.
#define SFUL_USER_GAVE_MORE_INPUT_THAN_ASKED_FOR -4
// Argument 'str' is an empty string.
#define SFUL_ARG_STR_IS_EMPTY_STRING -5
// The length of argument 'str' is greater than 'SFUL_INTEGER_STR_SIZE - 1'.
#define SFUL_LENGTH_OF_ARG_STR_IS_OUT_OF_BOUNDS -6
// Argument 'msg_for_user' is NULL.
#define SFUL_ARG_MSG_FOR_USER_IS_NULL -7
// Argument 'min' is less than 'SFUL_INT_MIN' or greater than 'SFUL_INT_MAX'.
#define SFUL_ARG_MIN_IS_OUT_OF_BOUNDS -8
// Argument 'max' is less than 'SFUL_INT_MIN' or greater than 'SFUL_INT_MAX'.
#define SFUL_ARG_MAX_IS_OUT_OF_BOUNDS -9
// Argument 'max' is less than argument 'min'.
#define SFUL_ARG_MAX_IS_LESS_THAN_ARG_MIN -10
/* END OF SUCCESS AND ERROR CODES */
// AFAIK, all unix/linux terminals return only a maximum of 4096 characters of
// user input (including the newline character). If the user input is greater
// than 4096 characters (including the newline character), then the character at
// the position 4096 (here, position starts from 1) is replaced by the newline
// character, and the rest of the input is discarded. So, the terminal returns
// a maximum of 4096 characters (including the newline character).
//
// You can reduce the following constant according to your requirements, but
// increasing it beyond 4096 will not serve any purpose because of the reason
// given above.
#define SFUL_MAX_INPUT_SIZE_ALLOWED_FROM_STDIN 4096 // including null
// terminating character
// The size of the integer string is 10 (including null terminating character)
// so this means that the max number of digits in this string can be 9. If we
// keep the max number of digits as 10, then in some cases, all these digits can
// be 9, and in these cases when we convert the string to integer, then there
// will be integer overflow because 9999999999 (9 is 10 times) is greater than
// INT_MAX. So, to prevent the integer overflow we have limited the max number
// of integer digits in the string to 9. Since the string will be null
// terminated, so accounting for the null terminating character, the size of the
// integer string becomes 10.
#define SFUL_INTEGER_STR_SIZE 10 // including null terminating character
// To understand the following constants, please read the documentation of
// 'SFUL_INTEGER_STR_SIZE' above.
#define SFUL_INT_MIN -99999999
#define SFUL_INT_MAX 999999999
// 'SFUL_Y_OR_N_STR_SIZE' is defined to be 2 characters including the null
// terminating character. This is because we are expecting only one character
// from the user (either 'y' or 'n', 'y' means yes and 'n' means no). If the
// user inputs more than one character, then we will reject the input, and ask
// for new input from the user (this will go on indefinitely until the user
// inputs only 'y' or 'n', or the user terminates this program. So, the size of
// 2 characters (including the null terminating character) is enough to catch
// whether the user has inputted only one character or more than one character.
#define SFUL_Y_OR_N_STR_SIZE 2 // including null terminating character
/*
* IMPORTANT NOTES:
*
* 1. Please make sure that the argument 'error_num_ptr' (that is required
* by some functions) is a pointer to an 'int' data type else the
* program may crash. If 'error_num_ptr' is NULL, then the program will
* surely crash.
*
* 2. If you call a function that has 'error_num_ptr' as an argument, then
* after the function returns, you should first check whether the value
* of '*error_num_ptr' is 'SFUL_SUCCESS' or not. If it is not
* 'SFUL_SUCCESS', then this means that some error has happened in the
* called function, and so in this case, there is no point in
* checking/using the return value of the called function (in case there
* is some return value). The return value of the called function (in
* case there is some return value) will make sense only when the value
* of '*error_num_ptr' is 'SFUL_SUCCESS'.
*
* 3. If the value of '*error_num_ptr' is not 'SFUL_SUCCESS', then the
* value of '*error_num_ptr' will be a negative error number that will
* signify which particular error has happened.
*/
/*
* sful_convert_err_num_to_err_str():
*
* Description:
*
* Function sful_convert_err_num_to_err_str() returns an error string
* corresponding to the given error number.
*/
const char *sful_convert_err_num_to_err_str(int error_num);
/*
* sful_get_input_from_stdin_and_clear_stdin():
*
* Description:
*
* Function sful_get_input_from_stdin_and_clear_stdin() reads at most
* 'size - 1' characters from stdin, and stores them in 'str'. Then, 'str'
* is null terminated by appending the null terminating character ('\0') to
* 'str'.
*
* If argument 'clear_stdin' is greater than 0, then stdin is cleared by
* this function before returning in all cases (both successful and error
* cases). Clearing stdin means that all the remaining characters in stdin
* are read and discarded, and there are no characters left in stdin (stdin
* becomes empty).
*
* You should always set 'clear_stdin' to a value greater than 0 so that
* stdin is cleared of remaining characters, and you don't get old input
* when stdin is read the next time.
*
* Return values:
*
* On success, 'SFUL_SUCCESS' is returned, and 'str' contains the read
* characters.
*
* On error, the appropriate negative error number is returned, and in this
* case, the characters in 'str' shouldn't be used. The error conditions
* are described below.
*
* Error conditions:
*
* If 'str' is NULL, then it is an error, and nothing is read from stdin,
* and a negative error number is returned.
*
* If 'size' is less than 1 or greater than
* 'SFUL_MAX_INPUT_SIZE_ALLOWED_FROM_STDIN', then it is an error, and
* nothing is read from stdin, and a negative error number is returned.
*
* If the user inputs more than 'size - 1' characters, then this function
* treats this as an error, and then it memsets all the characters it
* stored in 'str' to 0, and then it returns the negative error number
* 'SFUL_USER_GAVE_MORE_INPUT_THAN_ASKED_FOR'.
*/
int sful_get_input_from_stdin_and_clear_stdin(char *str, int size,
int clear_stdin);
/*
* sful_clear_stdin():
*
* Description:
*
* Function sful_clear_stdin() reads and discards all characters from
* stdin. When this function returns then stdin is empty, it doesn't
* contain any characters.
*
* This function is not thread-safe because it makes stdin non-blocking
* for some time.
*
* Return value:
*
* This function doesn't return anything.
*/
void sful_clear_stdin(void);
/*
* sful_wait_for_user_to_press_enter():
*
* Description:
*
* Function sful_wait_for_user_to_press_enter() blocks until the user
* presses the "ENTER" key. After the user has pressed the "ENTER" key,
* this function clears stdin (by calling sful_clear_stdin()), and then
* this function returns.
*
* Return value:
*
* This function doesn't return anything.
*/
void sful_wait_for_user_to_press_enter(void);
/*
* sful_get_integer_from_user_within_range_inclusive():
*
* Description:
*
* Function sful_get_integer_from_user_within_range_inclusive() prints the
* message given in the argument 'msg_for_user' and waits for an input from
* the user. If the input is an integer within the range 'min' - 'max'
* (both 'min' and 'max' inclusive) then this function returns the inputted
* integer else it prints the message again and waits for the user input
* again and this goes on in an endless cycle until the user inputs an
* integer within 'min' - 'max' range (both 'min' and 'max' inclusive) or
* if an error happens.
*
* Return values:
*
* On success, '*error_num_ptr' is set to 'SFUL_SUCCESS' and an integer is
* returned which is in the range 'min' - 'max' (both 'min' and 'max'
* inclusive).
*
* On error, '*error_num_ptr' is set to the appropriate negative error
* number and, in this case, the value returned by this function shouldn't
* be used.
*/
int sful_get_integer_from_user_within_range_inclusive(const char *msg_for_user,
int min, int max, int *error_num_ptr);
/*
* sful_get_y_or_n_from_user():
*
* Description:
*
* Function sful_get_y_or_n_from_user() prints the message given in the
* argument 'msg_for_user' and waits for an input from the user. If the
* input is either 'y' or 'n' (without quotes) ('y' means yes and 'n' means
* no), then this function returns the inputted value else it prints the
* message again and waits for the user input again and this goes on in an
* endless cycle until the user inputs either 'y' or 'n' (without quotes)
* or an error happens.
*
* Return values:
*
* On success, '*error_num_ptr' is set to 'SFUL_SUCCESS' and the user input
* ('y' or 'n' (without quotes)) is returned.
*
* On error, '*error_num_ptr' is set to the appropriate negative error
* number and, in this case, the value returned by this function shouldn't
* be used.
*/
char sful_get_y_or_n_from_user(const char *msg_for_user, int *error_num_ptr);
/*
* sful_is_str_allowed_integer():
*
* For this function (sful_is_str_allowed_integer()), the allowed integer
* is from 'SFUL_INT_MIN' to 'SFUL_INT_MAX'. To understand more about these
* limits, please see the documentation of 'SFUL_INTEGER_STR_SIZE' above.
*
* This function expects only numeric characters in 'str' and optionally a
* leading '+' or '-' character.
*
* This function returns 'SFUL_SUCCESS' only when all of the following
* conditions are met:
*
* ** 'str' is not null.
* ** The first character of 'str' is not the null terminating
* character (means 'str' is not an empty string).
* ** Length of 'str' is less than 'SFUL_INTEGER_STR_SIZE'.
* ** 'str' contains only numeric characters and optionally a
* leading '+' or '-' character.
*
* If all of the above conditions are not met, then this function returns
* an appropriate negative error number.
*/
int sful_is_str_allowed_integer(const char *str);
#endif
-----------------------------------
compile_stdin_functions_library.sh
-----------------------------------
#!/bin/bash
set -x
rm -f stdin_functions_library.o
gcc -c -Wall -Werror -Wextra -Wundef -Wunreachable-code -Winit-self
-Wparentheses -Wconversion -Wsign-conversion -Wsign-compare
-Werror-implicit-function-declaration -Wmissing-prototypes
-Wmissing-declarations -Wno-unused-parameter -Wformat-security
stdin_functions_library.c
----
Powered by blists - more mailing lists