Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1126 savelij 1
/* strutil.c */
2
/*****************************************************************************/
3
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
4
/*                                                                           */
5
/* AS-Portierung                                                             */
6
/*                                                                           */
7
/* haeufig benoetigte String-Funktionen                                      */
8
/*                                                                           */
9
/*****************************************************************************/
10
 
11
#include "stdinc.h"
12
#include <ctype.h>
13
#include <string.h>
14
#include <stdarg.h>
15
#include <assert.h>
16
 
17
#include "dynstr.h"
18
#include "strutil.h"
19
#undef strlen   /* VORSICHT, Rekursion!!! */
20
 
21
char HexStartCharacter;     /* characters to use for 10,11,...35 */
22
char SplitByteCharacter;    /* output large numbers per-byte with given split char */
23
 
24
/*--------------------------------------------------------------------------*/
25
/* eine bestimmte Anzahl Leerzeichen liefern */
26
 
27
const char *Blanks(int cnt)
28
{
29
  static const char *BlkStr = "                                                                                                           ";
30
  static int BlkStrLen = 0;
31
 
32
  if (!BlkStrLen)
33
    BlkStrLen = strlen(BlkStr);
34
 
35
  if (cnt < 0)
36
    cnt = 0;
37
  if (cnt > BlkStrLen)
38
    cnt = BlkStrLen;
39
 
40
  return BlkStr + (BlkStrLen - cnt);
41
}
42
 
43
/*!------------------------------------------------------------------------
44
 * \fn     SysString(char *pDest, size_t DestSize, LargeWord i, int System, int Stellen, Boolean ForceLeadZero, char StartCharacter, char SplitCharacter)
45
 * \brief  convert number to string in given number system, leading zeros
46
 * \param  pDest where to write
47
 * \param  DestSize size of dest buffer
48
 * \param  i number to convert
49
 * \param  Stellen minimum length of output
50
 * \param  ForceLeadZero prepend zero if first character is no number
51
 * \param  System number system
52
 * \param  StartCharacter 'a' or 'A' for hex digits
53
 * \param  SplitCharacter split bytes if not NUL
54
 * ------------------------------------------------------------------------ */
55
 
56
char *SysStringCore(char *pDest, char *pDestCurr, LargeWord Num, int System, int Stellen, char StartCharacter)
57
{
58
  LargeWord Digit;
59
 
60
  do
61
  {
62
    if (pDestCurr <= pDest)
63
      break;
64
    Digit = Num % System;
65
    if (Digit < 10)
66
      *(--pDestCurr) = Digit + '0';
67
    else
68
      *(--pDestCurr) = Digit - 10 + StartCharacter;
69
    Num /= System;
70
    Stellen--;
71
  }
72
  while ((Stellen > 0) || Num);
73
  return pDestCurr;
74
}
75
 
76
int SysString(char *pDest, size_t DestSize, LargeWord Num, int System, int Stellen, Boolean ForceLeadZero, char StartCharacter, char SplitCharacter)
77
{
78
  int Len = 0;
79
  char *pDestCurr, *pDestNext;
80
 
81
  if (DestSize < 1)
82
    return 0;
83
 
84
  if (Stellen > (int)DestSize - 1)
85
    Stellen = DestSize - 1;
86
 
87
  pDestCurr = pDest + DestSize - 1;
88
  *pDestCurr = '\0';
89
  if (SplitCharacter)
90
  {
91
    LargeWord Part;
92
    int ThisLen;
93
    static int SystemByteLen[37];
94
 
95
    if (!SystemByteLen[System])
96
    {
97
      char Dummy[50];
98
 
99
      SystemByteLen[System] = SysString(Dummy, sizeof(Dummy), 0xff, System, 0, False, StartCharacter, False);
100
    }
101
 
102
    do
103
    {
104
      Part = Num % 256;
105
      Num = Num / 256;
106
      pDestNext = SysStringCore(pDest, pDestCurr, Part, System, Num ? SystemByteLen[System] : Stellen, StartCharacter);
107
      ThisLen = pDestCurr - pDestNext;
108
      Len += ThisLen;
109
      pDestCurr = pDestNext;
110
      Stellen -= ThisLen;
111
      if (Num)
112
      {
113
        if (pDestCurr <= pDest)
114
          break;
115
        *(--pDestCurr) = SplitCharacter;
116
        Len++;
117
      }
118
    }
119
    while ((Stellen > 0) || Num);
120
  }
121
  else
122
  {
123
    pDestNext = SysStringCore(pDest, pDestCurr, Num, System, Stellen, StartCharacter);
124
    Len += pDestCurr - pDestNext;
125
    pDestCurr = pDestNext;
126
  }
127
 
128
  if (ForceLeadZero && !isdigit(*pDestCurr) && (pDestCurr > pDest))
129
  {
130
    *(--pDestCurr) = '0';
131
    Len++;
132
  }
133
 
134
  if (pDestCurr != pDest)
135
    strmov(pDest, pDestCurr);
136
  return Len;
137
}
138
 
139
/*---------------------------------------------------------------------------*/
140
/* strdup() is not part of ANSI C89 */
141
 
142
char *as_strdup(const char *s)
143
{
144
  char *ptr;
145
 
146
  if (!s)
147
    return NULL;
148
  ptr = (char *) malloc(strlen(s) + 1);
149
#ifdef CKMALLOC
150
  if (!ptr)
151
  {
152
    fprintf(stderr, "strdup: out of memory?\n");
153
    exit(255);
154
  }
155
#endif
156
  if (ptr != 0)
157
    strcpy(ptr, s);
158
  return ptr;
159
}
160
/*---------------------------------------------------------------------------*/
161
/* ...so is snprintf... */
162
 
163
typedef enum { eNotSet, eSet, eFinished } tArgState;
164
 
165
typedef struct
166
{
167
  tArgState ArgState[3];
168
  Boolean InFormat, LeadZero, Signed, LeftAlign, AddPlus, ForceLeadZero, ForceUpper;
169
  int Arg[3], CurrArg, IntSize;
170
} tFormatContext;
171
 
172
typedef struct
173
{
174
  char *p_dest;
175
  size_t dest_remlen;
176
  as_dynstr_t *p_dynstr;
177
} dest_format_context_t;
178
 
179
static void ResetFormatContext(tFormatContext *pContext)
180
{
181
  int z;
182
 
183
  for (z = 0; z < 3; z++)
184
  {
185
    pContext->Arg[z] = 0;
186
    pContext->ArgState[z] = eNotSet;
187
  }
188
  pContext->CurrArg = 0;
189
  pContext->IntSize = 0;
190
  pContext->InFormat =
191
  pContext->LeadZero =
192
  pContext->ForceLeadZero =
193
  pContext->Signed =
194
  pContext->LeftAlign =
195
  pContext->AddPlus =
196
  pContext->ForceUpper = False;
197
}
198
 
