/*
 * dxlAPRS toolchain
 *
 * Copyright (C) Christian Rabler <oe5dxl@oevsv.at>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */


#define X2C_int32
#define X2C_index32
#ifndef aprsstr_H_
#include "aprsstr.h"
#endif
#define aprsstr_C_
#ifndef osi_H_
#include "osi.h"
#endif

/* string lib by oe5dxl */
/* needed by hpm-libs */
/*FROM osi IMPORT WrInt, WrStrLn; */
static uint8_t CRCL[256];

static uint8_t CRCH[256];


extern void aprsstr_Assign(char a[], uint32_t a_len, char b[],
                uint32_t b_len)
{
   uint32_t i;
   i = 0UL;
   for (;;) {
      a[i] = b[i];
      if (a[i]==0 || i>=a_len-1) return;
      ++i;
      if (i>b_len-1) {
         if (i<=a_len-1) a[i] = 0;
         return;
      }
   }
} /* end Assign() */


extern void aprsstr_Append(char a[], uint32_t a_len, char b[],
                uint32_t b_len)
{
   uint32_t j;
   uint32_t i;
   j = aprsstr_Length(a, a_len);
   i = 0UL;
   for (;;) {
      if (j>a_len-1) return;
      a[j] = b[i];
      if (a[j]==0) return;
      ++i;
      ++j;
      if (i>b_len-1) {
         if (j<=a_len-1) a[j] = 0;
         return;
      }
   }
} /* end Append() */


extern void aprsstr_Delstr(char a[], uint32_t a_len, uint32_t from,
                uint32_t len)
{
   uint32_t l;
   l = aprsstr_Length(a, a_len);
   while (from+len<l) {
      a[from] = a[from+len];
      ++from;
   }
   if (from<=l) a[from] = 0;
} /* end Delstr() */


extern uint32_t aprsstr_Length(char a[], uint32_t a_len)
{
   uint32_t i;
   i = 0UL;
   while (i<=a_len-1 && a[i]) ++i;
   return i;
} /* end Length() */


extern void aprsstr_Caps(char s[], uint32_t s_len)
{
   uint32_t i;
   i = 0UL;
   while (i<=s_len-1 && s[i]) {
      s[i] = X2C_CAP(s[i]);
      ++i;
   }
} /* end Caps() */


extern void aprsstr_Extractword(char from[], uint32_t from_len,
                char word[], uint32_t word_len)
{
   uint32_t j;
   uint32_t i;
   i = 0UL;
   while ((i<=from_len-1 && from[i]) && from[i]==' ') ++i;
   j = 0UL;
   while ((i<=from_len-1 && from[i]) && from[i]!=' ') {
      /* copy first word */
      if (j<=word_len-1) {
         word[j] = from[i];
         ++j;
      }
      ++i;
   }
   if (j<=word_len-1) word[j] = 0;
   j = 0UL;
   while ((i<=from_len-1 && from[i]) && from[i]==' ') ++i;
   while (i<=from_len-1 && from[i]) {
      from[j] = from[i]; /* delete extract */
      ++j;
      ++i;
   }
   if (j<=from_len-1) from[j] = 0;
} /* end Extractword() */


extern void aprsstr_IntToStr(int32_t x, uint32_t f, char s[],
                uint32_t s_len)
{
   uint32_t j;
   uint32_t i;
   char neg;
   s[s_len-1] = 0;
   i = s_len-1;
   if (x<0L) {
      x = -x;
      neg = 1;
   }
   else neg = 0;
   do {
      --i;
      s[i] = (char)(x%10L+48L);
      x = (int32_t)((uint32_t)x/10UL);
   } while (!(x==0L || i==0UL));
   if (neg && i>0UL) {
      --i;
      s[i] = '-';
   }
   if (f<s_len-1) f = (s_len-1)-f;
   else f = 1UL;
   while (i>f) {
      --i;
      s[i] = ' ';
   }
   if (i>0UL) {
      j = 0UL;
      while (i<=s_len-1) {
         s[j] = s[i];
         ++j;
         ++i;
      }
   }
} /* end IntToStr() */


extern void aprsstr_CardToStr(uint32_t x, uint32_t f, char s[],
                uint32_t s_len)
{
   uint32_t j;
   uint32_t i;
   s[s_len-1] = 0;
   i = s_len-1;
   do {
      --i;
      s[i] = (char)(x%10UL+48UL);
      x = x/10UL;
   } while (!(x==0UL || i==0UL));
   if (f<s_len-1) f = (s_len-1)-f;
   else f = 1UL;
   while (i>f) {
      --i;
      s[i] = ' ';
   }
   if (i>0UL) {
      j = 0UL;
      while (i<=s_len-1) {
         s[j] = s[i];
         ++j;
         ++i;
      }
   }
} /* end CardToStr() */


