Updated previously posted string struct and utility functions
Previous link: User-friendly string struct and utility functions
What is updated ?
- typedef of sstring is a major update. previously, users had to do sstring var; and then var._str = value, But now, users can do sstring var = "Value";
- Buffer overflows have been fixed
- major bugs and features have been improved and fixed
- All functions now have error checking methods
- conversion from c-style array strings to sstrings and vice-versa is now easily possible through sstr2cstr() and cstr2sstr() functions!
- conversion from string to number [double/float/int] type is easily possible. It has some unique things such as it can tell if the string is a number, if an error has occured and returns the actual number!
- Sstrinputpass() introduces new type of password input method!
- All functions have slight improvements
Any suggestions, bug-report or feedbacks are Happily Welcomed!
- Files -
sstring.h
#ifndef SSTRING_H_DEFINED
//stdbool for sstrnum typedef
#include<stdbool.h>
#define SSTRING_H_DEFINED
//define the maximum char limit here
#define GLOBAL_MAX_CHAR_LIMIT 400
#define NO_ERR -1
#define GMCL_CORRUPT -10
#define INVALID_ARGS -11
#define GMCL_ERR -12
typedef struct{
double _num;
bool is_num;
int _err;
}sstrnum;
typedef char * sstring;
typedef struct{
char _str[GLOBAL_MAX_CHAR_LIMIT];
int _err;
}sstrfunc;
typedef struct{
char _char;
int _err;
}charfunc;
typedef sstrfunc sstrfuncerr;
void nullify(char * _Buff,int _count);
sstrnum sstr2num(sstring _str);
sstrfunc cstr2sstr(char * _Buff);
int sstr2cstr(sstring _sstr,char * _Cstr,size_t _upto);
sstrfunc sstrappend(sstring _var1,sstring _var2);
sstrfunc sstrinput();
ssize_t sstrfind(size_t init,sstring _str,sstring _find);
size_t sstrlen(sstring _str);
sstrfunc ssetchar(sstring _str,ssize_t _pos,char _ch);
sstrfunc ssubstr(sstring _str,int _pos,size_t _len);
charfunc sgetchar(sstring _str,ssize_t _pos);
sstrfunc sstrinputpass(sstring show);
void showerrs();
#endif
sstring.c
#include<stdio.h>
#include<string.h>
#include "sstring.h"
#include<stdbool.h>
#include<conio.h>
#include<stdlib.h>
#include<math.h>
/*
A Big Note To the ones saying dont return Local Variable Adresses
Below functions dont return any local variable addresses
to prove it, call the functions MULTIPLE times -> you will see yourself
They return a typedef of strfunc which contains the string in array format
when the user does [functionname]([parameters])._str; the str array value is sent to the pointer
so no issue will be created! :D
*/
size_t sstrlen(sstring _str){
//just as support for sstrings
// all functions included are better!
return strlen(_str);
}
bool isGMCLCorrupt(){
//checks if global max char limit is corrupted
if(GLOBAL_MAX_CHAR_LIMIT<=0){
return true;
}else{
return false;
}
}
sstrfunc cstr2sstr(char * _Buff){
sstrfunc _null;
nullify(_null._str,GLOBAL_MAX_CHAR_LIMIT);
_null._err = NO_ERR;
if(isGMCLCorrupt()){
_null._err = GMCL_CORRUPT;
return _null;
}
if(strlen(_Buff)>=GLOBAL_MAX_CHAR_LIMIT){
_null._err = GMCL_ERR;
return _null;
}
//blank string
if(strlen(_Buff)==0){
return _null;
}
sstrfunc _ret;
strncpy(_ret._str,_Buff,strlen(_Buff));
_ret._err = NO_ERR;
return _ret;
}
int sstr2cstr(sstring _sstr,char * _Cstr,size_t _upto){
//first null out the _Cstr upto given length
nullify(_Cstr,_upto);
if(isGMCLCorrupt()){
return GMCL_CORRUPT;
}
if(sstrlen(_sstr)>=GLOBAL_MAX_CHAR_LIMIT){
return GMCL_ERR;
}
//blank string
if(sstrlen(_sstr)==0){
return NO_ERR;
}
strncpy(_Cstr,_sstr,_upto);
return NO_ERR;
}
sstrnum sstr2num(sstring _str){
char cchar;
int minus = 1;
int plus=0;
sstrnum _return;
int pointplace=0;
_return._err = NO_ERR;
_return.is_num = true;
if(isGMCLCorrupt()){
_return._err = GMCL_CORRUPT;
_return._num = 0;
_return.is_num = false;
return _return;
}else if(sstrlen(_str)>=GLOBAL_MAX_CHAR_LIMIT){
_return._err = GMCL_ERR;
_return._num = 0;
_return.is_num = false;
return _return;
}
for(int i=0;i<sstrlen(_str);i++){
cchar = _str[i];
//if non integer found
if(cchar<'0'||cchar>'9'){
if(cchar=='-'&&i==0){
minus = -1;
}else if(cchar=='-'&&i>0){
_return._num = 0;
_return.is_num = false;
_return._err = NO_ERR;
return _return;
}else if(cchar=='.'&&pointplace==0){
pointplace+=1;
}else if(cchar=='.'&&!(pointplace==0)){
_return._num = 0;
_return.is_num = false;
_return._err = NO_ERR;
return _return;
}else if(cchar=='+'&&plus==0){
plus=1;
}else if(cchar=='+'&&plus==1){
_return._num = 0;
_return.is_num = false;
_return._err = NO_ERR;
return _return;
}else{
_return._num = 0;
_return.is_num = false;
_return._err = NO_ERR;
return _return;
}
}else{
if(i==0){
_return._num =cchar-'0';
}else{
if(pointplace){
_return._num+= (cchar-'0')/pow(10,pointplace);
pointplace+=1;
}else{
_return._num*=10;
_return._num+= (cchar-'0');
}
}
}
}
_return._num*=minus;
return _return;
}
sstrfunc ssubstr(sstring _str,int _pos,size_t _len){
//dont store anything make null return value
sstrfunc _null;
//is global max char limit corrupted??
//returning null means error was caught!
if(isGMCLCorrupt()){
//gmcl is corrupt! errcode: #defined in sstring.h
_null._err = GMCL_CORRUPT;
return _null;
}
if(_pos<0){
_null._err = INVALID_ARGS;
return _null;
}
if(sstrlen(_str)>=GLOBAL_MAX_CHAR_LIMIT||_pos>=GLOBAL_MAX_CHAR_LIMIT||_len>=GLOBAL_MAX_CHAR_LIMIT){
_null._err = GMCL_ERR;
return _null;
}
if(_pos>=sstrlen(_str)||_pos<0||_len>=sstrlen(_str)||_len<0){
_null._err = INVALID_ARGS;
return _null;
}
sstrfunc _ret;
_ret._err = NO_ERR;
strncpy(_ret._str,_str+_pos,_len);
_ret._str[_len] = '\0';
return _ret;
}
sstrfunc sstrappend(sstring _var1,sstring _var2){
//dont store anything make null return value
sstrfunc _null;
//is global max char limit corrupted??
//returning null means error was caught!
if(isGMCLCorrupt()){
//gmcl is corrupt! errcode: #defined in sstring.h
_null._err = GMCL_CORRUPT;
return _null;
}
if(sstrlen(_var1)+sstrlen(_var2)>=GLOBAL_MAX_CHAR_LIMIT){
_null._err = GMCL_ERR;
return _null;
}
//use of string.h functions -> far easier than my previous headscratching!
char _ret1[sstrlen(_var1)+sstrlen(_var2)];
strcpy(_ret1,_var1);
strcat(_ret1,_var2);
sstrfunc _ret;
//no errors :D
_ret._err = NO_ERR;
strcpy(_ret._str,_ret1);
return _ret;
}
void nullify(char * _Buff,int _count){
if(isGMCLCorrupt()){
exit(GMCL_CORRUPT);
}else if(_count>GLOBAL_MAX_CHAR_LIMIT+1){
exit(GMCL_ERR);
}else{
for(int i=0;i<_count+1;i++){
_Buff[i] = '\0';
}
}
}
sstrfunc sstrinput(){
//dont store anything make null return value
sstrfunc _null;
//is global max char limit corrupted??
//returning null means error was caught!
if(isGMCLCorrupt()){
_null._err = GMCL_CORRUPT;
return _null;
}
char _tmp[GLOBAL_MAX_CHAR_LIMIT];
//fgets for safety :)
fgets(_tmp,GLOBAL_MAX_CHAR_LIMIT,stdin);
sstrfunc _ret;
//ret._str is array upto GLOBAL_MAX_CHAR_LIMIT
//also tmp is array upto GLOBAL_MAX_CHAR_LIMIT
//so its safe :) to use strcpy same as strncpy
strcpy(_ret._str,_tmp);
//'\n' avoided
_ret._str[strlen(_tmp)-1] = '\0';
_ret._err = NO_ERR;
return _ret;
}
sstrfunc sstrinputpass(sstring show){
//dont store anything make null return value
sstrfunc _null;
//is global max char limit corrupted??
//returning null means error was caught!
if(isGMCLCorrupt()){
_null._err = GMCL_CORRUPT;
return _null;
}
char _tmp[GLOBAL_MAX_CHAR_LIMIT];
//nullify string [if i dont use this WiErD things happen]
nullify(_tmp,GLOBAL_MAX_CHAR_LIMIT+1);
char tmpchar;
int done=0;
//until a certain char has not been pressed
while(1>0){
//take chars only upto global max char limit
if(done>=GLOBAL_MAX_CHAR_LIMIT-1){
break;
}
tmpchar = getch();
if(tmpchar=='\r'){
break;
}else if(tmpchar=='\b'){
if(strlen(_tmp)>0){
_tmp[strlen(_tmp)-1] = '\0';
for(int i=0;i<sstrlen(show);i++){
printf("\b");
}
for(int i=0;i<sstrlen(show);i++){
printf(" ");
}
for(int i=0;i<sstrlen(show);i++){
printf("\b");
}
}
}else{
_tmp[strlen(_tmp)]=tmpchar;
printf(show);
done+=1;}
}
//print newline buffer
printf("\n");
sstrfunc _ret;
//ret._str is array upto GLOBAL_MAX_CHAR_LIMIT
//also tmp is array upto GLOBAL_MAX_CHAR_LIMIT
//so its safe :) to use strcpy same as strncpy
strcpy(_ret._str,_tmp);
//no errors
_ret._err = NO_ERR;
return _ret;
}
sstrfunc ssetchar(sstring _str,ssize_t _pos,char _ch){
sstrfunc _null;
//is global max char limit corrupted??
//returning null means error was caught!
if(isGMCLCorrupt()){
_null._err = GMCL_CORRUPT;
return _null;
}
sstrfunc _ret;
if(sstrlen(_str)>=GLOBAL_MAX_CHAR_LIMIT){
_null._err = GMCL_ERR;
return _null;
}
if(_pos>=sstrlen(_str)||_pos<0){
_null._err = INVALID_ARGS;
return _null;
}
strcpy(_ret._str,_str);
_ret._str[_pos] = _ch;
_ret._err = NO_ERR;
return _ret;
}
void showerrs(){
printf("\n---- ERRORS Corresponding to their codes ----\n");
printf("%d :- GMCL [global max char limit] is corrupted\n",GMCL_CORRUPT);
printf("%d :- INVALID ARGS [the provided arguments are invalid]\n",INVALID_ARGS);
printf("%d :- GMCL_ERR [provided variable has length greater than GMCL]\n",GMCL_ERR);
printf("Other :- Unknown Error - Not Known Errors \n");
printf("---------------------------------------------\n");
}
charfunc sgetchar(sstring _str,ssize_t _pos){
charfunc _null;
//is global max char limit corrupted??
if(isGMCLCorrupt()){
_null._err = GMCL_CORRUPT;
return _null;
}
// condition checking which are likely make error after
if(sstrlen(_str)>=GLOBAL_MAX_CHAR_LIMIT){
_null._err = GMCL_ERR;
return _null;
}
if(_pos>=sstrlen(_str)||_pos<0||sstrlen(_str)<0){
_null._err = INVALID_ARGS;
return _null;
}
charfunc chr;
chr._char = _str[_pos];
chr._err = NO_ERR;
return chr;
}
//if the length of string is in size_t
//and charachters in it can also be beyond int who knows!
//used ssize_t to support returning negative numbers, i.e -> -1 and errors
//init is the place to start finding
ssize_t sstrfind(size_t init,sstring _str,sstring _find){
size_t _len1 = sstrlen(_str);
size_t _len2 = sstrlen(_find);
size_t matching = 0;
//is global max char limit corrupted??
if(isGMCLCorrupt()){
return GMCL_CORRUPT;
}
if(sstrlen(_str)>=GLOBAL_MAX_CHAR_LIMIT||sstrlen(_find)>=GLOBAL_MAX_CHAR_LIMIT){
return GMCL_ERR;
}
//some weird conditions check [user, are u fooling the function ?]
if(_len2>_len1||init<0||init>_len1-1){
return INVALID_ARGS;
}
//security check
if(_len1>=GLOBAL_MAX_CHAR_LIMIT||_len2>=GLOBAL_MAX_CHAR_LIMIT){
return GMCL_ERR;
}
if(_len1==0||_len2==0){
//obviously it wont be found if the string itself is null or the tobefound string is null
return -1;
}
//the main finder -by myself
for(size_t i=init;i<_len1+1;i++){
if(_str[i]==_find[0]){
for(int z=0;z<_len2+1;z++){
if(matching==_len2){
return i;
}
else if(_str[i+z]==_find[z]){
matching+=1;
}
else{
matching=0;
break;
}
}
}
}
return -1;
}
example-usage.c
#include<stdio.h>
#include "sstring.h"
#include<string.h>
#include<stdbool.h>
#include<stdlib.h>
/*
Example usage of sstring.h functions
initially we dont need to include stdlib.h or string.h
But are included for c-style arr conversion showcase & for exit() functions inside here
*/
//User can handle errors in their **Own** Way
void ErrCheck(sstrfuncerr _str){
if(_str._err!=NO_ERR){
printf("\n--- Error %d ---",_str._err);
showerrs();
//terminate the program upon error
//again user can do anything like return value and etc.
exit(_str._err);
}
}
void ErrCodeCheck(int _code){
if(_code<NO_ERR){
printf("\n--- Error %d ---",_code);
showerrs();
//terminate the program upon error
//again user can do anything like return value and etc.
exit(_code);
}
}
void GenerateErr(int _code){
if(_code!=NO_ERR){
printf("\n--- Error %d ---",_code);
showerrs();
exit(_code);
}
}
int main(){
//---------------- Simplicity Showcase -------------------
sstring a;
a = "This is a sample string!";
printf("Sample: %s \n\n",a);
// ----------------- Functions ShowCase -------------------
//all functions of sstring have error checking methods!
//create an error checking variable
sstrfuncerr var;
// -=-=- Sstrinput() -=-=-
// No other scanf() or gets() support sstring so, specially sstrinput() for sstrings!
printf("Sstrinput: ");
var = sstrinput();
//errcheck
ErrCheck(var);
a = var._str;
//-=-=- Sstrlen() -=-=-
// strlen() from string.h also can do this but added as a support for sstrings!
printf("Length of a: %d\n\n",sstrlen(a)); // Or printf("Length of a: %d\n\n",strlen(a)); <- from string.h same thing!
//-=-=- Sstrfind() -=-=-
//lets find space
int check;
check = sstrfind(0,a," ");
//errcheck
//default err check
ErrCodeCheck(check);
//unknown err check
if(check>sstrlen(a)&&check!=-1){
GenerateErr(check);
}
if(check==-1){
printf("Space not found!\n");
}else{
printf("Space found at %d charachter!\n",check);
}
//-=-=- Ssubstr() -=-=-
var = ssubstr(a,0,sstrlen(a)-2);
//errcheck
ErrCheck(var);
a = var._str;
printf("Without having last two chars : %s\n",a);
//Inputting passwords so easy!
printf("\nEnter Password: ");
var = sstrinputpass("*");
//errcheck
ErrCheck(var);
a = var._str;
printf("Shh! Your password is : \"%s\"\n",a);
//Converting to number
printf("\nEnter a num: ");
var = sstrinput();
//errcheck
ErrCheck(var);
a = var._str;
double num;
sstrnum ret_num;
//main conversion works on float, double or int values all negative or positive or '+' in front!
//also can tell if the given string is number or not
//also has error checking support!
ret_num = sstr2num(a);
//error check
if(ret_num._err!=NO_ERR){
GenerateErr(ret_num._err);
//if not a number
}else if(ret_num.is_num==false){
printf("You didnt enter a number!");
//if a number
}else if(ret_num.is_num==true){
num = ret_num._num;
printf("You entered: %f\n",num);
}
//-=-=- Conversion from array type to sstring and vice-versa -=-=-
char arr_type_str[GLOBAL_MAX_CHAR_LIMIT];
sstring sstr_type_str;
int _errcheck;
//first sstring to arr type strings
//fill up sstring
sstr_type_str = "If you see this, Sstr2Arr conversion success done!";
//convert
_errcheck = sstr2cstr(sstr_type_str,arr_type_str,GLOBAL_MAX_CHAR_LIMIT);
//error check
ErrCodeCheck(_errcheck);
//display
printf("\nSstr 2 Arr: %s\n",arr_type_str);
//Now arr type strings to sstrings!
//first lets nullify our string [previously used]
nullify(arr_type_str,sstrlen(arr_type_str));
//fill up array type string
strcpy(arr_type_str,"If you see this, Arr2Sstr conversion success done!");
//errcheck first
ErrCheck(cstr2sstr(arr_type_str));
//convert
sstr_type_str = cstr2sstr(arr_type_str)._str;
//display
printf("Arr 2 Sstr: %s\n",sstr_type_str);
}
_
begins so manystruct
member names? \$\endgroup\$_
is used \$\endgroup\$