File:  [Coherent Logic Development] / freem / src / strings.c
Revision 1.2: download - view: text, annotated - select for diffs
Sun Mar 9 15:20:18 2025 UTC (7 months, 1 week ago) by snw
Branches: MAIN
CVS tags: HEAD
Begin formatting overhaul and REUSE compliance

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

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