199
/*!------------------------------------------------------------------------
200
 * \fn     limit_minus_one(dest_format_context_t *p_dest_ctx, size_t cnt)
201
 * \brief  check if space is left to append given # of characters, plus trailing NUL
202
 * \param  p_dest_ctx destination context
203
 * \param  cnt requested # of characters to append
204
 * \return actual # that can be appended
205
 * ------------------------------------------------------------------------ */
206
 
207
static size_t limit_minus_one(dest_format_context_t *p_dest_ctx, size_t cnt)
208
{
209
  /* anyway still enough space? */
210
 
211
  if (p_dest_ctx->dest_remlen > cnt)
212
    return cnt;
213
 
214
  /* not enough space: try to realloc dynamic string dest */
215
 
216
  if (p_dest_ctx->p_dynstr)
217
  {
218
    size_t curr_len = p_dest_ctx->p_dest - p_dest_ctx->p_dynstr->p_str;
219
    size_t new_capacity = as_dynstr_roundup_len(curr_len + cnt + 1);
220
 
221
    /* if realloc successful, pointer into string buffer must be adapted: */
222
 
223
    if (!as_dynstr_realloc(p_dest_ctx->p_dynstr, new_capacity))
224
    {
225
      p_dest_ctx->p_dest = p_dest_ctx->p_dynstr->p_str + curr_len;
226
      p_dest_ctx->dest_remlen = p_dest_ctx->p_dynstr->capacity - curr_len;
227
    }
228
  }
229
 
230
  /* pathological case... */
231
 
232
  if (!p_dest_ctx->dest_remlen)
233
    return 0;
234
 
235
  /* truncation */
236
 
237
  else
238
    return (cnt >= p_dest_ctx->dest_remlen) ? p_dest_ctx->dest_remlen - 1 : cnt;
239
}
240
 
241
/*!------------------------------------------------------------------------
242
 * \fn     append_pad(dest_format_context_t *p_dest_ctx, char src, size_t cnt)
243
 * \brief  append given character n times
244
 * \param  p_dest_ctx destination context
245
 * \param  src character to append
246
 * \param  cnt # of times to append
247
 * \return actual # of characters appended
248
 * ------------------------------------------------------------------------ */
249
 
250
static size_t append_pad(dest_format_context_t *p_dest_ctx, char src, size_t cnt)
251
{
252
  cnt = limit_minus_one(p_dest_ctx, cnt);
253
 
254
  if (cnt > 0)
255
  {
256
    memset(p_dest_ctx->p_dest, src, cnt);
257
    p_dest_ctx->p_dest += cnt;
258
    p_dest_ctx->dest_remlen -= cnt;
259
  }
260
  return cnt;
261
}
262
 
263
#if 0
264
static int FloatConvert(char *pDest, size_t DestSize, double Src, int Digits, Boolean TruncateTrailingZeros, char FormatType)
265
{
266
  int DecPt;
267
  int Sign, Result = 0;
268
  char *pBuf, *pEnd, *pRun;
269
 
270
  (void)FormatType;
271
 
272
  if (DestSize < Digits + 6)
273
  {
274
    *pDest = '\0';
275
    return Result;
276
  }
277
 
278
  if (Digits < 0)
279
    Digits = 6;
280
 
281
  pBuf = ecvt(Src, Digits + 1, &DecPt, &Sign);
282
  puts(pBuf);
283
  pEnd = pBuf + strlen(pBuf) - 1;
284
  if (TruncateTrailingZeros)
285
  {
286
    for (; pEnd > pBuf + 1; pEnd--)
287
      if (*pEnd != '0')
288
        break;
289
  }
290
 
291
  pRun = pDest;
292
  if (Sign)
293
    *pRun++ = '-';
294
  *pRun++ = *pBuf;
295
  *pRun++ = '.';
296
  memcpy(pRun, pBuf + 1, pEnd - pBuf); pRun += pEnd - pBuf;
297
  *pRun = '\0';
298
  Result = pRun - pDest;
299
  Result += as_snprintf(pRun, DestSize - Result, "e%+02d", DecPt - 1);
300
  return Result;
301
}
302
#else
303
static int FloatConvert(char *pDest, size_t DestSize, double Src, int Digits, Boolean TruncateTrailingZeros, char FormatType)
304
{
305
  char Format[10];
306
 
307
  (void)DestSize;
308
  (void)TruncateTrailingZeros;
309
  strcpy(Format, "%0.*e");
310
  Format[4] = (HexStartCharacter == 'a') ? FormatType : toupper(FormatType);
311
  sprintf(pDest, Format, Digits, Src);
312
  return strlen(pDest);
313
}
314
#endif
315
 
316
/*!------------------------------------------------------------------------
317
 * \fn     append(dest_format_context_t *p_dest_ctx, const char *p_src, size_t cnt, tFormatContext *pFormatContext)
318
 * \brief  append given data, with possible left/right padding
319
 * \param  p_dest_ctx destination context
320
 * \param  p_src data to append
321
 * \param  cnt length of data to append
322
 * \param  pFormatContext formatting context
323
 * \return actual # of characters appended
324
 * ------------------------------------------------------------------------ */
325
 
326
static size_t append(dest_format_context_t *p_dest_ctx, const char *p_src, size_t cnt, tFormatContext *pFormatContext)
327
{
328
  size_t pad_len, result = 0;
329
 
330
  pad_len = (pFormatContext->Arg[0] > (int)cnt) ? pFormatContext->Arg[0] - cnt : 0;
331
 
332
  if ((pad_len > 0) && !pFormatContext->LeftAlign)
333
    result += append_pad(p_dest_ctx, ' ', pad_len);
334
 
335
  cnt = limit_minus_one(p_dest_ctx, cnt);
336
  if (cnt > 0)
337
  {
338
    memcpy(p_dest_ctx->p_dest, p_src, cnt);
339
    p_dest_ctx->p_dest += cnt;
340
    p_dest_ctx->dest_remlen -= cnt;
341
  }
342
 
343
  if ((pad_len > 0) && pFormatContext->LeftAlign)
344
    result += append_pad(p_dest_ctx, ' ', pad_len);
345
 
346
  if (pFormatContext->InFormat)
347
    ResetFormatContext(pFormatContext);
348
 
349
  return result + cnt;
350
}
351
 
352
/*!------------------------------------------------------------------------
353
 * \fn     vsprcatf_core(dest_format_context_t *p_dest_ctx, const char *pFormat, va_list ap)
354
 * \brief  The actual core routine to process the format string
355
 * \param  p_dest_ctx context describing destination
356
 * \param  pFormat format specifier
357
 * \param  ap format arguments
358
 * \return # of characters appended
359
 * ------------------------------------------------------------------------ */