extern void aprsstr_FixToStr(float x, uint32_t f, char s[],
                uint32_t s_len)
{
   uint32_t i;
   int32_t n;
   char neg;
   neg = x<0.0f;
   if (neg) x = -x;
   n = (int32_t)(uint32_t)X2C_TRUNCC(x,0UL,X2C_max_longcard);
   x = x-(float)n;
   aprsstr_IntToStr(n, 1UL, s, s_len);
   i = aprsstr_Length(s, s_len);
   if (neg) {
      n = (int32_t)i;
      while (n>0L) {
         s[n] = s[n-1L];
         --n;
      }
      s[0UL] = '-';
      ++i;
   }
   if (f>0UL) {
      s[i] = '.';
      ++i;
      while (f>1UL) {
         /*& (x>0.0)*/
         x = x*10.0f;
         n = (int32_t)(uint32_t)X2C_TRUNCC(x,0UL,X2C_max_longcard);
         x = x-(float)n;
         s[i] = (char)(n+48L);
         ++i;
         --f;
      }
      s[i] = 0;
   }
} /* end FixToStr() */


extern char aprsstr_StrToCard(char s[], uint32_t s_len,
                uint32_t * x)
{
   uint32_t i;
   char ok0;
   uint32_t tmp;
   *x = 0UL;
   ok0 = 0;
   tmp = s_len-1;
   i = 0UL;
   if (i<=tmp) for (;; i++) {
      if ((uint8_t)s[i]>='0' && (uint8_t)s[i]<='9') {
         *x =  *x*10UL+((uint32_t)(uint8_t)s[i]-48UL);
         ok0 = 1;
      }
      else return ok0 && s[i]==0;
      if (i==tmp) break;
   } /* end for */
   return ok0;
} /* end StrToCard() */


extern char aprsstr_StrToInt(char s[], uint32_t s_len,
                int32_t * x)
{
   uint32_t i;
   char ok0;
   *x = 0L;
   ok0 = 0;
   i = 0UL;
   if (s[0UL]=='-') i = 1UL;
   while ((i<=s_len-1 && (uint8_t)s[i]>='0') && (uint8_t)s[i]<='9') {
      *x =  *x*10L+(int32_t)((uint32_t)(uint8_t)s[i]-48UL);
      ok0 = 1;
      ++i;
   }
   if (i>s_len-1 || s[i]) ok0 = 0;
   if (s[0UL]=='-') *x = -*x;
   return ok0;
} /* end StrToInt() */

#define aprsstr_M (X2C_DIVR(X2C_max_real,100.0f))


extern char aprsstr_StrToFix(float * x, char s[],
                uint32_t s_len)
{
   uint32_t i;
   float p;
   char ok0;
   char neg;
   i = 0UL;
   neg = 0;
   ok0 = 0;
   while (i<=s_len-1 && s[i]==' ') ++i;
   if (s[i]=='-') {
      neg = 1;
      ++i;
   }
   *x = 0.0f;
   while ((i<=s_len-1 && (uint8_t)s[i]>='0') && (uint8_t)s[i]<='9') {
      if (*x<X2C_DIVR(X2C_max_real,100.0f)) {
         *x =  *x*10.0f+(float)((uint32_t)(uint8_t)s[i]-48UL);
      }
      ++i;
      ok0 = 1;
   }
   if (i<=s_len-1 && s[i]=='.') {
      ++i;
      p = 0.1f;
      while ((i<=s_len-1 && (uint8_t)s[i]>='0') && (uint8_t)s[i]<='9') {
         *x = *x+p*(float)((uint32_t)(uint8_t)s[i]-48UL);
         p = p*0.1f;
         ++i;
         ok0 = 1;
      }
   }
   if (neg) *x = -*x;
   return ok0 && (i>s_len-1 || s[i]==0);
} /* end StrToFix() */


extern char aprsstr_StrCmp(char a[], uint32_t a_len,
                char b[], uint32_t b_len)
{
   uint32_t i;
   i = 0UL;
   for (;;) {
      if (a[i]!=b[i]) return 0;
      if ((a[i]==0 || i>=a_len-1) || i>=b_len-1) return 1;
      ++i;
   }
   return 0;
} /* end StrCmp() */


extern int32_t aprsstr_InStr(char a[], uint32_t a_len, char b[],
                uint32_t b_len)
