/* *************************************************************************** * * Author: Teunis van Beelen * * Copyright (C) 2009 - 2023 Teunis van Beelen * * Email: teuniz@protonmail.com * *************************************************************************** * * This program 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 3 of the License. * * This program 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 program. If not, see . * *************************************************************************** */ #include "utils.h" #define FLT_ROUNDS 1 /* size is size of destination */ /* dest points to src2 relative to src1 */ void get_relative_path_from_absolut_paths(char *dest, const char *src1, const char *src2, int size) { int i, len1, len2, len_min, delim_shared=0, delim1=0, delim2=0; if(size < 1) return; dest[0] = 0; len1 = strlen(src1); len2 = strlen(src2); len_min = (len1 > len2) ? len2 : len1; if(!len_min) return; for(i=0; i= 0) && dir) { cut = delim_pos3 - delim_pos1; for(j=delim_pos1; j<(len-cut+1); j++) { path[j] = path[j+cut]; } len = strlen(path); i = 0; dots = 0; dir = 0; continue; } dots = 0; } else { dots = 3; letter++; } } } /* removes extension including the dot */ void remove_extension_from_filename(char *str) { int i, len; len = strlen(str); if(len < 1) { return; } for(i=len-1; i>=0; i--) { if((str[i]=='/') || (str[i]=='\\')) { return; } if(str[i]=='.') { str[i] = 0; return; } } } /* sz is size of destination, returns length of filename */ int get_filename_from_path(char *dest, const char *src, int sz) { int i, len; if(sz<1) { return -1; } if(sz<2) { dest[0] = 0; return 0; } len = strlen(src); if(len < 1) { dest[0] = 0; return 0; } for(i=len-1; i>=0; i--) { if((src[i]=='/') || (src[i]=='\\')) { break; } } i++; if(i == len) { dest[0] = 0; return 0; } strncpy(dest, src + i, sz); dest[sz-1] = 0; return strlen(dest); } /* sz is size of destination, returns length of directory */ /* last character of destination is not a slash! */ int get_directory_from_path(char *dest, const char *src, int sz) { int i, len; if(sz<1) { return -1; } if(sz<2) { dest[0] = 0; return 0; } len = strlen(src); if(len < 1) { dest[0] = 0; return 0; } for(i=len-1; i>0; i--) { if((src[i]=='/') || (src[i]=='\\')) { break; } } strlcpy(dest, src, sz); if(i < sz) { dest[i] = 0; } return strlen(dest); } void convert_trailing_zeros_to_spaces(char *str) { int i, j, len; len = strlen(str); for(i=0; i=0; j--) { if((str[j]!='.')&&(str[j]!='0')) { break; } if(str[j]=='.') { str[j] = ' '; break; } str[j] = ' '; } break; } } } void remove_trailing_spaces(char *str) { int i, len; len = strlen(str); if(!len) return; for(i=(len-1); i>=0; i--) { if(str[i]!=' ') break; } str[i+1] = 0; } void remove_leading_spaces(char *str) { int i, diff, len; len = strlen(str); for(i=0; i=0; i--) { if(str[i]!=' ') break; } str[i+1] = 0; } /* removes trailing zero's from one or more occurrences of a decimal fraction in a string */ void remove_trailing_zeros(char *str) { int i, j, len, numberfound, dotfound, decimalzerofound, trailingzerofound=1; while(trailingzerofound) { numberfound = 0; dotfound = 0; decimalzerofound = 0; trailingzerofound = 0; len = strlen(str); for(i=0; i '9')) { if(decimalzerofound) { if(str[i-decimalzerofound-1] == '.') { decimalzerofound++; } for(j=i; j<(len+1); j++) { str[j-decimalzerofound] = str[j]; } trailingzerofound = 1; break; } if(str[i] != '.') { numberfound = 0; dotfound = 0; decimalzerofound = 0; } } else { numberfound = 1; if(str[i] > '0') { decimalzerofound = 0; } } if((str[i] == '.') && numberfound) { dotfound = 1; } if((str[i] == '0') && dotfound) { decimalzerofound++; } } } if(decimalzerofound) { if(str[i-decimalzerofound-1] == '.') { decimalzerofound++; } for(j=i; j<(len+1); j++) { str[j-decimalzerofound] = str[j]; } } if(len > 1) { if(!((str[len - 2] < '0') || (str[i] > '9'))) { if(str[len - 1] == '.') { str[len - 1] = 0; } } } } void utf8_to_latin1(char *utf8_str) { int i, j, len; unsigned char *str; str = (unsigned char *)utf8_str; len = strlen(utf8_str); if(!len) { return; } j = 0; for(i=0; i 127) && (str[i] < 192))) { str[j++] = '.'; continue; } if(str[i] > 223) { str[j++] = 0; return; /* can only decode Latin-1 ! */ } if((str[i] & 224) == 192) /* found a two-byte sequence containing Latin-1, Greek, Cyrillic, Coptic, Armenian, Hebrew, etc. characters */ { if((i + 1) == len) { str[j++] = 0; return; } if((str[i] & 252) != 192) /* it's not a Latin-1 character */ { str[j++] = '.'; i++; continue; } if((str[i + 1] & 192) != 128) /* UTF-8 violation error */ { str[j++] = 0; return; } str[j] = str[i] << 6; str[j] += (str[i + 1] & 63); i++; j++; continue; } str[j++] = str[i]; } if(j 4096) len = 4096; str = (unsigned char *)latin1_str; j = 0; for(i=0; i126)&&(str[i]<160)) tmp_str[j] = '.'; if(str[i]>159) { if((len-j)<2) { tmp_str[j] = ' '; } else { tmp_str[j] = 192 + (str[i]>>6); j++; tmp_str[j] = 128 + (str[i]&63); } } j++; if(j>=len) break; } for(i=0; i 126)) { *s = '.'; } } } void latin1_to_ascii(char *str, int len) { /* ISO 8859-1 except for characters 0x80 to 0x9f which are taken from the extension CP-1252 */ int i, value; const char conv_table[]=".E.,F\".++^.Se.zY.i....|....<...-....\'u.....>...?AAAAAAECEEEEIIIIDNOOOOOxOUUUUYtsaaaaaaeceeeeiiiidnooooo:0uuuuyty"; for(i=0; i31)&&(value<127)) { continue; } if(value < 32) { str[i] = '.'; continue; } str[i] = conv_table[value - 127]; } } int utf8_set_byte_len(char *str, int new_len) { int i, len; if(str == NULL) return 0; if(new_len < 1) return 0; len = strlen(str); if(new_len >= len) return len; for(i=new_len-1; i>=0; i--) { if((((unsigned char *)str)[i] & 0b11000000) != 0b10000000) { str[i] = 0; return i; } } str[0] = 0; return 0; } int utf8_set_char_len(char *str, int new_len) { int i, j=0; if(str == NULL) return 0; if(new_len < 0) return 0; for(i=0; ; i++) { if(str[i] == 0) break; if((((unsigned char *)str)[i] & 0b11000000) != 0b10000000) { if(j == new_len) { str[i] = 0; return j; } j++; } } return j; } int utf8_strlen(const char *str) { int i, j=0; if(str == NULL) return 0; for(i=0; ; i++) { if(str[i] == 0) break; if((((unsigned char *)str)[i] & 0b11000000) != 0b10000000) { j++; } } return j; } int utf8_idx(const char *str, int idx) { int i, j=0; if(str == NULL) return 0; for(i=0; ; i++) { if(str[i] == 0) break; if((((unsigned char *)str)[i] & 0b11000000) != 0b10000000) { if(j == idx) return i; j++; } } return 0; } void str_replace_ctrl_chars(char *str, char c) { int i; if(str == NULL) return; for(i=0; ; i++) { if(str[i] == 0) return; if((((unsigned char *)str)[i] < 32) || (((unsigned char *)str)[i] == 127)) { str[i] = c; } } } int antoi(const char *input_str, int len) { char str[4096]; if(len > 4095) len = 4095; strncpy(str, input_str, len); str[len] = 0; return atoi_nonlocalized(str); } /* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */ /* if sign is zero, only negative numbers will have the sign '-' character */ /* if sign is one, the sign '+' or '-' character will always be printed */ /* returns the amount of characters printed */ int fprint_int_number_nonlocalized(FILE *file, int q, int minimum, int sign) { int flag=0, z, i, j=0, base = 1000000000; if(minimum < 0) { minimum = 0; } if(minimum > 9) { flag = 1; } if(q < 0) { fputc('-', file); j++; base = -base; } else { if(sign) { fputc('+', file); j++; } } for(i=10; i; i--) { if(minimum == i) { flag = 1; } z = q / base; q %= base; if(z || flag) { fputc('0' + z, file); j++; flag = 1; } base /= 10; } if(!flag) { fputc('0', file); j++; } return j; } /* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */ /* if sign is zero, only negative numbers will have the sign '-' character */ /* if sign is one, the sign '+' or '-' character will always be printed */ /* returns the amount of characters printed */ int fprint_ll_number_nonlocalized(FILE *file, long long q, int minimum, int sign) { int flag=0, z, i, j=0; long long base = 1000000000000000000LL; if(minimum < 0) { minimum = 0; } if(minimum > 18) { flag = 1; } if(q < 0LL) { fputc('-', file); j++; base = -base; } else { if(sign) { fputc('+', file); j++; } } for(i=19; i; i--) { if(minimum == i) { flag = 1; } z = q / base; q %= base; if(z || flag) { fputc('0' + z, file); j++; flag = 1; } base /= 10LL; } if(!flag) { fputc('0', file); j++; } return j; } /* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */ /* if sign is zero, only negative numbers will have the sign '-' character */ /* if sign is one, the sign '+' or '-' character will always be printed */ /* returns the amount of characters printed */ // int sprint_int_number_nonlocalized(char *str, int q, int minimum, int sign) // { // int flag=0, z, i, j=0, base = 1000000000; // // if(minimum < 0) // { // minimum = 0; // } // // if(minimum > 9) // { // flag = 1; // } // // if(q < 0) // { // str[j++] = '-'; // // q = -q; // } // else // { // if(sign) // { // str[j++] = '+'; // } // } // // for(i=10; i; i--) // { // if(minimum == i) // { // flag = 1; // } // // z = q / base; // // q %= base; // // if(z || flag) // { // str[j++] = '0' + z; // // flag = 1; // } // // base /= 10; // } // // if(!flag) // { // str[j++] = '0'; // } // // str[j] = 0; // // return j; // } /* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */ /* if sign is zero, only negative numbers will have the sign '-' character */ /* if sign is one, the sign '+' or '-' character will always be printed */ /* returns the amount of characters printed */ int sprint_ll_number_nonlocalized(char *str, long long q, int minimum, int sign) { int flag=0, z, i, j=0; long long base = 1000000000000000000LL; if(minimum < 0) { minimum = 0; } if(minimum > 18) { flag = 1; } if(q < 0LL) { str[j++] = '-'; base = -base; } else { if(sign) { str[j++] = '+'; } } for(i=19; i; i--) { if(minimum == i) { flag = 1; } z = q / base; q %= base; if(z || flag) { str[j++] = '0' + z; flag = 1; } base /= 10LL; } if(!flag) { str[j++] = '0'; } str[j] = 0; return j; } // int sprint_number_nonlocalized(char *str, double nr) // { // int flag=0, z, i, j=0, q, base = 1000000000; // // double var; // // q = (int)nr; // // var = nr - q; // // if(nr < 0.0) // { // str[j++] = '-'; // // if(q < 0) // { // q = -q; // } // } // // for(i=10; i; i--) // { // z = q / base; // // q %= base; // // if(z || flag) // { // str[j++] = '0' + z; // // flag = 1; // } // // base /= 10; // } // // if(!flag) // { // str[j++] = '0'; // } // // base = 100000000; // // var *= (base * 10); // // q = (int)var; // // if(q < 0) // { // q = -q; // } // // if(!q) // { // str[j] = 0; // // return j; // } // // str[j++] = '.'; // // for(i=9; i; i--) // { // z = q / base; // // q %= base; // // str[j++] = '0' + z; // // base /= 10; // } // // str[j] = 0; // // j--; // // for(; j>0; j--) // { // if(str[j] == '0') // { // str[j] = 0; // } // else // { // j++; // // break; // } // } // // return j; // } double atof_nonlocalized(const char *str) { int i=0, dot_pos=-1, decimals=0, sign=1; double value, value2=0.0; value = atoi_nonlocalized(str); while(str[i] == ' ') { i++; } if((str[i] == '+') || (str[i] == '-')) { if(str[i] == '-') { sign = -1; } i++; } for(; ; i++) { if(str[i] == 0) { break; } if(((str[i] < '0') || (str[i] > '9')) && (str[i] != '.')) { break; } if(dot_pos >= 0) { if((str[i] >= '0') && (str[i] <= '9')) { decimals++; } else { break; } } if(str[i] == '.') { if(dot_pos < 0) { dot_pos = i; } } } if(decimals) { value2 = atoi_nonlocalized(str + dot_pos + 1) * sign; i = 1; while(decimals--) { i *= 10; } value2 /= i; } return value + value2; } int atoi_nonlocalized(const char *str) { int i=0, value=0, sign=1; while(str[i] == ' ') { i++; } if((str[i] == '+') || (str[i] == '-')) { if(str[i] == '-') { sign = -1; } i++; } for( ; ; i++) { if(str[i] == 0) { break; } if((str[i] < '0') || (str[i] > '9')) { break; } value *= 10; value += (str[i] - '0'); } return value * sign; } long long atoll_x(const char *str, int dimension) { int i, radix, negative=0; long long value=0LL; while(*str==' ') { str++; } if(*str=='-') { negative = 1; str++; } else { if(*str=='+') { str++; } } for(i=0; ; i++) { if(str[i]=='.') { str += (i + 1); break; } if((str[i]<'0') || (str[i]>'9')) { if(negative) { return value * dimension * -1LL; } else { return value * dimension; } } value *= 10LL; value += str[i] - '0'; } radix = 1; for(i=0; radix'9')) { break; } radix *= 10; value *= 10LL; value += str[i] - '0'; } if(negative) { return value * (dimension / radix) * -1LL; } else { return value * (dimension / radix); } } int is_integer_number(const char *str) { int i=0, l, hasspace = 0, hassign=0, digit=0; l = strlen(str); if(!l) return 1; if((str[0]=='+')||(str[0]=='-')) { hassign++; i++; } for(; i57)) { return 1; } else { if(hasspace) { return 1; } digit++; } } } if(digit) return 0; else return 1; } int is_number(const char *str) { int i=0, len, hasspace=0, hassign=0, digit=0, hasdot=0, hasexp=0; len = strlen(str); if(!len) return 1; if((str[0]=='+')||(str[0]=='-')) { hassign++; i++; } for(; i57))&&str[i]!='.') { return 1; } else { if(hasspace) { return 1; } if(str[i]=='.') { if(hasdot) return 1; hasdot++; } else { digit++; } } } } if(hasexp) { if(++i==len) { return 1; } if((str[i]=='+')||(str[i]=='-')) { hassign++; i++; } for(; i57)) { return 1; } else { if(hasspace) { return 1; } digit++; } } } } if(digit) return 0; else return 1; } void strntolower(char *s, int n) { int i; for(i=0; i 1000) value /=10; while(value < 100) value *=10; if(value > 670) { return 10; } else if(value > 300) { return 50; } else if(value > 135) { return 20; } else { return 10; } return 10; } void hextoascii(char *str) { int i, len; char scratchpad[4]; len = strlen(str) / 2; for(i=0; i 999.999) { val /= 10; exp++; } val = nearbyint(val); for(i=0; iexp; i--) { val /= 10; } return val * polarity; } double round_up_step125(double val, double *ratio) { int i, exp=0; double ltmp; while(val < 0.999) { val *= 10; exp--; } while(val > 9.999) { val /= 10; exp++; } val = nearbyint(val); if(val > 4.999) { ltmp = 10; if(ratio != NULL) { *ratio = 2; } } else if(val > 1.999) { ltmp = 5; if(ratio != NULL) { *ratio = 2.5; } } else { ltmp = 2; if(ratio != NULL) { *ratio = 2; } } for(i=0; iexp; i--) { ltmp /= 10; } if((ltmp < 1e-13) && (ltmp > -1e-13)) { return 0; } return ltmp; } double round_down_step125(double val, double *ratio) { int i, exp=0; double ltmp; while(val < 0.999) { val *= 10; exp--; } while(val > 9.999) { val /= 10; exp++; } val = nearbyint(val); if(val < 1.001) { ltmp = 0.5; if(ratio != NULL) { *ratio = 2; } } else if(val < 2.001) { ltmp = 1; if(ratio != NULL) { *ratio = 2; } } else if(val < 5.001) { ltmp = 2; if(ratio != NULL) { *ratio = 2.5; } } else { ltmp = 5; if(ratio != NULL) { *ratio = 2; } } for(i=0; iexp; i--) { ltmp /= 10; } if((ltmp < 1e-13) && (ltmp > -1e-13)) { return 0; } return ltmp; } int convert_to_metric_suffix(char *dest, double value, int decimals, int sz) { double ftmp; char suffix=' '; if(sz < 1) return 0; if(value < 0) { ftmp = value * -1; } else { ftmp = value; } if(ftmp > 0.999999e12 && ftmp < 0.999999e15) { ftmp = ftmp / 1e12; suffix = 'T'; } else if(ftmp > 0.999999e9) { ftmp = ftmp / 1e9; suffix = 'G'; } else if(ftmp > 0.999999e6) { ftmp = ftmp / 1e6; suffix = 'M'; } else if(ftmp > 0.999999e3) { ftmp /= 1e3; suffix = 'K'; } else if(ftmp > 0.999999e-3 && ftmp < 0.999999) { ftmp *= 1e3; suffix = 'm'; } else if( ftmp > 0.999999e-6 && ftmp < 0.999999e-3) { ftmp *= 1e6; suffix = 'u'; } else if(ftmp > 0.999999e-9 && ftmp < 0.999999e-6) { ftmp *= 1e9; suffix = 'n'; } else if(ftmp > 0.999999e-12 && ftmp < 0.999999e-9) { ftmp *= 1e12; suffix = 'p'; } if((decimals < 0) || (decimals > 6)) decimals = 3; if(value < 0) ftmp *=-1; return snprintf(dest, sz, "%.*f%c", decimals, ftmp, suffix); } int strtoipaddr(unsigned int *dest, const char *src) { int i, err=1; unsigned int val; char *ptr, str[64]; if(strlen(src) < 7) { return -1; } strncpy(str, src, 64); str[63] = 0; ptr = strtok(str, "."); if(ptr != NULL) { val = atoi(ptr) << 24; for(i=0; i<3; i++) { ptr = strtok(NULL, "."); if(ptr == NULL) { break; } val += atoi(ptr) << (16 - (i * 8)); } err = 0; } if(err) { return -1; } *dest = val; return 0; } int dblcmp(double val1, double val2) { long double diff = (long double)val1 - (long double)val2; if(diff > 1e-13l) { return 1; } else if(-diff > 1e-13l) { return -1; } else { return 0; } } int base64_dec(const void *src, void *dest, int len) { int i, j, idx; const unsigned char *arr_in=(const unsigned char *)src; unsigned char *arr_out=(unsigned char *)dest; union{ unsigned char four[4]; unsigned short two[2]; unsigned int one; } var; unsigned char base64[256]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,62,0,0,0,63,52,53,54,55,56,57,58,59,60,61,0,0,0,0,0,0, 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0, 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; var.one = 0; for(i=0, j=0, idx=0; i>= 6; arr_out[j++] = var.four[0]; } else if(idx == 3) { var.one >>= 6; arr_out[j++] = var.four[1]; arr_out[j++] = var.four[0]; } return j; } /* returns also empty tokens */ char * strtok_r_e(char *str, const char *delim, char **saveptr) { int i, j, delim_len; char *ptr; char *buf; if(delim == NULL) return NULL; delim_len = strlen(delim); if(delim_len < 1) return NULL; if(str != NULL) { buf = str; } else { buf = *saveptr; } for(i=0; ; i++) { if(buf[i] == 0) { if(i) { ptr = buf; buf += i; *saveptr = buf; return ptr; } else { return NULL; } } for(j=0; j sz) srclen = sz; memcpy(dst, src, srclen); dst[srclen] = 0; return srclen; } int strlcat(char *dst, const char *src, int sz) { int srclen, dstlen; dstlen = strlen(dst); sz -= dstlen + 1; if(sz < 1) return dstlen; srclen = strlen(src); if(srclen > sz) srclen = sz; memcpy(dst + dstlen, src, srclen); dst[dstlen + srclen] = 0; return (dstlen + srclen); } #endif void remove_leading_chars(char *str, int n) { int i, len; if(str == NULL) return; if(n < 1) return; len = strlen(str); if(n >= len) { str[0] = 0; return; } for(i=0; i<(len-n); i++) { str[i] = str[i + n]; } str[i] = 0; } void remove_trailing_chars(char *str, int n) { int len; if(str == NULL) return; if(n < 1) return; len = strlen(str); if(n >= len) { str[0] = 0; return; } str[len - n] = 0; } void str_insert_substr(char *str, int pos, int len, const char *substr, int subpos, int sublen) { int i, slen; if((pos >= len) || (pos < 0) || (len < 1) || (subpos >= sublen) || (subpos < 0) || (sublen < 1)) return; slen = strlen(str); if(pos > slen) return; if(sublen > (signed)strlen(substr)) sublen = strlen(substr); for(i=((slen+sublen)-1); i>=(pos + sublen); i--) { if(i < len) str[i] = str[i-sublen]; } for(i=0; i= len) || ((subpos + i) >= sublen)) break; str[pos + i] = substr[subpos + i]; } if((slen + sublen) < len) { str[slen + sublen] = 0; } else { str[len-1] = 0; } } int str_replace_substr(char *str, int len, int n, const char *dest_substr, const char *src_substr) { int i, pos, slen, destlen, srclen, occurrence=0, cnt=0, lendiff; slen = strlen(str); destlen = strlen(dest_substr); srclen = strlen(src_substr); lendiff = srclen - destlen; for(pos=0; pos 0) { for(i=((slen+lendiff)-1); i>=(pos + lendiff); i--) { if(i < len) str[i] = str[i-lendiff]; } } else if(lendiff < 0) { for(i=(pos + srclen); i<(slen+lendiff); i++) { if(i < len) str[i] = str[i-lendiff]; } } for(i=0; i= len) break; str[pos + i] = src_substr[i]; } if((slen + lendiff) < len) { slen += lendiff; str[slen] = 0; pos += lendiff; } else { str[len-1] = 0; slen = len; break; } cnt++; if(n != -1) break; } occurrence++; } } return cnt; } int convert_non_ascii_to_hex(char *dest, const char *src, int destlen) { int i, len, newlen=0; len = strlen(src); for(i=0; i 126)) { if((newlen + 7) >= destlen) { break; } newlen += snprintf(dest + newlen, 7, "<0x%.2x>", (unsigned char)src[i]); } else { if((newlen + 2) >= destlen) { break; } dest[newlen++] = src[i]; } } dest[newlen] = 0; return newlen; } /* returns greatest common divisor */ int t_gcd(int a, int b) { if(!a) { return b; } while(b) { if(a > b) { a = a - b; } else { b = b - a; } } return a; } /* returns least common multiple */ int t_lcm(int a, int b) { return ((a * b) / t_gcd(a, b)); } void ascii_toupper(char *p) { for(; *p; p++) { if((*p >= 'a') && (*p <= 'z')) { *p -= 32; } } }