360
 
361
static int vsprcatf_core(dest_format_context_t *p_dest_ctx, const char *pFormat, va_list ap)
362
{
363
  const char *pFormatStart = pFormat;
364
  int Result = 0;
365
  size_t OrigLen = strlen(p_dest_ctx->p_dest);
366
  tFormatContext FormatContext;
367
  LargeInt IntArg;
368
 
369
  if (p_dest_ctx->dest_remlen > OrigLen)
370
    p_dest_ctx->dest_remlen -= OrigLen;
371
  else
372
    p_dest_ctx->dest_remlen = 0;
373
  p_dest_ctx->p_dest += OrigLen;
374
 
375
  ResetFormatContext(&FormatContext);
376
  for (; *pFormat; pFormat++)
377
    if (FormatContext.InFormat)
378
      switch (*pFormat)
379
      {
380
        case '0': case '1': case '2': case '3': case '4':
381
        case '5': case '6': case '7': case '8': case '9':
382
        {
383
          if (!FormatContext.CurrArg && !FormatContext.ArgState[FormatContext.CurrArg] && (*pFormat == '0'))
384
            FormatContext.LeadZero = True;
385
          FormatContext.Arg[FormatContext.CurrArg] = (FormatContext.Arg[FormatContext.CurrArg] * 10) + (*pFormat - '0');
386
          FormatContext.ArgState[FormatContext.CurrArg] = eSet;
387
          break;
388
        }
389
        case '-':
390
          if (!FormatContext.CurrArg && !FormatContext.ArgState[FormatContext.CurrArg])
391
            FormatContext.LeftAlign = True;
392
          break;
393
        case '+':
394
          FormatContext.AddPlus = True;
395
          break;
396
        case '~':
397
          FormatContext.ForceLeadZero = True;
398
          break;
399
        case '*':
400
          FormatContext.Arg[FormatContext.CurrArg] = va_arg(ap, int);
401
          FormatContext.ArgState[FormatContext.CurrArg] = eFinished;
402
          break;
403
        case '.':
404
          if (FormatContext.CurrArg < 3)
405
            FormatContext.CurrArg++;
406
          break;
407
        case 'c':
408
        {
409
          char ch = va_arg(ap, int);
410
 
411
          Result += append(p_dest_ctx, &ch, 1, &FormatContext);
412
          break;
413
        }
414
        case '%':
415
          Result += append(p_dest_ctx, "%", 1, &FormatContext);
416
          break;
417
        case 'l':
418
        {
419
          FormatContext.IntSize++;
420
          FormatContext.CurrArg = 2;
421
          break;
422
        }
423
        case 'd':
424
        {
425
          if (FormatContext.IntSize >= 3)
426
            IntArg = va_arg(ap, LargeInt);
427
          else
428
#ifndef NOLONGLONG
429
          if (FormatContext.IntSize >= 2)
430
            IntArg = va_arg(ap, long long);
431
          else
432
#endif
433
          if (FormatContext.IntSize >= 1)
434
            IntArg = va_arg(ap, long);
435
          else
436
            IntArg = va_arg(ap, int);
437
          FormatContext.Arg[1] = 10;
438
          FormatContext.Signed = True;
439
          goto IntCommon;
440
        }
441
        case 'u':
442
        {
443
          if (FormatContext.IntSize >= 3)
444
            IntArg = va_arg(ap, LargeWord);
445
          else
446
#ifndef NOLONGLONG
447
          if (FormatContext.IntSize >= 2)
448
            IntArg = va_arg(ap, unsigned long long);
449
          else
450
#endif
451
          if (FormatContext.IntSize >= 1)
452
            IntArg = va_arg(ap, unsigned long);
453
          else
454
            IntArg = va_arg(ap, unsigned);
455
          goto IntCommon;
456
        }
457
        case 'x':
458
        case 'X':
459
        {
460
          if (FormatContext.IntSize >= 3)
461
            IntArg = va_arg(ap, LargeWord);
462
          else
463
#ifndef NOLONGLONG
464
          if (FormatContext.IntSize >= 2)
465
            IntArg = va_arg(ap, unsigned long long);
466
          else
467
#endif
468
          if (FormatContext.IntSize)
469
            IntArg = va_arg(ap, unsigned long);
470
          else
471
            IntArg = va_arg(ap, unsigned);
472
          FormatContext.Arg[1] = 16;
473
          FormatContext.ForceUpper = as_isupper(*pFormat);
474
          goto IntCommon;
475
        }
476
        IntCommon:
477
        {
478
          char Str[100], *pStr = Str;
479
          int Cnt;
480
          int NumPadZeros = 0;
481
 
482
          if (FormatContext.Signed)
483
          {
484
            if (IntArg < 0)
485
            {
486
              *pStr++ = '-';
487
              IntArg = 0 - IntArg;
488
            }
489
            else if (FormatContext.AddPlus)
490
              *pStr++ = '+';
491
          }
492
          if (FormatContext.LeadZero)
493
          {
494
            NumPadZeros = FormatContext.Arg[0];
495
            FormatContext.Arg[0] = 0;
496
          }
497
          Cnt = (pStr - Str)
498
              + SysString(pStr, sizeof(Str) - (pStr - Str), IntArg,
499
                          FormatContext.Arg[1] ? FormatContext.Arg[1] : 10,
500
                          NumPadZeros, FormatContext.ForceLeadZero,
501
                          FormatContext.ForceUpper ? 'A' : HexStartCharacter,
502
                          SplitByteCharacter);
503
          if (Cnt > (int)sizeof(Str))
504
            Cnt = sizeof(Str);
505
          Result += append(p_dest_ctx, Str, Cnt, &FormatContext);
506
          break;
507
        }
508
        case 'e':
509
        case 'f':
510
        case 'g':
511
        {
512
          char Str[100];
513
          int Cnt;
514
 
515
          Cnt = FloatConvert(Str, sizeof(Str), va_arg(ap, double), FormatContext.Arg[1], False, *pFormat);
516
          if (Cnt > (int)sizeof(Str))
517
            Cnt = sizeof(Str);
518
          Result += append(p_dest_ctx, Str, Cnt, &FormatContext);
519
          break;
520
        }
521
        case 's':
522
        {
523
          const char *pStr = va_arg(ap, char*);
524
          size_t cnt = FormatContext.Arg[1]
525
                     ? as_strnlen(pStr, FormatContext.Arg[1])
526
                     : strlen(pStr);
527
 
528
          Result += append(p_dest_ctx, pStr, cnt, &FormatContext);
529
          break;
530
        }
531
        default:
532
          fprintf(stderr, "invalid format: '%c' in '%s'\n", *pFormat, pFormatStart);
533
          exit(255);
534
      }
535
    else if (*pFormat == '%')
536
      FormatContext.InFormat = True;
537
    else
538
      Result += append(p_dest_ctx, pFormat, 1, &FormatContext);
539
 
540
  if (p_dest_ctx->dest_remlen > 0)
541
    *(p_dest_ctx->p_dest++) = '\0';
542
  return Result;
543
}
544
 