/* position b in a else -1*/
{
   uint32_t j;
   uint32_t i;
   if (b[0UL]) {
      i = 0UL;
      j = 0UL;
      while (i+j<=a_len-1 && a[i+j]) {
         if (a[i+j]!=b[j]) {
            j = 0UL;
            ++i;
         }
         else {
            ++j;
            if (j>b_len-1 || b[j]==0) return (int32_t)i;
         }
      }
   }
   return -1L;
} /* end InStr() */


extern void aprsstr_rightbound(char s[], uint32_t s_len, uint32_t p)
{
   uint32_t i;
   if (s_len-1<p) p = s_len-1;
   if (p<s_len-1) s[p] = 0;
   i = aprsstr_Length(s, s_len);
   while (p>0UL) {
      --p;
      if (i>0UL) {
         --i;
         s[p] = s[i];
      }
      else s[p] = ' ';
   }
} /* end rightbound() */


extern void aprsstr_TimeToStr(uint32_t t, char s[], uint32_t s_len)
{
   char h[21];
   uint32_t d;
   d = t/86400UL;
   s[0UL] = 0;
   if (d>0UL) {
      aprsstr_IntToStr((int32_t)d, 1UL, s, s_len);
      aprsstr_Append(s, s_len, "d", 2ul);
   }
   aprsstr_IntToStr((int32_t)((t/3600UL)%24UL), 2UL, h, 21ul);
   if (h[0U]==' ') h[0U] = '0';
   aprsstr_Append(s, s_len, h, 21ul);
   aprsstr_Append(s, s_len, ":", 2ul);
   aprsstr_IntToStr((int32_t)((t/60UL)%60UL), 2UL, h, 21ul);
   if (h[0U]==' ') h[0U] = '0';
   aprsstr_Append(s, s_len, h, 21ul);
   aprsstr_Append(s, s_len, ":", 2ul);
   aprsstr_IntToStr((int32_t)(t%60UL), 2UL, h, 21ul);
   if (h[0U]==' ') h[0U] = '0';
   aprsstr_Append(s, s_len, h, 21ul);
} /* end TimeToStr() */


static void tostr(char tstr[], uint32_t tstr_len, uint32_t n,
                const char s[], uint32_t s_len)
{
   char h[2];
   h[1U] = 0;
   h[0U] = (char)(48UL+n/10UL);
   aprsstr_Append(tstr, tstr_len, h, 2ul);
   h[0U] = (char)(48UL+n%10UL);
   aprsstr_Append(tstr, tstr_len, h, 2ul);
   aprsstr_Append(tstr, tstr_len, s, s_len);
} /* end tostr() */


extern void aprsstr_DateToStr(uint32_t time0, char tstr[],
                uint32_t tstr_len)
{
   uint32_t monthlen;
   uint32_t day;
   uint32_t year;
   uint32_t mon;
   char k[13];
   tstr[0UL] = 0;
   day = 25568UL+time0/86400UL;
   /*IF day>=36584 THEN INC(day) END;*/
   year = (day*4UL)/1461UL;
   day = 1UL+((day*4UL)%1461UL)/4UL;
   mon = 0UL;
   k[0U] = 0;
   aprsstr_Append(k, 13ul, "3303232332323", 14ul);
   if ((year&3UL)==0UL) k[2U] = '1';
   for (;;) {
      ++mon;
      monthlen = (uint32_t)(uint8_t)k[mon]-20UL;
      if (day<=monthlen) break;
      day -= monthlen;
   }
   tostr(tstr, tstr_len, 19UL+year/100UL, "", 1ul);
   tostr(tstr, tstr_len, year%100UL, ".", 2ul);
   tostr(tstr, tstr_len, mon, ".", 2ul);
   tostr(tstr, tstr_len, day, " ", 2ul);
   tostr(tstr, tstr_len, (time0/3600UL)%24UL, ":", 2ul);
   tostr(tstr, tstr_len, (time0/60UL)%60UL, ":", 2ul);
   tostr(tstr, tstr_len, time0%60UL, "", 1ul);
} /* end DateToStr() */


static uint32_t dig(char * err, char c)
{
   if ((uint8_t)c<'0' || (uint8_t)c>'9') {
      *err = 1;
      return 0UL;
   }
   else return (uint32_t)(uint8_t)c-48UL;
   return 0;
} /* end dig() */


extern char aprsstr_StrToTime(char s[], uint32_t s_len,
                uint32_t * time0)
