Annotation of sbbs/src/sbbs3/str_util.c, revision 1.1.1.2

1.1       root        1: /* str_util.c */
                      2: 
                      3: /* Synchronet string utility routines */
                      4: 
1.1.1.2 ! root        5: /* $Id: str_util.c,v 1.46 2010/06/07 07:01:21 rswindell Exp $ */
1.1       root        6: 
                      7: /****************************************************************************
                      8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
                      9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
                     10:  *                                                                                                                                                     *
1.1.1.2 ! root       11:  * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html         *
1.1       root       12:  *                                                                                                                                                     *
                     13:  * This program is free software; you can redistribute it and/or                       *
                     14:  * modify it under the terms of the GNU General Public License                         *
                     15:  * as published by the Free Software Foundation; either version 2                      *
                     16:  * of the License, or (at your option) any later version.                                      *
                     17:  * See the GNU General Public License for more details: gpl.txt or                     *
                     18:  * http://www.fsf.org/copyleft/gpl.html                                                                                *
                     19:  *                                                                                                                                                     *
                     20:  * Anonymous FTP access to the most recent released source is available at     *
                     21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
                     22:  *                                                                                                                                                     *
                     23:  * Anonymous CVS access to the development source and modification history     *
                     24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
                     25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
                     26:  *     (just hit return, no password is necessary)                                                     *
                     27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
                     28:  *                                                                                                                                                     *
                     29:  * For Synchronet coding style and modification guidelines, see                                *
                     30:  * http://www.synchro.net/source.html                                                                          *
                     31:  *                                                                                                                                                     *
                     32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
                     33:  * format) via e-mail to [email protected]                                                                      *
                     34:  *                                                                                                                                                     *
                     35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
                     36:  ****************************************************************************/
                     37: 
                     38: #include "sbbs.h"
                     39: 
                     40: /****************************************************************************/
1.1.1.2 ! root       41: /* For all the functions that take a 'dest' argument, pass NULL to have the    */
        !            42: /* function malloc the buffer for you and return it.                                           */
1.1       root       43: /****************************************************************************/
1.1.1.2 ! root       44: 
        !            45: /****************************************************************************/
        !            46: /* Removes ctrl-a codes from the string 'str'                                                          */
        !            47: /****************************************************************************/
        !            48: char* DLLCALL remove_ctrl_a(const char *str, char *dest)
1.1       root       49: {
1.1.1.2 ! root       50:        int     i,j;
1.1       root       51: 
1.1.1.2 ! root       52:        if(dest==NULL && (dest=strdup(str))==NULL)
        !            53:                return NULL;
        !            54:        for(i=j=0;str[i];i++) {
        !            55:                if(str[i]==CTRL_A) {
1.1       root       56:                        i++;
1.1.1.2 ! root       57:                        if(str[i]==0 || toupper(str[i])=='Z')   /* EOF */
        !            58:                                break;
        !            59:                        /* convert non-destructive backspace to a destructive backspace */
        !            60:                        if(str[i]=='<' && j)    
        !            61:                                j--;
        !            62:                }
        !            63:                else dest[j++]=str[i]; 
1.1       root       64:        }
1.1.1.2 ! root       65:        dest[j]=0;
        !            66:        return dest;
1.1       root       67: }
                     68: 
1.1.1.2 ! root       69: char* DLLCALL strip_ctrl(const char *str, char* dest)
1.1       root       70: {
1.1.1.2 ! root       71:        int     i,j;
1.1       root       72: 
1.1.1.2 ! root       73:        if(dest==NULL && (dest=strdup(str))==NULL)
        !            74:                return NULL;
        !            75:        for(i=j=0;str[i];i++) {
        !            76:                if(str[i]==CTRL_A) {
1.1       root       77:                        i++;
1.1.1.2 ! root       78:                        if(str[i]==0 || toupper(str[i])=='Z')   /* EOF */
        !            79:                                break;
        !            80:                        /* convert non-destructive backspace to a destructive backspace */
        !            81:                        if(str[i]=='<' && j)    
        !            82:                                j--;
        !            83:                }
1.1       root       84:                else if((uchar)str[i]>=' ')
1.1.1.2 ! root       85:                        dest[j++]=str[i];
1.1       root       86:        }
1.1.1.2 ! root       87:        dest[j]=0;
        !            88:        return dest;
1.1       root       89: }
                     90: 