545
/*!------------------------------------------------------------------------
546
 * \fn     as_vsdprcatf(as_dynstr_t *p_dest, const char *pFormat, va_list ap)
547
 * \brief  append to dynamic string by format
548
 * \param  p_dest string to be appended to
549
 * \param  pFormat format specifier
550
 * \param  ap format arguments
551
 * \return # of characters appended
552
 * ------------------------------------------------------------------------ */
553
 
554
int as_vsdprcatf(as_dynstr_t *p_dest, const char *pFormat, va_list ap)
555
{
556
  dest_format_context_t ctx;
557
 
558
  ctx.p_dest = p_dest->p_str;
559
  ctx.dest_remlen = p_dest->capacity;
560
  ctx.p_dynstr = p_dest;
561
  return vsprcatf_core(&ctx, pFormat, ap);
562
}
563
 
564
/*!------------------------------------------------------------------------
565
 * \fn     as_vsdprintf(as_dynstr_t *p_dest, const char *pFormat, va_list ap)
566
 * \brief  print to dynamic string by format
567
 * \param  p_dest string to be appended to
568
 * \param  pFormat format specifier
569
 * \param  ap format arguments
570
 * \return # of characters written
571
 * ------------------------------------------------------------------------ */
572
 
573
int as_vsdprintf(as_dynstr_t *p_dest, const char *pFormat, va_list ap)
574
{
575
  if (p_dest->capacity > 0)
576
    p_dest->p_str[0] = '\0';
577
  return as_vsdprcatf(p_dest, pFormat, ap);
578
}
579
 
580
/*!------------------------------------------------------------------------
581
 * \fn     as_sdprcatf(as_dynstr_t *p_dest, const char *pFormat, ...)
582
 * \brief  append to dynamic string by format
583
 * \param  p_dest string to be appended to
584
 * \param  pFormat format specifier
585
 * \param  ... format arguments
586
 * \return # of characters written
587
 * ------------------------------------------------------------------------ */
588
 
589
int as_sdprcatf(as_dynstr_t *p_dest, const char *pFormat, ...)
590
{
591
  va_list ap;
592
  int ret;
593
 
594
  va_start(ap, pFormat);
595
  ret = as_vsdprcatf(p_dest, pFormat, ap);
596
  va_end(ap);
597
  return ret;
598
}
599
 
600
/*!------------------------------------------------------------------------
601
 * \fn     as_sdprintf(as_dynstr_t *p_dest, const char *pFormat, ...)
602
 * \brief  print to dynamic string by format
603
 * \param  p_dest string to be appended to
604
 * \param  pFormat format specifier
605
 * \param  ... format arguments
606
 * \return # of characters written
607
 * ------------------------------------------------------------------------ */
608
 
609
int as_sdprintf(as_dynstr_t *p_dest, const char *pFormat, ...)
610
{
611
  va_list ap;
612
  int ret;
613
 
614
  va_start(ap, pFormat);
615
  ret = as_vsdprintf(p_dest, pFormat, ap);
616
  va_end(ap);
617
  return ret;
618
}
619
 
620
/*!------------------------------------------------------------------------
621
 * \fn     as_vsnprcatf(char *pDest, size_t DestSize, const char *pFormat, va_list ap)
622
 * \brief  append to string by format
623
 * \param  pDest string to be appended to
624
 * \param  DestSize capacity of string
625
 * \param  pFormat format specifier
626
 * \param  ap format arguments
627
 * \return # of characters appended
628
 * ------------------------------------------------------------------------ */
629
 
630
int as_vsnprcatf(char *pDest, size_t DestSize, const char *pFormat, va_list ap)
631
{
632
  dest_format_context_t ctx;
633
 
634
  if (DestSize == sizeof(char*))
635
  {
636
    fprintf(stderr, "pointer size passed to as_vsnprcatf\n");
637
    exit(2);
638
  }
639
 
640
  ctx.p_dest = pDest;
641
  ctx.dest_remlen = DestSize;
642
  ctx.p_dynstr = NULL;
643
  return vsprcatf_core(&ctx, pFormat, ap);
644
}
645
 
646
/*!------------------------------------------------------------------------
647
 * \fn     as_vsnprintf(char *pDest, size_t DestSize, const char *pFormat, va_list ap)
648
 * \brief  print to string by format
649
 * \param  pDest string to be appended to
650
 * \param  DestSize capacity of string
651
 * \param  pFormat format specifier
652
 * \param  ap format arguments
653
 * \return # of characters written
654
 * ------------------------------------------------------------------------ */
655
 
656
int as_vsnprintf(char *pDest, size_t DestSize, const char *pFormat, va_list ap)
657
{
658
  if (DestSize > 0)
659
    *pDest = '\0';
660
  return as_vsnprcatf(pDest, DestSize, pFormat, ap);
661
}
662
 
663
/*!------------------------------------------------------------------------
664
 * \fn     as_snprintf(char *pDest, size_t DestSize, const char *pFormat, ...)
665
 * \brief  print to string by format
666
 * \param  pDest string to be appended to
667
 * \param  DestSize capacity of string
668
 * \param  pFormat format specifier
669
 * \param  ... format arguments
670
 * \return # of characters written
671
 * ------------------------------------------------------------------------ */
672
 
673
int as_snprintf(char *pDest, size_t DestSize, const char *pFormat, ...)
674
{
675
  va_list ap;
676
  int Result;
677
 
678
  va_start(ap, pFormat);
679
  if (DestSize > 0)
680
    *pDest = '\0';
681
  Result = as_vsnprcatf(pDest, DestSize, pFormat, ap);
682
  va_end(ap);
683
  return Result;
684
}
685
 
686
/*!------------------------------------------------------------------------
687
 * \fn     as_snprcatf(char *pDest, size_t DestSize, const char *pFormat, ...)
688
 * \brief  append to string by format
689
 * \param  pDest string to be appended to
690
 * \param  DestSize capacity of string
691
 * \param  pFormat format specifier
692
 * \param  ... format arguments
693
 * \return # of characters appended
694
 * ------------------------------------------------------------------------ */
695
 
696
int as_snprcatf(char *pDest, size_t DestSize, const char *pFormat, ...)
697
{
698
  va_list ap;
699
  int Result;
700
 
701
  va_start(ap, pFormat);
702
  Result = as_vsnprcatf(pDest, DestSize, pFormat, ap);
703
  va_end(ap);
704
  return Result;
705
}
706
 
