File:  [Coherent Logic Development] / freem / src / strings.c
Revision 1.8: download - view: text, annotated - select for diffs
Thu May 1 17:02:30 2025 UTC (3 months ago) by snw
Branches: MAIN
CVS tags: HEAD
Further debugging improvements

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>