/* <yyyy mm dd hh> to s since 1970*/
{
   uint32_t mi;
   uint32_t h;
   uint32_t k;
   uint32_t d;
   uint32_t m;
   uint32_t y;
   char err;
   char aprsstr_StrToTime_ret;
   X2C_PCOPY((void **)&s,s_len);
   err = 0;
   y = dig(&err, s[0UL])*1000UL+dig(&err, s[1UL])*100UL+dig(&err,
                s[2UL])*10UL+dig(&err, s[3UL]);
   if (y<1970UL || y>2100UL) {
      aprsstr_StrToTime_ret = 0;
      goto label;
   }
   *time0 = (y-1970UL)*365UL+(y-1969UL)/4UL;
   m = dig(&err, s[5UL])*10UL+dig(&err, s[6UL]);
   d = dig(&err, s[8UL])*10UL+dig(&err, s[9UL]);
   if (d<1UL || d>31UL) {
      aprsstr_StrToTime_ret = 0;
      goto label;
   }
   k = (uint32_t)((y&3UL)==0UL);
   *time0 += d-1UL;
   if (m>2UL) *time0 += k;
   switch (m) {
   case 1UL:
      break;
   case 2UL:
      if (d>28UL+k) err = 1;
      *time0 += 31UL;
      break;
   case 3UL:
      *time0 += 59UL;
      break;
   case 4UL:
      if (d>30UL) err = 1;
      *time0 += 90UL;
      break;
   case 5UL:
      *time0 += 120UL;
      break;
   case 6UL:
      if (d>30UL) err = 1;
      *time0 += 151UL;
      break;
   case 7UL:
      *time0 += 181UL;
      break;
   case 8UL:
      *time0 += 212UL;
      break;
   case 9UL:
      if (d>30UL) err = 1;
      *time0 += 243UL;
      break;
   case 10UL:
      *time0 += 273UL;
      break;
   case 11UL:
      if (d>30UL) err = 1;
      *time0 += 304UL;
      break;
   case 12UL:
      *time0 += 334UL;
      break;
   default:;
      err = 1;
      break;
   } /* end switch */
   if (err) {
      aprsstr_StrToTime_ret = 0;
      goto label;
   }
   h = dig(&err, s[11UL])*10UL+dig(&err, s[12UL]);
   if (h>24UL) {
      aprsstr_StrToTime_ret = 0;
      goto label;
   }
   mi = dig(&err, s[14UL])*10UL+dig(&err, s[15UL]);
   if (mi>=60UL) {
      aprsstr_StrToTime_ret = 0;
      goto label;
   }
   *time0 = ( *time0*24UL+h)*3600UL+mi*60UL;
   aprsstr_StrToTime_ret = 1;
   label:;
   X2C_PFREE(s);
   return aprsstr_StrToTime_ret;
} /* end StrToTime() */


static char Hex(uint32_t d)
{
   d = d&15UL;
   if (d>9UL) d += 7UL;
   return (char)(d+48UL);
} /* end Hex() */


extern void aprsstr_CtrlHex(char s[], uint32_t s_len)
/* replace ctrl char by <hex> */
{
   uint32_t len;
   uint32_t j;
   uint32_t i;
   uint32_t tmp;
   len = aprsstr_Length(s, s_len);
   i = 0UL;
   while (i<len && len<(s_len-1)-4UL) {
      if ((uint8_t)s[i]<' ') {
         len += 3UL;
         tmp = i+4UL;
         j = len;
         if (j>=tmp) for (;; j--) {
            s[j] = s[j-3UL];
            if (j==tmp) break;
         } /* end for */
         j = (uint32_t)(uint8_t)s[i];
         s[i] = '<';
         ++i;
         s[i] = Hex(j/16UL);
         ++i;
         s[i] = Hex(j);
         ++i;
         s[i] = '>';
      }
      ++i;
   }
   s[i] = 0;
} /* end CtrlHex() */

#define aprsstr_PORTSEP ":"

#define aprsstr_CHECKSEP "/"

#define aprsstr_DEFAULTIP 0x7F000001 