707
int as_strcasecmp(const char *src1, const char *src2)
708
{
709
  if (!src1)
710
    src1 = "";
711
  if (!src2)
712
    src2 = "";
713
  while (tolower(*src1) == tolower(*src2))
714
  {
715
    if ((!*src1) && (!*src2))
716
      return 0;
717
    src1++;
718
    src2++;
719
  }
720
  return ((int) tolower(*src1)) - ((int) tolower(*src2));
721
}      
722
 
723
int as_strncasecmp(const char *src1, const char *src2, size_t len)
724
{
725
  if (!src1)
726
    src1 = "";
727
  if (!src2)
728
    src2 = "";
729
  while (tolower(*src1) == tolower(*src2))
730
  {
731
    if (--len == 0)
732
      return 0;
733
    if ((!*src1) && (!*src2))
734
      return 0;
735
    src1++;
736
    src2++;
737
  }
738
  return ((int) tolower(*src1)) - ((int) tolower(*src2));
739
}      
740
 
741
#ifdef NEEDS_STRSTR
742
char *strstr(const char *haystack, const char *needle)
743
{
744
  int lh = strlen(haystack), ln = strlen(needle);
745
  int z;
746
  char *p;
747
 
748
  for (z = 0; z <= lh - ln; z++)
749
    if (strncmp(p = haystack + z, needle, ln) == 0)
750
      return p;
751
  return NULL;
752
}
753
#endif
754
 
755
/*!------------------------------------------------------------------------
756
 * \fn     strrmultchr(const char *haystack, const char *needles)
757
 * \brief  find the last occurence of either character in string
758
 * \param  haystack string to search in
759
 * \param  needles characters to search for
760
 * \return last occurence or NULL
761
 * ------------------------------------------------------------------------ */
762
 
763
char *strrmultchr(const char *haystack, const char *needles)
764
{
765
  const char *pPos;
766
 
767
  for (pPos = haystack + strlen(haystack) - 1; pPos >= haystack; pPos--)
768
    if (strchr(needles, *pPos))
769
      return (char*)pPos;
770
  return NULL;
771
}
772
 
773
/*---------------------------------------------------------------------------*/
774
/* das originale strncpy plaettet alle ueberstehenden Zeichen mit Nullen */
775
 
776
size_t strmaxcpy(char *dest, const char *src, size_t Max)
777
{
778
  size_t cnt = strlen(src);
779
 
780
  /* leave room for terminating NUL */
781
 
782
  if (!Max)
783
    return 0;
784
  if (cnt + 1 > Max)
785
    cnt = Max - 1;
786
  memcpy(dest, src, cnt);
787
  dest[cnt] = '\0';
788
  return cnt;
789
}
790
 
791
/*---------------------------------------------------------------------------*/
792
/* einfuegen, mit Begrenzung */
793
 
794
size_t strmaxcat(char *Dest, const char *Src, size_t MaxLen)
795
{
796
  int TLen = strlen(Src);
797
  size_t DLen = strlen(Dest);
798
 
799
  if (TLen > (int)MaxLen - 1 - (int)DLen)
800
    TLen = MaxLen - DLen - 1;
801
  if (TLen > 0)
802
  {
803
    memcpy(Dest + DLen, Src, TLen);
804
    Dest[DLen + TLen] = '\0';
805
    return DLen + TLen;
806
  }
807
  else
808
    return DLen;
809
}
810
 
811
void strprep(char *Dest, const char *Src)
812
{
813
  memmove(Dest + strlen(Src), Dest, strlen(Dest) + 1);
814
  memmove(Dest, Src, strlen(Src));
815
}
816
 
817
/*!------------------------------------------------------------------------
818
 * \fn     strmaxprep(char *p_dest, const char *p_src, size_t max_len)
819
 * \brief  prepend as much as possible from src to dest
820
 * \param  p_dest string to be prepended
821
 * \param  p_src string to prepend
822
 * \param  max_len capacity of p_dest
823
 * ------------------------------------------------------------------------ */
824
 
825
void strmaxprep(char *p_dest, const char *p_src, size_t max_len)
826
{
827
  size_t src_len = strlen(p_src),
828
         dest_len = strlen(p_dest);
829
 
830
  assert(dest_len + 1 <= max_len);
831
  if (src_len > max_len - dest_len - 1)
832
    src_len = max_len - dest_len - 1;
833
  memmove(p_dest + src_len, p_dest, dest_len + 1);
834
  memmove(p_dest, p_src, src_len);
835
}
836
 
837
/*!------------------------------------------------------------------------
838
 * \fn     strmaxprep2(char *p_dest, const char *p_src, size_t max_len)
839
 * \brief  prepend as much as possible from src to dest, and possibly truncate dest by that
840
 * \param  p_dest string to be prepended
841
 * \param  p_src string to prepend
842
 * \param  max_len capacity of p_dest
843
 * ------------------------------------------------------------------------ */
844
 
845
void strmaxprep2(char *p_dest, const char *p_src, size_t max_len)
846
{
847
  size_t src_len = strlen(p_src),
848
         dest_len = strlen(p_dest);
849
 
850
  assert(max_len > 0);
851
  if (src_len >= max_len)
852
    src_len = max_len - 1;
853
  max_len -= src_len;
854
  if (dest_len >= max_len)
855
    dest_len = max_len - 1;
856
  memmove(p_dest + src_len, p_dest, dest_len + 1);
857
  memmove(p_dest, p_src, src_len);
858
}
859
 
860
void strins(char *Dest, const char *Src, int Pos)
861
{
862
  memmove(Dest + Pos + strlen(Src), Dest + Pos, strlen(Dest) + 1 - Pos);
863
  memmove(Dest + Pos, Src, strlen(Src));
864
}
865
 
866
void strmaxins(char *Dest, const char *Src, int Pos, size_t MaxLen)
867
{
868
  size_t RLen;
869
 
870
  RLen = strlen(Src);
871
  if (RLen > MaxLen - strlen(Dest))
872
    RLen = MaxLen - strlen(Dest);
873
  memmove(Dest + Pos + RLen, Dest + Pos, strlen(Dest) + 1 - Pos);
874
  memmove(Dest + Pos, Src, RLen);
875
}
876
 
877
int strlencmp(const char *pStr1, unsigned Str1Len,
878
              const char *pStr2, unsigned Str2Len)