1.1.1.2 ! root       91: char* DLLCALL strip_exascii(const char *str, char* dest)
1.1       root       92: {
1.1.1.2 ! root       93:        int     i,j;
1.1       root       94: 
1.1.1.2 ! root       95:        if(dest==NULL && (dest=strdup(str))==NULL)
        !            96:                return NULL;
        !            97:        for(i=j=0;str[i];i++)
1.1       root       98:                if(!(str[i]&0x80))
1.1.1.2 ! root       99:                        dest[j++]=str[i];
        !           100:        dest[j]=0;
        !           101:        return dest;
        !           102: }
        !           103: 
        !           104: char* DLLCALL strip_space(const char *str, char* dest)
        !           105: {
        !           106:        int     i,j;
        !           107: 
        !           108:        if(dest==NULL && (dest=strdup(str))==NULL)
        !           109:                return NULL;
        !           110:        for(i=j=0;str[i];i++)
        !           111:                if(!isspace((unsigned char)str[i]))
        !           112:                        dest[j++]=str[i];
        !           113:        dest[j]=0;
        !           114:        return dest;
1.1       root      115: }
                    116: 
1.1.1.2 ! root      117: char* DLLCALL prep_file_desc(const char *str, char* dest)
1.1       root      118: {
1.1.1.2 ! root      119:        int     i,j;
1.1       root      120: 
1.1.1.2 ! root      121:        if(dest==NULL && (dest=strdup(str))==NULL)
        !           122:                return NULL;
1.1       root      123:        for(i=j=0;str[i];i++)
1.1.1.2 ! root      124:                if(str[i]==CTRL_A && str[i+1]!=0) {
1.1       root      125:                        i++;
1.1.1.2 ! root      126:                        if(toupper(str[i])=='Z')        /* EOF */
        !           127:                                break;
        !           128:                        /* convert non-destructive backspace to a destructive backspace */
        !           129:                        if(str[i]=='<' && j)    
        !           130:                                j--;
        !           131:                }
        !           132:                else if(j && str[i]<=' ' && dest[j-1]==' ')
1.1       root      133:                        continue;
1.1.1.2 ! root      134:                else if(i && !isalnum((unsigned char)str[i]) && str[i]==str[i-1])
1.1       root      135:                        continue;
                    136:                else if((uchar)str[i]>=' ')
1.1.1.2 ! root      137:                        dest[j++]=str[i];
1.1       root      138:                else if(str[i]==TAB || (str[i]==CR && str[i+1]==LF))
1.1.1.2 ! root      139:                        dest[j++]=' ';
        !           140:        dest[j]=0;
        !           141:        return dest;
1.1       root      142: }
                    143: 
                    144: /****************************************************************************/
1.1.1.2 ! root      145: /* Pattern matching string search of 'insearchof' in 'string'.                         */
1.1       root      146: /****************************************************************************/
1.1.1.2 ! root      147: BOOL DLLCALL findstr_in_string(const char* insearchof, char* string)
1.1       root      148: {
                    149:        char*   p;
1.1.1.2 ! root      150:        char    str[256];
1.1       root      151:        char    search[81];
                    152:        int             c;
                    153:        int             i;
1.1.1.2 ! root      154:        BOOL    found=FALSE;
1.1       root      155: 
1.1.1.2 ! root      156:        if(string==NULL || insearchof==NULL)
        !           157:                return(FALSE);
1.1       root      158: 
                    159:        SAFECOPY(search,insearchof);
                    160:        strupr(search);
1.1.1.2 ! root      161:        SAFECOPY(str,string);
1.1       root      162: 
1.1.1.2 ! root      163:        p=str;  
        !           164:        SKIP_WHITESPACE(p);
1.1       root      165: 
1.1.1.2 ! root      166:        if(*p==';')             /* comment */
        !           167:                return(FALSE);
1.1       root      168: 
1.1.1.2 ! root      169:        if(*p=='!')     {       /* !match */
        !           170:                found=TRUE;
        !           171:                p++;
        !           172:        }
1.1       root      173: 
1.1.1.2 ! root      174:        truncsp(p);
        !           175:        c=strlen(p);
        !           176:        if(c) {
        !           177:                c--;
        !           178:                strupr(p);
        !           179:                if(p[c]=='~') {
        !           180:                        p[c]=0;
        !           181:                        if(strstr(search,p))
        !           182:                                found=!found; 
        !           183:                }
1.1       root      184: 
1.1.1.2 ! root      185:                else if(p[c]=='^' || p[c]=='*') {
        !           186:                        p[c]=0;
        !           187:                        if(!strncmp(p,search,c))
        !           188:                                found=!found; 
1.1       root      189:                }
                    190: 
1.1.1.2 ! root      191:                else if(p[0]=='*') {
        !           192:                        i=strlen(search);
        !           193:                        if(i<c)
        !           194:                                return(found);
        !           195:                        if(!strncmp(p+1,search+(i-c),c))
        !           196:                                found=!found; 
        !           197:                }
1.1       root      198: 
1.1.1.2 ! root      199:                else if(!strcmp(p,search))
        !           200:                        found=!found; 
        !           201:        } 
        !           202:        return(found);
        !           203: }
