1 /* $Id: str.c,v 1.26 2020-10-18 00:46:41 phil Exp $ */
2 
3 /*
4  * str.c - string functions
5  * 10/27/93
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H defined */
11 
12 #include <stdlib.h>		       /* before stdio(?) */
13 #include <stdarg.h>
14 #include <ctype.h>
15 #include <stdio.h>			/* for lib.h */
16 
17 #include "h.h"
18 #include "snotypes.h"
19 #include "macros.h"
20 #include "lib.h"			/* for prototypes */
21 #include "str.h"
22 
23 void
trimsp(struct spec * sp1,struct spec * sp2)24 trimsp(struct spec *sp1, struct spec *sp2) {
25     register char *cp;
26     register int len;
27 
28     len = S_L(sp2);
29     cp = S_SP(sp2) + len - 1;
30 
31     while (len > 0 && isspace((unsigned char)*cp)) {
32 	len--;
33 	cp--;
34     }
35 
36     _SPEC(sp1) = _SPEC(sp2);
37     S_L(sp1) = len;
38 }
39 
40 void
raise1(struct spec * sp)41 raise1(struct spec *sp) {
42     register char *cp;
43     register int len;
44 
45     len = S_L(sp);
46     cp = S_SP(sp);
47 
48     while (len-- > 0) {
49 	if (islower((unsigned char)*cp))
50 	    *cp = toupper((unsigned char)*cp);
51 	cp++;
52     }
53 }
54 
55 /* 8/19/96 -- for GENVUP/VPXPTR */
56 int
raise2(struct spec * sp1,struct spec * sp2)57 raise2(struct spec *sp1, struct spec *sp2) {
58     register char *sp, *dp;
59     register int len;
60     register int raised;
61 
62     len = S_L(sp1);
63     sp = S_SP(sp1);
64     dp = S_SP(sp2);
65     raised = 0;
66 
67     while (len-- > 0) {
68 	if (islower((unsigned char)*sp)) {
69 	    *dp++ = toupper((unsigned char)*sp);
70 	    sp++;
71 	    raised++;
72 	}
73 	else
74 	    *dp++ = *sp++;
75     }
76     return raised > 0;
77 }
78 
79 /* support for LPAD/RPAD 8/26/96 */
80 int
pad(struct descr * dir,struct spec * out,struct spec * subj,struct spec * pad)81 pad(struct descr *dir,			/* LPAD=0,RPAD=1 */
82     struct spec *out,
83     struct spec *subj,
84     struct spec *pad) {
85     int npad;
86     size_t slen;
87     char *dp;
88     char pc;
89 
90     slen = S_L(subj);
91     npad = S_L(out) - slen;
92     dp = S_SP(out);
93 
94     if (S_L(pad) == 0)			/* null string */
95 	pc = ' ';			/* default to space */
96     else
97 	pc = *S_SP(pad);
98 
99     if (D_A(dir) == 0) {		/* LPAD */
100 	while (npad-- > 0)
101 	    *dp++ = pc;
102     }
103 
104     memcpy(dp, S_SP(subj), slen);
105     dp += slen;
106 
107     if (D_A(dir) != 0) {		/* RPAD */
108 	while (npad-- > 0)
109 	    *dp++ = pc;
110     }
111 
112     return 0;
113 }
114 
115 /* support for REVERSE 9/18/96 */
116 int
reverse(struct spec * dest,struct spec * src)117 reverse(struct spec *dest, struct spec *src) {
118     register char *sp, *dp;
119     register int len;
120 
121     len = S_L(src);
122     sp = S_SP(src) + len;
123     dp = S_SP(dest);
124 
125     while (len--) {
126 	*dp++ =  *--sp;
127     }
128     return 0;
129 }
130 
131 /* support for SUBSTR 9/18/96 */
132 int
substr(struct spec * dest,struct spec * src,struct descr * pos)133 substr(struct spec *dest, struct spec *src, struct descr *pos) {
134     register char *sp, *dp;
135     register int len;
136 
137     sp = S_SP(src) + D_A(pos);
138     dp = S_SP(dest);
139     len = S_L(dest);
140 
141     while (len--) {
142 	*dp++ =  *sp++;
143     }
144     return 0;
145 }
146 
147 /* copy from specifier to c-string */
148 void
spec2str(struct spec * sp,char * dest,int size)149 spec2str(struct spec *sp, char *dest, int size) {
150     int l;
151 
152     l = S_L(sp);
153     if (l > size-1)
154 	l = size-1;
155 
156     strncpy(dest, S_SP(sp), l);
157     dest[l] = '\0';
158 }
159 
160 /* 2/15/2012 */
161 /* copy from specifier to c-string */
162 char *
mspec2str(struct spec * sp)163 mspec2str(struct spec *sp) {
164     int l = S_L(sp) + 1;
165     char *str = malloc(l);
166     if (str)
167 	spec2str(sp, str, l);
168     return str;
169 }
170 
171 /*  6/12/98 */
172 
173 /*#define APDSP_NLENS 4096*/
174 #ifdef APDSP_NLENS
175 int apdsp_lens[APDSP_NLENS];
176 #endif /* APDSP_NLENS defined */
177 
178 void
apdsp(struct spec * base,struct spec * str)179 apdsp(struct spec *base, struct spec *str) {
180     size_t len;
181     register char *src, *dst;
182 
183     len = S_L(str);
184     src = S_SP(str);
185     dst = S_SP(base)+S_L(base);
186 
187 #ifdef APDSP_NLENS
188     if (len > APDSP_NLENS)
189 	apdsp_lens[APDSP_NLENS-1]++;
190     else
191 	apdsp_lens[len]++;
192 #endif /* APDSP_NLENS defined */
193 
194     S_L(base) += len;
195 
196 #define THRESH 4
197     if (len >= THRESH) {		/* XXX also check alignment? */
198 	memcpy(dst, src, len);
199     }
200     else {
201 	while (len > 0) {
202 	    *dst++ = *src++;
203 	    len--;
204 	}
205     }
206 }
207 
208 /* added 3/4/2012 */
209 char *
strjoin(const char * str0,...)210 strjoin(const char *str0, ...) {
211     va_list vp;
212     int len;
213     char *str;
214     const char *tp;
215 
216     va_start(vp, str0);
217     len = strlen(str0) + 1;
218     while ((tp = va_arg(vp, const char *)))
219 	len += strlen(tp);
220     va_end(vp);
221 
222     str = malloc(len);
223     if (!str)
224 	return NULL;
225 
226     va_start(vp, str0);
227     strcpy(str, str0);
228     while ((tp = va_arg(vp, const char *)))
229 	strcat(str, tp);
230     va_end(vp);
231     return str;
232 }
233 
234 #ifdef BLOCKS
235 /* for BLOCKS; translated from the BAL macro 9/26/2013 */
236 /*
237 #define DEBUG_MERGSP
238 #define DEBUG_MERGSP2
239 */
240 #ifdef DEBUG_MERGSP2
241 #define DUMP(S,L) dump(#S, S, L)
242 static void
dump(char * n,char * s,int l)243 dump(char *n, char *s, int l) {
244     fprintf(stderr, "%-4s '", n);
245     while (l-- > 0) {
246 	char c = *s++;
247 	if (c == '\0') c = '~';
248 	fputc(c, stderr);
249     }
250     fprintf(stderr, "'\n");
251 }
252 #else
253 #define DUMP(S,L)
254 #endif
255 
256 void
mergsp(struct spec * sp1,struct spec * sp2,struct spec * sp3)257 mergsp(struct spec *sp1, struct spec *sp2, struct spec *sp3) {
258     int len = S_L(sp2);			/* GR1 "length" */
259     char *dest = S_SP(sp1);		/* GR2 "first string" */
260     char *src = S_SP(sp2);		/* GR3 "2nd string" */
261     char bg = *S_SP(sp3);		/* GR4 "background" */
262     char c;				/* GR5 */
263 #ifdef DEBUG_MERGSP
264     fprintf(stderr, "mergsp len %d bg '%c'\n", len, bg);
265 #endif
266     if (len < 1)
267 	return;
268     DUMP(src, len);
269     DUMP(dest, len);
270     do {
271 	--len;
272 	c = src[len];
273 	if (c != bg)
274 	    dest[len] = c;
275     } while (len > 0);
276     DUMP(dest, S_L(sp2));
277 }
278 
279 /* 10/11/2013 BLOCKS BLAND routine requires BLT-like behavior! */
280 void
movblk2(struct descr * d1,struct descr * d2,int_t len)281 movblk2(struct descr *d1, struct descr *d2, int_t len) {
282     while (len > 0) {
283 	*++d1 = *++d2;
284 	len -= DESCR;
285     }
286 }
287 #endif /* BLOCKS */
288