879
{
880
  const char *p1, *p2, *p1End, *p2End;
881
  int Diff;
882
 
883
  for (p1 = pStr1, p1End = p1 + Str1Len,
884
       p2 = pStr2, p2End = p2 + Str2Len;
885
       p1 < p1End && p2 < p2End; p1++, p2++)
886
  {
887
    Diff = ((int)*p1) - ((int)*p2);
888
    if (Diff)
889
      return Diff;
890
  }
891
  return ((int)Str1Len) - ((int)Str2Len);
892
}
893
 
894
unsigned fstrlenprint(FILE *pFile, const char *pStr, unsigned StrLen)
895
{
896
  unsigned Result = 0;
897
  const char *pRun, *pEnd;
898
 
899
  for (pRun = pStr, pEnd = pStr + StrLen; pRun < pEnd; pRun++)
900
    if ((*pRun == '\\') || (*pRun == '"') || (*pRun == ' ') || (!isprint(*pRun)))
901
    {
902
      fprintf(pFile, "\\%03d", *pRun);
903
      Result += 4;
904
    }
905
    else
906
    {
907
      fputc(*pRun, pFile);
908
      Result++;
909
    }
910
 
911
  return Result;
912
}
913
 
914
size_t as_strnlen(const char *pStr, size_t MaxLen)
915
{
916
  size_t Res = 0;
917
 
918
  for (; (MaxLen > 0); MaxLen--, pStr++, Res++)
919
    if (!*pStr)
920
      break;
921
  return Res;
922
}
923
 
924
/*!------------------------------------------------------------------------
925
 * \fn     strreplace(char *pHaystack, const char *pFrom, const char *pTo, size_t ToMaxLen, size_t HaystackSize)
926
 * \brief  replaces all occurences of From to To in Haystack
927
 * \param  pHaystack string to search in
928
 * \param  pFrom what to find
929
 * \param  pFrom what to find
930
 * \param  pTo what to replace it with
931
 * \param  ToMaxLen if not -1, max. length of pTo (not NUL-terminated)
932
 * \param  HaystackSize buffer capacity
933
 * \return # of occurences
934
 * ------------------------------------------------------------------------ */
935
 
936
int strreplace(char *pHaystack, const char *pFrom, const char *pTo, size_t ToMaxLen, size_t HaystackSize)
937
{
938
  int HaystackLen = -1, FromLen = -1, ToLen = -1, Count = 0;
939
  int HeadLen, TailLen;
940
  char *pSearch, *pPos;
941
 
942
  pSearch = pHaystack;
943
  while (True)
944
  {
945
    /* find an occurence */
946
 
947
    pPos = strstr(pSearch, pFrom);
948
    if (!pPos)
949
      return Count;
950
 
951
    /* compute some stuff upon first occurence when needed */
952
 
953
    if (FromLen < 0)
954
    {
955
      HaystackLen = strlen(pHaystack);
956
      FromLen = strlen(pFrom);
957
    }
958
    ToLen = (ToMaxLen > 0) ? as_strnlen(pTo, ToMaxLen) : strlen(pTo);
959
 
960
    /* See how much of the remainder behind 'To' still fits into buffer after replacement,
961
       and move accordingly: */
962
 
963
    HeadLen = pPos - pHaystack;
964
    TailLen = HaystackLen - HeadLen - FromLen;
965
    if (HeadLen + ToLen + TailLen >= (int)HaystackSize)
966
    {
967
      TailLen = HaystackSize - 1 - HeadLen - ToLen;
968
      if (TailLen < 0)
969
        TailLen = 0;
970
    }
971
    if (TailLen > 0)
972
      memmove(pPos + ToLen, pPos + FromLen, TailLen);
973
 
974
    /* See how much of 'To' still fits into buffer, and set accordingly: */
975
 
976
    if (HeadLen + ToLen >= (int)HaystackSize)
977
    {
978
      ToLen = HaystackSize - 1 - ToLen;
979
      if (ToLen < 0)
980
        ToLen = 0;
981
    }
982
    if (ToLen > 0)
983
      memcpy(pPos, pTo, ToLen);
984
 
985
    /* Update length & terminate new string */
986
 
987
    HaystackLen = HeadLen + ToLen + TailLen;
988
    pHaystack[HaystackLen] = '\0';
989
 
990
    /* continue searching behind replacement: */
991
 
992
    pSearch = &pHaystack[HeadLen + ToLen];
993
 
994
    Count++;
995
  }
996
}
997
 
998
/*---------------------------------------------------------------------------*/
999
/* Bis Zeilenende lesen */
1000
 
1001
void ReadLn(FILE *Datei, char *Zeile)
1002
{
1003
  char *ptr;
1004
  int l;
1005
 
1006
  *Zeile = '\0';
1007
  ptr = fgets(Zeile, 256, Datei);
1008
  if ((!ptr) && (ferror(Datei) != 0))
1009
    *Zeile = '\0';
1010
  l = strlen(Zeile);
1011
  if ((l > 0) && (Zeile[l - 1] == '\n'))
1012
    Zeile[--l] = '\0';
1013
  if ((l > 0) && (Zeile[l - 1] == '\r'))
1014
    Zeile[--l] = '\0';
1015
  if ((l > 0) && (Zeile[l - 1] == 26))
1016
    Zeile[--l] = '\0';
1017
}
1018
 
1019
#if 0
1020
 
1021
static void dump(const char *pLine, unsigned Cnt)
1022
{
1023
  unsigned z;
1024
 
1025
  fputc('\n', stderr);
1026
  for (z = 0; z < Cnt; z++)
1027
  {
1028
    fprintf(stderr, " %02x", pLine[z]);
1029
    if ((z & 15) == 15)
1030
      fputc('\n', stderr);
1031
  }
1032
  fputc('\n', stderr);
1033
}
1034
 
1035
#endif
1036
 
1037
/*!------------------------------------------------------------------------
1038
 * \fn     ReadLnCont(FILE *Datei, as_dynstr_t *p_line)
1039
 * \brief  read line, regarding \ continuation characters
1040
 * \param  Datei where to read from
1041
 * \param  pLine dest buffer
1042
 * \return # of lines read
1043
 * ------------------------------------------------------------------------ */
1044
 
