Subversion Repositories pentevo

Rev

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

  1. /* asmsub.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS-Portierung                                                             */
  6. /*                                                                           */
  7. /* Unterfunktionen, vermischtes                                              */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11.  
  12. #include "stdinc.h"
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <stdarg.h>
  16.  
  17. #include "version.h"
  18. #include "be_le.h"
  19. #include "stdhandl.h"
  20. #include "console.h"
  21. #include "nls.h"
  22. #include "chardefs.h"
  23. #include "nlmessages.h"
  24. #include "cmdarg.h"
  25. #include "as.rsc"
  26. #include "strutil.h"
  27. #include "stringlists.h"
  28. #include "chunks.h"
  29. #include "ioerrs.h"
  30. #include "intformat.h"
  31. #include "errmsg.h"
  32. #include "asmdef.h"
  33. #include "asmpars.h"
  34. #include "asmdebug.h"
  35. #include "asmlist.h"
  36. #include "as.h"
  37.  
  38. #include "asmsub.h"
  39.  
  40.  
  41. #ifdef __TURBOC__
  42. #ifdef __DPMI16__
  43. #define STKSIZE 32768
  44. #else
  45. #define STKSIZE 49152
  46. #endif
  47. #endif
  48.  
  49. #define VALID_S1 1
  50. #define VALID_SN 2
  51. #define VALID_M1 4
  52. #define VALID_MN 8
  53.  
  54. static StringList CopyrightList, OutList, ShareOutList, ListOutList;
  55.  
  56. static LongWord StartStack, MinStack, LowStack;
  57.  
  58. static unsigned ValidSymCharLen;
  59. static Byte *ValidSymChar;
  60.  
  61. /****************************************************************************/
  62. /* Modulinitialisierung */
  63.  
  64. void AsmSubPassInit(void)
  65. {
  66.   PageLength = 60;
  67.   PageWidth = 0;
  68. }
  69.  
  70. /****************************************************************************/
  71. /* Copyrightlistenverwaltung */
  72.  
  73. void AddCopyright(const char *NewLine)
  74. {
  75.   AddStringListLast(&CopyrightList, NewLine);
  76. }
  77.  
  78. void WriteCopyrights(void(*PrintProc)(const char *))
  79. {
  80.   StringRecPtr Lauf;
  81.   const char *p_line;
  82.  
  83.   for (p_line = GetStringListFirst(CopyrightList, &Lauf);
  84.        p_line; p_line = GetStringListNext(&Lauf))
  85.     PrintProc(p_line);
  86. }
  87.  
  88. /*--------------------------------------------------------------------------*/
  89. /* ermittelt das erste/letzte Auftauchen eines Zeichens ausserhalb */
  90. /* "geschuetzten" Bereichen */
  91.  
  92. static char *QuotPosCore(const char *s, int (*SearchFnc)(const char*, const char*), const char *pSearch, tQualifyQuoteFnc QualifyQuoteFnc)
  93. {
  94.   register ShortInt Brack = 0, AngBrack = 0;
  95.   register const char *i;
  96.   Boolean InSglQuot = False, InDblQuot = False, ThisEscaped = False, NextEscaped = False;
  97.  
  98.   for (i = s; *i; i++, ThisEscaped = NextEscaped)
  99.   {
  100.     NextEscaped = False;
  101.     if (!SearchFnc(i, pSearch))
  102.     {
  103.       if (!AngBrack && !Brack && !InSglQuot && !InDblQuot)
  104.         return (char*)i;
  105.     }
  106.     switch (*i)
  107.     {
  108.       case '"':
  109.         if (!InSglQuot && !ThisEscaped)
  110.           InDblQuot = !InDblQuot;
  111.         break;
  112.       case '\'':
  113.         if (!InDblQuot && !ThisEscaped)
  114.         {
  115.           if (InSglQuot || !QualifyQuoteFnc || QualifyQuoteFnc(s, i))
  116.             InSglQuot = !InSglQuot;
  117.         }
  118.         break;
  119.       case '\\':
  120.         if ((InSglQuot || InDblQuot) && !ThisEscaped)
  121.           NextEscaped = True;
  122.         break;
  123.       case '(':
  124.         if (!AngBrack && !InDblQuot && !InSglQuot)
  125.           Brack++;
  126.         break;
  127.       case ')':
  128.         if (!AngBrack && !InDblQuot && !InSglQuot)
  129.           Brack--;
  130.         break;
  131.       case '[':
  132.         if (!Brack && !InDblQuot && !InSglQuot)
  133.           AngBrack++;
  134.         break;
  135.       case ']':
  136.         if (!Brack && !InDblQuot && !InSglQuot)
  137.           AngBrack--;
  138.         break;
  139.     }
  140.   }
  141.  
  142.   return NULL;
  143. }
  144.  
  145. static int SearchSingleChar(const char *pPos, const char *pSearch)
  146. {
  147.   return ((int)*pSearch) - ((int)*pPos);
  148. }
  149.  
  150. static int SearchMultChar(const char *pPos, const char *pSearch)
  151. {
  152.   return !strchr(pSearch, *pPos);
  153. }
  154.  
  155. static int SearchMultString(const char *pPos, const char *pSearch)
  156. {
  157.   int len;
  158.  
  159.   while (True)
  160.   {
  161.     if (!(len = strlen(pSearch)))
  162.       return 1;
  163.     if (!strncmp(pPos, pSearch, len))
  164.       return 0;
  165.     pSearch += len + 1;
  166.   }
  167. }
  168.  
  169. char *QuotMultPosQualify(const char *s, const char *pSearch, tQualifyQuoteFnc QualifyQuoteFnc)
  170. {
  171.   return QuotPosCore(s, SearchMultChar, pSearch, QualifyQuoteFnc);
  172. }
  173.  
  174. char *QuotPosQualify(const char *s, char Zeichen, tQualifyQuoteFnc QualifyQuoteFnc)
  175. {
  176.   return QuotPosCore(s, SearchSingleChar, &Zeichen, QualifyQuoteFnc);
  177. }
  178.  
  179. char *QuotSMultPosQualify(const char *s, const char *pStrs, tQualifyQuoteFnc QualifyQuoteFnc)
  180. {
  181.   return QuotPosCore(s, SearchMultString, pStrs, QualifyQuoteFnc);
  182. }
  183.  
  184. char *RQuotPos(char *s, char Zeichen)
  185. {
  186.   ShortInt Brack = 0, AngBrack = 0;
  187.   char *i;
  188.   Boolean Quot = False, Paren = False;
  189.  
  190.   for (i = s + strlen(s) - 1; i >= s; i--)
  191.     if (*i == Zeichen)
  192.     {
  193.       if ((!AngBrack) && (!Brack) && (!Paren) && (!Quot))
  194.         return i;
  195.     }
  196.     else switch (*i)
  197.     {
  198.       case '"':
  199.         if ((!Brack) && (!AngBrack) && (!Quot))
  200.           Paren = !Paren;
  201.         break;
  202.       case '\'':
  203.         if ((!Brack) && (!AngBrack) && (!Paren))
  204.           Quot = !Quot;
  205.         break;
  206.       case ')':
  207.         if ((!AngBrack) && (!Paren) && (!Quot))
  208.           Brack++;
  209.         break;
  210.       case '(':
  211.         if ((!AngBrack) && (!Paren) && (!Quot))
  212.           Brack--;
  213.         break;
  214.       case ']':
  215.         if ((!Brack) && (!Paren) && (!Quot))
  216.           AngBrack++;
  217.         break;
  218.       case '[':
  219.         if ((!Brack) && (!Paren) && (!Quot))
  220.           AngBrack--;
  221.         break;
  222.     }
  223.  
  224.   return NULL;
  225. }
  226.  
  227. /*--------------------------------------------------------------------------*/
  228. /* ermittelt das erste (nicht-) Leerzeichen in einem String */
  229.  
  230. char *FirstBlank(const char *s)
  231. {
  232.   const char *h, *Min = NULL;
  233.  
  234.   h = strchr(s, ' ');
  235.   if (h)
  236.     if ((!Min) || (h < Min))
  237.       Min = h;
  238.   h = strchr(s, Char_HT);
  239.   if (h)
  240.     if ((!Min) || (h < Min))
  241.       Min = h;
  242.   return (char*)Min;
  243. }
  244.  
  245. /*--------------------------------------------------------------------------*/
  246. /* einen String in zwei Teile zerlegen */
  247.  
  248. void SplitString(char *Source, char *Left, char *Right, char *Trenner)
  249. {
  250.   char Save;
  251.   LongInt slen = strlen(Source);
  252.  
  253.   if ((!Trenner) || (Trenner >= Source + slen))
  254.     Trenner = Source + slen;
  255.   Save = (*Trenner);
  256.   *Trenner = '\0';
  257.   strmov(Left, Source);
  258.   *Trenner = Save;
  259.   if (Trenner >= Source + slen)
  260.     *Right = '\0';
  261.   else
  262.     strmov(Right, Trenner + 1);
  263. }
  264.  
  265. /*--------------------------------------------------------------------------*/
  266. /* verbesserte Grossbuchstabenfunktion */
  267.  
  268. /* einen String in Grossbuchstaben umwandeln.  Dabei Stringkonstanten in Ruhe */
  269. /* lassen */
  270.  
  271. void UpString(char *s)
  272. {
  273.   char *z;
  274.   int hypquot = 0;
  275.   Boolean LastBk = FALSE, ThisBk;
  276.  
  277.   for (z = s; *z != '\0'; z++)
  278.   {
  279.     ThisBk = FALSE;
  280.     switch (*z)
  281.     {
  282.       case '\\':
  283.         ThisBk = TRUE;
  284.         break;
  285.       case '\'':
  286.         if ((!(hypquot & 2)) && (!LastBk))
  287.           hypquot ^= 1;
  288.         break;
  289.       case '"':
  290.         if ((!(hypquot & 1)) && (!LastBk))
  291.           hypquot ^= 2;
  292.         break;
  293.       default:
  294.         if (!hypquot)
  295.           *z = UpCaseTable[(int)*z];
  296.     }
  297.     LastBk = ThisBk;
  298.   }
  299. }
  300.  
  301. /*!------------------------------------------------------------------------
  302.  * \fn     MatchChars(const char *pStr, const char *pPattern, ...)
  303.  * \brief  see if beginning of string matches given pattern
  304.  * \param  pStr string to check
  305.  * \param  pPattern expected pattern
  306.  * \return * to character following match or NULL if no match
  307.  * ------------------------------------------------------------------------ */
  308.  
  309. char *MatchChars(const char *pStr, const char *pPattern, ...)
  310. {
  311.   va_list ap;
  312.   char *pResult = NULL;
  313.  
  314.   va_start(ap, pPattern);
  315.   for (; *pPattern; pPattern++)
  316.     switch (*pPattern)
  317.     {
  318.       /* single space in pattern matches arbitrary # of spaces in string */
  319.       case ' ':
  320.         for (; as_isspace(*pStr); pStr++);
  321.         break;
  322.       case '?':
  323.       {
  324.         const char *pPatternStr = va_arg(ap, const char*);
  325.         char *pSave = va_arg(ap, char*);
  326.  
  327.         if (!strchr(pPatternStr, as_toupper(*pStr)))
  328.           goto func_exit;
  329.         if (pSave)
  330.           *pSave = *pStr;
  331.         pStr++;
  332.         break;
  333.       }
  334.       default:
  335.         if (as_toupper(*pStr) != as_toupper(*pPattern))
  336.           goto func_exit;
  337.         pStr++;
  338.     }
  339.   pResult = (char*)pStr;
  340. func_exit:
  341.   va_end(ap);
  342.   return pResult;
  343. }
  344.  
  345. /*!------------------------------------------------------------------------
  346.  * \fn     MatchCharsRev(const char *pStr, const char *pPattern, ...)
  347.  * \brief  see if end of string matches given pattern
  348.  * \param  pStr string to check
  349.  * \param  pPattern expected pattern
  350.  * \return * to trailing string matching pattern or NULL if no match
  351.  * ------------------------------------------------------------------------ */
  352.  
  353. char *MatchCharsRev(const char *pStr, const char *pPattern, ...)
  354. {
  355.   va_list ap;
  356.   char *pResult = NULL;
  357.   const char *pPatternRun = pPattern + strlen(pPattern) - 1,
  358.              *pStrRun = pStr + strlen(pStr) - 1;
  359.  
  360.   va_start(ap, pPattern);
  361.   for (; pPatternRun >= pPattern; pPatternRun--)
  362.     switch (*pPatternRun)
  363.     {
  364.       /* single space in pattern matches arbitrary # of spaces in string */
  365.       case ' ':
  366.         for (; (pStrRun >= pStr) && as_isspace(*pStrRun); pStrRun--);
  367.         break;
  368.       case '?':
  369.       {
  370.         const char *pPatternStr = va_arg(ap, const char*);
  371.         char *pSave = va_arg(ap, char*);
  372.  
  373.         if (!strchr(pPatternStr, as_toupper(*pStrRun)))
  374.           goto func_exit;
  375.         if (pSave)
  376.           *pSave = *pStrRun;
  377.         pStrRun--;
  378.         break;
  379.       }
  380.       default:
  381.         if ((pStrRun < pStr) || (as_toupper(*pStrRun) != as_toupper(*pPatternRun)))
  382.           goto func_exit;
  383.         pStrRun--;
  384.     }
  385.   pResult = (char*)(pStrRun + 1);
  386. func_exit:
  387.   va_end(ap);
  388.   return pResult;
  389. }
  390.  
  391. /*!------------------------------------------------------------------------
  392.  * \fn     as_iterate_str_quoted(const char *p_str, as_quoted_iterator_cb_t callback, as_quoted_iterator_cb_data_t *p_cb_data)
  393.  * \brief  iterate through string, skipping quoted areas
  394.  * \param  p_str string to iterate through
  395.  * \param  callback is called for all characters outside quoted areas
  396.  * \param  p_cb_data callback data
  397.  * ------------------------------------------------------------------------ */
  398.  
  399. void as_iterate_str_quoted(const char *p_str, as_quoted_iterator_cb_t callback, as_quoted_iterator_cb_data_t *p_cb_data)
  400. {
  401.   const char *p_run;
  402.   Boolean this_escaped, next_escaped;
  403.  
  404.   p_cb_data->p_str = p_str;
  405.   p_cb_data->in_single_quote =
  406.   p_cb_data->in_double_quote = False;
  407.  
  408.   for (p_run = p_str, this_escaped = False;
  409.        *p_run;
  410.        p_run++, this_escaped = next_escaped)
  411.   {
  412.     next_escaped = False;
  413.  
  414.     switch(*p_run)
  415.     {
  416.       case '\\':
  417.         if ((p_cb_data->in_single_quote || p_cb_data->in_double_quote) && !this_escaped)
  418.           next_escaped = True;
  419.         break;
  420.       case '\'':
  421.         if (p_cb_data->in_double_quote) { }
  422.         else if (!p_cb_data->in_single_quote && (!QualifyQuote || QualifyQuote(p_str, p_run)))
  423.           p_cb_data->in_single_quote = True;
  424.         else if (!this_escaped) /* skip escaped ' in '...' */
  425.           p_cb_data->in_single_quote = False;
  426.         break;
  427.       case '"':
  428.         if (p_cb_data->in_single_quote) { }
  429.         else if (!p_cb_data->in_double_quote)
  430.           p_cb_data->in_double_quote = True;
  431.         else if (!this_escaped) /* skip escaped " in "..." */
  432.           p_cb_data->in_double_quote = False;
  433.         break;
  434.       default:
  435.         if (!p_cb_data->in_single_quote && !p_cb_data->in_double_quote)
  436.         {
  437.           if (!callback(p_run, p_cb_data))
  438.             return;
  439.         }
  440.     }
  441.   }
  442. }
  443.  
  444. /*!------------------------------------------------------------------------
  445.  * \fn     FindClosingParenthese(const char *pStr)
  446.  * \brief  find matching closing parenthese
  447.  * \param  pStr * to string right after opening parenthese
  448.  * \return * to closing parenthese or NULL
  449.  * ------------------------------------------------------------------------ */
  450.  
  451. typedef struct
  452. {
  453.   as_quoted_iterator_cb_data_t data;
  454.   int nest;
  455.   const char *p_ret;
  456. } close_par_cb_data_t;
  457.  
  458. static Boolean close_par_cb(const char *p_pos, as_quoted_iterator_cb_data_t *p_cb_data)
  459. {
  460.   close_par_cb_data_t *p_data = (close_par_cb_data_t*)p_cb_data;
  461.  
  462.   switch(*p_pos)
  463.   {
  464.     case '(':
  465.       p_data->nest++;
  466.       break;
  467.     case ')':
  468.       if (!--p_data->nest)
  469.       {
  470.         p_data->p_ret = p_pos;
  471.         return False;
  472.       }
  473.       break;
  474.   }
  475.   return True;
  476. }
  477.  
  478. char *FindClosingParenthese(const char *pStr)
  479. {
  480.   close_par_cb_data_t data;
  481.  
  482.   data.nest = 1;
  483.   data.p_ret = NULL;
  484.  
  485.   as_iterate_str_quoted(pStr, close_par_cb,&data.data);
  486.  
  487.   return (char*)data.p_ret;
  488. }
  489.  
  490. /*!------------------------------------------------------------------------
  491.  * \fn     FindOpeningParenthese(const char *pStrBegin, const char *pStrEnd, const char Bracks[2])
  492.  * \brief  find matching opening parenthese in string
  493.  * \param  pStrBegin start of string
  494.  * \param  pStrEnd end of string, preceding closing parenthese in question
  495.  * \param  Bracks opening & closing parenthese
  496.  * \return * to opening parenthese or NULL if not found
  497.  * ------------------------------------------------------------------------ */
  498.  
  499. typedef struct
  500. {
  501.   as_quoted_iterator_cb_data_t data;
  502.   int nest;
  503.   const char *p_str_end;
  504.   const char *p_ret;
  505.   const char *p_bracks;
  506. } open_par_cb_data_t;
  507.  
  508. static Boolean open_par_cb(const char *p_pos, as_quoted_iterator_cb_data_t *p_cb_data)
  509. {
  510.   open_par_cb_data_t *p_data = (open_par_cb_data_t*)p_cb_data;
  511.  
  512.   if (*p_pos == p_data->p_bracks[0])
  513.   {
  514.     if (!p_data->nest)
  515.       p_data->p_ret = p_pos;
  516.     p_data->nest++;
  517.   }
  518.   else if (*p_pos == p_data->p_bracks[1])
  519.     p_data->nest--;
  520.  
  521.   /* We are interested in the opening parenthese that is nearest to the closing
  522.      one and on same level, so continue searching: */
  523.  
  524.   return ((p_pos + 1) < p_data->p_str_end);
  525. }
  526.  
  527. char *FindOpeningParenthese(const char *pStrBegin, const char *pStrEnd, const char Bracks[2])
  528. {
  529.   open_par_cb_data_t data;
  530.  
  531.   data.nest = 0;
  532.   data.p_ret = NULL;
  533.   data.p_bracks = Bracks;
  534.   data.p_str_end = pStrEnd;
  535.  
  536.   as_iterate_str_quoted(pStrBegin, open_par_cb, &data.data);
  537.  
  538.   return (char*)data.p_ret;
  539. }
  540.  
  541. /****************************************************************************/
  542.  
  543. ShortInt StrCaseCmp(const char *s1, const char *s2, LongInt Hand1, LongInt Hand2)
  544. {
  545.   int tmp;
  546.  
  547.   tmp = as_toupper(*s1) - as_toupper(*s2);
  548.   if (!tmp)
  549.     tmp = as_strcasecmp(s1, s2);
  550.   if (!tmp)
  551.     tmp = Hand1 - Hand2;
  552.   if (tmp < 0)
  553.     return -1;
  554.   if (tmp > 0)
  555.     return 1;
  556.   return 0;
  557. }
  558.  
  559. /****************************************************************************/
  560. /* an einen Dateinamen eine Endung anhaengen */
  561.  
  562. void AddSuffix(char *s, const char *Suff)
  563. {
  564.   char *p, *z, *Part;
  565.  
  566.   p = NULL;
  567.   for (z = s; *z != '\0'; z++)
  568.     if (*z == PATHSEP)
  569.       p = z;
  570.   Part = p ? p : s;
  571.   if (!strchr(Part, '.'))
  572.     strmaxcat(s, Suff, STRINGSIZE);
  573. }
  574.  
  575.  
  576. /*--------------------------------------------------------------------------*/
  577. /* von einem Dateinamen die Endung loeschen */
  578.  
  579. void KillSuffix(char *s)
  580. {
  581.   char *p, *z, *Part;
  582.  
  583.   p = NULL;
  584.   for (z = s; *z != '\0'; z++)
  585.     if (*z == PATHSEP)
  586.       p = z;
  587.   Part = p ? p : s;
  588.   Part = strchr(Part, '.');
  589.   if (Part)
  590.     *Part = '\0';
  591. }
  592.  
  593. /*--------------------------------------------------------------------------*/
  594. /* Pfadanteil (Laufwerk+Verzeichnis) von einem Dateinamen abspalten */
  595.  
  596. char *PathPart(char *Name)
  597. {
  598.   static String s;
  599.   char *p;
  600.  
  601.   strmaxcpy(s, Name, STRINGSIZE);
  602.  
  603.   p = strrchr(Name, PATHSEP);
  604. #ifdef DRSEP
  605.   if (!p)
  606.     p = strrchr(Name, DRSEP);
  607. #endif
  608.  
  609.   if (!p)
  610.     *s = '\0';
  611.   else
  612.     s[1] = '\0';
  613.  
  614.   return s;
  615. }
  616.  
  617. /*--------------------------------------------------------------------------*/
  618. /* Namensanteil von einem Dateinamen abspalten */
  619.  
  620. const char *NamePart(const char *Name)
  621. {
  622.   const char *p = strrchr(Name, PATHSEP);
  623.  
  624. #ifdef DRSEP
  625.   if (!p)
  626.     p = strrchr(Name, DRSEP);
  627. #endif
  628.  
  629.   return p ? p + 1 : Name;
  630. }
  631.  
  632. /****************************************************************************/
  633. /* eine Gleitkommazahl in einen String umwandeln */
  634.  
  635. void FloatString(char *pDest, size_t DestSize, Double f)
  636. {
  637. #define MaxLen 18
  638.   char *p, *d, ExpChar = HexStartCharacter + ('E' - 'A');
  639.   sint n, ExpVal, nzeroes;
  640.   Boolean WithE, OK;
  641.  
  642.   /* 1. mit Maximallaenge wandeln, fuehrendes Vorzeichen weg */
  643.  
  644.   (void)DestSize;
  645.   as_snprintf(pDest, DestSize, "%27.15e", f);
  646.   for (p = pDest; (*p == ' ') || (*p == '+'); p++);
  647.   if (p != pDest)
  648.     strmov(pDest, p);
  649.  
  650.   /* 2. Exponenten soweit als moeglich kuerzen, evtl. ganz streichen */
  651.  
  652.   p = strchr(pDest, ExpChar);
  653.   if (!p)
  654.     return;
  655.   switch (*(++p))
  656.   {
  657.     case '+':
  658.       strmov(p, p + 1);
  659.       break;
  660.     case '-':
  661.       p++;
  662.       break;
  663.   }
  664.  
  665.   while (*p == '0')
  666.     strmov(p, p + 1);
  667.   WithE = (*p != '\0');
  668.   if (!WithE)
  669.     pDest[strlen(pDest) - 1] = '\0';
  670.  
  671.   /* 3. Nullen am Ende der Mantisse entfernen, Komma bleibt noch */
  672.  
  673.   p = WithE ? strchr(pDest, ExpChar) : pDest + strlen(pDest);
  674.   p--;
  675.   while (*p == '0')
  676.   {
  677.     strmov(p, p + 1);
  678.     p--;
  679.   }
  680.  
  681.   /* 4. auf die gewuenschte Maximalstellenzahl begrenzen */
  682.  
  683.   p = WithE ? strchr(pDest, ExpChar) : pDest + strlen(pDest);
  684.   d = strchr(pDest, '.');
  685.   n = p - d - 1;
  686.  
  687.   /* 5. Maximallaenge ueberschritten ? */
  688.  
  689.   if (strlen(pDest) > MaxLen)
  690.     strmov(d + (n - (strlen(pDest) - MaxLen)), d + n);
  691.  
  692.   /* 6. Exponentenwert berechnen */
  693.  
  694.   if (WithE)
  695.   {
  696.     p = strchr(pDest, ExpChar);
  697.     ExpVal = ConstLongInt(p + 1, &OK, 10);
  698.   }
  699.   else
  700.   {
  701.     p = pDest + strlen(pDest);
  702.     ExpVal = 0;
  703.   }
  704.  
  705.   /* 7. soviel Platz, dass wir den Exponenten weglassen und evtl. Nullen
  706.        anhaengen koennen ? */
  707.  
  708.   if (ExpVal > 0)
  709.   {
  710.     nzeroes = ExpVal - (p - strchr(pDest, '.') - 1); /* = Zahl von Nullen, die anzuhaengen waere */
  711.  
  712.     /* 7a. nur Kommaverschiebung erforderlich. Exponenten loeschen und
  713.           evtl. auch Komma */
  714.  
  715.     if (nzeroes <= 0)
  716.     {
  717.       *p = '\0';
  718.       d = strchr(pDest, '.');
  719.       strmov(d, d + 1);
  720.       if (nzeroes != 0)
  721.       {
  722.         memmove(pDest + strlen(pDest) + nzeroes + 1, pDest + strlen(pDest) + nzeroes, -nzeroes);
  723.         pDest[strlen(pDest) - 1 + nzeroes] = '.';
  724.       }
  725.     }
  726.  
  727.     /* 7b. Es muessen Nullen angehaengt werden. Schauen, ob nach Loeschen von
  728.           Punkt und E-Teil genuegend Platz ist */
  729.  
  730.     else
  731.     {
  732.       n = strlen(p) + 1 + (MaxLen - strlen(pDest)); /* = Anzahl freizubekommender Zeichen+Gutschrift */
  733.       if (n >= nzeroes)
  734.       {
  735.         *p = '\0';
  736.         d = strchr(pDest, '.');
  737.         strmov(d, d + 1);
  738.         d = pDest + strlen(pDest);
  739.         for (n = 0; n < nzeroes; n++)
  740.           *(d++) = '0';
  741.         *d = '\0';
  742.       }
  743.     }
  744.   }
  745.  
  746.   /* 8. soviel Platz, dass Exponent wegkann und die Zahl mit vielen Nullen
  747.        vorne geschrieben werden kann ? */
  748.  
  749.   else if (ExpVal < 0)
  750.   {
  751.     n = (-ExpVal) - (strlen(p)); /* = Verlaengerung nach Operation */
  752.     if (strlen(pDest) + n <= MaxLen)
  753.     {
  754.       *p = '\0';
  755.       d = strchr(pDest, '.');
  756.       strmov(d, d + 1);
  757.       d = (pDest[0] == '-') ? pDest + 1 : pDest;
  758.       memmove(d - ExpVal + 1, d, strlen(pDest) + 1);
  759.       *(d++) = '0';
  760.       *(d++) = '.';
  761.       for (n = 0; n < -ExpVal - 1; n++)
  762.         *(d++) = '0';
  763.     }
  764.   }
  765.  
  766.  
  767.   /* 9. Ueberfluessiges Komma entfernen */
  768.  
  769.   if (WithE)
  770.     p = strchr(pDest, ExpChar);
  771.   else
  772.     p = pDest + strlen(pDest);
  773.   if (p && (*(p - 1) == '.'))
  774.     strmov(p - 1, p);
  775. }
  776.  
  777. /****************************************************************************/
  778. /* Symbol in String wandeln */
  779.  
  780. void StrSym(const TempResult *t, Boolean WithSystem, as_dynstr_t *p_dest, unsigned Radix)
  781. {
  782.   LargeInt IntVal;
  783.  
  784.   if (p_dest->capacity)
  785.     p_dest->p_str[0] = '\0';
  786.   switch (t->Typ)
  787.   {
  788.     case TempInt:
  789.       IntVal = t->Contents.Int;
  790.     IsInt:
  791.     {
  792.       String Buf;
  793.  
  794.       if (WithSystem)
  795.       {
  796.         switch (IntConstMode)
  797.         {
  798.           case eIntConstModeMoto:
  799.             as_sdprcatf(p_dest, "%s", GetIntConstMotoPrefix(Radix));
  800.             break;
  801.           case eIntConstModeC:
  802.             as_sdprcatf(p_dest, "%s", GetIntConstCPrefix(Radix));
  803.             break;
  804.           case eIntConstModeIBM:
  805.             as_sdprcatf(p_dest, "%s", GetIntConstIBMPrefix(Radix));
  806.             break;
  807.           default:
  808.             break;
  809.         }
  810.       }
  811.       SysString(Buf, sizeof(Buf), IntVal, Radix,
  812.                 1, (16 == Radix) && (IntConstMode == eIntConstModeIntel),
  813.                 HexStartCharacter, SplitByteCharacter);
  814.       as_sdprcatf(p_dest, "%s", Buf);
  815.       if (WithSystem)
  816.       {
  817.         switch (IntConstMode)
  818.         {
  819.           case eIntConstModeIntel:
  820.             as_sdprcatf(p_dest, GetIntConstIntelSuffix(Radix));
  821.             break;
  822.           case eIntConstModeIBM:
  823.             as_sdprcatf(p_dest, GetIntConstIBMSuffix(Radix));
  824.             break;
  825.           default:
  826.             break;
  827.         }
  828.       }
  829.       break;
  830.     }
  831.     case TempFloat:
  832.       FloatString(p_dest->p_str, p_dest->capacity, t->Contents.Float);
  833.       break;
  834.     case TempString:
  835.       as_tempres_append_dynstr(p_dest, t);
  836.       break;
  837.     case TempReg:
  838.       if (t->Contents.RegDescr.Dissect)
  839.         t->Contents.RegDescr.Dissect(p_dest->p_str, p_dest->capacity, t->Contents.RegDescr.Reg, t->DataSize);
  840.       else
  841.       {
  842.         IntVal = t->Contents.RegDescr.Reg;
  843.         goto IsInt;
  844.       }
  845.       break;
  846.     default:
  847.       as_sdprintf(p_dest, "???");
  848.   }
  849. }
  850.  
  851. /****************************************************************************/
  852. /* Listingzaehler zuruecksetzen */
  853.  
  854. void ResetPageCounter(void)
  855. {
  856.   int z;
  857.  
  858.   for (z = 0; z <= ChapMax; z++)
  859.     PageCounter[z] = 0;
  860.   LstCounter = 0;
  861.   ChapDepth = 0;
  862. }
  863.  
  864. /*--------------------------------------------------------------------------*/
  865. /* eine neue Seite im Listing beginnen */
  866.  
  867. void NewPage(ShortInt Level, Boolean WithFF)
  868. {
  869.   ShortInt z;
  870.   String Header, s;
  871.   char Save;
  872.  
  873.   if (ListOn == 0)
  874.     return;
  875.  
  876.   LstCounter = 0;
  877.  
  878.   if (ChapDepth < (Byte) Level)
  879.   {
  880.     memmove(PageCounter + (Level - ChapDepth), PageCounter, (ChapDepth + 1) * sizeof(Word));
  881.     for (z = 0; z <= Level - ChapDepth; PageCounter[z++] = 1);
  882.     ChapDepth = Level;
  883.   }
  884.   for (z = 0; z <= Level - 1; PageCounter[z++] = 1);
  885.   PageCounter[Level]++;
  886.  
  887.   if ((WithFF) && (!ListToNull))
  888.   {
  889.     errno = 0;
  890.     fprintf(LstFile, "%c", Char_FF);
  891.     ChkIO(ErrNum_ListWrError);
  892.   }
  893.  
  894.   as_snprintf(Header, sizeof(Header), " AS V%s%s%s",
  895.               Version,
  896.               getmessage(Num_HeadingFileNameLab),
  897.               NamePart(SourceFile));
  898.   if (strcmp(CurrFileName, "INTERNAL")
  899.    && *CurrFileName
  900.    && strcmp(NamePart(CurrFileName), NamePart(SourceFile)))
  901.   {
  902.     strmaxcat(Header, "(", STRINGSIZE);
  903.     strmaxcat(Header, NamePart(CurrFileName), STRINGSIZE);
  904.     strmaxcat(Header, ")", STRINGSIZE);
  905.   }
  906.   strmaxcat(Header, getmessage(Num_HeadingPageLab), STRINGSIZE);
  907.  
  908.   for (z = ChapDepth; z >= 0; z--)
  909.   {
  910.     as_snprintf(s, sizeof(s), IntegerFormat, PageCounter[z]);
  911.     strmaxcat(Header, s, STRINGSIZE);
  912.     if (z != 0)
  913.       strmaxcat(Header, ".", STRINGSIZE);
  914.   }
  915.  
  916.   strmaxcat(Header, " - ", STRINGSIZE);
  917.   NLS_CurrDateString(s, sizeof(s));
  918.   strmaxcat(Header, s, STRINGSIZE);
  919.   strmaxcat(Header, " ", STRINGSIZE);
  920.   NLS_CurrTimeString(False, s, sizeof(s));
  921.   strmaxcat(Header, s, STRINGSIZE);
  922.  
  923.   if (PageWidth != 0)
  924.     while (strlen(Header) > PageWidth)
  925.     {
  926.       Save = Header[PageWidth];
  927.       Header[PageWidth] = '\0';
  928.       if (!ListToNull)
  929.       {
  930.         errno = 0;
  931.         fprintf(LstFile, "%s\n", Header);
  932.         ChkIO(ErrNum_ListWrError);
  933.       }
  934.       Header[PageWidth] = Save;
  935.       strmov(Header, Header + PageWidth);
  936.     }
  937.  
  938.   if (!ListToNull)
  939.   {
  940.     errno = 0;
  941.     fprintf(LstFile, "%s\n", Header);
  942.     ChkIO(ErrNum_ListWrError);
  943.  
  944.     if (PrtTitleString[0])
  945.     {
  946.       errno = 0;
  947.       fprintf(LstFile, "%s\n", PrtTitleString);
  948.       ChkIO(ErrNum_ListWrError);
  949.     }
  950.  
  951.     errno = 0;
  952.     fprintf(LstFile, "\n\n");
  953.     ChkIO(ErrNum_ListWrError);
  954.   }
  955. }
  956.  
  957. /*--------------------------------------------------------------------------*/
  958. /* eine Zeile ins Listing schieben */
  959.  
  960. void WrLstLine(const char *Line)
  961. {
  962.   int LLength;
  963.   char bbuf[2500];
  964.   String LLine;
  965.   int blen = 0, hlen, z, Start;
  966.  
  967.   if ((ListOn == 0) || (ListToNull))
  968.     return;
  969.  
  970.   if (PageLength == 0)
  971.   {
  972.     errno = 0;
  973.     fprintf(LstFile, "%s\n", Line);
  974.     ChkIO(ErrNum_ListWrError);
  975.   }
  976.   else
  977.   {
  978.     if ((PageWidth == 0) || ((strlen(Line) << 3) < PageWidth))
  979.       LLength = 1;
  980.     else
  981.     {
  982.       blen = 0;
  983.       for (z = 0; z < (int)strlen(Line);  z++)
  984.         if (Line[z] == Char_HT)
  985.         {
  986.           memset(bbuf + blen, ' ', 8 - (blen & 7));
  987.           blen += 8 - (blen&7);
  988.         }
  989.         else
  990.           bbuf[blen++] = Line[z];
  991.       LLength = blen / PageWidth;
  992.       if (blen % PageWidth)
  993.         LLength++;
  994.     }
  995.     if (LLength == 1)
  996.     {
  997.       errno = 0;
  998.       fprintf(LstFile, "%s\n", Line);
  999.       ChkIO(ErrNum_ListWrError);
  1000.       if ((++LstCounter) == PageLength)
  1001.         NewPage(0, True);
  1002.     }
  1003.     else
  1004.     {
  1005.       Start = 0;
  1006.       for (z = 1; z <= LLength; z++)
  1007.       {
  1008.         hlen = PageWidth;
  1009.         if (blen - Start < hlen)
  1010.           hlen = blen - Start;
  1011.         memcpy(LLine, bbuf + Start, hlen);
  1012.         LLine[hlen] = '\0';
  1013.         errno = 0;
  1014.         fprintf(LstFile, "%s\n", LLine);
  1015.         if ((++LstCounter) == PageLength)
  1016.           NewPage(0, True);
  1017.         Start += hlen;
  1018.       }
  1019.     }
  1020.   }
  1021. }
  1022.  
  1023. /*****************************************************************************/
  1024. /* Ausdruck in Spalte vor Listing */
  1025.  
  1026. void SetListLineVal(TempResult *t)
  1027. {
  1028.   as_dynstr_t str;
  1029.  
  1030.   as_dynstr_ini(&str, STRINGSIZE);
  1031.   StrSym(t, True, &str, ListRadixBase);
  1032.   as_snprintf(ListLine, STRINGSIZE, "=%s", str.p_str);
  1033.   as_dynstr_free(&str);
  1034. }
  1035.  
  1036. /*!------------------------------------------------------------------------
  1037.  * \fn     PrintOneLineMuted(FILE *pFile, const char *pLine,
  1038.                              const struct sLineComp *pMuteComponent,
  1039.                              const struct sLineComp *pMuteComponent2)
  1040.  * \brief  print a line, with a certain component muted out (i.e. replaced by spaces)
  1041.  * \param  pFile where to write
  1042.  * \param  pLine line to print
  1043.  * \param  pMuteComponent component to mute in printout
  1044.  * ------------------------------------------------------------------------ */
  1045.  
  1046. static Boolean CompMatch(int Col, const struct sLineComp *pComp)
  1047. {
  1048.   return (pComp
  1049.        && (pComp->StartCol >= 0)
  1050.        && (Col >= pComp->StartCol)
  1051.        && (Col < pComp->StartCol + (int)pComp->Len));
  1052. }
  1053.  
  1054. void PrintOneLineMuted(FILE *pFile, const char *pLine,
  1055.                        const struct sLineComp *pMuteComponent,
  1056.                        const struct sLineComp *pMuteComponent2)
  1057. {
  1058.   int z, Len = strlen(pLine);
  1059.   Boolean Match;
  1060.  
  1061.   errno = 0;
  1062.   for (z = 0; z < Len; z++)
  1063.   {
  1064.     Match = CompMatch(z, pMuteComponent) || CompMatch(z, pMuteComponent2);
  1065.     fputc(Match ? ' ' : pLine[z], pFile);
  1066.   }
  1067.   fputc('\n', pFile);
  1068.   ChkIO(ErrNum_ListWrError);
  1069. }
  1070.  
  1071. /*!------------------------------------------------------------------------
  1072.  * \fn     PrLineMarker(FILE *pFile, const char *pLine, const char *pPrefix, const char *pTrailer,
  1073.                         char Marker, const struct sLineComp *pLineComp)
  1074.  * \brief  print a line, optionally with a marking of a component below
  1075.  * \param  pFile where to write
  1076.  * \param  pLine line to print/underline
  1077.  * \param  pPrefix what to print before (under)line
  1078.  * \param  pTrailer what to print after (under)line
  1079.  * \param  Marker character to use for marking
  1080.  * \param  pLineComp position and length of optional marker
  1081.  * ------------------------------------------------------------------------ */
  1082.  
  1083. void PrLineMarker(FILE *pFile, const char *pLine, const char *pPrefix, const char *pTrailer,
  1084.                   char Marker, const struct sLineComp *pLineComp)
  1085. {
  1086.   const char *pRun;
  1087.   int z;
  1088.  
  1089.   fputs(pPrefix, pFile);
  1090.   for (pRun = pLine; *pRun; pRun++)
  1091.     fputc(TabCompressed(*pRun), pFile);
  1092.   fprintf(pFile, "%s\n", pTrailer);
  1093.  
  1094.   if (pLineComp && (pLineComp->StartCol >= 0) && (pLineComp->Len > 0))
  1095.   {
  1096.     fputs(pPrefix, pFile);
  1097.     if (pLineComp->StartCol > 0)
  1098.       fprintf(pFile, "%*s", pLineComp->StartCol, "");
  1099.     for (z = 0; z < (int)pLineComp->Len; z++)
  1100.       fputc(Marker, pFile);
  1101.     fprintf(pFile, "%s\n", pTrailer);
  1102.   }
  1103. }
  1104.  
  1105. /****************************************************************************/
  1106. /* einen Symbolnamen auf Gueltigkeit ueberpruefen */
  1107.  
  1108. static Byte GetValidSymChar(unsigned Ch)
  1109. {
  1110.   return (Ch < ValidSymCharLen) ? ValidSymChar[Ch] : 0;
  1111. }
  1112.  
  1113. static char *ChkNameUpTo(const char *pSym, const char *pUpTo, Byte _Mask)
  1114. {
  1115.   Byte Mask = _Mask;
  1116.   unsigned Ch;
  1117.   const char *pPrev;
  1118.  
  1119.   if (!*pSym)
  1120.     return (char*)pSym;
  1121.  
  1122.   while (*pSym && (pSym != pUpTo))
  1123.   {
  1124.     pPrev = pSym;
  1125.     if (ValidSymCharLen > 256)
  1126.       Ch = UTF8ToUnicode(&pSym);
  1127.     else
  1128.       Ch = ((unsigned int)*pSym++) & 0xff;
  1129.  
  1130.     if (!(GetValidSymChar(Ch) & Mask))
  1131.       return (char*)pPrev;
  1132.     Mask = _Mask << 1;
  1133.   }
  1134.   return (char*)pSym;
  1135. }
  1136.  
  1137. char *ChkSymbNameUpTo(const char *pSym, const char *pUpTo)
  1138. {
  1139.   char *pResult = ChkNameUpTo(pSym, pUpTo, VALID_S1);
  1140.  
  1141.   /* If NULL as UpTo was given, and all is fine up to end of string,
  1142.      also return NULL as result.  So Equation 'Result==UpTo' is fulfilled: */
  1143.  
  1144.   if (!pUpTo && !*pResult)
  1145.      pResult= NULL;
  1146.   return pResult;
  1147. }
  1148.  
  1149. Boolean ChkSymbName(const char *pSym)
  1150. {
  1151.   const char *pEnd = ChkSymbNameUpTo(pSym, NULL);
  1152.   return *pSym && !pEnd;
  1153. }
  1154.  
  1155. char *ChkMacSymbNameUpTo(const char *pSym, const char *pUpTo)
  1156. {
  1157.   char *pResult = ChkNameUpTo(pSym, pUpTo, VALID_M1);
  1158.  
  1159.   /* If NULL as UpTo was given, and all is fine up to end of string,
  1160.      also return NULL as result.  So Equation 'Result==UpTo' is fulfilled: */
  1161.  
  1162.   if (!pUpTo && !*pResult)
  1163.      pResult= NULL;
  1164.   return pResult;
  1165. }
  1166.  
  1167. Boolean ChkMacSymbName(const char *pSym)
  1168. {
  1169.   const char *pEnd = ChkMacSymbNameUpTo(pSym, NULL);
  1170.   return *pSym && !pEnd;
  1171. }
  1172.  
  1173. Boolean ChkMacSymbChar(char ch)
  1174. {
  1175.   return !!(GetValidSymChar(ch) & (VALID_M1 | VALID_MN));
  1176. }
  1177.  
  1178. /*!------------------------------------------------------------------------
  1179.  * \fn     visible_strlen(const char *pSym)
  1180.  * \brief  retrieve 'visible' length of string, regarding multi-byte
  1181.            sequences for UTF-8
  1182.  * \param  pSym symbol name
  1183.  * \return visible length in characters
  1184.  * ------------------------------------------------------------------------ */
  1185.  
  1186. unsigned visible_strlen(const char *pSym)
  1187. {
  1188.   if (ValidSymCharLen > 256)
  1189.   {
  1190.     unsigned Result = 0;
  1191.  
  1192.     while (*pSym)
  1193.       Result += as_wcwidth(UTF8ToUnicode(&pSym));
  1194.     return Result;
  1195.   }
  1196.   else
  1197.     return strlen(pSym);
  1198. }
  1199.  
  1200. /****************************************************************************/
  1201.  
  1202. LargeWord ProgCounter(void)
  1203. {
  1204.   return PCs[ActPC];
  1205. }
  1206.  
  1207. /*--------------------------------------------------------------------------*/
  1208. /* aktuellen Programmzaehler mit Phasenverschiebung holen */
  1209.  
  1210. LargeWord EProgCounter(void)
  1211. {
  1212.   return PCs[ActPC] + Phases[ActPC];
  1213. }
  1214.  
  1215. /*--------------------------------------------------------------------------*/
  1216. /* Granularitaet des aktuellen Segments holen */
  1217.  
  1218. Word Granularity(void)
  1219. {
  1220.   return Grans[ActPC];
  1221. }
  1222.  
  1223. /*--------------------------------------------------------------------------*/
  1224. /* Linstingbreite des aktuellen Segments holen */
  1225.  
  1226. Word ListGran(void)
  1227. {
  1228.   return ListGrans[ActPC];
  1229. }
  1230.  
  1231. /*--------------------------------------------------------------------------*/
  1232. /* pruefen, ob alle Symbole einer Formel im korrekten Adressraum lagen */
  1233.  
  1234. void ChkSpace(Byte AddrSpace, unsigned AddrSpaceMask)
  1235. {
  1236.   AddrSpaceMask &= ~(1 << AddrSpace);
  1237.  
  1238.   if (AddrSpaceMask) WrError(ErrNum_WrongSegment);
  1239. }
  1240.  
  1241. /****************************************************************************/
  1242. /* eine Chunkliste im Listing ausgeben & Speicher loeschen */
  1243.  
  1244. void PrintChunk(ChunkList *NChunk, DissectBitProc Dissect, int ItemsPerLine)
  1245. {
  1246.   LargeWord NewMin, FMin;
  1247.   Boolean Found;
  1248.   Word p = 0, z;
  1249.   int BufferZ;
  1250.   String BufferS;
  1251.   int MaxItemLen = 79 / ItemsPerLine;
  1252.  
  1253.   NewMin = 0;
  1254.   BufferZ = 0;
  1255.   *BufferS = '\0';
  1256.  
  1257.   do
  1258.   {
  1259.     /* niedrigsten Start finden, der ueberhalb des letzten Endes liegt */
  1260.  
  1261.     Found = False;
  1262.     FMin = IntTypeDefs[LargeUIntType].Max;
  1263.     for (z = 0; z < NChunk->RealLen; z++)
  1264.       if (NChunk->Chunks[z].Start >= NewMin)
  1265.         if (FMin > NChunk->Chunks[z].Start)
  1266.         {
  1267.           Found = True;
  1268.           FMin = NChunk->Chunks[z].Start;
  1269.           p = z;
  1270.         }
  1271.  
  1272.     if (Found)
  1273.     {
  1274.       char Num[30];
  1275.  
  1276.       Dissect(Num, sizeof(Num), NChunk->Chunks[p].Start);
  1277.       strmaxcat(BufferS, Num, STRINGSIZE);
  1278.       if (NChunk->Chunks[p].Length != 1)
  1279.       {
  1280.         strmaxcat(BufferS, "-", STRINGSIZE);
  1281.         Dissect(Num, sizeof(Num), NChunk->Chunks[p].Start + NChunk->Chunks[p].Length - 1);
  1282.         strmaxcat(BufferS, Num, STRINGSIZE);
  1283.       }
  1284.       strmaxcat(BufferS, Blanks(MaxItemLen - strlen(BufferS) % MaxItemLen), STRINGSIZE);
  1285.       if (++BufferZ == ItemsPerLine)
  1286.       {
  1287.         WrLstLine(BufferS);
  1288.         *BufferS = '\0';
  1289.         BufferZ = 0;
  1290.       }
  1291.       NewMin = NChunk->Chunks[p].Start + NChunk->Chunks[p].Length;
  1292.     }
  1293.   }
  1294.   while (Found);
  1295.  
  1296.   if (BufferZ != 0)
  1297.     WrLstLine(BufferS);
  1298. }
  1299.  
  1300. /*--------------------------------------------------------------------------*/
  1301. /* Listen ausgeben */
  1302.  
  1303. void PrintUseList(void)
  1304. {
  1305.   int z, z2, l;
  1306.   String s;
  1307.  
  1308.   for (z = 1; z < SegCount; z++)
  1309.     if (SegChunks[z].Chunks)
  1310.     {
  1311.       as_snprintf(s, sizeof(s), "  %s%s%s",
  1312.                   getmessage(Num_ListSegListHead1), SegNames[z],
  1313.                   getmessage(Num_ListSegListHead2));
  1314.       WrLstLine(s);
  1315.       strcpy(s, "  ");
  1316.       l = strlen(SegNames[z]) + strlen(getmessage(Num_ListSegListHead1)) + strlen(getmessage(Num_ListSegListHead2));
  1317.       for (z2 = 0; z2 < l; z2++)
  1318.         strmaxcat(s, "-", STRINGSIZE);
  1319.       WrLstLine(s);
  1320.       WrLstLine("");
  1321.       PrintChunk(SegChunks + z,
  1322.                  (z == SegBData) ? DissectBit : Default_DissectBit,
  1323.                  (z == SegBData) ? 3 : 4);
  1324.       WrLstLine("");
  1325.     }
  1326. }
  1327.  
  1328. void ClearUseList(void)
  1329. {
  1330.   int z;
  1331.  
  1332.   for (z = 1; z < SegCount; z++)
  1333.     ClearChunk(SegChunks + z);
  1334. }
  1335.  
  1336. /****************************************************************************/
  1337. /* Include-Pfadlistenverarbeitung */
  1338.  
  1339. /*!------------------------------------------------------------------------
  1340.  * \fn     get_first_path_from_list(const char *p_path_list, char *p_first_path, size_t first_path_size)
  1341.  * \brief  extract first path from list of paths
  1342.  * \param  p_path_list path list
  1343.  * \param  p_first_path where to put component
  1344.  * \param  first_path_size buffer size
  1345.  * \return p_path_list for next call of get_first_path_from_list()
  1346.  * ------------------------------------------------------------------------ */
  1347.  
  1348. static const char *get_first_path_from_list(const char *p_path_list, char *p_first_path, size_t first_path_size)
  1349. {
  1350.   const char *p;
  1351.  
  1352.   p = strchr(p_path_list, DIRSEP);
  1353.   if (!p)
  1354.   {
  1355.     strmaxcpy(p_first_path, p_path_list, first_path_size);
  1356.     return "";
  1357.   }
  1358.   else
  1359.   {
  1360.     strmemcpy(p_first_path, first_path_size, p_path_list, p - p_path_list);
  1361.     return p + 1;
  1362.   }
  1363. }
  1364.  
  1365. /*!------------------------------------------------------------------------
  1366.  * \fn     AddIncludeList(const char *p_new_path)
  1367.  * \brief  add path to include list
  1368.  * \param  p_new_path path to add
  1369.  * ------------------------------------------------------------------------ */
  1370.  
  1371. void AddIncludeList(const char *p_new_path)
  1372. {
  1373.   const char *p_list_run = IncludeList;
  1374.   String one_path;
  1375.  
  1376.   /* path already present in list? */
  1377.  
  1378.   while (*p_list_run)
  1379.   {
  1380.     p_list_run = get_first_path_from_list(p_list_run, one_path, sizeof(one_path));
  1381.     if (!strcmp(one_path, p_new_path))
  1382.       return;
  1383.   }
  1384.  
  1385.   /* no -> prepend */
  1386.  
  1387.   if (*IncludeList != '\0')
  1388.     strmaxprep(IncludeList, SDIRSEP, STRINGSIZE);
  1389.   strmaxprep(IncludeList, p_new_path, STRINGSIZE);
  1390. }
  1391.  
  1392. /*!------------------------------------------------------------------------
  1393.  * \fn     RemoveIncludeList(const char *p_rem_path)
  1394.  * \brief  remove one path from include list
  1395.  * \param  p_rem_path path to remove
  1396.  * ------------------------------------------------------------------------ */
  1397.  
  1398. void RemoveIncludeList(const char *p_rem_path)
  1399. {
  1400.   String one_path;
  1401.   const char *p_list_run, *p_list_next;
  1402.  
  1403.   p_list_run = IncludeList;
  1404.   while (*p_list_run)
  1405.   {
  1406.     p_list_next = get_first_path_from_list(p_list_run, one_path, sizeof(one_path));
  1407.     if (!strcmp(one_path, p_rem_path))
  1408.       strmov((char*)p_list_run, p_list_next);
  1409.     else
  1410.       p_list_run = p_list_next;
  1411.   }
  1412. }
  1413.  
  1414. /****************************************************************************/
  1415. /* Listen mit Ausgabedateien */
  1416.  
  1417. void ClearOutList(void)
  1418. {
  1419.   ClearStringList(&OutList);
  1420. }
  1421.  
  1422. void AddToOutList(const char *NewName)
  1423. {
  1424.   AddStringListLast(&OutList, NewName);
  1425. }
  1426.  
  1427. void RemoveFromOutList(const char *OldName)
  1428. {
  1429.   RemoveStringList(&OutList, OldName);
  1430. }
  1431.  
  1432. char *MoveFromOutListFirst(void)
  1433. {
  1434.   return MoveAndCutStringListFirst(&OutList);
  1435. }
  1436.  
  1437. void ClearShareOutList(void)
  1438. {
  1439.   ClearStringList(&ShareOutList);
  1440. }
  1441.  
  1442. void AddToShareOutList(const char *NewName)
  1443. {
  1444.   AddStringListLast(&ShareOutList, NewName);
  1445. }
  1446.  
  1447. void RemoveFromShareOutList(const char *OldName)
  1448. {
  1449.   RemoveStringList(&ShareOutList, OldName);
  1450. }
  1451.  
  1452. char *MoveFromShareOutListFirst(void)
  1453. {
  1454.   return MoveAndCutStringListFirst(&ShareOutList);
  1455. }
  1456.  
  1457. void ClearListOutList(void)
  1458. {
  1459.   ClearStringList(&ListOutList);
  1460. }
  1461.  
  1462. void AddToListOutList(const char *NewName)
  1463. {
  1464.   AddStringListLast(&ListOutList, NewName);
  1465. }
  1466.  
  1467. void RemoveFromListOutList(const char *OldName)
  1468. {
  1469.   RemoveStringList(&ListOutList, OldName);
  1470. }
  1471.  
  1472. char *MoveFromListOutListFirst(void)
  1473. {
  1474.   return MoveAndCutStringListFirst(&ListOutList);
  1475. }
  1476.  
  1477. /****************************************************************************/
  1478. /* Tokenverarbeitung */
  1479.  
  1480. typedef int (*tCompareFnc)(const char *s1, const char *s2, size_t n);
  1481.  
  1482. int ReplaceLine(as_dynstr_t *p_str, const char *pSearch, const char *pReplace, Boolean CaseSensitive)
  1483. {
  1484.   int SearchLen = strlen(pSearch), ReplaceLen = strlen(pReplace), StrLen = strlen(p_str->p_str), DeltaLen = ReplaceLen - SearchLen;
  1485.   int NumReplace = 0, Pos, End, CmpRes, Avail, nCopy, nMove;
  1486.   tCompareFnc Compare = CaseSensitive ? strncmp : as_strncasecmp;
  1487.  
  1488.   Pos = 0;
  1489.   while (Pos <= StrLen - SearchLen)
  1490.   {
  1491.     End = Pos + SearchLen;
  1492.     CmpRes = Compare(&p_str->p_str[Pos], pSearch, SearchLen);
  1493.     if ((!CmpRes)
  1494.      && ((Pos == 0) || !ChkMacSymbChar(p_str->p_str[Pos - 1]))
  1495.      && ((End >= StrLen) || !ChkMacSymbChar(p_str->p_str[End])))
  1496.     {
  1497.       if (StrLen + DeltaLen + 1 > (int)p_str->capacity)
  1498.         as_dynstr_realloc(p_str, as_dynstr_roundup_len(p_str->capacity + DeltaLen));
  1499.       Avail = p_str->capacity - 1 - Pos;
  1500.       nCopy = ReplaceLen; if (nCopy > Avail) nCopy = Avail;
  1501.       Avail -= nCopy;
  1502.       nMove = StrLen - (Pos + SearchLen); if (nMove > Avail) nMove = Avail;
  1503.       memmove(&p_str->p_str[Pos + nCopy], &p_str->p_str[Pos + SearchLen], nMove);
  1504.       memcpy(&p_str->p_str[Pos], pReplace, nCopy);
  1505.       p_str->p_str[Pos + nCopy + nMove] = '\0';
  1506.       Pos += nCopy;
  1507.       StrLen += DeltaLen;
  1508.       NumReplace++;
  1509.     }
  1510.     else
  1511.       Pos++;
  1512.   }
  1513.   return NumReplace;
  1514. }
  1515.  
  1516. static void SetToken(char *Token, unsigned TokenNum)
  1517. {
  1518.   Token[0] = (TokenNum >> 4) + 1;
  1519.   Token[1] = (TokenNum & 15) + 1;
  1520.   Token[2] = 0;
  1521. }
  1522.  
  1523. /*!------------------------------------------------------------------------
  1524.  * \fn     CompressLine(const char *TokNam, unsigned TokenNum, as_dynstr_t *p_str, Boolean ThisCaseSensitive)
  1525.  * \brief  compress tokens in line
  1526.  * \param  TokNam name to compress into token
  1527.  * \param  TokenNum token #
  1528.  * \param  p_str string to work on
  1529.  * \param  ThisCaseSensitive operate case sensitive?
  1530.  * ------------------------------------------------------------------------ */
  1531.  
  1532. int CompressLine(const char *TokNam, unsigned TokenNum, as_dynstr_t *p_str, Boolean ThisCaseSensitive)
  1533. {
  1534.   char Token[3];
  1535.   SetToken(Token, TokenNum);
  1536.   return ReplaceLine(p_str, TokNam, Token, ThisCaseSensitive);
  1537. }
  1538.  
  1539. /*!------------------------------------------------------------------------
  1540.  * \fn     ExpandLine(const char *TokNam, unsigned TokenNum, as_dynstr_t *p_str)
  1541.  * \brief  expand tokens in line
  1542.  * \param  TokNam name to expand token to
  1543.  * \param  TokenNum token #
  1544.  * \param  p_str string to work on
  1545.  * ------------------------------------------------------------------------ */
  1546.  
  1547. void ExpandLine(const char *TokNam, unsigned TokenNum, as_dynstr_t *p_str)
  1548. {
  1549.   char Token[3];
  1550.   SetToken(Token, TokenNum);
  1551.   (void)ReplaceLine(p_str, Token, TokNam, True);
  1552. }
  1553.  
  1554. void KillCtrl(char *Line)
  1555. {
  1556.   char *z;
  1557.  
  1558.   if (*(z = Line) == '\0')
  1559.     return;
  1560.   do
  1561.   {
  1562.     if (*z == '\0');
  1563.     else if (*z == Char_HT)
  1564.     {
  1565.       strmov(z, z + 1);
  1566.       strprep(z, Blanks(8 - ((z - Line) % 8)));
  1567.     }
  1568.     else if ((*z & 0xe0) == 0)
  1569.       *z = ' ';
  1570.     z++;
  1571.   }
  1572.   while (*z != '\0');
  1573. }
  1574.  
  1575. /****************************************************************************/
  1576. /* Buchhaltung */
  1577.  
  1578. void BookKeeping(void)
  1579. {
  1580.   if (MakeUseList)
  1581.     if (AddChunk(SegChunks + ActPC, ProgCounter(), CodeLen, ActPC == SegCode))
  1582.       WrError(ErrNum_Overlap);
  1583.   if (DebugMode != DebugNone)
  1584.   {
  1585.     AddSectionUsage(ProgCounter(), CodeLen);
  1586.     AddLineInfo(InMacroFlag, CurrLine, CurrFileName, ActPC, PCs[ActPC], CodeLen);
  1587.   }
  1588. }
  1589.  
  1590. /****************************************************************************/
  1591. /* Differenz zwischen zwei Zeiten mit Tagesueberlauf berechnen */
  1592.  
  1593. long DTime(long t1, long t2)
  1594. {
  1595.   LongInt d;
  1596.  
  1597.   d = t2 - t1;
  1598.   if (d < 0) d += (24*360000);
  1599.   return (d > 0) ? d : -d;
  1600. }
  1601.  
  1602. /*--------------------------------------------------------------------------*/
  1603. /* Init/Deinit passes */
  1604.  
  1605. typedef struct sProcStore
  1606. {
  1607.   struct sProcStore *pNext;
  1608.   SimpProc Proc;
  1609. } tProcStore;
  1610.  
  1611. static tProcStore *pInitPassProcStore = NULL,
  1612.                   *pClearUpProcStore = NULL;
  1613.  
  1614. void InitPass(void)
  1615. {
  1616.   tProcStore *pStore;
  1617.  
  1618.   for (pStore = pInitPassProcStore; pStore; pStore = pStore->pNext)
  1619.     pStore->Proc();
  1620. }
  1621.  
  1622. void ClearUp(void)
  1623. {
  1624.   tProcStore *pStore;
  1625.  
  1626.   for (pStore = pClearUpProcStore; pStore; pStore = pStore->pNext)
  1627.     pStore->Proc();
  1628. }
  1629.  
  1630. void AddInitPassProc(SimpProc NewProc)
  1631. {
  1632.   tProcStore *pNewStore = (tProcStore*)calloc(1, sizeof(*pNewStore));
  1633.  
  1634.   pNewStore->pNext = pInitPassProcStore;
  1635.   pNewStore->Proc = NewProc;
  1636.   pInitPassProcStore = pNewStore;
  1637. }
  1638.  
  1639. void AddClearUpProc(SimpProc NewProc)
  1640. {
  1641.   tProcStore *pNewStore = (tProcStore*)calloc(1, sizeof(*pNewStore));
  1642.  
  1643.   pNewStore->pNext = pClearUpProcStore;
  1644.   pNewStore->Proc = NewProc;
  1645.   pClearUpProcStore = pNewStore;
  1646. }
  1647.  
  1648. /*!------------------------------------------------------------------------
  1649.  * \fn     GTime(void)
  1650.  * \brief  fetch time of day in units of 10 ms
  1651.  * \return time of day
  1652.  * ------------------------------------------------------------------------ */
  1653.  
  1654. #ifdef __MSDOS__
  1655.  
  1656. #include <dos.h>
  1657.  
  1658. long GTime(void)
  1659. {
  1660.   struct time tbuf;
  1661.   long result;
  1662.  
  1663.   gettime(&tbuf);
  1664.   result = tbuf.ti_hour;
  1665.   result = (result * 60) + tbuf.ti_min;
  1666.   result = (result * 60) + tbuf.ti_sec;
  1667.   result = (result * 100) + tbuf.ti_hund;
  1668.   return result;
  1669. }
  1670.  
  1671. # define GTIME_DEFINED
  1672. #endif /* __MSDOS__ */
  1673.  
  1674. #ifdef __IBMC__
  1675.  
  1676. #include <time.h>
  1677. #define INCL_DOSDATETIME
  1678. #include <os2.h>
  1679.  
  1680. long GTime(void)
  1681. {
  1682.   DATETIME dt;
  1683.   struct tm ts;
  1684.   DosGetDateTime(&dt);
  1685.   memset(&ts, 0, sizeof(ts));
  1686.   ts.tm_year = dt.year - 1900;
  1687.   ts.tm_mon  = dt.month - 1;
  1688.   ts.tm_mday = dt.day;
  1689.   ts.tm_hour = dt.hours;
  1690.   ts.tm_min  = dt.minutes;
  1691.   ts.tm_sec  = dt.seconds;
  1692.   return (mktime(&ts) * 100) + (dt.hundredths);
  1693. }
  1694.  
  1695. # define GTIME_DEFINED
  1696. #endif /* __IBMC__ */
  1697.  
  1698. #ifdef _WIN32
  1699.  
  1700. # include <windows.h>
  1701.  
  1702. # ifdef NOLONGLONG
  1703. #  include "math64.h"
  1704. # endif
  1705.  
  1706. long GTime(void)
  1707. {
  1708.   FILETIME ft;
  1709.  
  1710.   GetSystemTimeAsFileTime(&ft);
  1711. # ifdef NOLONGLONG
  1712.   {
  1713.     static const t64 offs = { 0xd53e8000, 0x019db1de },
  1714.                      div = { 100000, 0 },
  1715.                      mod = { 8640000, 0 };
  1716.     t64 acc;
  1717.  
  1718.     /* time since 1 Jan 1601 in 100ns units */
  1719.     acc.low = ft.dwLowDateTime;
  1720.     acc.high = ft.dwHighDateTime;
  1721.     /* -> time since 1 Jan 1970 in 100ns units */
  1722.     sub64(&acc, &acc, &offs);
  1723.     /* -> time since 1 Jan 1970 in 10ms units */
  1724.     div64(&acc, &acc, &div);
  1725.     /* -> time since 0:00:00.0 in 10ms units */
  1726.     mod64(&acc, &acc, &mod);
  1727.     return acc.low;
  1728.   }
  1729. # else /* !NOLONGLONG */
  1730. #  define _W32_FT_OFFSET (116444736000000000ULL)
  1731.   unsigned long long time_tot;
  1732.   /* time since 1 Jan 1601 in 100ns units */
  1733.   time_tot =  ((unsigned long long)ft.dwLowDateTime )      ;
  1734.   time_tot += ((unsigned long long)ft.dwHighDateTime) << 32;
  1735.  
  1736.   /* -> time since 1 Jan 1970 in 100ns units */
  1737.   time_tot -= _W32_FT_OFFSET;
  1738.   /* -> time since 1 Jan 1970 in 10ms units */
  1739.   time_tot /= 100000ULL;
  1740.   /* -> time since 0:00:00.0 in 10ms units */
  1741.   time_tot %= 8640000ULL;
  1742.   return time_tot;
  1743. # endif /* NOLONGLONG */
  1744. }
  1745.  
  1746. # define GTIME_DEFINED
  1747. #endif /* _WIN32 */
  1748.  
  1749. #ifndef GTIME_DEFINED
  1750.  
  1751. #include <sys/time.h>
  1752.  
  1753. long GTime(void)
  1754. {
  1755.   struct timeval tv;
  1756.  
  1757.   gettimeofday(&tv, NULL);
  1758.   tv.tv_sec %= 86400;
  1759.   return (tv.tv_sec * 100) + (tv.tv_usec/10000);
  1760. }
  1761.  
  1762. #endif /* GTIME_DEFINED */
  1763.  
  1764. /*-------------------------------------------------------------------------*/
  1765. /* Stackfehler abfangen - bis auf DOS nur Dummies */
  1766.  
  1767. #ifdef __TURBOC__
  1768.  
  1769. #ifdef __DPMI16__
  1770. #else
  1771. unsigned _stklen = STKSIZE;
  1772. unsigned _ovrbuffer = 64*48;
  1773. #endif
  1774. #include <malloc.h>
  1775.  
  1776. void ChkStack(void)
  1777. {
  1778.   LongWord avail = stackavail();
  1779.   if (avail < MinStack)
  1780.     WrError(ErrNum_StackOvfl);
  1781.   if (avail < LowStack)
  1782.     LowStack = avail;
  1783. }
  1784.  
  1785. void ResetStack(void)
  1786. {
  1787.   LowStack = stackavail();
  1788. }
  1789.  
  1790. LongWord StackRes(void)
  1791. {
  1792.   return LowStack - MinStack;
  1793. }
  1794. #endif /* __TURBOC__ */
  1795.  
  1796. #ifdef CKMALLOC
  1797. #undef malloc
  1798. #undef realloc
  1799.  
  1800. void *ckmalloc(size_t s)
  1801. {
  1802.   void *tmp;
  1803.  
  1804. #ifdef __TURBOC__
  1805.   if (coreleft() < HEAPRESERVE + s)
  1806.     WrError(ErrNum_HeapOvfl);
  1807. #endif
  1808.  
  1809.   tmp = malloc(s);
  1810.   if (!tmp && (s > 0))
  1811.     WrError(ErrNum_HeapOvfl);
  1812.   return tmp;
  1813. }
  1814.  
  1815. void *ckrealloc(void *p, size_t s)
  1816. {
  1817.   void *tmp;
  1818.  
  1819. #ifdef __TURBOC__
  1820.   if (coreleft() < HEAPRESERVE + s)
  1821.     WrError(ErrNum_HeapOvfl);
  1822. #endif
  1823.  
  1824.   tmp = realloc(p, s);
  1825.   if (!tmp)
  1826.     WrError(ErrNum_HeapOvfl);
  1827.   return tmp;
  1828. }
  1829. #endif
  1830.  
  1831. static void SetValidSymChar(unsigned Ch, Byte Value)
  1832. {
  1833.   ValidSymChar[Ch] = Value;
  1834. }
  1835.  
  1836. static void SetValidSymChars(unsigned Start, unsigned Stop, Byte Value)
  1837. {
  1838.   for (; Start <= Stop; Start++)
  1839.     SetValidSymChar(Start, Value);
  1840. }
  1841.  
  1842. static as_cmd_result_t cmd_underscore_macroargs(Boolean negate, const char *p_arg)
  1843. {
  1844.   unsigned ch = (unsigned)'_';
  1845.  
  1846.   UNUSED(p_arg);
  1847.   if (negate)
  1848.     ValidSymChar[ch] &= ~(VALID_M1 | VALID_MN);
  1849.   else
  1850.     ValidSymChar[ch] |= (VALID_M1 | VALID_MN);
  1851.   return e_cmd_ok;
  1852. }
  1853.  
  1854. static const as_cmd_rec_t cmd_params[] =
  1855. {
  1856.   { "underscore-macroargs", cmd_underscore_macroargs }
  1857. };
  1858.  
  1859. void asmsub_init(void)
  1860. {
  1861. #ifdef __TURBOC__
  1862. #ifdef __MSDOS__
  1863. #ifdef __DPMI16__
  1864.   char *MemFlag, *p;
  1865.   String MemVal, TempName;
  1866.   unsigned long FileLen;
  1867. #else
  1868.   char *envval;
  1869.   int ovrerg;
  1870. #endif
  1871. #endif
  1872. #endif
  1873.  
  1874.   InitStringList(&CopyrightList);
  1875.   InitStringList(&OutList);
  1876.   InitStringList(&ShareOutList);
  1877.   InitStringList(&ListOutList);
  1878.  
  1879. #ifdef __TURBOC__
  1880. #ifdef __MSDOS__
  1881. #ifdef __DPMI16__
  1882.   /* Fuer DPMI evtl. Swapfile anlegen */
  1883.  
  1884.   MemFlag = getenv("ASXSWAP");
  1885.   if (MemFlag)
  1886.   {
  1887.     strmaxcpy(MemVal, MemFlag, STRINGSIZE);
  1888.     p = strchr(MemVal, ',');
  1889.     if (!p)
  1890.       strcpy(TempName, "ASX.TMP");
  1891.     else
  1892.     {
  1893.       *p = NULL;
  1894.       strcpy(TempName, MemVal);
  1895.       strmov(MemVal, p + 1);
  1896.     };
  1897.     KillBlanks(TempName);
  1898.     KillBlanks(MemVal);
  1899.     FileLen = strtol(MemFlag, &p, 0);
  1900.     if (*p != '\0')
  1901.     {
  1902.       fputs(getmessage(Num_ErrMsgInvSwapSize), stderr);
  1903.       exit(4);
  1904.     }
  1905.     if (MEMinitSwapFile(TempName, FileLen << 20) != RTM_OK)
  1906.     {
  1907.       fputs(getmessage(Num_ErrMsgSwapTooBig), stderr);
  1908.       exit(4);
  1909.     }
  1910.   }
  1911. #else
  1912.   /* Bei DOS Auslagerung Overlays in XMS/EMS versuchen */
  1913.  
  1914.   envval = getenv("USEXMS");
  1915.   if ((envval) && (as_toupper(*envval) == 'N'))
  1916.     ovrerg = -1;
  1917.   else
  1918.     ovrerg = _OvrInitExt(0, 0);
  1919.   if (ovrerg != 0)
  1920.   {
  1921.     envval = getenv("USEEMS");
  1922.     if ((!envval) || (as_toupper(*envval) != 'N'))
  1923.       _OvrInitEms(0, 0, 0);
  1924.   }
  1925. #endif
  1926. #endif
  1927. #endif
  1928.  
  1929. #ifdef __TURBOC__
  1930.   StartStack = stackavail();
  1931.   LowStack = stackavail();
  1932.   MinStack = StartStack - STKSIZE + 0x800;
  1933. #else
  1934.   StartStack = LowStack = MinStack = 0;
  1935. #endif
  1936.  
  1937.   as_cmd_register(cmd_params, as_array_size(cmd_params));
  1938.  
  1939.   /* initialize array of valid characters */
  1940.  
  1941.   ValidSymCharLen = (NLS_GetCodepage() == eCodepageUTF8) ? 1280 : 256;
  1942.   ValidSymChar = (Byte*) calloc(ValidSymCharLen, sizeof(Byte));
  1943.  
  1944.   /* The basic ASCII stuff: letters, dot and underscore are allowed
  1945.      anywhere, numbers not at beginning: */
  1946.  
  1947.   SetValidSymChars('a', 'z', VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1948.   SetValidSymChars('A', 'Z', VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1949.   SetValidSymChars('0', '9',            VALID_SN |            VALID_MN);
  1950.   SetValidSymChar ('.'     , VALID_S1 | VALID_SN                      );
  1951.   SetValidSymChar ('_'     , VALID_S1 | VALID_SN                      );
  1952.  
  1953.   /* Extensions, depending on character set: */
  1954.  
  1955.   switch (NLS_GetCodepage())
  1956.   {
  1957.     case eCodepage1251:
  1958.       SetValidSymChar (0xa3      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1959.       SetValidSymChar (0xb3      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1960.       SetValidSymChar (0xa8      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1961.       SetValidSymChar (0xb8      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1962.       SetValidSymChar (0xaa      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1963.       SetValidSymChar (0xba      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1964.       SetValidSymChar (0xaf      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1965.       SetValidSymChar (0xbf      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1966.       SetValidSymChar (0xbd      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1967.       SetValidSymChar (0xbe      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1968.       goto iso8859_1;
  1969.     case eCodepage1252:
  1970.       SetValidSymChar (0x8a      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1971.       SetValidSymChar (0x9a      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1972.       SetValidSymChar (0x8c      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1973.       SetValidSymChar (0x9c      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1974.       SetValidSymChar (0x8e      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1975.       SetValidSymChar (0x9e      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1976.       SetValidSymChar (0x9f      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1977.       goto iso8859_1;
  1978.     case eCodepage850:
  1979.       SetValidSymChars(0xb5, 0xb7, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1980.       SetValidSymChars(0xc6, 0xc7, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1981.       SetValidSymChars(0xd0, 0xd9, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1982.       SetValidSymChar (0xde      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1983.       SetValidSymChars(0xe0, 0xed, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1984.       /* fall-through */
  1985.     case eCodepage437:
  1986.       SetValidSymChars(128, 165, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1987.       SetValidSymChar (225     , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1988.       break;
  1989.     case eCodepage866:
  1990.       SetValidSymChars(0x80, 0xaf, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1991.       SetValidSymChars(0xe0, 0xf7, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1992.       break;
  1993.     case eCodepageISO8859_15:
  1994.       SetValidSymChar (0xa6      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1995.       SetValidSymChar (0xa8      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1996.       SetValidSymChar (0xb4      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1997.       SetValidSymChar (0xb8      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1998.       SetValidSymChar (0xbc      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  1999.       SetValidSymChar (0xbd      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2000.       SetValidSymChar (0xbe      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2001.       /* fall-through */
  2002.     case eCodepageISO8859_1:
  2003.     iso8859_1:
  2004.       SetValidSymChar (0xa1      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2005.       SetValidSymChar (0xa2      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2006.       SetValidSymChars(0xc0, 0xff, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2007.       break;
  2008.     case eCodepageKOI8_R:
  2009.       SetValidSymChar (0xa3      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2010.       SetValidSymChar (0xb3      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2011.       SetValidSymChars(0xc0, 0xff, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2012.       break;
  2013.     case eCodepageUTF8:
  2014.     {
  2015.       const tNLSCharacterTab *pTab = GetCharacterTab(eCodepageUTF8);
  2016.       tNLSCharacter ch;
  2017.       unsigned Unicode;
  2018.       const char *pCh;
  2019.  
  2020.       for (ch = (tNLSCharacter)0; ch < eCH_cnt; ch++)
  2021.       {
  2022.         if ((ch == eCH_e2) || (ch == eCH_mu) || (ch == eCH_iquest) || (ch == eCH_iexcl))
  2023.           continue;
  2024.         pCh = &((*pTab)[ch][0]);
  2025.         Unicode = UTF8ToUnicode(&pCh);
  2026.         if (Unicode < ValidSymCharLen)
  2027.           SetValidSymChar (Unicode, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2028.       }
  2029.  
  2030.       /* Greek */
  2031.  
  2032.       SetValidSymChar ( 895      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2033.       SetValidSymChar ( 902      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2034.       SetValidSymChar (1011      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2035.       SetValidSymChar (1016      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2036.       SetValidSymChar (1018      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2037.       SetValidSymChar (1019      , VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2038.       SetValidSymChars( 904,  974, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2039.       SetValidSymChars( 984, 1007, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2040.  
  2041.       /* Cyrillic */
  2042.  
  2043.       SetValidSymChars(0x400, 0x481, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2044.       SetValidSymChars(0x48a, 0x4ff, VALID_S1 | VALID_SN | VALID_M1 | VALID_MN);
  2045.     }
  2046.     default:
  2047.       break;
  2048.   }
  2049.  
  2050. #if 0
  2051.   for (z = 0; z < ValidSymCharLen; z++)
  2052.   {
  2053.     if (!(z & 15))
  2054.       fprintf(stderr, "%02x:", z);
  2055.     fprintf(stderr, " %x", ValidSymChar[z]);
  2056.     if ((z & 15) == 15)
  2057.       fprintf(stderr, "\n");
  2058.   }
  2059. #endif
  2060.  
  2061.   version_init();
  2062. }
  2063.