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