extern int32_t aprsstr_GetIp2(char h[], uint32_t h_len,
                uint32_t * ip, uint32_t * dp, uint32_t * lp,
                char * check)
{
   uint32_t n;
   uint32_t p;
   uint32_t i;
   char ok0;
   int32_t aprsstr_GetIp2_ret;
   X2C_PCOPY((void **)&h,h_len);
   p = 0UL;
   h[h_len-1] = 0;
   *ip = 0UL;
   for (i = 0UL; i<=5UL; i++) {
      if (i>=3UL || h[0UL]!=':') {
         n = 0UL;
         ok0 = 0;
         while ((uint8_t)h[p]>='0' && (uint8_t)h[p]<='9') {
            ok0 = 1;
            n = (n*10UL+(uint32_t)(uint8_t)h[p])-48UL;
            ++p;
         }
         if (!ok0) {
            aprsstr_GetIp2_ret = -1L;
            goto label;
         }
      }
      if (i<3UL) {
         if (h[0UL]!=':') {
            if (h[p]!='.' || n>255UL) {
               aprsstr_GetIp2_ret = -1L;
               goto label;
            }
            *ip =  *ip*256UL+n;
         }
      }
      else if (i==3UL) {
         if (h[0UL]!=':') {
            *ip =  *ip*256UL+n;
            if (h[p]!=':' || n>255UL) {
               aprsstr_GetIp2_ret = -1L;
               goto label;
            }
         }
         else {
            p = 0UL;
            *ip = 2130706433UL;
         }
      }
      else if (i==4UL) {
         *check = h[p]=='/';
         if (h[p]!=':' && h[p]!='/' || n>65535UL) {
            aprsstr_GetIp2_ret = -1L;
            goto label;
         }
         *dp = n;
      }
      else if (n>65535UL) {
         aprsstr_GetIp2_ret = -1L;
         goto label;
      }
      *lp = n;
      ++p;
   } /* end for */
   aprsstr_GetIp2_ret = 0L;
   label:;
   X2C_PFREE(h);
   return aprsstr_GetIp2_ret;
} /* end GetIp2() */


extern void aprsstr_ipv4tostr(uint32_t ip, char s[], uint32_t s_len)
{
   char h[21];
   aprsstr_IntToStr((int32_t)(ip/16777216UL), 0UL, s, s_len);
   aprsstr_Append(s, s_len, ".", 2ul);
   aprsstr_IntToStr((int32_t)(ip/65536UL&255UL), 0UL, h, 21ul);
   aprsstr_Append(s, s_len, h, 21ul);
   aprsstr_Append(s, s_len, ".", 2ul);
   aprsstr_IntToStr((int32_t)(ip/256UL&255UL), 0UL, h, 21ul);
   aprsstr_Append(s, s_len, h, 21ul);
   aprsstr_Append(s, s_len, ".", 2ul);
   aprsstr_IntToStr((int32_t)(ip&255UL), 0UL, h, 21ul);
   aprsstr_Append(s, s_len, h, 21ul);
} /* end ipv4tostr() */


extern void aprsstr_HashCh(char c, uint8_t * hashl, uint8_t * hashh)
{
   uint8_t b;
   if (c!=' ') {
      b = (uint8_t)((uint8_t)(uint8_t)c^*hashl);
      *hashl = CRCL[b]^*hashh;
      *hashh = CRCH[b];
   }
} /* end HashCh() */


extern void aprsstr_AppCRC(char frame[], uint32_t frame_len,
                int32_t size)
{
   uint8_t h;
   uint8_t l;
   uint8_t b;
   int32_t i;
   int32_t tmp;
   l = 0U;
   h = 0U;
   tmp = size-1L;
   i = 0L;
   if (i<=tmp) for (;; i++) {
      b = (uint8_t)((uint8_t)(uint8_t)frame[i]^l);
      l = CRCL[b]^h;
      h = CRCH[b];
      if (i==tmp) break;
   } /* end for */
   frame[size] = (char)l;
   frame[size+1L] = (char)h;
} /* end AppCRC() */


extern uint32_t aprsstr_Hash(char frame[], uint32_t frame_len,
                int32_t start, int32_t end)
{
   uint8_t h;
   uint8_t l;
   uint8_t b;
   int32_t i;
   char c;
   int32_t tmp;
   l = 0U;
   h = 0U;
   tmp = end-1L;
   i = start;
   if (i<=tmp) for (;; i++) {
      c = frame[i];
      if (c!=' ') {
         b = (uint8_t)((uint8_t)(uint8_t)c^l);
         l = CRCL[b]^h;
         h = CRCH[b];
      }
      if (i==tmp) break;
   } /* end for */
   return (uint32_t)(uint8_t)(char)l+(uint32_t)(uint8_t)
                (char)h*256UL;
} /* end Hash() */

static char aprsstr_CTRL = '\003';

static char aprsstr_PID = '\360';

#define aprsstr_cTO ">"

#define aprsstr_cVIA ","

#define aprsstr_cLASTCALL ":"

#define aprsstr_cSSID "-"

#define aprsstr_cREPEATED "*"

#define aprsstr_MAXVIAS 8

#define aprsstr_MAXSSID 15

#define aprsstr_SSIDBASE 48

#define aprsstr_CALLFILL " "

#define aprsstr_MAXINFOLEN 256