1.1       root      204: 
1.1.1.2 ! root      205: /****************************************************************************/
        !           206: /* Pattern matching string search of 'insearchof' in 'list'.                           */
        !           207: /****************************************************************************/
        !           208: BOOL DLLCALL findstr_in_list(const char* insearchof, str_list_t list)
        !           209: {
        !           210:        size_t  index;
        !           211:        BOOL    found=FALSE;
        !           212:        char*   p;
1.1       root      213: 
1.1.1.2 ! root      214:        if(list==NULL || insearchof==NULL)
        !           215:                return(FALSE);
        !           216: 
        !           217:        for(index=0; list[index]!=NULL; index++) {
        !           218:                p=list[index];
        !           219:                SKIP_WHITESPACE(p);
        !           220:                found=findstr_in_string(insearchof,p);
        !           221:                if(found!=(*p=='!'))
        !           222:                        break;
1.1       root      223:        }
1.1.1.2 ! root      224:        return(found);
        !           225: }
        !           226: 
        !           227: /****************************************************************************/
        !           228: /* Pattern matching string search of 'insearchof' in 'fname'.                          */
        !           229: /****************************************************************************/
        !           230: BOOL DLLCALL findstr(const char* insearchof, const char* fname)
        !           231: {
        !           232:        char            str[256];
        !           233:        BOOL            found=FALSE;
        !           234:        FILE*           fp;
        !           235: 
        !           236:        if(insearchof==NULL || fname==NULL)
        !           237:                return(FALSE);
        !           238: 
        !           239:        if((fp=fopen(fname,"r"))==NULL)
        !           240:                return(FALSE); 
        !           241: 
        !           242:        while(!feof(fp) && !ferror(fp) && !found) {
        !           243:                if(!fgets(str,sizeof(str),fp))
        !           244:                        break;
        !           245:                found=findstr_in_string(insearchof,str);
        !           246:        }
        !           247: 
        !           248:        fclose(fp);
1.1       root      249:        return(found);
                    250: }
                    251: 
                    252: /****************************************************************************/
                    253: /* Searches the file <name>.can in the TEXT directory for matches                      */
                    254: /* Returns TRUE if found in list, FALSE if not.                                                                */
                    255: /****************************************************************************/
1.1.1.2 ! root      256: BOOL DLLCALL trashcan(scfg_t* cfg, const char* insearchof, const char* name)
1.1       root      257: {
                    258:        char fname[MAX_PATH+1];
                    259: 
1.1.1.2 ! root      260:        return(findstr(insearchof,trashcan_fname(cfg,name,fname,sizeof(fname))));
        !           261: }
        !           262: 
        !           263: /****************************************************************************/
        !           264: char* DLLCALL trashcan_fname(scfg_t* cfg, const char* name, char* fname, size_t maxlen)
        !           265: {
        !           266:        safe_snprintf(fname,maxlen,"%s%s.can",cfg->text_dir,name);
        !           267:        return fname;
        !           268: }
        !           269: 
        !           270: /****************************************************************************/
        !           271: str_list_t DLLCALL trashcan_list(scfg_t* cfg, const char* name)
        !           272: {
        !           273:        char    fname[MAX_PATH+1];
        !           274:        FILE*   fp;
        !           275:        str_list_t      list;
        !           276: 
        !           277:        if((fp=fopen(trashcan_fname(cfg, name, fname, sizeof(fname)),"r"))==NULL)
        !           278:                return NULL;
        !           279: 
        !           280:        list=strListReadFile(fp,NULL,255);
        !           281: 
        !           282:        fclose(fp);
        !           283: 
        !           284:        return list;
1.1       root      285: }
                    286: 
                    287: /****************************************************************************/
                    288: /* Returns the number of characters in 'str' not counting ctrl-ax codes                */
                    289: /* or the null terminator                                                                                                      */
                    290: /****************************************************************************/
