adamkdean

software engineering

Excel Formula - Nice Currency!

By Adam K Dean on

I hate it in Excel when my currency has to be either spaced out nicely OR red when negative. There is the currency, which has nice colours, for negatives, which is good. But then the accounting format has nice spacing, with the pound sign on the left.

Well, now I can have both!

_-£* #,##0.00;[Red]-£* #,##0.00

Woop!

Example

New String.Format for C - strrep2

By Adam K Dean on

Following on from the problems I had with my previous string.format C function, I decided to rewrite it today under heavy valgrind observation.

So I re-wrote it and now get the all clear from valgrind:

==25693== HEAP SUMMARY: ==25693== in use at exit: 0 bytes in 0 blocks ==25693== total heap usage: 43 allocs, 43 frees, 161 bytes allocated ==25693== ==25693== All heap blocks were freed -- no leaks are possible

/*
 * File:   strrep2.c
 * Author: Adam K Dean
 * Description: string replacement (replication of string.replace for C)
 *
 * Original created on 11 January 2011, 10:01
 * This version (2) created on 14 January 2011, 9:36
 */

// usage
int main()
{
    char str[] = "ab{0}def{1}hi{2}";
    char *rep = strrep2(str, 3, "c", "g", "j");

    printf("%s\n", rep);

    free(rep);

    return (EXIT_SUCCESS);
}

char *strrep2(char *format, int argc, char *argv, ...)
{
    char *args[argc];
    char *tmp_left, *tmp_right, *arg, *fstr;
    char *start, *end, *param;
    int l_len, r_len, f_sz, argn;

    va_list marker;
    va_start(marker, *argv);
    for(int i = 0; i < argc; i++)
    {
        args[i] = (char *)calloc(strlen(argv) + 1, sizeof(char));
        strcpy(args[i], argv);
        argv = va_arg(marker, char *);
    }
    va_end(marker);

    fstr = (char *)calloc(strlen(format) + 1, sizeof(char));
    strcpy(fstr, format);

    for(int c = 1; c < strlen(fstr) - 1; c++)
    {
        start = (char *)calloc(2, sizeof(char));
        param = (char *)calloc(2, sizeof(char));
        end = (char *)calloc(2, sizeof(char));
        strncpy(start, &fstr[c-1], 1);
        strncpy(param, &fstr[c], 1);
        strncpy(end, &fstr[c+1], 1);

        if (start[0] == '{' && end[0] == '}' && isdigit(param[0]))
        {
            argn = atoi(&param[0]);
            if (argn < 0 || argn >= argc) continue;

            arg = args[argn];

            l_len = c - 1;
            r_len = (strlen(fstr) - 3) - l_len;

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

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

            f_sz = l_len + r_len + strlen(arg);

            fstr = (char *)realloc(fstr, (f_sz + 1) * sizeof(char));

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

            free(tmp_left);
            free(tmp_right);
        }

        free(start);
        free(param);
        free(end);
    }

    // free args
    for(int i = 0; i < argc; i++) free(args[i]);

    return fstr;
}

MySql Version "Correlated Sub-Queries and Group By Unions"

By Adam K Dean on

If you look at this SQL article [old link removed], you may either be impressed or insult me for bad coding practise. FYI, it does run on 1000 rows in < 1 second. When I was using MsSql (before I migrated to CentOS/Mono/MySql) I sometimes had to go to extortionate amounts of effort to get stuff done, but with MySql it all seems, a bit too easy.. So from the giant SQL that you saw in the previous article, I can do all that on the same tables (bar one change) with the following SQL:

SELECT t_Hosts.Id AS Id, t_Records.Id AS RecordId, Hostname, 

Frequency, PingStatus, PingLatency, HttpStatusCode, 

HttpOnlineStatus, HttpLatency, CheckDate

FROM t_Hosts 

LEFT JOIN t_Records ON t_Hosts.Id = t_Records.HostId

WHERE t_Records.CheckDate IS NULL

OR t_Records.CheckDate < DATE_SUB(NOW(), INTERVAL t_Hosts.Frequency MINUTE);

This happens to have caused more trouble than it's worth, so it's back to a datetime now.

Also, make sure that you add an alias for the second Id or it may overwrite the first tables Id!

Edit: It would seem this doesn't work, and is actually flawed. My old logic (@mcfly version) is actually the way to go, not streakys stupid left join crap!

Below is the MySQL Version.

SELECT t_Hosts.Id AS Id, MAX(Hostname) AS Hostname, MAX(Frequency) AS Frequency
FROM t_Hosts
LEFT JOIN t_Records
ON t_Hosts.Id = t_Records.HostId 
GROUP BY t_Hosts.Id
HAVING MAX(CheckDate) <= DATE_SUB(NOW(), INTERVAL MAX(Frequency) MINUTE)
UNION
SELECT Id, Hostname, Frequency
FROM t_Hosts
WHERE (
   Id NOT IN (
      SELECT HostId
      FROM t_Records
      WHERE (HostId IS NOT NULL)
   )
)

Uri to Hostname in C (GNU-C99)

By Adam K Dean on

Another C function which works quite well and has no bugs that I know of yet...

Updated: fixed this now, leak free!

/*
 * File:   utohn.c
 * Author: Adam K Dean
 * Description: gets a hostname from an uri
 *
 * Created on 11 January 2011, 22:12
 */

/* int utohn(char *uri, char *hostname)
 * Uri to Hostname
 * Author: Adam K Dean
 */
char *utohn(char *uri)
{
    char *pch, *hostname;
    if ((pch = strstr(uri, "://")) != NULL)
    {
        pch += 3;
        int i = 0;
        while(pch[i] != '/' && pch[i] != ':' && pch[i] != '\0') i++;
        hostname = (char *)calloc(i + 1, sizeof(char));
        return strncpy(hostname, pch, i);
    }
    else return NULL;
}

and usage code:

int main(int argc, char** argv)
{
    char hn1[] = "http://www.gentoo.org/";
    char hn2[] = "http://www.gentoo.org/docs/";
    char hn3[] = "http://www.gentoo.org:80/";
    char hn4[] = "127.0.0.1";

    printf("%s -> %s\n", hn1, utohn(hn1));
    printf("%s -> %s\n", hn2, utohn(hn2));
    printf("%s -> %s\n", hn3, utohn(hn3));
    printf("%s -> %s\n", hn4, utohn(hn4));

    return (EXIT_SUCCESS);
}

and results:

http://www.gentoo.org/ -> www.gentoo.org http://www.gentoo.org/docs/ -> www.gentoo.org http://www.gentoo.org:80/ -> www.gentoo.org 127.0.0.1 -> (null)

P.S, I have no affiliation with gentoo, and actually use centos.. I just like how easy it is to type gentoo..very nice!

Enjoy

Fixed String.Format in C (GNU-C99)

By Adam K Dean on

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);
}