1: /*
2: * $Id: strings.c,v 1.4 2025/04/09 19:52:02 snw Exp $
3: * freem string library
4: *
5: *
6: * Author: Serena Willis <snw@coherent-logic.com>
7: * Copyright (C) 1998 MUG Deutschland
8: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
26: * $Log: strings.c,v $
27: * Revision 1.4 2025/04/09 19:52:02 snw
28: * Eliminate as many warnings as possible while building with -Wall
29: *
30: * Revision 1.3 2025/03/09 19:50:47 snw
31: * Second phase of REUSE compliance and header reformat
32: *
33: *
34: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
35: * SPDX-License-Identifier: AGPL-3.0-or-later
36: **/
37:
38: #include "mpsdef.h"
39: #include <ctype.h>
40: #include <stdarg.h>
41: #include <string.h>
42: #include <stdlib.h>
43:
44: /* length of 'source' string in bytes */
45: long int stlen (const char *source)
46: {
47: register int length = 0;
48:
49: while (*source++ != EOL) length++;
50:
51: return length;
52: }
53:
54: long int stnlen (const char *source, size_t siz)
55: {
56: register int length = 0;
57:
58: while ((*source++ != EOL) && (length < siz)) length++;
59:
60: return length;
61: }
62:
63: /* copy string from 'source' to 'dest' */
64: long int stcpy (char *dest, const char *source)
65: {
66: register int count = 0;
67:
68: while ((*dest++ = *source++) != EOL) count++;
69:
70: return count;
71: }
72:
73: long int stncpy (char *dest, const char *source, size_t siz)
74: {
75: register int count = 0;
76:
77: while (((*dest++ = *source++) != EOL) && (count < siz)) count++;
78:
79: return count;
80: }
81:
82:
83: /* copy exactly 'length' characters from source to dest */
84: void stcpy0 (char *dest, const char *source, long length)
85: {
86: while (length-- > 0) *dest++ = *source++;
87:
88: return;
89: }
90:
91:
92: /* copy exactly 'length' characters from source to dest*/
93: void stcpy1 (char *dest, const char *source, long length)
94: {
95: while (length-- > 0) *dest-- = *source--;
96:
97: return;
98: }
99:
100:
101: /* concatenate string from 'source' to the end of 'dest' */
102: short int stcat (char *dest, const char *source)
103: {
104: register int i = 0;
105:
106: while (dest[i++] != EOL);
107:
108: i--;
109:
110: while ((dest[i] = *source++) != EOL) {
111:
112: if (i++ >= STRLEN) {
113: //printf("i = %d\r\n", i);
114: dest[--i] = EOL;
115: return FALSE;
116: }
117:
118: }
119:
120: return TRUE;
121: }
122:
123: /* compare str1 and str2 */
124: short int stcmp (char *str1, char *str2)
125: {
126: while (*str1 == *str2) {
127:
128: if (*str1 == EOL) return 0;
129:
130: str1++;
131: str2++;
132:
133: }
134:
135: return *str1 - *str2;
136: }
137:
138: /* trim whitespace from string 's' */
139: char *trim (char *s)
140: {
141:
142: char *t = strdup (s);
143: char *end;
144: char *result;
145: int final_len;
146:
147: if (t == NULL) return NULL;
148:
149: while (isspace ((unsigned char) *t)) t++;
150:
151: if (*t == 0) return t;
152:
153: end = t + strlen (t) - 1;
154:
155: while (end > t && isspace ((unsigned char) *end)) end--;
156:
157: end[1] = '\0';
158:
159: /* recover waste ('t' still occupies the same heap
160: * as it did before the whitespace was stripped)
161: */
162:
163: final_len = strlen (t);
164: result = (char *) malloc ((final_len + 1) * sizeof (char));
165:
166: if (result == NULL) return NULL;
167:
168: strcpy (result, t);
169: free (t);
170:
171: return result;
172:
173: }
174:
175:
176: /* convert EOL-terminated string 'mstr' to NUL-terminated string in-place */
177: void stcnv_m2c(char *mstr)
178: {
179: mstr[stlen(mstr)] = NUL;
180: }
181:
182: void stncnv_m2c(char *mstr, size_t siz)
183: {
184: mstr[stnlen (mstr, siz)] = NUL;
185: }
186:
187: /* convert NUL-terminated string 'cstr' to EOL-terminated string in-place */
188: void stcnv_c2m(char *cstr)
189: {
190: register int i;
191:
192: for(i = 0; i < 256; i++) {
193:
194: if(cstr[i] == '\0') {
195: cstr[i] = '\201';
196:
197: return;
198: }
199:
200: }
201: }
202:
203: void stncnv_c2m(char *cstr, size_t siz)
204: {
205: register int i;
206:
207: for (i = 0; i < siz; i++) {
208:
209: if (cstr[i] == NUL) {
210: cstr[i] = EOL;
211: return;
212: }
213:
214: }
215:
216: return;
217: }
218:
219: /* convert at most 'count' characters of *key into human-readable format in *buf */
220: size_t key_to_name(char *buf, const char *key, size_t count)
221: {
222: size_t i;
223: int j = 0;
224: int first = 1;
225: int has_subs = 0;
226: int in_strlit = 0;
227: char c;
228: char next;
229:
230: if (key[0] == NUL) {
231: buf[0] = NUL;
232:
233: return 0;
234: }
235:
236: buf[0] = '^';
237:
238: for (i = 0; i < count; i++) {
239:
240: c = key[i];
241: next = key[i + 1];
242:
243: switch (c) {
244:
245: case EOL:
246:
247: if (first == 0) {
248:
249: if (has_subs == 1) {
250:
251: if (!in_strlit) {
252: buf[j++] = ')';
253: buf[j] = NUL;
254: }
255: else {
256: buf[j++] = '\"';
257: buf[j++] = ')';
258: buf[j] = NUL;
259: }
260:
261: }
262: else {
263: buf[j] = NUL;
264: }
265:
266: }
267: else {
268: buf[j] = NUL;
269: }
270:
271: return i;
272:
273:
274: case DELIM:
275:
276: if (first == 1) {
277:
278: buf[j] = '(';
279: first = 0;
280: has_subs = 1;
281:
282: }
283: else {
284:
285: if (!in_strlit) {
286: buf[j] = ',';
287: }
288: else {
289:
290: buf[j++] = '\"';
291: buf[j] = ',';
292:
293: in_strlit = 0;
294:
295: }
296:
297: }
298:
299: if (isalpha(next) && !in_strlit) {
300: in_strlit = 1;
301: buf[++j] = '\"';
302: }
303: else if (in_strlit) {
304: in_strlit = 0;
305: buf[++j] = '\"';
306: }
307:
308: break;
309:
310:
311: default:
312: buf[j] = key[i];
313: break;
314: }
315:
316: j++;
317: }
318:
319: return count;
320:
321: }
322:
323: size_t name_to_key(char *buf, const char *name, size_t count)
324: {
325: size_t i;
326: size_t j = 0;
327:
328: short insubs = FALSE;
329: short instr = FALSE;
330:
331: char ch;
332:
333: for (i = 0; i < count; i++) buf[i] = NUL;
334:
335: for (i = 0; i < count; i++) {
336:
337: ch = name[i];
338:
339: switch (ch) {
340:
341: case EOL:
342: buf[j] = ch;
343: goto n_to_k_done;
344:
345: case '(':
346: if (insubs == FALSE && instr == FALSE) {
347: insubs = TRUE;
348: buf[j++] = DELIM;
349: }
350: else {
351: if (instr == TRUE) {
352: buf[j++] = ch;
353: }
354: }
355: break;
356:
357:
358: case ')':
359: if (insubs == TRUE && instr == FALSE) {
360: buf[j] = EOL;
361:
362: goto n_to_k_done;
363: }
364: else {
365: if (insubs == TRUE && instr == TRUE) {
366: buf[j++] = ch;
367: }
368: }
369: break;
370:
371:
372: case ',':
373: if (insubs == TRUE && instr == FALSE) {
374: if (buf[j - 1] != DELIM) {
375: buf[j++] = DELIM;
376: }
377: }
378: else if (insubs == TRUE && instr == TRUE) {
379: buf[j++] = ch;
380: }
381:
382: break;
383:
384:
385: case '"':
386:
387: if (insubs == TRUE && instr == FALSE) {
388: instr = TRUE;
389:
390: if (buf[j - 1] != DELIM) {
391: buf[j++] = DELIM;
392: }
393:
394: break;
395: }
396:
397: if (instr == TRUE) {
398: instr = FALSE;
399: buf[j++] = DELIM;
400: }
401:
402: break;
403:
404:
405: default:
406: buf[j++] = ch;
407: break;
408: }
409:
410: }
411:
412: n_to_k_done:
413:
414: return j;
415:
416: }
417:
418: void create_var_key (char *buf, int subct, char *nam, ...)
419: {
420: int i;
421: va_list args;
422:
423: strcat (buf, nam);
424: strcat (buf, "\202");
425:
426: va_start (args, nam);
427:
428: for (i = 0; i < subct; i++) {
429:
430: strcat (buf, va_arg (args, char *));
431:
432: if (i < (subct - 1)) strcat (buf, "\202");
433:
434: }
435:
436: va_end (args);
437:
438: strcat (buf, "\201");
439: }
440:
441: void trim_decimal (char *s)
442: {
443: register int i;
444:
445: for (i = stlen (s) - 1; s[i] == '0'; i--) s[i] = EOL;
446:
447: if (s[i] == '.') s[i] = EOL;
448: }
449:
450: void uuid_v4 (char *buf)
451: {
452:
453: char *chars = "0123456789abcdef";
454: int seg3num;
455: int seg4num;
456: int i;
457:
458: char seg1[9];
459: char seg2[5];
460: char seg3[5];
461: char seg4[5];
462: char seg5[13];
463:
464: seg3num = (rand () % 4095) + 16384;
465: seg4num = (rand () % 16383) + 32768;
466:
467: for (i = 0; i < 9; i++) {
468: seg1[i] = chars[rand () % 16];
469: }
470:
471: seg1[8] = '\0';
472:
473: for (i = 0; i < 4; i++) {
474: seg2[i] = chars[rand () % 16];
475: }
476:
477: seg2[4] = '\0';
478:
479: snprintf (seg3, 5, "%04x", seg3num);
480: snprintf (seg4, 5, "%04x", seg4num);
481:
482: for (i = 0; i < 12; i++) {
483: seg5[i] = chars[rand () % 16];
484: }
485:
486: seg5[12] = '\0';
487:
488: sprintf (buf, "%s-%s-%s-%s-%s", seg1, seg2, seg3, seg4, seg5);
489:
490: return;
491:
492: }
493:
494:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>