1.1.1.2 ! root      291: size_t bstrlen(const char *str)
1.1       root      292: {
1.1.1.2 ! root      293:        size_t i=0;
1.1       root      294: 
                    295:        while(*str) {
1.1.1.2 ! root      296:                if(*str==CTRL_A) {
1.1       root      297:                        str++;
1.1.1.2 ! root      298:                        if(toupper(*str)=='Z')  /* EOF */
        !           299:                                break;
        !           300:                        if(*str=='[')
        !           301:                                i=0;
        !           302:                        else if(*str=='<' && i)
        !           303:                                i--;
        !           304:                } else
1.1       root      305:                        i++;
                    306:                if(!(*str)) break;
1.1.1.2 ! root      307:                str++; 
        !           308:        }
1.1       root      309:        return(i);
                    310: }
                    311: 
                    312: /****************************************************************************/
                    313: /* Returns in 'string' a character representation of the number in l with   */
                    314: /* commas.                                                                                                                                     */
                    315: /****************************************************************************/
                    316: char* DLLCALL ultoac(ulong l, char *string)
                    317: {
                    318:        char str[256];
                    319:        int i,j,k;
                    320: 
                    321:        ultoa(l,str,10);
                    322:        i=strlen(str)-1;
                    323:        j=i/3+1+i;
                    324:        string[j--]=0;
                    325:        for(k=1;i>-1;k++) {
                    326:                string[j--]=str[i--];
                    327:                if(j>0 && !(k%3))
1.1.1.2 ! root      328:                        string[j--]=','; 
        !           329:        }
1.1       root      330:        return(string);
                    331: }
                    332: 
                    333: /****************************************************************************/
                    334: /* Truncate string at first occurance of char in specified character set       */
                    335: /****************************************************************************/
                    336: char* DLLCALL truncstr(char* str, const char* set)
                    337: {
                    338:        char* p;
                    339: 
                    340:        p=strpbrk(str,set);
                    341:        if(p!=NULL && *p!=0)
                    342:                *p=0;
                    343: 
                    344:        return(p);
                    345: }
                    346: 
                    347: /****************************************************************************/
                    348: /* rot13 encoder/decoder - courtesy of Mike Acar                                                       */
                    349: /****************************************************************************/
                    350: char* DLLCALL rot13(char* str)
                    351: {
                    352:        char ch, cap;
                    353:        char* p;
                    354:   
                    355:        p=str;
                    356:        while((ch=*p)!=0) {
                    357:                cap = ch & 32;
                    358:                ch &= ~cap;
                    359:                ch = ((ch >= 'A') && (ch <= 'Z') ? ((ch - 'A' + 13) % 26 + 'A') : ch) | cap;
                    360:                *(p++)=ch;
                    361:     }
                    362: 
                    363:        return(str);
                    364: }
                    365: 
                    366: /****************************************************************************/
                    367: /* Puts a backslash on path strings if not just a drive letter and colon       */
                    368: /****************************************************************************/
1.1.1.2 ! root      369: char* backslashcolon(char *str)
1.1       root      370: {
                    371:     int i;
                    372: 
                    373:        i=strlen(str);
                    374:        if(i && !IS_PATH_DELIM(str[i-1]) && str[i-1]!=':') {
                    375:                str[i]=PATH_DELIM; 
                    376:                str[i+1]=0; 
                    377:        }
1.1.1.2 ! root      378: 
        !           379:        return str;
1.1       root      380: }
                    381: 
                    382: /****************************************************************************/
                    383: /* Compares pointers to pointers to char. Used in conjuction with qsort()   */
                    384: /****************************************************************************/
1.1.1.2 ! root      385: int pstrcmp(const char **str1, const char **str2)
1.1       root      386: {
                    387:        return(strcmp(*str1,*str2));
                    388: }
                    389: 
                    390: /****************************************************************************/
                    391: /* Returns the number of characters that are the same between str1 and str2 */
                    392: /****************************************************************************/
1.1.1.2 ! root      393: int strsame(const char *str1, const char *str2)
1.1       root      394: {
                    395:        int i,j=0;
                    396: 
                    397:        for(i=0;str1[i];i++)
                    398:                if(str1[i]==str2[i]) j++;
                    399:        return(j);
                    400: }
                    401: 
                    402: 
                    403: /****************************************************************************/
                    404: /* Returns string for 2 digit hex+ numbers up to 575                                           */
                    405: /****************************************************************************/
                    406: char *hexplus(uint num, char *str)
                    407: {
                    408:        sprintf(str,"%03x",num);
                    409:        str[0]=num/0x100 ? 'f'+(num/0x10)-0xf : str[1];
                    410:        str[1]=str[2];
                    411:        str[2]=0;
                    412:        return(str);
                    413: }
                    414: 
                    415: /****************************************************************************/
                    416: /* Converts an ASCII Hex string into an ulong                               */
                    417: /* by Steve Deppe (Ille Homine Albe)                                                                           */
                    418: /****************************************************************************/
1.1.1.2 ! root      419: ulong ahtoul(const char *str)
1.1       root      420: {
                    421:     ulong l,val=0;
                    422: 
                    423:        while((l=(*str++)|0x20)!=0x20)
                    424:                val=(l&0xf)+(l>>6&1)*9+val*16;
                    425:        return(val);
                    426: }
                    427: 
                    428: /****************************************************************************/
                    429: /* Converts hex-plus string to integer                                                                         */
                    430: /****************************************************************************/
