|
|
1.1 root 1: /* str_util.c */
2:
3: /* Synchronet string utility routines */
4:
5: /* $Id: str_util.c,v 1.30 2004/09/11 09:36:19 rswindell Exp $ */
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: * *
11: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
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: /****************************************************************************/
41: /* Removes ctrl-a codes from the string 'instr' */
42: /****************************************************************************/
43: char* DLLCALL remove_ctrl_a(char *instr, char *outstr)
44: {
45: char str[1024],*p;
46: uint i,j;
47:
48: for(i=j=0;instr[i] && j<sizeof(str)-1;i++) {
49: if(instr[i]==CTRL_A && instr[i+1]!=0)
50: i++;
51: else str[j++]=instr[i];
52: }
53: str[j]=0;
54: if(outstr!=NULL)
55: p=outstr;
56: else
57: p=instr;
58: strcpy(p,str);
59: return(p);
60: }
61:
62: char* DLLCALL strip_ctrl(char *str)
63: {
64: char tmp[1024];
65: int i,j;
66:
67: for(i=j=0;str[i] && j<(int)sizeof(tmp)-1;i++) {
68: if(str[i]==CTRL_A && str[i+1]!=0)
69: i++;
70: else if((uchar)str[i]>=' ')
71: tmp[j++]=str[i];
72: }
73: if(i!=j) {
74: tmp[j]=0;
75: strcpy(str,tmp);
76: }
77: return(str);
78: }
79:
80: char* DLLCALL strip_exascii(char *str)
81: {
82: char tmp[1024];
83: int i,j;
84:
85: for(i=j=0;str[i] && j<(int)sizeof(tmp)-1;i++)
86: if(!(str[i]&0x80))
87: tmp[j++]=str[i];
88: tmp[j]=0;
89: strcpy(str,tmp);
90: return(str);
91: }
92:
93: char* DLLCALL prep_file_desc(char *str)
94: {
95: char tmp[1024];
96: int i,j;
97:
98: for(i=j=0;str[i];i++)
99: if(str[i]==CTRL_A && str[i+1]!=0)
100: i++;
101: else if(j && str[i]<=' ' && tmp[j-1]==' ')
102: continue;
103: else if(i && !isalnum(str[i]) && str[i]==str[i-1])
104: continue;
105: else if((uchar)str[i]>=' ')
106: tmp[j++]=str[i];
107: else if(str[i]==TAB || (str[i]==CR && str[i+1]==LF))
108: tmp[j++]=' ';
109: tmp[j]=0;
110: strcpy(str,tmp);
111: return(str);
112: }
113:
114: /****************************************************************************/
115: /* Pattern matching string search of 'insearchof' in 'fname'. */
116: /****************************************************************************/
117: BOOL DLLCALL findstr(char* insearchof, char* fname)
118: {
119: char* p;
120: char str[128];
121: char search[81];
122: int c;
123: int i;
124: BOOL found;
125: FILE* stream;
126:
127: if((stream=fopen(fname,"r"))==NULL)
128: return(FALSE);
129:
130: SAFECOPY(search,insearchof);
131: strupr(search);
132:
133: found=FALSE;
134:
135: while(!feof(stream) && !ferror(stream) && !found) {
136: if(!fgets(str,sizeof(str),stream))
137: break;
138:
139: found=FALSE;
140:
141: p=str;
142: while(*p && *p<=' ') p++; /* Skip white-space */
143:
144: if(*p==';') /* comment */
145: continue;
146:
147: if(*p=='!') { /* !match */
148: found=TRUE;
149: p++;
150: }
151:
152: truncsp(p);
153: c=strlen(p);
154: if(c) {
155: c--;
156: strupr(p);
157: if(p[c]=='~') {
158: p[c]=0;
159: if(strstr(search,p))
160: found=!found;
161: }
162:
163: else if(p[c]=='^' || p[c]=='*') {
164: p[c]=0;
165: if(!strncmp(p,search,c))
166: found=!found;
167: }
168:
169: else if(p[0]=='*') {
170: i=strlen(search);
171: if(i<c)
172: continue;
173: if(!strncmp(p+1,search+(i-c),c))
174: found=!found;
175: }
176:
177: else if(!strcmp(p,search))
178: found=!found;
179: }
180: }
181: fclose(stream);
182: return(found);
183: }
184:
185: /****************************************************************************/
186: /* Searches the file <name>.can in the TEXT directory for matches */
187: /* Returns TRUE if found in list, FALSE if not. */
188: /****************************************************************************/
189: BOOL DLLCALL trashcan(scfg_t* cfg, char* insearchof, char* name)
190: {
191: char fname[MAX_PATH+1];
192:
193: sprintf(fname,"%s%s.can",cfg->text_dir,name);
194: return(findstr(insearchof,fname));
195: }
196:
197: /****************************************************************************/
198: /* Returns the number of characters in 'str' not counting ctrl-ax codes */
199: /* or the null terminator */
200: /****************************************************************************/
201: int bstrlen(char *str)
202: {
203: int i=0;
204:
205: while(*str) {
206: if(*str==CTRL_A)
207: str++;
208: else
209: i++;
210: if(!(*str)) break;
211: str++; }
212: return(i);
213: }
214:
215: /****************************************************************************/
216: /* Returns in 'string' a character representation of the number in l with */
217: /* commas. */
218: /****************************************************************************/
219: char* DLLCALL ultoac(ulong l, char *string)
220: {
221: char str[256];
222: int i,j,k;
223:
224: ultoa(l,str,10);
225: i=strlen(str)-1;
226: j=i/3+1+i;
227: string[j--]=0;
228: for(k=1;i>-1;k++) {
229: string[j--]=str[i--];
230: if(j>0 && !(k%3))
231: string[j--]=','; }
232: return(string);
233: }
234:
235: /****************************************************************************/
236: /* Truncate string at first occurance of char in specified character set */
237: /****************************************************************************/
238: char* DLLCALL truncstr(char* str, const char* set)
239: {
240: char* p;
241:
242: p=strpbrk(str,set);
243: if(p!=NULL && *p!=0)
244: *p=0;
245:
246: return(p);
247: }
248:
249: /****************************************************************************/
250: /* rot13 encoder/decoder - courtesy of Mike Acar */
251: /****************************************************************************/
252: char* DLLCALL rot13(char* str)
253: {
254: char ch, cap;
255: char* p;
256:
257: p=str;
258: while((ch=*p)!=0) {
259: cap = ch & 32;
260: ch &= ~cap;
261: ch = ((ch >= 'A') && (ch <= 'Z') ? ((ch - 'A' + 13) % 26 + 'A') : ch) | cap;
262: *(p++)=ch;
263: }
264:
265: return(str);
266: }
267:
268: /****************************************************************************/
269: /* Puts a backslash on path strings if not just a drive letter and colon */
270: /****************************************************************************/
271: void backslashcolon(char *str)
272: {
273: int i;
274:
275: i=strlen(str);
276: if(i && !IS_PATH_DELIM(str[i-1]) && str[i-1]!=':') {
277: str[i]=PATH_DELIM;
278: str[i+1]=0;
279: }
280: }
281:
282: /****************************************************************************/
283: /* Compares pointers to pointers to char. Used in conjuction with qsort() */
284: /****************************************************************************/
285: int pstrcmp(char **str1, char **str2)
286: {
287: return(strcmp(*str1,*str2));
288: }
289:
290: /****************************************************************************/
291: /* Returns the number of characters that are the same between str1 and str2 */
292: /****************************************************************************/
293: int strsame(char *str1, char *str2)
294: {
295: int i,j=0;
296:
297: for(i=0;str1[i];i++)
298: if(str1[i]==str2[i]) j++;
299: return(j);
300: }
301:
302:
303: /****************************************************************************/
304: /* Returns string for 2 digit hex+ numbers up to 575 */
305: /****************************************************************************/
306: char *hexplus(uint num, char *str)
307: {
308: sprintf(str,"%03x",num);
309: str[0]=num/0x100 ? 'f'+(num/0x10)-0xf : str[1];
310: str[1]=str[2];
311: str[2]=0;
312: return(str);
313: }
314:
315: /****************************************************************************/
316: /* Converts an ASCII Hex string into an ulong */
317: /* by Steve Deppe (Ille Homine Albe) */
318: /****************************************************************************/
319: ulong ahtoul(char *str)
320: {
321: ulong l,val=0;
322:
323: while((l=(*str++)|0x20)!=0x20)
324: val=(l&0xf)+(l>>6&1)*9+val*16;
325: return(val);
326: }
327:
328: /****************************************************************************/
329: /* Converts hex-plus string to integer */
330: /****************************************************************************/
331: uint hptoi(char *str)
332: {
333: char tmp[128];
334: uint i;
335:
336: if(!str[1] || toupper(str[0])<='F')
337: return(ahtoul(str));
338: strcpy(tmp,str);
339: tmp[0]='F';
340: i=ahtoul(tmp)+((toupper(str[0])-'F')*0x10);
341: return(i);
342: }
343:
344: /****************************************************************************/
345: /* Returns 1 if a is a valid ctrl-a code, 0 if it isn't. */
346: /****************************************************************************/
347: BOOL DLLCALL validattr(char a)
348: {
349:
350: switch(toupper(a)) {
351: case '+': /* push attr */
352: case '-': /* pop attr */
353: case '_': /* clear */
354: case 'B': /* blue fg */
355: case 'C': /* cyan fg */
356: case 'G': /* green fg */
357: case 'H': /* high fg */
358: case 'I': /* blink */
359: case 'K': /* black fg */
360: case 'L': /* cls */
361: case 'M': /* magenta fg */
362: case 'N': /* normal */
363: case 'P': /* pause */
364: case 'R': /* red fg */
365: case 'W': /* white fg */
366: case 'Y': /* yellow fg */
367: case '0': /* black bg */
368: case '1': /* red bg */
369: case '2': /* green bg */
370: case '3': /* brown bg */
371: case '4': /* blue bg */
372: case '5': /* magenta bg */
373: case '6': /* cyan bg */
374: case '7': /* white bg */
375: return(TRUE);
376: }
377: return(FALSE);
378: }
379:
380: /****************************************************************************/
381: /* Strips invalid Ctrl-Ax sequences from str */
382: /* Returns number of ^A's in line */
383: /****************************************************************************/
384: size_t DLLCALL strip_invalid_attr(char *strin)
385: {
386: char str[1024];
387: size_t a,c,d;
388:
389: for(a=c=d=0;strin[c] && d<sizeof(str)-1;c++) {
390: if(strin[c]==CTRL_A && strin[c+1]!=0) {
391: a++;
392: if(!validattr(strin[c+1])) {
393: c++;
394: continue;
395: }
396: }
397: str[d++]=strin[c];
398: }
399: str[d]=0;
400: strcpy(strin,str);
401: return(a);
402: }
403:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.