diff options
Diffstat (limited to 'src/routines.c')
-rw-r--r-- | src/routines.c | 800 |
1 files changed, 800 insertions, 0 deletions
diff --git a/src/routines.c b/src/routines.c new file mode 100644 index 0000000..8ce937b --- /dev/null +++ b/src/routines.c @@ -0,0 +1,800 @@ +/* + * routines.c + * + * Random Useful Routines and Functions + * + * (c) 2002-2005 Thomas White <taw27@srcf.ucam.org> + * Part of TuxMessenger - GTK+-based MSN Messenger client + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 dated June, 1991. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <glob.h> +#include <gdk/gdk.h> + +#include "debug.h" + +char *routines_glob(const char *filename) { + + char *full_filename; + glob_t glob_result; + int glob_retval; + + glob_retval = glob(filename, GLOB_TILDE, NULL, &glob_result); + if ( glob_retval != 0 ) { + + debug_print("glob() failed: "); + switch ( glob_retval ) { + case GLOB_NOSPACE : debug_print("GLOB_NOSPACE\n"); break; + case GLOB_ABORTED : debug_print("GLOB_ABORTED\n"); break; + case GLOB_NOMATCH : debug_print("GLOB_NOMATCH\n"); break; + default : debug_print("Unknown!\n"); break; + } + return NULL; + + } + full_filename = malloc(strlen(glob_result.gl_pathv[0])+1); + strcpy(full_filename, glob_result.gl_pathv[0]); + globfree(&glob_result); + + return full_filename; + +} + +/* TCL-style lindex using ' ' as a separator */ +char *routines_lindex(char *string, unsigned int pos) { + + unsigned int i; + unsigned int s=0; + char *minibuffer; + unsigned int max_output_length = strlen(string); + for ( i=0; i<strlen(string); i++ ) { + + if ( string[i] == ' ' ) + s++; + if ( s == pos ) { + + char ch='z'; + unsigned int p=0; + char *result; + result = malloc(2+max_output_length); + if ( s == 0 ) + i--; + while ((ch != '\0') && (p<max_output_length)) { + + ch = string[i+p+1]; + if ( ch == ' ' ) + ch = '\0'; + if ( ch == '\r' ) + ch = '\0'; + if ( ch == '\n' ) + ch = '\0'; + result[p]=ch; + p++; + + } + result[p]='\0'; + + /* now copy the string into a buffer that's the right size */ + minibuffer=malloc(strlen(result)+sizeof(char)); + strcpy(minibuffer, result); + free(result); + return minibuffer; + + } + + } + /* whoopsie didn't find it */ + minibuffer = malloc(1); + minibuffer[0]='\0'; + return minibuffer; /* return something that can safely be freed */ + +} + +/* same as above, but returns all of the rest of the string, without stopping at the next space*/ +char *routines_lindexend(char *string, unsigned int pos) { + + unsigned int i; + unsigned int s=0; + char *minibuffer; + unsigned int max_output_length = strlen(string); + + for ( i=0; i<strlen(string); i++ ) { + if ( string[i] == ' ' ) + s++; + if ( s == pos ) { + char ch='z'; + unsigned int p=0; + char *result; + result = malloc(2+max_output_length); + if ( s == 0 ) + i--; + while ((ch != '\0') && (p<max_output_length)) { + ch = string[i+p+1]; + if ( ch == '\n' ) + ch = '\0'; + if ( ch == '\r' ) + ch = '\0'; + result[p]=ch; + p++; + } + result[p]='\0'; + + /* now copy the string into a buffer that's the right size */ + minibuffer=malloc(strlen(result)+sizeof(char)); + strcpy(minibuffer, result); + free(result); + return minibuffer; + } + } + /* whoopsie didn't find it */ + minibuffer = malloc(1); + minibuffer[0]='\0'; + return minibuffer; /* return something that can still be freed */ + +} + +/* Convert a single hex digit char to an int */ +static unsigned int routines_unhex(char ch) { + + switch (ch) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': return 10; + case 'b': return 11; + case 'c': return 12; + case 'd': return 13; + case 'e': return 14; + case 'f': return 15; + case 'A': return 10; + case 'B': return 11; + case 'C': return 12; + case 'D': return 13; + case 'E': return 14; + case 'F': return 15; /* yes I know i could have done it differently... */ + } + + return 0; /* clearly this would be the caller's fault... */ + +} + +char *routines_urldecode(const char *words) { + + char *result; + char first_char=' ', second_char=' '; + unsigned int i, s=0, j=0; + + result = malloc(strlen(words)+1); + for ( i=0; i<=strlen(words); i++ ) { + + char ch; + ch=words[i]; + + if ( isxdigit(ch) && (s==2) ) { + + unsigned int new_ch = 0; + unsigned int first_num, second_num; + j-=2; + second_char=ch; + + /* now we take our two hex digits and decimalize... */ + first_num = routines_unhex(first_char); + second_num = routines_unhex(second_char); + new_ch = (char) second_num + (16 * first_num); + if ( new_ch == '\0' ) + new_ch = ' '; /* no way... */ + if ( new_ch == '\10' ) + new_ch = ' '; /* f--k off... */ + if ( new_ch == '\13' ) + new_ch = ' '; /* grrr */ + + ch=new_ch; + s=0; + + } + if ( isxdigit(ch) && (s==1) ) { + s=2; + first_char=ch; + } + if (ch=='%') { + s=1; + } + result[j]=ch; + j++; + + } + return result; + +} + +char *routines_urlencode(const char *words) { + + char *result; + unsigned int i, p; + + result = malloc((3*strlen(words))+1); /* this is the maximum possible size it could be */ + p = 0; + for ( i=0; i<strlen(words); i++ ) { + char ch; + ch = words[i]; + if ( ch == ' ' ) { + result[p]='%'; + p++; + result[p]='2'; + p++; + result[p]='0'; + } else if ( ch == '<' ) { + result[p]='%'; + p++; + result[p]='3'; + p++; + result[p]='C'; + } else if( ch == '>' ) { + result[p]='%'; + p++; + result[p]='3'; + p++; + result[p]='E'; + } else if ( ch == '=' ) { + result[p]='%'; + p++; + result[p]='3'; + p++; + result[p]='D'; + } else if ( ch == '@' ) { + result[p]='%'; + p++; + result[p]='4'; + p++; + result[p]='0'; + } else if ( ch == '\"' ) { + result[p]='%'; + p++; + result[p]='2'; + p++; + result[p]='2'; + } else if ( ch == '/' ) { + result[p]='%'; + p++; + result[p]='2'; + p++; + result[p]='F'; + } else if ( ch == '+' ) { + result[p]='%'; + p++; + result[p]='2'; + p++; + result[p]='B'; + } else { + result[p]=ch; + } + p++; + } + result[p]='\0'; + return result; +} + +/* extract hostname from hostname:port style string */ +char *routines_hostname(const char *input) { + + unsigned int i, n=0; + char ch='z'; + char *output; + + /* First we must check that there is actually a colon present */ + for ( i=0; i<strlen(input); i++ ) { + if ( input[i] == ':' ) { + n++; + } + } + /* if there's no colon, host is just the same as the input */ + if ( n == 0 ) + return strdup(input); + + i = 0; + /* A few bytes get wasted here */ + output = malloc(strlen(input)); + while ( ch != '\0' ) { + + ch = input[i]; + if ( ch == ':' ) { + ch = '\0'; + } + output[i] = ch; + i++; + + } + return output; + /* You can free the output string when you've finished with it */ + +} + +/* extract the port number from hostname:port */ +int routines_port(const char *input) { + + char ch='z'; + unsigned int i=0, n=0; + + /* first we must check that there is actually a colon present */ + for ( i=0; i<strlen(input); i++ ) { + if ( input[i] == ':' ) + n++; + } + /* Bail out if no port specified */ + if ( n == 0 ) { + return 0; + } + + i=0; + while ( (ch != ':') && (i<=strlen(input)) ) { + ch = input[i]; + i++; + } + + return atoi(input+i); +} + +static char routines_base64char(unsigned int sextet) { + + switch (sextet) { + + case 0 : return 'A'; + case 1 : return 'B'; + case 2 : return 'C'; + case 3 : return 'D'; + case 4 : return 'E'; + case 5 : return 'F'; + case 6 : return 'G'; + case 7 : return 'H'; + case 8 : return 'I'; + case 9 : return 'J'; + case 10 : return 'K'; + case 11 : return 'L'; + case 12 : return 'M'; + case 13 : return 'N'; + case 14 : return 'O'; + case 15 : return 'P'; + case 16 : return 'Q'; + case 17 : return 'R'; + case 18 : return 'S'; + case 19 : return 'T'; + case 20 : return 'U'; + case 21 : return 'V'; + case 22 : return 'W'; + case 23 : return 'X'; + case 24 : return 'Y'; + case 25 : return 'Z'; + case 26 : return 'a'; + case 27 : return 'b'; + case 28 : return 'c'; + case 29 : return 'd'; + case 30 : return 'e'; + case 31 : return 'f'; + case 32 : return 'g'; + case 33 : return 'h'; + case 34 : return 'i'; + case 35 : return 'j'; + case 36 : return 'k'; + case 37 : return 'l'; + case 38 : return 'm'; + case 39 : return 'n'; + case 40 : return 'o'; + case 41 : return 'p'; + case 42 : return 'q'; + case 43 : return 'r'; + case 44 : return 's'; + case 45 : return 't'; + case 46 : return 'u'; + case 47 : return 'v'; + case 48 : return 'w'; + case 49 : return 'x'; + case 50 : return 'y'; + case 51 : return 'z'; + case 52 : return '0'; + case 53 : return '1'; + case 54 : return '2'; + case 55 : return '3'; + case 56 : return '4'; + case 57 : return '5'; + case 58 : return '6'; + case 59 : return '7'; + case 60 : return '8'; + case 61 : return '9'; + case 62 : return '+'; + case 63 : return '/'; + + } + + return 'A'; + +} + +static int routines_unbase64char(unsigned char sextet) { + + switch (sextet) { + + case 'A' : return 0; + case 'B' : return 1; + case 'C' : return 2; + case 'D' : return 3; + case 'E' : return 4; + case 'F' : return 5; + case 'G' : return 6; + case 'H' : return 7; + case 'I' : return 8; + case 'J' : return 9; + case 'K' : return 10; + case 'L' : return 11; + case 'M' : return 12; + case 'N' : return 13; + case 'O' : return 14; + case 'P' : return 15; + case 'Q' : return 16; + case 'R' : return 17; + case 'S' : return 18; + case 'T' : return 19; + case 'U' : return 20; + case 'V' : return 21; + case 'W' : return 22; + case 'X' : return 23; + case 'Y' : return 24; + case 'Z' : return 25; + case 'a' : return 26; + case 'b' : return 27; + case 'c' : return 28; + case 'd' : return 29; + case 'e' : return 30; + case 'f' : return 31; + case 'g' : return 32; + case 'h' : return 33; + case 'i' : return 34; + case 'j' : return 35; + case 'k' : return 36; + case 'l' : return 37; + case 'm' : return 38; + case 'n' : return 39; + case 'o' : return 40; + case 'p' : return 41; + case 'q' : return 42; + case 'r' : return 43; + case 's' : return 44; + case 't' : return 45; + case 'u' : return 46; + case 'v' : return 47; + case 'w' : return 48; + case 'x' : return 49; + case 'y' : return 50; + case 'z' : return 51; + case '0' : return 52; + case '1' : return 53; + case '2' : return 54; + case '3' : return 55; + case '4' : return 56; + case '5' : return 57; + case '6' : return 58; + case '7' : return 59; + case '8' : return 60; + case '9' : return 61; + case '+' : return 62; + case '/' : return 63; + + } + + return 0; + +} + +char *routines_base64givenlength(char *base64_input, ssize_t length) { + + ssize_t i; + char *base64_output; + unsigned int sextet; + size_t j = 0; + + /* One extra byte for \0 terminator, another for rounding error. */ + base64_output = malloc((4*length)/3 + 4); + + for ( i=0; i<=length-3; i+=3 ) { + + /* First sextet */ + sextet = (base64_input[i] & 0xfc) >> 2; + base64_output[j++] = routines_base64char(sextet); + + /* Second sextet */ + sextet = ((base64_input[i] & 0x3) << 4) + ((base64_input[i+1] & 0xf0) >> 4); + base64_output[j++] = routines_base64char(sextet); + + /* Third sextet */ + sextet = ((base64_input[i+1] & 0x0f) << 2) + ((base64_input[i+2] & 0xc0) >> 6); + base64_output[j++] = routines_base64char(sextet); + + /* Fourth sextet */ + sextet = (base64_input[i+2] & 0x3f); + base64_output[j++] = routines_base64char(sextet); + + } + + switch ((length) % 3) { + + case 1 : { + + /* One byte left over */ + i = length-1; + + sextet = (base64_input[i] & 0xfc) >> 2; + base64_output[j++] = routines_base64char(sextet); + + sextet = (base64_input[i] & 0x03) << 4; + base64_output[j++] = routines_base64char(sextet); + + base64_output[j++] = '='; + base64_output[j++] = '='; + + break; + + } + + case 2 : { + + /* Two bytes left over */ + i = length-2; + + sextet = (base64_input[i] & 0xfc) >> 2; + base64_output[j++] = routines_base64char(sextet); + + sextet = ((base64_input[i] & 0x3) << 4) + ((base64_input[i+1] & 0xf0) >> 4); + base64_output[j++] = routines_base64char(sextet); + + sextet = (base64_input[i+1] & 0x0f) << 2; + base64_output[j++] = routines_base64char(sextet); + + base64_output[j++] = '='; + + break; + + } + + } + + base64_output[j++] = '\0'; + + return base64_output; + +} + +/* Base64-encode something. Needs to have a NULL terminator. */ +char *routines_base64(char *base64_input) { + return routines_base64givenlength(base64_input, strlen(base64_input)+1); +} + +/* Decode Base64 string (with terminator) and put pointer to result at "output". Return length of result. */ +size_t routines_base64decode(const char *base64_input, char **output) { + + size_t len = 0; + size_t ptr = 0; + char *op = malloc(strlen(base64_input)); + + assert(strlen(base64_input) % 4 == 0 ); + + while ( ptr < strlen(base64_input) ) { + + op[len] = (routines_unbase64char(base64_input[ptr]) << 2) + ((routines_unbase64char(base64_input[ptr+1]) & 48) >> 4); + op[len+1] = ((routines_unbase64char(base64_input[ptr+1]) & 15) << 4) + ((routines_unbase64char(base64_input[ptr+2]) & 60) >> 2); + op[len+2] = ((routines_unbase64char(base64_input[ptr+2]) & 3) << 6) + routines_unbase64char(base64_input[ptr+3]); + + len+=3; + ptr+=4; + + } + + if ( base64_input[ptr-1] == '=' ) { + len--; + } + if ( base64_input[ptr-2] == '=' ) { + len--; + } + + *output = op; + return len; + +} + +static char *routines_randomhexbyte() { + + int j; + char *response = malloc(3); + + /* Taken from the "rand()" man page. */ + j = 1 +(int)(256.0*rand()/(RAND_MAX+1.0)); + sprintf(response, "%2hhx", j); + + return response; + +} + +/* Generate a GUID */ +char *routines_guid() { + + int i, k; + char *guid; + + guid = malloc(39); + assert(guid != NULL); + strcpy(guid, "{"); + + for ( i=0; i<4; i++ ) { + + char *byte; + byte = routines_randomhexbyte(); + strncat(guid, byte, 2); + free(byte); + + } + + for ( k=0; k<3; k++ ) { + + strcat(guid, "-"); + for ( i=0; i<2; i++ ) { + + char *byte; + byte = routines_randomhexbyte(); + strncat(guid, byte, 2); + free(byte); + + } + + } + + /* To be a valid GUID, the version and variant fields need to be set appropriately. */ + guid[15] = '4'; + guid[20] = 'a'; + + strcat(guid, "-"); + for ( i=0; i<6; i++ ) { + + char *byte; + byte = routines_randomhexbyte(); + strncat(guid, byte, 2); + free(byte); + + } + strcat(guid, "}"); + + /* Fix up spaces. */ + for ( i=0; i<(strlen(guid)-1); i++ ) { + if ( guid[i] == ' ' ) { + guid[i] = '0'; + } + } + + return guid; + +} + +/* Replace triangular brackets with something Pango can handle. */ +char *routines_killtriangles(const char *input) { + + char *output; + size_t i; + size_t j = 0; + + output = malloc(2*strlen(input)+1); + for ( i=0; i<=strlen(input); i++ ) { + if ( input[i] == '<' ) { + output[j] = '&'; j++; + output[j] = 'l'; j++; + output[j] = 't'; j++; + output[j] = ';'; j++; + } else if ( input[i] == '>' ) { + output[j] = '&'; j++; + output[j] = 'g'; j++; + output[j] = 't'; j++; + output[j] = ';'; j++; + } else { + output[j] = input[i]; j++; + } + } + + return output; + +} + +/* Replace triangular brackets and ampersands with something Pango can handle. */ +char *routines_killtriangles_and_ampersands(const char *input) { + + char *output; + size_t i; + size_t j = 0; + + output = malloc(2*strlen(input)+1); + for ( i=0; i<=strlen(input); i++ ) { + if ( input[i] == '<' ) { + output[j] = '&'; j++; + output[j] = 'l'; j++; + output[j] = 't'; j++; + output[j] = ';'; j++; + } else if ( input[i] == '>' ) { + output[j] = '&'; j++; + output[j] = 'g'; j++; + output[j] = 't'; j++; + output[j] = ';'; j++; + } else if ( input[i] == '&' ) { + output[j] = '&'; j++; + output[j] = 'a'; j++; + output[j] = 'm'; j++; + output[j] = 'p'; j++; + output[j] = ';'; j++; + } else { + output[j] = input[i]; j++; + } + } + + return output; + +} + +char *routines_flipcolour(const char *colour) { + + char *flipped = malloc(7); + char scratch; + strncpy(flipped, colour, 6); + flipped[6] = '\0'; + + scratch = flipped[0]; + flipped[0] = flipped[4]; + flipped[4] = scratch; + + scratch = flipped[1]; + flipped[1] = flipped[5]; + flipped[5] = scratch; + + return flipped; + +} + +char *routines_gdk_to_hashrgb(const GdkColor *colour) { + + char *string; + + if ( colour == NULL ) { + return NULL; + } + + string = malloc(8); + /* RGB order */ + snprintf(string, 8, "#%02hhx%02hhx%02hhx", colour->red >> 8, colour->green >> 8, colour->blue >> 8); + string[7] = '\0'; + + return string; + +} |