Adam K Dean

Fixed String.Format in C (GNU-C99)

Published on 12 January 2011 at 22:00 by Adam

I have fixed my strrep string replace function, for now, as there was a bug with using atoi.

I have also realised I was calling it string.replace - my bad - it's actually string.format I was thinking of, but more of a var for var replacement without the formatting!

I have now finished writing the C# String.Replace replication in C (GNU-C99) and it works great. The following code will allow you to substitute strings (char *s) in a format string like in C#. For example you can input "this {0} a test, {0} it {1}?" along with "is" and "working" to get "this is a test, is it working?".

Update: fixed and now leak free.

/*
 * File:   strrep.c
 * Author: Adam K Dean
 * Description: string replacement (replication of string.replace for C)
 *
 * Created on 11 January 2011, 10:01
 * Fixed on 12 January 2011, 12:44
 */

char *strrep(char *format, int argc, char *arg, ...);
void itoa(int value, char *str, int base);
void strreverse(char *begin, char *end);

int main()
{
    char *ret = strrep("this {0} a test, {0} it {1}?", 2, "is", "working");
    printf("%s\n", ret);

    return 0;
}

/* char *strrep(char *format, int argc, char *arg, ...)
 * String.Replace replication
 * Author: Adam K Dean
 */
char *strrep(char *format, int argc, char *arg, ...)
{
    char *tmp_left, *tmp_right;
    char start, end, param;
    int l_len, r_len, f_sz;

    va_list marker;
    va_start(marker, *arg);

    for(int i = 0; i < argc; i++)
    {
        printf("arg: %s\n", arg);

        for(int c = 1; c < strlen(format) - 1; c++)
        {
            start = format[c-1];
            param = format[c];
            end = format[c+1];

            char *ialpha = (char *)malloc((int_strlen(i) + 1) * sizeof(ialpha));
            itoa(i, ialpha, 10);

            if (start == '{' && end == '}' && isdigit(param) && param == ialpha[0])
            {
                l_len = c - 1;
                r_len = (strlen(format) - 3) - l_len;

                tmp_left = (char *)calloc(l_len + 1, sizeof(char));
                tmp_right = (char *)calloc(r_len + 1, sizeof(char));

                strncpy(tmp_left, format, l_len);
                strncpy(tmp_right, &format[c + 2], r_len);                

                f_sz = l_len + r_len + strlen(arg);

                format = (char *)calloc(f_sz + 1, sizeof(char));

                strcpy(format, tmp_left);
                strcpy(&format[l_len], arg);
                strcpy(&format[l_len + strlen(arg)], tmp_right);

                free(tmp_left);
                free(tmp_right);
            }

            free(ialpha);
        }

        arg = va_arg(marker, char *);
    }

    va_end(marker);
    return format;
}

/* int_strlen(int val)
 * String length of an int
 * Author: Adam K Dean
 */
int int_strlen(int val)
{
    int v = val / 10;
    int i = 1, count = 1;

    while(v > i - 1)
    {
        i *= 10;
        count ++;
    }

    return count;
}

void strreverse(char *begin, char *end)
{
    char aux;
    while(end > begin)
        aux = *end, *end-- = *begin, *begin++ = aux;
}

void itoa(int value, char *str, int base)
{
    static char num[] = "0123456789abcdefghijklmnopqrstuvwxyz";

    char* wstr=str;
    int sign;

    if (base<2 || base>35){ *wstr='\0'; return; }

    if ((sign=value) < 0) value = -value;

    do *wstr++ = num[value % base]; while(value /= base);

    if(sign < 0) *wstr++ = '-';
    *wstr = '\0';

    strreverse(str, wstr - 1);
}


This post was first published on 12 January 2011 at 22:00. It was filed under archive with tags c.