|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.