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 | } |