static char call(int32_t * p, char raw[], uint32_t raw_len,
                uint32_t * i, char mon[], uint32_t mon_len,
                char sep1, char sep2, char sep3,
                uint32_t sbase)
{
   uint32_t s;
   uint32_t l;
   l = 0UL;
   while ((((mon[*i] && mon[*i]!=sep1) && mon[*i]!=sep2) && mon[*i]!=sep3)
                && mon[*i]!='-') {
      s = (uint32_t)(uint8_t)mon[*i]*2UL&255UL;
      if (s<=64UL) return 0;
      raw[*p] = (char)s;
      ++*p;
      ++*i;
      ++l;
      if (l>=7UL) return 0;
   }
   while (l<6UL) {
      raw[*p] = '@';
      ++*p;
      ++l;
   }
   s = 0UL;
   if (mon[*i]=='-') {
      ++*i;
      while ((uint8_t)mon[*i]>='0' && (uint8_t)mon[*i]<='9') {
         s = (s*10UL+(uint32_t)(uint8_t)mon[*i])-48UL;
         ++*i;
      }
      if (s>15UL) return 0;
   }
   raw[*p] = (char)((s+sbase)*2UL);
   ++*p;
   return 1;
} /* end call() */


extern void aprsstr_mon2raw(char mon[], uint32_t mon_len,
                char raw[], uint32_t raw_len, int32_t * p)
{
   uint32_t r;
   uint32_t n;
   uint32_t i;
   uint32_t tmp;
   *p = 7L;
   i = 0UL;
   if (!call(p, raw, raw_len, &i, mon, mon_len, '>', 0, 0, 48UL)) {
      *p = 0L; /* from call */
      return;
   }
   *p = 0L;
   if (mon[i]!='>') return;
   /* ">" */
   ++i;
   if (!call(p, raw, raw_len, &i, mon, mon_len, ':', ',', 0, 112UL)) {
      *p = 0L; /* dest call bit 7 for UI v2 command */
      return;
   }
   /*  IF NOT call(cLASTCALL, cVIA, 0C, SSIDBASE) THEN p:=0; RETURN END;
                (* dest call bit 7 for UI v2 command *) */
   *p = 14L;
   n = 0UL;
   while (mon[i]==',') {
      ++i;
      if (!call(p, raw, raw_len, &i, mon, mon_len, ':', ',', '*', 48UL)) {
         *p = 0L;
         return;
      }
      ++n;
      if (n>8UL) {
         *p = 0L;
         return;
      }
      if (mon[i]=='*') {
         /* "*" has repeatet sign */
         ++i;
         r = (uint32_t)*p;
         if (r>=21UL) for (tmp = (uint32_t)(r-21UL)/7UL;;) {
            raw[r-1UL] = (char)((uint32_t)(uint8_t)raw[r-1UL]+128UL);
                 /* set "has repeated" flags */
            if (!tmp) break;
            --tmp;
            r -= 7UL;
         } /* end for */
      }
   }
   if (*p==0L || mon[i]!=':') {
      *p = 0L; /* ":" start of info sign */
      return;
   }
   raw[*p-1L] = (char)((uint32_t)(uint8_t)raw[*p-1L]+1UL);
                /* end address field mark */
   raw[*p] = '\003';
   ++*p;
   raw[*p] = '\360';
   ++*p;
   ++i;
   n = 256UL;
   while (mon[i] && i<=mon_len-1) {
      /* copy info part */
      if (*p>=(int32_t)(raw_len-1)-2L || n==0UL) {
         *p = 0L; /* spare 2 bytes for crc */
         return;
      }
      raw[*p] = mon[i];
      ++*p;
      ++i;
      --n;
   }
   aprsstr_AppCRC(raw, raw_len, *p);
   *p += 2L;
} /* end mon2raw() */


extern char aprsstr_Call2Str(char r[], uint32_t r_len,
                char t[], uint32_t t_len, uint32_t pos,
                uint32_t * len)
{
   uint32_t ssid;
   uint32_t e;
   uint32_t i;
   char c;
   uint32_t tmp;
   e = pos;
   tmp = pos+5UL;
   i = pos;
   if (i<=tmp) for (;; i++) {
      if (r[i]!='@') e = i;
      if (i==tmp) break;
   } /* end for */
   tmp = e;
   i = pos;
   if (i<=tmp) for (;; i++) {
      c = (char)((uint32_t)(uint8_t)r[i]>>1);
      if ((uint8_t)c<=' ') {
         t[*len] = 0;
         *len = 0UL;
         return 0;
      }
      t[*len] = c;
      ++*len;
      if (i==tmp) break;
   } /* end for */
   ssid = (uint32_t)(uint8_t)r[pos+6UL]>>1&15UL;
   if (ssid>0UL) {
      t[*len] = '-';
      ++*len;
      if (ssid>9UL) {
         t[*len] = '1';
         ++*len;
      }
      t[*len] = (char)(ssid%10UL+48UL);
      ++*len;
   }
   return 1;
} /* end Call2Str() */