1045
size_t ReadLnCont(FILE *Datei, as_dynstr_t *p_line)
1046
{
1047
  char *ptr, *pDest;
1048
  size_t l, Count, LineCount;
1049
  Boolean Terminated;
1050
 
1051
  /* read from input until no continuation is present */
1052
 
1053
  pDest = p_line->p_str;
1054
  LineCount = Count = 0;
1055
  while (1)
1056
  {
1057
    /* get a line from file, possibly reallocating until everything up to \n fits */
1058
 
1059
    while (1)
1060
    {
1061
      if (p_line->capacity - Count < 128)
1062
        as_dynstr_realloc(p_line, p_line->capacity + 128);
1063
 
1064
      pDest = p_line->p_str + Count;
1065
      *pDest = '\0';
1066
      ptr = fgets(pDest, p_line->capacity - Count, Datei);
1067
      if (!ptr)
1068
      {
1069
        if (ferror(Datei) != 0)
1070
          *pDest = '\0';
1071
        break;
1072
      }
1073
 
1074
      /* If we have a trailing \n, we read up to end of line: */
1075
 
1076
      l = strlen(pDest);
1077
      Terminated = ((l > 0) && (pDest[l - 1] == '\n'));
1078
 
1079
      /* srtrip possible CR preceding LF: */
1080
 
1081
      if (Terminated)
1082
      {
1083
        /* strip LF, and possible CR, and bail out: */
1084
 
1085
        pDest[--l] = '\0';
1086
        if ((l > 0) && (pDest[l - 1] == '\r'))
1087
          pDest[--l] = '\0';
1088
      }
1089
 
1090
      Count += l;
1091
      pDest += l;
1092
 
1093
      if (Terminated)
1094
        break;
1095
    }
1096
 
1097
    LineCount++;
1098
    if ((Count > 0) && (p_line->p_str[Count - 1] == 26))
1099
      p_line->p_str[--Count] = '\0';
1100
 
1101
    /* optional line continuation */
1102
 
1103
    if ((Count > 0) && (p_line->p_str[Count - 1] == '\\'))
1104
      p_line->p_str[--Count] = '\0';
1105
    else
1106
      break;
1107
  }
1108
 
1109
  return LineCount;
1110
}
1111
 
1112
/*!------------------------------------------------------------------------
1113
 * \fn     DigitVal(char ch, int Base)
1114
 * \brief  get value of hex digit
1115
 * \param  ch digit
1116
 * \param  Base Number System
1117
 * \return 0..Base-1 or -1 if no valid digit
1118
 * ------------------------------------------------------------------------ */
1119
 
1120
int DigitVal(char ch, int Base)
1121
{
1122
  int Result;
1123
 
1124
  /* Ziffern 0..9 ergeben selbiges */
1125
 
1126
  if ((ch >= '0') && (ch <= '9'))
1127
    Result = ch - '0';
1128
 
1129
  /* Grossbuchstaben fuer Hexziffern */
1130
 
1131
  else if ((ch >= 'A') && (ch <= 'Z'))
1132
    Result = ch - 'A' + 10;
1133
 
1134
  /* Kleinbuchstaben nicht vergessen...! */
1135
 
1136
  else if ((ch >= 'a') && (ch <= 'z'))
1137
    Result = ch - 'a' + 10;
1138
 
1139
  /* alles andere ist Schrott */
1140
 
1141
  else
1142
    Result = -1;
1143
 
1144
  return (Result >= Base) ? -1 : Result;
1145
}
1146
 
1147
/*--------------------------------------------------------------------*/
1148
/* Zahlenkonstante umsetzen: $ hex, % binaer, @ oktal */
1149
/* inp: Eingabezeichenkette */
1150
/* erg: Zeiger auf Ergebnis-Longint */
1151
/* liefert TRUE, falls fehlerfrei, sonst FALSE */
1152
 
1153
LargeInt ConstLongInt(const char *inp, Boolean *pErr, LongInt Base)
1154
{
1155
  static const char Prefixes[4] = { '$', '@', '%', '\0' }; /* die moeglichen Zahlensysteme */
1156
  static const char Postfixes[4] = { 'H', 'O', '\0', '\0' };
1157
  static const LongInt Bases[3] = { 16, 8, 2 };            /* die dazugehoerigen Basen */
1158
  LargeInt erg, val;
1159
  int z, vorz = 1;  /* Vermischtes */
1160
  int InpLen = strlen(inp);
1161
 
1162
  /* eventuelles Vorzeichen abspalten */
1163
 
1164
  if (*inp == '-')
1165
  {
1166
    vorz = -1;
1167
    inp++;
1168
    InpLen--;
1169
  }
1170
 
1171
  /* Sonderbehandlung 0x --> $ */
1172
 
1173
  if ((InpLen >= 2)
1174
   && (*inp == '0')
1175
   && (as_toupper(inp[1]) == 'X'))
1176
  {
1177
    inp += 2;
1178
    InpLen -= 2;
1179
    Base = 16;
1180
  }
1181
 
1182
  /* Jetzt das Zahlensystem feststellen.  Vorgabe ist dezimal, was
1183
     sich aber durch den Initialwert von Base jederzeit aendern
1184
     laesst.  Der break-Befehl verhindert, dass mehrere Basenzeichen
1185
     hintereinander eingegeben werden koennen */
1186
 
1187
  else if (InpLen > 0)
1188
  {
1189
    for (z = 0; z < 3; z++)
1190
      if (*inp == Prefixes[z])
1191
      {
1192
        Base = Bases[z];
1193
        inp++;
1194
        InpLen--;
1195
        break;
1196
      }
1197
      else if (as_toupper(inp[InpLen - 1]) == Postfixes[z])
1198
      {
1199
        Base = Bases[z];
1200
        InpLen--;
1201
        break;
1202
      }
1203
  }
1204
 
1205
  /* jetzt die Zahlenzeichen der Reihe nach durchverwursten */
1206
 
1207
  erg = 0;
1208
  *pErr = False;
1209
  for(; InpLen > 0; inp++, InpLen--)
1210
  {
1211
    val = DigitVal(*inp, 16);
1212
    if (val < -0)
1213
      break;
1214
 
1215
    /* entsprechend der Basis zulaessige Ziffer ? */
1216
 
1217
    if (val >= Base)
1218
      break;
1219
 
1220
    /* Zahl linksschieben, zusammenfassen, naechster bitte */
1221
 
1222
    erg = erg * Base + val;
1223
  }
1224
 
1225
  /* bis zum Ende durchgelaufen ? */
1226
 
1227
  if (!InpLen)
1228
  {
1229
    /* Vorzeichen beruecksichtigen */
1230
 
1231
    erg *= vorz;
1232
    *pErr = True;
1233
  }
1234
 
1235
  return erg;
1236
}
1237
 
1238
/*--------------------------------------------------------------------------*/
1239
/* alle Leerzeichen aus einem String loeschen */
1240
 
1241
void KillBlanks(char *s)
1242
{
1243
  char *z, *dest;
1244
  Boolean InSgl = False, InDbl = False, ThisEscaped = False, NextEscaped = False;
1245
 
1246
  dest = s;
1247
  for (z = s; *z != '\0'; z++, ThisEscaped = NextEscaped)
1248
  {
1249
    NextEscaped = False;
1250
    switch (*z)
1251
    {
1252
      case '\'':
1253
        if (!InDbl && !ThisEscaped)
1254
          InSgl = !InSgl;
1255
        break;
1256
      case '"':
1257
        if (!InSgl && !ThisEscaped)
1258
          InDbl = !InDbl;
1259
        break;
1260
      case '\\':
1261
        if ((InSgl || InDbl) && !ThisEscaped)
1262
          NextEscaped = True;
1263
        break;
1264
    }
1265
    if (!as_isspace(*z) || InSgl || InDbl)
1266
      *dest++ = *z;
1267
  }
1268
  *dest = '\0';
1269
}
1270
 
