Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

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