static void brandghost(char b[], uint32_t b_len, uint32_t brand)
{
   uint32_t l;
   uint32_t j;
   uint32_t i;
   char s1[21];
   char s[21];
   uint32_t tmp;
   i = 0UL;
   for (;;) {
      if (i>=b_len-1 || b[i]==0) return;
      if (b[i]==',' || b[i]==':') break;
      ++i;
   }
   /*
     IF NOT v1 & (b[i]=",") THEN
       IF ((b[i+1]<>"W") OR (b[i+2]<>"I") OR (b[i+3]<>"D") OR (b[i+4]<>"E")
       OR (b[i+5]<>"1") OR (b[i+6]<>"-") OR (b[i+7]<>"1")
       OR (b[i+8]<>",")
       OR (b[i+9]<>"W") OR (b[i+10]<>"I") OR (b[i+11]<>"D") OR (b[i+12]<>"E")
                 OR (b[i+13]<>"2")
       OR (b[i+14]<>"-") OR (b[i+15]<>"1") & (b[i+15]<>"2") OR (b[i+16]<>":")
                )
       & ((b[i+1]<>"R") OR (b[i+2]<>"E") OR (b[i+3]<>"L") OR (b[i+4]<>"A")
                OR (b[i+5]<>"Y")
       OR (b[i+6]<>":")) THEN v1:=TRUE END;
     END;
   */
   if (b[i]==',') {
      j = i+1UL;
      for (;;) {
         /* goto end of first via */
         if (j>=b_len-1 || b[j]==0) return;
         if (b[j]==':' || b[j]==',') break;
         ++j;
      }
      if (brand<256UL && ((((j<=3UL || (uint8_t)b[j-1UL]<'0')
                || (uint8_t)b[j-1UL]>'9') || b[j-2UL]!='-')
                || b[j-1UL]!=b[j-3UL])) return;
      /* frame has n<>N so known as not direct */
      j = i+1UL;
      for (;;) {
         /* look for h-bit */
         if (j>=b_len-1 || b[j]==0) return;
         if (b[j]==':') break;
         if (b[j]=='*') return;
         /* frame has h bit so known as not direct */
         ++j;
      }
   }
   strncpy(s,",GHOST",21u);
   aprsstr_IntToStr((int32_t)brand, 0UL, s1, 21ul);
   aprsstr_Append(s, 21ul, s1, 21ul);
   aprsstr_Append(s, 21ul, "*", 2ul);
   l = aprsstr_Length(s, 21ul);
   i = 0UL;
   while ((i<=b_len-1 && b[i]) && b[i]!=':') ++i;
   if (b[i]==':') {
      j = i;
      while (j<=b_len-1 && b[j]) ++j;
      if (b[j]==0 && j+l<b_len-1) {
         /* insert ,GHOSTnnn* */
         while (j>=i) {
            b[j+l] = b[j];
            --j;
         }
         tmp = l-1UL;
         i = 0UL;
         if (i<=tmp) for (;; i++) {
            ++j;
            b[j] = s[i];
            if (i==tmp) break;
         } /* end for */
      }
   }
} /* end brandghost() */