1271
int CopyNoBlanks(char *pDest, const char *pSrc, size_t MaxLen)
1272
{
1273
  const char *pSrcRun;
1274
  char *pDestRun = pDest;
1275
  size_t Cnt = 0;
1276
  Byte Flags = 0;
1277
  char ch;
1278
  Boolean ThisEscaped, PrevEscaped;
1279
 
1280
  /* leave space for NUL */
1281
 
1282
  MaxLen--;
1283
 
1284
  PrevEscaped = False;
1285
  for (pSrcRun = pSrc; *pSrcRun; pSrcRun++)
1286
  {
1287
    ch = *pSrcRun;
1288
    ThisEscaped = False;
1289
    switch (ch)
1290
    {
1291
      case '\'':
1292
        if (!(Flags & 2) && !PrevEscaped)
1293
          Flags ^= 1;
1294
        break;
1295
      case '"':
1296
        if (!(Flags & 1) && !PrevEscaped)
1297
          Flags ^= 2;
1298
        break;
1299
      case '\\':
1300
        if (!PrevEscaped)
1301
          ThisEscaped = True;
1302
        break;
1303
    }
1304
    if (!as_isspace(ch) || Flags)
1305
      *(pDestRun++) = ch;
1306
    if (++Cnt >= MaxLen)
1307
      break;
1308
    PrevEscaped = ThisEscaped;
1309
  }
1310
  *pDestRun = '\0';
1311
 
1312
  return Cnt;
1313
}
1314
 
1315
/*--------------------------------------------------------------------------*/
1316
/* fuehrende Leerzeichen loeschen */
1317
 
1318
int KillPrefBlanks(char *s)
1319
{
1320
  char *z = s;
1321
 
1322
  while ((*z != '\0') && as_isspace(*z))
1323
    z++;
1324
  if (z != s)
1325
    strmov(s, z);
1326
  return z - s;
1327
}
1328
 
1329
/*--------------------------------------------------------------------------*/
1330
/* anhaengende Leerzeichen loeschen */
1331
 
1332
int KillPostBlanks(char *s)
1333
{
1334
  char *z = s + strlen(s) - 1;
1335
  int count = 0;
1336
 
1337
  while ((z >= s) && as_isspace(*z))
1338
  {
1339
    *(z--) = '\0';
1340
    count++;
1341
  }
1342
  return count;
1343
}
1344
 
1345
/*--------------------------------------------------------------------------*/
1346
 
1347
int strqcmp(const char *s1, const char *s2)
1348
{
1349
  int erg = (*s1) - (*s2);
1350
 
1351
  return (erg != 0) ? erg : strcmp(s1, s2);
1352
}
1353
 
1354
/*--------------------------------------------------------------------------*/
1355
 
1356
/* we need a strcpy() with a defined behaviour in case of overlapping source
1357
   and destination: */
1358
 
1359
char *strmov(char *pDest, const char *pSrc)
1360
{
1361
  memmove(pDest, pSrc, strlen(pSrc) + 1);
1362
  return pDest;
1363
}
1364
 
1365
#ifdef __GNUC__
1366
 
1367
#ifdef strcpy
1368
# undef strcpy
1369
#endif
1370
char *strcpy(char *pDest, const char *pSrc)
1371
{
1372
  int l = strlen(pSrc) + 1;
1373
  int Overlap = 0;
1374
 
1375
  if (pSrc < pDest)
1376
  {
1377
    if (pSrc + l > pDest)
1378
      Overlap = 1;
1379
  }
1380
  else if (pSrc > pDest)
1381
  {
1382
    if (pDest + l > pSrc)
1383
      Overlap = 1;
1384
  }
1385
  else if (l > 0)
1386
  {
1387
    Overlap = 1;
1388
  }
1389
 
1390
  if (Overlap)
1391
  {
1392
    fprintf(stderr, "overlapping strcpy() called from address %p, resolve this address with addr2line and report to author\n",
1393
            __builtin_return_address(0));
1394
    abort();
1395
  }
1396
 
1397
  return strmov(pDest, pSrc);
1398
}
1399
 
1400
#endif
1401
 
1402
/*!------------------------------------------------------------------------
1403
 * \fn     strmemcpy(char *pDest, size_t DestSize, const char *pSrc, size_t SrcLen)
1404
 * \brief  copy string with length limitation
1405
 * \param  pDest where to write
1406
 * \param  DestSize destination capacity
1407
 * \param  pSrc copy source
1408
 * \param  SrcLen # of characters to copy at most
1409
 * \return actual, possibly limited length
1410
 * ------------------------------------------------------------------------ */
1411
 
1412
int strmemcpy(char *pDest, size_t DestSize, const char *pSrc, size_t SrcLen)
1413
{
1414
  if (DestSize < SrcLen + 1)
1415
    SrcLen = DestSize - 1;
1416
  memmove(pDest, pSrc, SrcLen);
1417
  pDest[SrcLen] = '\0';
1418
  return SrcLen;
1419
}
1420
 
1421
/*--------------------------------------------------------------------------*/
1422
 
1423
char *ParenthPos(char *pHaystack, char Needle)
1424
{
1425
  char *pRun;
1426
  int Level = 0;
1427
 
1428
  for (pRun = pHaystack; *pRun; pRun++)
1429
  {
1430
    switch (*pRun)
1431
    {
1432
      case '(':
1433
        Level++;
1434
        break;
1435
      case ')':
1436
        if (Level < 1)
1437
          return NULL;
1438
        Level--;
1439
        break;
1440
      default:
1441
        if (*pRun == Needle && !Level)
1442
          return pRun;
1443
    }
1444
  }
1445
  return NULL;
1446
}
1447
 
1448
/*!------------------------------------------------------------------------
1449
 * \fn     TabCompressed(char in)
1450
 * \brief  replace TABs with spaces for error display
1451
 * \param  in character to compress
1452
 * \return compressed result
1453
 * ------------------------------------------------------------------------ */
1454
 
1455
char TabCompressed(char in)
1456
{
1457
  return (in == '\t') ? ' ' : (as_isprint(in) ? in : '*');
1458
}
1459
 
1460
/*--------------------------------------------------------------------------*/
1461
 
1462
void strutil_init(void)
1463
{
1464
  HexStartCharacter = 'A';
1465
}