1.1.1.2 ! root      431: uint hptoi(const char *str)
1.1       root      432: {
                    433:        char tmp[128];
                    434:        uint i;
                    435: 
                    436:        if(!str[1] || toupper(str[0])<='F')
                    437:                return(ahtoul(str));
                    438:        strcpy(tmp,str);
                    439:        tmp[0]='F';
                    440:        i=ahtoul(tmp)+((toupper(str[0])-'F')*0x10);
                    441:        return(i);
                    442: }
                    443: 
                    444: /****************************************************************************/
1.1.1.2 ! root      445: /* Returns TRUE if a is a valid ctrl-a "attribute" code, FALSE if it isn't. */
1.1       root      446: /****************************************************************************/
1.1.1.2 ! root      447: BOOL DLLCALL valid_ctrl_a_attr(char a)
1.1       root      448: {
                    449:        switch(toupper(a)) {
                    450:                case '+':       /* push attr    */
                    451:                case '-':   /* pop attr         */
                    452:                case '_':   /* clear        */
                    453:                case 'B':   /* blue     fg  */
                    454:                case 'C':   /* cyan     fg  */
                    455:                case 'G':   /* green    fg  */
                    456:                case 'H':   /* high     fg  */
                    457:                case 'I':   /* blink        */
                    458:                case 'K':   /* black    fg  */
                    459:                case 'M':   /* magenta  fg  */
                    460:                case 'N':   /* normal       */
                    461:                case 'R':   /* red      fg  */
                    462:                case 'W':   /* white    fg  */
                    463:                case 'Y':   /* yellow   fg  */
                    464:                case '0':   /* black    bg  */
                    465:                case '1':   /* red      bg  */
                    466:                case '2':   /* green    bg  */
                    467:                case '3':   /* brown    bg  */
                    468:                case '4':   /* blue     bg  */
                    469:                case '5':   /* magenta  bg  */
                    470:                case '6':   /* cyan     bg  */
                    471:                case '7':   /* white    bg  */
                    472:                        return(TRUE); 
                    473:        }
                    474:        return(FALSE);
                    475: }
                    476: 
                    477: /****************************************************************************/
1.1.1.2 ! root      478: /* Returns TRUE if a is a valid QWKnet compatible Ctrl-A code, else FALSE      */
        !           479: /****************************************************************************/
        !           480: BOOL DLLCALL valid_ctrl_a_code(char a)
        !           481: {
        !           482:        switch(toupper(a)) {
        !           483:                case 'P':               /* Pause */
        !           484:                case 'L':               /* CLS */
        !           485:                case ',':               /* 100ms delay */
        !           486:                        return TRUE;
        !           487:        }
        !           488:        return valid_ctrl_a_attr(a);
        !           489: }
        !           490: 
        !           491: /****************************************************************************/
        !           492: /****************************************************************************/
        !           493: char DLLCALL ctrl_a_to_ascii_char(char a)
        !           494: {
        !           495:        switch(toupper(a)) {
        !           496:                case 'L':   /* cls          */
        !           497:                        return FF;
        !           498:                case '<':       /* backspace    */
        !           499:                        return '\b';
        !           500:                case '[':       /* CR                   */
        !           501:                        return '\r';
        !           502:                case ']':       /* LF                   */
        !           503:                        return '\n';
        !           504:        }
        !           505:        return 0;
        !           506: }
        !           507: 
        !           508: /****************************************************************************/
        !           509: /* Strips invalid Ctrl-Ax "attribute" sequences from str                    */
1.1       root      510: /* Returns number of ^A's in line                                           */
                    511: /****************************************************************************/
1.1.1.2 ! root      512: size_t DLLCALL strip_invalid_attr(char *str)
1.1       root      513: {
1.1.1.2 ! root      514:     char*      dest;
        !           515:     size_t     a,c,d;
1.1       root      516: 
1.1.1.2 ! root      517:        dest=str;
        !           518:        for(a=c=d=0;str[c];c++) {
        !           519:                if(str[c]==CTRL_A) {
1.1       root      520:                        a++;
1.1.1.2 ! root      521:                        if(str[c+1]==0)
        !           522:                                break;
        !           523:                        if(!valid_ctrl_a_attr(str[c+1])) {
        !           524:                                /* convert non-destructive backspace to a destructive backspace */
        !           525:                                if(str[c+1]=='<' && d)  
        !           526:                                        d--;
1.1       root      527:                                c++;
                    528:                                continue; 
1.1.1.2 ! root      529:                        }
1.1       root      530:                }
1.1.1.2 ! root      531:                dest[d++]=str[c]; 
1.1       root      532:        }
1.1.1.2 ! root      533:        dest[d]=0;
1.1       root      534:        return(a);
                    535: }
                    536: 