extern void aprsstr_raw2mon(char raw[], uint32_t raw_len,
                char mon[], uint32_t mon_len, uint32_t len,
                uint32_t * p, aprsstr_GHOSTSET ghostset)
{
   uint32_t brand;
   uint32_t i;
   char hcheck;
   if ((((((len>21UL && !((uint32_t)(uint8_t)raw[13UL]&1))
                && raw[14UL]=='\202') && raw[15UL]=='\240')
                && raw[16UL]=='\244') && raw[17UL]=='\246')
                && raw[18UL]=='@') brand = 256UL;
   else {
      brand = (uint32_t)(uint8_t)raw[6UL]/32UL+((uint32_t)(uint8_t)
                raw[13UL]/32UL)*8UL;
   }
   *p = 0UL;
   mon[0UL] = 0;
   i = 0UL;
   while (!((uint32_t)(uint8_t)raw[i]&1)) {
      ++i;
      if (i>len) {
         mon[0UL] = 0; /* no address end mark found */
         return;
      }
   }
   if (i%7UL!=6UL) {
      mon[0UL] = 0; /* address end not modulo 7 error */
      return;
   }
   if (!aprsstr_Call2Str(raw, raw_len, mon, mon_len, 7UL, p)) {
      mon[0UL] = 0;
      return;
   }
   mon[*p] = '>';
   ++*p;
   if (!aprsstr_Call2Str(raw, raw_len, mon, mon_len, 0UL, p)) {
      mon[0UL] = 0;
      return;
   }
   i = 14UL;
   hcheck = 1;
   while (i+6UL<len && !((uint32_t)(uint8_t)raw[i-1UL]&1)) {
      mon[*p] = ',';
      ++*p;
      if (!aprsstr_Call2Str(raw, raw_len, mon, mon_len, i, p)) {
         mon[0UL] = 0;
         return;
      }
      if ((uint32_t)(uint8_t)raw[i+6UL]>=128UL) {
         if (!hcheck) {
            mon[0UL] = 0; /* wrong H bit */
            return;
         }
         if (((uint32_t)(uint8_t)raw[i+6UL]&1) || (uint32_t)(uint8_t)
                raw[i+13UL]<128UL) {
            mon[*p] = '*';
            ++*p;
         }
      }
      else hcheck = 0;
      i += 7UL;
   }
   if (raw[i]!='\003' && raw[i]!='\023') {
      mon[0UL] = 0; /* not UI frame */
      return;
   }
   if (raw[i]=='\023') brand += 64UL;
   if (raw[i+1UL]!='\360') brand += 128UL;
   i += 2UL; /* ctrl, pid */
   mon[*p] = ':';
   ++*p;
   while (i<len && *p<(mon_len-1)-1UL) {
      if (raw[i]) {
         mon[*p] = raw[i];
         ++*p;
      }
      ++i;
   }
   /*
     mon[p]:=15C; INC(p);
     mon[p]:=12C; INC(p);
   */
   mon[*p] = 0;
   ++*p;
   mon[*p] = 0;
   /*FOR i:=0 TO 256 DO IF i IN ghostset THEN WrInt(i, 4) END; END;
                WrStrLn("=ghs"); */
   if (X2C_INL((int32_t)256,257,ghostset) && brand>255UL || X2C_INL(brand,
                257,ghostset)) brandghost(mon, mon_len, brand);
/*WrInt(ORD(raw[6]) DIV 32,1); WrInt(ORD(raw[13]) DIV 32,1);WrStrLn(mon); */
} /* end raw2mon() */


extern void aprsstr_extrudp2(char ib[], uint32_t ib_len, char ud[],
                 uint32_t ud_len, int32_t * len)
/* extract axudp2 header */
{
   int32_t j;
   int32_t i;
   i = 0L;
   j = 0L;
   do {
      ud[i] = ib[i];
      ++i;
   } while (!((i>=(int32_t)(ud_len-1) || i>=*len) || ib[i]==0));
   ud[i] = 0;
   ++i;
   if (i>=*len) *len = 0L;
   else {
      *len -= i;
      while (j<*len) {
         ib[j] = ib[i];
         ++j;
         ++i;
      }
   }
} /* end extrudp2() */


extern void aprsstr_cleanfilename(char s[], uint32_t s_len)
{
   uint32_t j;
   uint32_t i;
   i = 0UL;
   j = 0UL;
   while (i<=s_len-1 && s[i]) {
      /* remove leftside junk */
      if (j>0UL || (uint8_t)s[i]>' ') {
         s[j] = s[i];
         ++j;
      }
      ++i;
   }
   while (j>0UL && (uint8_t)s[j-1UL]<=' ') --j;
   if (j<=s_len-1) s[j] = 0;
} /* end cleanfilename() */

#define aprsstr_POLINOM 0x8408 


static void Gencrctab(void)
{
   uint32_t c;
   uint32_t crc;
   uint32_t i;
   for (c = 0UL; c<=255UL; c++) {
      crc = 255UL-c;
      for (i = 0UL; i<=7UL; i++) {
         if ((crc&1)) crc = (uint32_t)((uint32_t)(crc>>1)^0x8408UL);
         else crc = crc>>1;
      } /* end for */
      CRCL[c] = (uint8_t)crc;
      CRCH[c] = (uint8_t)(255UL-(crc>>8));
   } /* end for */
} /* end Gencrctab() */


extern void aprsstr_BEGIN(void)
{
   static int aprsstr_init = 0;
   if (aprsstr_init) return;
   aprsstr_init = 1;
   if (sizeof(uint8_t)!=1) X2C_ASSERT(0);
   if (sizeof(aprsstr_GHOSTSET)!=36) X2C_ASSERT(0);
   osi_BEGIN();
   Gencrctab();
}

