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