Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

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