2
\$\begingroup\$

Here is a code file (I use it as a stand alone header file to be included in my projects) that contains macros to generate ANSI encoded strings that when printed are colorized. Also, the module contains useful string functions that are found in PHP standard library: strpos, stripos and substring functions: substr, subnstr.

I would like this module to be reviewed for glitches because I was unable to find any but as soon as I think that someone will hopefully find one so I can fix it!

#ifndef __JP__STRINGS_
#define __JP__STRINGS_


/* AUTHOR JACOB PSIMOS 2016 */
/* [email protected] */

#include <sys/types.h>
#include <ctype.h>
#include <string.h>


/* 
    Colorize String Macros
    Use like this:

    char buffer[26]; //Note at least +11 extra buffer size to store ANSI color code
    GREEN("hello world!", buffer, 26);

    printf("%s\n", buffer);
*/
#define RED(s,b,bs) snprintf(b,bs,"\33[0;31m%s\33[0m",s)
#define GREEN(s,b,bs) snprintf(b,bs,"\33[0;32m%s\33[0m",s)
#define YELLOW(s,b,bs) snprintf(b,bs,"\33[0;33m%s\33[0m",s)
#define BLUE(s,b,bs) snprintf(b,bs,"\33[0;34m%s\33[0m",s)
#define MAGENTA(s,b,bs) snprintf(b,bs,"\33[0;35m%s\33[0m",s)
#define CYAN(s,b,bs) snprintf(b,bs,"\33[0;36m%s\33[0m",s)
#define LIGHT_RED(s,b,bs) snprintf(b,bs,"\33[1;31m%s\33[0m",s)
#define LIGHT_GREEN(s,b,bs) snprintf(b,bs,"\33[1;32m%s\33[0m",s)
#define LIGHT_YELLOW(s,b,bs) snprintf(b,bs,"\33[1;33m%s\33[0m",s)
#define LIGHT_BLUE(s,b,bs) snprintf(b,bs,"\33[1;34m%s\33[0m",s)
#define LIGHT_MAGENTA(s,b,bs) snprintf(b,bs,"\33[1;35m%s\33[0m",s)
#define LIGHT_CYAN(s,b,bs) snprintf(b,bs,"\33[1;36m%s\33[0m",s)

/*  subnstr - substring
*   Fills char *out with a substring from char *str starting at 'start' for 'count' chars
*   Returns the length of the substring
*   bufsize = maximum size of *out buffer
*/
const size_t subnstr(const char *str, char *out, const size_t bufsize, const size_t start, const size_t count){
    if(bufsize < 1 || out == NULL || str == NULL){
        return -1;
    }

    const size_t len = strlen(str);
    size_t i;
    size_t pos = 0;
    for(i = start; pos < count && i < len && pos < bufsize - 1; i++){
            out[pos] = str[i];
            pos++;
    }
    out[pos] = '\0';
    return (size_t)pos;
}

/*  substr - substring
*   Fills char *out with a substring from char *str starting at size_t start until the end of char *str
*   Returns the length of the substring
*   bufsize = maximum size of *out buffer
*/
const size_t substr(const char *str, char *out, const size_t bufsize, const size_t start){
        if(str == NULL || out == NULL || bufsize < 1) {
            return -1;
        }

        const size_t len = strlen(str);
        size_t i;
        size_t pos = 0;
        for(i = start; i < len && pos < bufsize - 1; i++){
                out[pos] = str[i];
                pos++;
        }
        out[pos] = '\0';
        return (size_t)pos;
}

/*  strpos - string position
*   Returns the position of 'needle' within 'haystack' starting at 'skip' or returns -1 if non existant
*   or buffer position does not fall within 'bufsize' bounds
*/
const size_t strpos(const char *needle, const char *haystack, const size_t bufsize, const size_t skip){
    if(skip <= bufsize - strlen(needle)){
        const char *ptr = strstr(haystack + skip, needle);
        const size_t pos = ptr != NULL ? (size_t)((unsigned long)ptr - (unsigned long)haystack) : -1;
        return (size_t)(pos > bufsize || pos < (unsigned long)haystack ? -1 : pos);
    }
return -1;
}

/*  stripos - case insensitive string position
*   Returns the position of 'needle' within 'haystack' starting at 'skip' or returns -1 if non existant
*   or buffer position does not fall within 'bufsize' bounds
*   bufsize - maximum size of haystack buffer (prevent out of bounds)
*/
const size_t stripos(const char *needle, const char *haystack, const size_t bufsize, const size_t skip){
    if(skip <= bufsize - strlen(needle)){
        const char *ptr = (const char*)strcasestr(haystack + skip, needle);
        const size_t pos = ptr != NULL ? (size_t)((unsigned long)ptr - (unsigned long)haystack) : -1;
        return (size_t)(pos > bufsize || pos < (unsigned long)haystack ? -1 : pos);
    }
    return -1;
}

const short strequals(const char *str1, const char *str2){
    int l1 = strlen(str1);
    int l2 = strlen(str2);

    if(l1 != l2){ return 0; }
    int i;
    for(i = 0; i < l1; i++){
        if(str1[i] != str2[i]){
            return 0;
        }
    }
    return 1;
}
#endif
\$\endgroup\$
1
  • \$\begingroup\$ Hi, I removed some of the tags that didn't seem relevant enough. If you feel this code is specific to Linux, edit your question to explain why and add in the tag again. Hope you don't mind :) \$\endgroup\$
    – jacwah
    Apr 4, 2016 at 13:44

1 Answer 1

2
\$\begingroup\$

Function Types

Since you say that this is in a header file, you will want to type your functions as static to avoid linker errors when used in multiple objects. They can also be const although that distinction is meaningless as the value is returned rather than the reference.

Excess Logic

You are including the <string.h> library and many of your functions are subsets of included functionality. I'd recommend replacing the excess logic with the C Library functions. For example, strequals() is the same as the standard strcmp() function and inverting the logic (while removing the pos/neg distinction). Thus you could write:

static short strequals(const char *str1, const char *str2){
    return !strcmp(str1, str2);
}

Signed/Unsigned mix

You use size_t as the return type in functions returning -1. This will return SIZE_T_MAX. In functions where you are length, you definitely don't want a large number returned for the invalid marker. You could use ssize_t instead to avoid this.

Color Macros

Hiding the snprintf here doesn't make sense because you are only allowing static strings in s. Better would be to define the macros using string concatenation:

#define COLOR_RED(s) "\x1b[31m" s "\x1b[0m"

Then you can use COLOR_RED() directly in both function calls and definitions.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.