1.1.1.2 ! root      537: /****************************************************************************/
        !           538: /****************************************************************************/
        !           539: char DLLCALL exascii_to_ascii_char(uchar ch)
        !           540: {
        !           541:        /* Seven bit table for EXASCII to ASCII conversion */
        !           542:        const char *sbtbl="CUeaaaaceeeiiiAAEaAooouuyOUcLYRfaiounNao?--24!<>"
        !           543:                        "###||||++||++++++--|-+||++--|-+----++++++++##[]#"
        !           544:                        "abrpEout*ono%0ENE+><rj%=o..+n2* ";
        !           545: 
        !           546:        if(ch&0x80)
        !           547:                return sbtbl[ch^0x80];
        !           548:        return ch;
        !           549: }
        !           550: 
        !           551: /****************************************************************************/
        !           552: /* Convert string from IBM extended ASCII to just ASCII                                                */
        !           553: /****************************************************************************/
        !           554: char* DLLCALL ascii_str(uchar* str)
        !           555: {
        !           556:        char*   p=str;
        !           557: 
        !           558:        while(*p) {
        !           559:                if((*p)&0x80)
        !           560:                        *p=exascii_to_ascii_char(*p);   
        !           561:                p++;
        !           562:        }
        !           563:        return((char*)str);
        !           564: }
        !           565: 
1.1       root      566: char* replace_named_values(const char* src
                    567:                                           ,char* buf
                    568:                                           ,size_t buflen       /* includes '\0' terminator */
                    569:                                           ,char* escape_seq
                    570:                                           ,named_string_t* string_list
                    571:                                           ,named_int_t* int_list
                    572:                                           ,BOOL case_sensitive)
                    573: {
                    574:        char    val[32];
                    575:        size_t  i;
                    576:        size_t  esc_len=0;
                    577:        size_t  name_len;
                    578:        size_t  value_len;
                    579:        char*   p = buf;
                    580:        int (*cmp)(const char*, const char*, size_t);
                    581: 
                    582:        if(case_sensitive)
                    583:                cmp=strncmp;
                    584:        else
                    585:                cmp=strnicmp;
                    586: 
                    587:        if(escape_seq!=NULL)
                    588:                esc_len = strlen(escape_seq);
                    589: 
                    590:        while(*src && (size_t)(p-buf) < buflen-1) {
                    591:                if(esc_len) {
                    592:                        if(cmp(src, escape_seq, esc_len)!=0) {
                    593:                                *p++ = *src++;
                    594:                                continue;
                    595:                        }
                    596:                        src += esc_len; /* skip the escape seq */
                    597:                }
                    598:                if(string_list) {
                    599:                        for(i=0; string_list[i].name!=NULL /* terminator */; i++) {
                    600:                                name_len = strlen(string_list[i].name);
                    601:                                if(cmp(src, string_list[i].name, name_len)==0) {
                    602:                                        value_len = strlen(string_list[i].value);
                    603:                                        if((p-buf)+value_len > buflen-1)        /* buffer overflow? */
                    604:                                                value_len = (buflen-1)-(p-buf); /* truncate value */
                    605:                                        memcpy(p, string_list[i].value, value_len);
                    606:                                        p += value_len;
                    607:                                        src += name_len;
                    608:                                        break;
                    609:                                }
                    610:                        }
                    611:                        if(string_list[i].name!=NULL) /* variable match */
                    612:                                continue;
                    613:                }
                    614:                if(int_list) {
                    615:                        for(i=0; int_list[i].name!=NULL /* terminator */; i++) {
                    616:                                name_len = strlen(int_list[i].name);
                    617:                                if(cmp(src, int_list[i].name, name_len)==0) {
                    618:                                        SAFEPRINTF(val,"%d",int_list[i].value);
                    619:                                        value_len = strlen(val);
                    620:                                        if((p-buf)+value_len > buflen-1)        /* buffer overflow? */
                    621:                                                value_len = (buflen-1)-(p-buf); /* truncate value */
                    622:                                        memcpy(p, val, value_len);
                    623:                                        p += value_len;
                    624:                                        src += name_len;
                    625:                                        break;
                    626:                                }
                    627:                        }
                    628:                        if(int_list[i].name!=NULL) /* variable match */
                    629:                                continue;
                    630:                }
                    631: 
                    632:                *p++ = *src++;
                    633:        }
                    634:        *p=0;   /* terminate string in destination buffer */
                    635: 
                    636:        return(buf);
                    637: }
                    638: 
                    639: char* replace_keyed_values(const char* src
                    640:                                           ,char* buf
                    641:                                           ,size_t buflen       /* includes '\0' terminator */
                    642:                                           ,char esc_char
                    643:                                           ,keyed_string_t* string_list
                    644:                                           ,keyed_int_t* int_list
                    645:                                           ,BOOL case_sensitive)
                    646: {
                    647:        char    val[32];
                    648:        size_t  i;
                    649:        size_t  value_len;
                    650:        char*   p = buf;
                    651: 
                    652: 
                    653:        while(*src && (size_t)(p-buf) < buflen-1) {
                    654:                if(esc_char) {
                    655:                        if(*src != esc_char) {
                    656:                                *p++ = *src++;
                    657:                                continue;
                    658:                        }
                    659:                        src ++; /* skip the escape char */
                    660:                }
                    661:                if(string_list) {
                    662:                        for(i=0; string_list[i].key!=0 /* terminator */; i++) {
                    663:                                if((case_sensitive && *src == string_list[i].key)
                    664:                                        || ((!case_sensitive) && toupper(*src) == toupper(string_list[i].key))) {
                    665:                                        value_len = strlen(string_list[i].value);
                    666:                                        if((p-buf)+value_len > buflen-1)        /* buffer overflow? */
                    667:                                                value_len = (buflen-1)-(p-buf); /* truncate value */
                    668:                                        memcpy(p, string_list[i].value, value_len);
                    669:                                        p += value_len;
                    670:                                        src++;
                    671:                                        break;
                    672:                                }
                    673:                        }
                    674:                        if(string_list[i].key!=0) /* variable match */
                    675:                                continue;
                    676:                }
                    677:                if(int_list) {
                    678:                        for(i=0; int_list[i].key!=0 /* terminator */; i++) {
                    679:                                if((case_sensitive && *src == int_list[i].key)
                    680:                                        || ((!case_sensitive) && toupper(*src) == toupper(int_list[i].key))) {
                    681:                                        SAFEPRINTF(val,"%d",int_list[i].value);
                    682:                                        value_len = strlen(val);
                    683:                                        if((p-buf)+value_len > buflen-1)        /* buffer overflow? */
                    684:                                                value_len = (buflen-1)-(p-buf); /* truncate value */
                    685:                                        memcpy(p, val, value_len);
                    686:                                        p += value_len;
                    687:                                        src++;
                    688:                                        break;
                    689:                                }
                    690:                        }
                    691:                        if(int_list[i].key!=0) /* variable match */
                    692:                                continue;
                    693:                }
                    694: 
                    695:                *p++ = *src++;
                    696:        }
                    697:        *p=0;   /* terminate string in destination buffer */
                    698: 
                    699:        return(buf);
                    700: }
                    701: 
                    702: 
                    703: #if 0  /* replace_*_values test */
                    704: 
                    705: void main(void)
                    706: {
                    707:        char buf[128];
                    708:        keyed_string_t strs[] = {
                    709:                { '+', "plus" },
                    710:                { '=', "equals" },
                    711:                { 0 }
                    712:        };
                    713:        keyed_int_t ints[] = {
                    714:                { 'o', 1 },
                    715:                { 't', 2 },
                    716:                { 'h', 3 },
                    717:                { NULL }
                    718:        };
                    719: 
                    720:        printf("'%s'\n", replace_keyed_values("$o $+ $t $= $h", buf, sizeof(buf), '$'
                    721:                ,strs, ints, FALSE));
                    722: 
                    723: }
                    724: 
                    725: #endif
                    726: 
                    727: #if 0 /* to be moved here from xtrn.cpp */
                    728: 
                    729: char* quoted_string(const char* str, char* buf, size_t maxlen)
                    730: {
                    731:        if(strchr(str,' ')==NULL)
                    732:                return((char*)str);
                    733:        safe_snprintf(buf,maxlen,"\"%s\"",str);
                    734:        return(buf);
                    735: }
                    736: 
                    737: #endif
                    738: 
                    739: #if 0 /* I think is is a misguided idea :-(  */
                    740: 
                    741: char* sbbs_cmdstr(const char* src
                    742:                                        ,char* buf
                    743:                                        ,size_t buflen  /* includes '\0' terminator */
                    744:                                        ,scfg_t* scfg
                    745:                                        ,user_t* user
                    746:                                        ,int node_num
                    747:                                        ,int minutes
                    748:                                        ,int rows
                    749:                                        ,int timeleft
                    750:                                        ,SOCKET socket_descriptor
                    751:                                        ,char* protocol
                    752:                                        ,char* ip_address
                    753:                                        ,char* fpath
                    754:                                        ,char* fspec
                    755:                                        )
                    756: {
                    757:        const char* nulstr = "";
                    758:        char alias_buf[LEN_ALIAS+1];
                    759:        char fpath_buf[MAX_PATH+1];
                    760:        char fspec_buf[MAX_PATH+1];
                    761:        char sysop_buf[sizeof(scfg->sys_op)];
                    762: 
                    763:        keyed_string_t str_list[] = {
                    764:                /* user alias */
                    765:                { 'a',  user!=NULL ? quoted_string(user->alias, alias_buf, sizeof(alias_buf)) : nulstr },
                    766:                { 'A',  user!=NULL ? user->alias : nulstr },
                    767:                
                    768:                /* connection */
                    769:                { 'c',  protocol },
                    770:                { 'C',  protocol },
                    771: 
                    772:                /* file path */
                    773:                { 'f',  quoted_string(fpath, fpath_buf, sizeof(fpath_buf)) },
                    774:                { 'F',  fpath },
                    775: 
                    776:                /* temp dir */
                    777:                { 'g',  scfg->temp_dir },
                    778:                { 'G',  scfg->temp_dir },
                    779: 
                    780:                /* IP address */
                    781:                { 'h',  ip_address },
                    782:                { 'H',  ip_address },
                    783: 
                    784:                /* data dir */
                    785:                { 'j',  scfg->data_dir },
                    786:                { 'J',  scfg->data_dir },
                    787: 
                    788:                /* ctrl dir */
                    789:                { 'k',  scfg->ctrl_dir },
                    790:                { 'K',  scfg->ctrl_dir },
                    791: 
                    792:                /* node dir */
                    793:                { 'n',  scfg->node_dir },
                    794:                { 'N',  scfg->node_dir },
                    795: 
                    796:                /* sysop */
                    797:                { 'o',  quoted_string(scfg->sys_op, sysop_buf, sizeof(sysop_buf)) },
                    798:                { 'O',  scfg->sys_op },
                    799: 
                    800:                /* protocol */
                    801:                { 'p',  protocol },
                    802:                { 'P',  protocol },
                    803: 
                    804:                /* system QWK-ID */
                    805:                { 'q',  scfg->sys_id },
                    806:                { 'Q',  scfg->sys_id },
                    807: 
                    808:                /* file spec */
                    809:                { 's',  quoted_string(fspec, fspec_buf, sizeof(fspec_buf)) },
                    810:                { 'S',  fspec },
                    811: 
                    812:                /* UART I/O Address (in hex) 'f' for FOSSIL */
                    813:                { 'u',  "f" },
                    814:                { 'U',  "f" },
                    815: 
                    816:                /* text dir */
                    817:                { 'z',  scfg->text_dir },
                    818:                { 'Z',  scfg->text_dir },
                    819: 
                    820:                /* exec dir */
                    821:                { '!',  scfg->exec_dir },
                    822:                { '@',
                    823: #ifndef __unix__
                    824:                        scfg->exec_dir
                    825: #else
                    826:                        nulstr
                    827: #endif
                    828:                },
                    829: 
                    830:                /* .exe (on Windows) */
                    831:                { '.',
                    832: #ifndef __unix__
                    833:                ".exe"
                    834: #else
                    835:                nulstr
                    836: #endif
                    837:                },
                    838: 
                    839:                /* terminator */
                    840:                { 0 }   
                    841:        };
                    842:        keyed_int_t int_list[] = {
                    843:                /* node number */
                    844:                { '#',  node_num },
                    845: 
                    846:                /* DTE rate */
                    847:                { 'b',  38400 },        
                    848:                { 'B',  38400 },
                    849: 
                    850:                /* DCE rate */
                    851:                { 'd',  30000 },
                    852:                { 'D',  30000 },
                    853: 
                    854:                /* Estimated Rate (cps) */
                    855:                { 'e',  3000 },
                    856:                { 'E',  3000 },
                    857: 
                    858:                { 'h',  socket_descriptor },
                    859:                { 'H',  socket_descriptor },
                    860: 
                    861:                { 'l',  user==NULL ? 0 : scfg->level_linespermsg[user->level] },
                    862:                { 'L',  user==NULL ? 0 : scfg->level_linespermsg[user->level] },
                    863: 
                    864:                { 'm',  minutes },
                    865:                { 'M',  minutes },
                    866: 
                    867:                { 'r',  rows },
                    868:                { 'R',  rows },
                    869: 
                    870:                /* Time left in seconds */
                    871:                { 't',  timeleft },
                    872:                { 'T',  timeleft },
                    873: 
                    874:                /* Credits */
                    875:                { '$',  user==NULL ? 0 : (user->cdt+user->freecdt) },
                    876: 
                    877:                /* terminator */
                    878:                { 0 }   
                    879:        };
                    880: 
                    881: 
                    882:        return replace_keyed_values(src, buf, buflen, '%', str_list, int_list, TRUE);
                    883: }
                    884: 
                    885: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.