Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1186 savelij 1
/* p2bin.c */
2
/*****************************************************************************/
3
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
4
/*                                                                           */
5
/* AS-Portierung                                                             */
6
/*                                                                           */
7
/* Umwandlung von AS-Codefiles in Binaerfiles                                */
8
/*                                                                           */
9
/*****************************************************************************/
10
 
11
#include "stdinc.h"
12
#include <string.h>
13
#include <ctype.h>
14
 
15
#include "version.h"
16
#include "be_le.h"
17
#include "bpemu.h"
18
#include "strutil.h"
19
#include "nls.h"
20
#include "nlmessages.h"
21
#include "p2bin.rsc"
22
#ifdef _USE_MSH
23
# include "p2bin.msh"
24
#endif
25
#include "ioerrs.h"
26
#include "chunks.h"
27
#include "stringlists.h"
28
#include "cmdarg.h"
29
#include "msg_level.h"
30
#include "toolutils.h"
31
 
32
#define BinSuffix ".bin"
33
 
34
 
35
typedef void (*ProcessProc)(
36
#ifdef __PROTOS__
37
const char *FileName, LongWord Offset
38
#endif
39
);
40
 
41
 
42
static FILE *TargFile;
43
static String TargName;
44
 
45
static LongWord StartAdr, StopAdr, EntryAdr, RealFileLen;
46
static LongWord MaxGran, Dummy;
47
static Boolean StartAuto, StopAuto, AutoErase, EntryAdrPresent, last_byte_no_pad;
48
 
49
static Byte FillVal, ValidSegment;
50
static Boolean DoCheckSum;
51
 
52
static Byte SizeDiv;
53
static LongWord ANDMask, ANDEq;
54
static ShortInt StartHeader;
55
 
56
static ChunkList UsedList;
57
 
58
 
59
#ifdef DEBUG
60
#define ChkIO(s) ChkIO_L(s, __LINE__)
61
 
62
static void ChkIO_L(char *s, int line)
63
{
64
  if (errno != 0)
65
  {
66
    fprintf(stderr, "%s %d\n", s, line);
67
    exit(3);
68
  }
69
}
70
#endif
71
 
72
static void ParamError(Boolean InEnv, char *Arg)
73
{
74
  fprintf(stderr, "%s%s\n%s\n",
75
          getmessage(InEnv ? Num_ErrMsgInvEnvParam:Num_ErrMsgInvParam),
76
          Arg, getmessage(Num_ErrMsgProgTerm));
77
}
78
 
79
#define BufferSize 4096
80
static Byte Buffer[BufferSize];
81
 
82
static void OpenTarget(void)
83
{
84
  LongWord Rest, Trans, AHeader;
85
 
86
  TargFile = fopen(TargName, OPENWRMODE);
87
  if (!TargFile)
88
    ChkIO(TargName);
89
  RealFileLen = ((StopAdr - StartAdr + 1) * MaxGran) / SizeDiv;
90
 
91
  AHeader = abs(StartHeader);
92
  if (StartHeader != 0)
93
  {
94
    memset(Buffer, 0, AHeader);
95
    if (fwrite(Buffer, 1, abs(StartHeader), TargFile) != AHeader)
96
      ChkIO(TargName);
97
  }
98
 
99
  memset(Buffer, FillVal, BufferSize);
100
 
101
  Rest = RealFileLen;
102
  while (Rest != 0)
103
  {
104
    Trans = min(Rest, BufferSize);
105
    if (fwrite(Buffer, 1, Trans, TargFile) != Trans)
106
      ChkIO(TargName);
107
    Rest -= Trans;
108
  }
109
}
110
 
111
static void CloseTarget(void)
112
{
113
  LongWord z, AHeader;
114
 
115
  AHeader = abs(StartHeader);
116
 
117
  /* write entry address to file? */
118
 
119
  if (EntryAdrPresent && (StartHeader != 0))
120
  {
121
    LongWord bpos;
122
 
123
    rewind(TargFile);
124
    bpos = ((StartHeader > 0) ? 0 : -1 - StartHeader) << 3;
125
    for (z = 0; z < AHeader; z++)
126
    {
127
      Buffer[z] = (EntryAdr >> bpos) & 0xff;
128
      bpos += (StartHeader > 0) ? 8 : -8;
129
    }
130
    if (fwrite(Buffer, 1, AHeader, TargFile) != AHeader)
131
      ChkIO(TargName);
132
  }
133
 
134
  if (EOF == fclose(TargFile))
135
    ChkIO(TargName);
136
 
137
  /* compute checksum over file? */
138
 
139
  if (DoCheckSum)
140
  {
141
    LongWord Sum, Size, Rest, Trans, Read;
142
 
143
    if (last_byte_no_pad)
144
      chkio_printf(TargName, "%s\n", getmessage(Num_WarnMessChecksumOverlaysData));
145
 
146
    TargFile = fopen(TargName, OPENUPMODE);
147
    if (!TargFile)
148
      ChkIO(TargName);
149
    if (fseek(TargFile, AHeader, SEEK_SET) == -1)
150
      ChkIO(TargName);
151
    Size = Rest = FileSize(TargFile) - AHeader - 1;
152
 
153
    Sum = 0;
154
    while (Rest > 0)
155
    {
156
      Trans = min(Rest, BufferSize);
157
      Rest -= Trans;
158
      Read = fread(Buffer, 1, Trans, TargFile);
159
      if (Read != Trans)
160
        chk_wr_read_error(TargName);
161
      for (z = 0; z < Trans; Sum += Buffer[z++]);
162
    }
163
    chkio_printf(TargName, "%s%08lX\n", getmessage(Num_InfoMessChecksum), LoDWord(Sum));
164
    Buffer[0] = 0x100 - (Sum & 0xff);
165
 
166
    /* Some systems require fflush() between read & write operations.  And
167
       some other systems again garble the file pointer upon an fflush(): */
168
 
169
    fflush(TargFile);
170
    if (fseek(TargFile, AHeader + Size, SEEK_SET) == -1)
171
      ChkIO(TargName);
172
    if (fwrite(Buffer, 1, 1, TargFile) != 1)
173
      ChkIO(TargName);
174
    fflush(TargFile);
175
 
176
    if (fclose(TargFile) == EOF)
177
      ChkIO(TargName);
178
  }
179
 
180
  if (Magic != 0)
181
    unlink(TargName);
182
}
183
 
184
static void ProcessFile(const char *FileName, LongWord Offset)
185
{
186
  FILE *SrcFile;
187
  Word TestID;
188
  Byte InpHeader, InpCPU, InpSegment;
189
  LongWord InpStart, SumLen;
190
  Word InpLen, TransLen, ResLen;
191
  Boolean doit;
192
  LongWord ErgStart, ErgStop;
193
  LongInt NextPos;
194
  Word ErgLen = 0;
195
  Byte Gran;
196
 
197
  SrcFile = fopen(FileName, OPENRDMODE);
198
  if (!SrcFile)
199
    ChkIO(FileName);
200
 
201
  if (!Read2(SrcFile, &TestID))
202
    chk_wr_read_error(FileName);
203
  if (TestID != FileID)
204
    FormatError(FileName, getmessage(Num_FormatInvHeaderMsg));
205
 
206
  if (msg_level >= e_msg_level_normal)
207
    chkio_printf(OutName, "%s==>>%s", FileName, TargName);
208
 
209
  SumLen = 0;
210
 
211
  do
212
  {
213
    ReadRecordHeader(&InpHeader, &InpCPU, &InpSegment, &Gran, FileName, SrcFile);
214
 
215
    if (InpHeader == FileHeaderStartAdr)
216
    {
217
      if (!Read4(SrcFile, &ErgStart))
218
        chk_wr_read_error(FileName);
219
      if (!EntryAdrPresent)
220
      {
221
        EntryAdr = ErgStart;
222
        EntryAdrPresent = True;
223
      }
224
    }
225
 
226
    else if (InpHeader == FileHeaderDataRec)
227
    {
228
      if (!Read4(SrcFile, &InpStart))
229
        chk_wr_read_error(FileName);
230
      if (!Read2(SrcFile, &InpLen))
231
        chk_wr_read_error(FileName);
232
 
233
      NextPos = ftell(SrcFile) + InpLen;
234
      if (NextPos >= FileSize(SrcFile) - 1)
235
        FormatError(FileName, getmessage(Num_FormatInvRecordLenMsg));
236
 
237
      doit = (FilterOK(InpHeader) && (InpSegment == ValidSegment));
238
 
239
      if (doit)
240
      {
241
        InpStart += Offset;
242
        ErgStart = max(StartAdr, InpStart);
243
        ErgStop = min(StopAdr, InpStart + (InpLen/Gran) - 1);
244
        if (ErgStop == StopAdr)
245
          last_byte_no_pad = True;
246
        doit = (ErgStop >= ErgStart);
247
        if (doit)
248
        {
249
          ErgLen = (ErgStop + 1 - ErgStart) * Gran;
250
          if (AddChunk(&UsedList, ErgStart, ErgStop - ErgStart + 1, True))
251
            chkio_fprintf(stderr, OutName, " %s\n", getmessage(Num_ErrMsgOverlap));
252
        }
253
      }
254
 
255
      if (doit)
256
      {
257
        /* an Anfang interessierender Daten */
258
 
259
        if (fseek(SrcFile, (ErgStart - InpStart) * Gran, SEEK_CUR) == -1)
260
          ChkIO(FileName);
261
 
262
        /* in Zieldatei an passende Stelle */
263
 
264
        if (fseek(TargFile, (((ErgStart - StartAdr) * Gran)/SizeDiv) + abs(StartHeader), SEEK_SET) == -1)
265
          ChkIO(TargName);
266
 
267
        /* umkopieren */
268
 
269
        while (ErgLen > 0)
270
        {
271
          TransLen = min(BufferSize, ErgLen);
272
          if (fread(Buffer, 1, TransLen, SrcFile) != TransLen)
273
            chk_wr_read_error(FileName);
274
          if (SizeDiv == 1) ResLen = TransLen;
275
          else
276
          {
277
            LongWord Addr;
278
 
279
            ResLen = 0;
280
            for (Addr = 0; Addr < (LongWord)TransLen; Addr++)
281
              if (((ErgStart * Gran + Addr) & ANDMask) == ANDEq)
282
                Buffer[ResLen++] = Buffer[Addr];
283
          }
284
          if (fwrite(Buffer, 1, ResLen, TargFile) != ResLen)
285
            ChkIO(TargName);
286
          ErgLen -= TransLen;
287
          ErgStart += TransLen;
288
          SumLen += ResLen;
289
        }
290
      }
291
      if (fseek(SrcFile, NextPos, SEEK_SET) == -1)
292
        ChkIO(FileName);
293
    }
294
    else
295
      SkipRecord(InpHeader, FileName, SrcFile);
296
  }
297
  while (InpHeader != 0);
298
 
299
  if (msg_level >= e_msg_level_normal)
300
  {
301
    chkio_printf(OutName, " (");
302
    chkio_printf(OutName, Integ32Format, SumLen);
303
    chkio_printf(OutName, " %s)\n", getmessage((SumLen == 1) ? Num_Byte : Num_Bytes));
304
  }
305
  if (!SumLen)
306
  {
307
    if (EOF == fputs(getmessage(Num_WarnEmptyFile), stdout))
308
      ChkIO(OutName);
309
  }
310
 
311
  if (fclose(SrcFile) == EOF)
312
    ChkIO(FileName);
313
}
314
 
315
static ProcessProc CurrProcessor;
316
static LongWord CurrOffset;
317
 
318
static void Callback(char *Name)
319
{
320
  CurrProcessor(Name, CurrOffset);
321
}
322
 
323
static void ProcessGroup(const char *GroupName_O, ProcessProc Processor)
324
{
325
  String Ext, GroupName;
326
 
327
  CurrProcessor = Processor;
328
  strmaxcpy(GroupName, GroupName_O, STRINGSIZE);
329
  strmaxcpy(Ext, GroupName, STRINGSIZE);
330
  if (!RemoveOffset(GroupName, &CurrOffset))
331
  {
332
    ParamError(False, Ext);
333
    exit(1);
334
  }
335
  AddSuffix(GroupName, STRINGSIZE, getmessage(Num_Suffix));
336
 
337
  if (!DirScan(GroupName, Callback))
338
    fprintf(stderr, "%s%s%s\n", getmessage(Num_ErrMsgNullMaskA), GroupName, getmessage(Num_ErrMsgNullMaskB));
339
}
340
 
341
static void MeasureFile(const char *FileName, LongWord Offset)
342
{
343
  FILE *f;
344
  Byte Header, CPU, Gran, Segment;
345
  Word Length, TestID;
346
  LongWord Adr, EndAdr;
347
  LongInt NextPos;
348
 
349
  f = fopen(FileName, OPENRDMODE);
350
  if (!f)
351
    ChkIO(FileName);
352
 
353
  if (!Read2(f, &TestID))
354
    chk_wr_read_error(FileName);
355
  if (TestID != FileMagic)
356
    FormatError(FileName, getmessage(Num_FormatInvHeaderMsg));
357
 
358
  do
359
  {
360
    ReadRecordHeader(&Header, &CPU, &Segment, &Gran, FileName, f);
361
 
362
    if (Header == FileHeaderDataRec)
363
    {
364
      if (!Read4(f, &Adr))
365
        chk_wr_read_error(FileName);
366
      if (!Read2(f, &Length))
367
        chk_wr_read_error(FileName);
368
      NextPos = ftell(f) + Length;
369
      if (NextPos > FileSize(f))
370
        FormatError(FileName, getmessage(Num_FormatInvRecordLenMsg));
371
 
372
      if (FilterOK(Header) && (Segment == ValidSegment))
373
      {
374
        Adr += Offset;
375
        EndAdr = Adr + (Length/Gran)-1;
376
        if (Gran > MaxGran)
377
          MaxGran = Gran;
378
        if (StartAuto)
379
          if (StartAdr > Adr)
380
            StartAdr = Adr;
381
        if (StopAuto)
382
          if (EndAdr > StopAdr)
383
            StopAdr = EndAdr;
384
      }
385
 
386
      fseek(f, NextPos, SEEK_SET);
387
    }
388
    else
389
      SkipRecord(Header, FileName, f);
390
  }
391
  while (Header != 0);
392
 
393
  if (fclose(f) == EOF)
394
    ChkIO(FileName);
395
}
396
 
397
/* --------------------------------------------- */
398
 
399
static as_cmd_result_t CMD_AdrRange(Boolean Negate, const char *Arg)
400
{
401
  if (Negate)
402
  {
403
    StartAdr = 0; StopAdr = 0x7fff;
404
    return e_cmd_ok;
405
  }
406
  else
407
    return CMD_Range(&StartAdr, &StopAdr,
408
                     &StartAuto, &StopAuto, Arg);
409
}
410
 
411
static as_cmd_result_t CMD_ByteMode(Boolean Negate, const char *pArg)
412
{
413
#define ByteModeCnt 9
414
  static const char *ByteModeStrings[ByteModeCnt] =
415
  {
416
    "ALL", "EVEN", "ODD", "BYTE0", "BYTE1", "BYTE2", "BYTE3", "WORD0", "WORD1"
417
  };
418
  static Byte ByteModeDivs[ByteModeCnt] =
419
  {
420
    1, 2, 2, 4, 4, 4, 4, 2, 2
421
  };
422
  static Byte ByteModeMasks[ByteModeCnt] =
423
  {
424
    0, 1, 1, 3, 3, 3, 3, 2, 2
425
  };
426
  static Byte ByteModeEqs[ByteModeCnt] =
427
  {
428
    0, 0, 1, 0, 1, 2, 3, 0, 2
429
  };
430
 
431
  int z;
432
  UNUSED(Negate);
433
 
434
  if (*pArg == '\0')
435
  {
436
    SizeDiv = 1;
437
    ANDEq = 0;
438
    ANDMask = 0;
439
    return e_cmd_ok;
440
  }
441
  else
442
  {
443
    String Arg;
444
 
445
    strmaxcpy(Arg, pArg, STRINGSIZE);
446
    NLS_UpString(Arg);
447
    ANDEq = 0xff;
448
    for (z = 0; z < ByteModeCnt; z++)
449
      if (strcmp(Arg, ByteModeStrings[z]) == 0)
450
      {
451
        SizeDiv = ByteModeDivs[z];
452
        ANDMask = ByteModeMasks[z];
453
        ANDEq   = ByteModeEqs[z];
454
      }
455
    if (ANDEq == 0xff)
456
      return e_cmd_err;
457
    else
458
      return e_cmd_arg;
459
  }
460
}
461
 
462
static as_cmd_result_t CMD_StartHeader(Boolean Negate, const char *Arg)
463
{
464
  Boolean err;
465
  ShortInt Sgn;
466
 
467
  if (Negate)
468
  {
469
    StartHeader = 0;
470
    return e_cmd_ok;
471
  }
472
  else
473
  {
474
    Sgn = 1;
475
    if (*Arg == '\0')
476
      return e_cmd_err;
477
    switch (as_toupper(*Arg))
478
    {
479
      case 'B':
480
        Sgn = -1;
481
        /* fall-through */
482
      case 'L':
483
        Arg++;
484
    }
485
    StartHeader = ConstLongInt(Arg, &err, 10);
486
    if ((!err) || (StartHeader > 4))
487
      return e_cmd_err;
488
    StartHeader *= Sgn;
489
    return e_cmd_arg;
490
  }
491
}      
492
 
493
static as_cmd_result_t CMD_EntryAdr(Boolean Negate, const char *Arg)
494
{
495
  Boolean err;
496
 
497
  if (Negate)
498
  {
499
    EntryAdrPresent = False;
500
    return e_cmd_ok;
501
  }
502
  else
503
  {
504
    EntryAdr = ConstLongInt(Arg, &err, 10);
505
    if (err)
506
      EntryAdrPresent = True;
507
    return (err) ? e_cmd_arg : e_cmd_err;
508
  }
509
}
510
 
511
static as_cmd_result_t CMD_FillVal(Boolean Negate, const char *Arg)
512
{
513
  Boolean err;
514
  UNUSED(Negate);
515
 
516
  FillVal = ConstLongInt(Arg, &err, 10);
517
  return err ? e_cmd_arg : e_cmd_err;
518
}
519
 
520
static as_cmd_result_t CMD_CheckSum(Boolean Negate, const char *Arg)
521
{
522
  UNUSED(Arg);
523
 
524
  DoCheckSum = !Negate;
525
  return e_cmd_ok;
526
}
527
 
528
static as_cmd_result_t CMD_AutoErase(Boolean Negate, const char *Arg)
529
{
530
  UNUSED(Arg);
531
 
532
  AutoErase = !Negate;
533
  return e_cmd_ok;
534
}
535
 
536
static as_cmd_result_t CMD_ForceSegment(Boolean Negate,  const char *Arg)
537
{
538
  int z = addrspace_lookup(Arg);
539
 
540
  if (z >= SegCount)
541
    return e_cmd_err;
542
 
543
  if (!Negate)
544
    ValidSegment = z;
545
  else if (ValidSegment == z)
546
    ValidSegment = SegCode;
547
 
548
  return e_cmd_arg;
549
}
550
 
551
static as_cmd_rec_t P2BINParams[] =
552
{
553
  { "f"        , CMD_FilterList },
554
  { "r"        , CMD_AdrRange },
555
  { "s"        , CMD_CheckSum },
556
  { "m"        , CMD_ByteMode },
557
  { "l"        , CMD_FillVal },
558
  { "e"        , CMD_EntryAdr },
559
  { "S"        , CMD_StartHeader },
560
  { "k"        , CMD_AutoErase },
561
  { "SEGMENT"  , CMD_ForceSegment }
562
};
563
 
564
int main(int argc, char **argv)
565
{
566
  as_cmd_results_t cmd_results;
567
  char *p_target_name;
568
  const char *p_src_name;
569
  StringRecPtr p_src_run;
570
 
571
  nls_init();
572
  if (!NLS_Initialize(&argc, argv))
573
    exit(4);
574
 
575
  be_le_init();
576
  strutil_init();
577
  bpemu_init();
578
#ifdef _USE_MSH
579
  nlmessages_init_buffer(p2bin_msh_data, sizeof(p2bin_msh_data), MsgId1, MsgId2);
580
#else
581
  nlmessages_init_file("p2bin.msg", *argv, MsgId1, MsgId2);
582
#endif
583
  ioerrs_init(*argv);
584
  chunks_init();
585
  as_cmdarg_init(*argv);
586
  msg_level_init();
587
  toolutils_init(*argv);
588
 
589
  InitChunk(&UsedList);
590
 
591
  StartAdr = 0;
592
  StopAdr = 0x7fff;
593
  StartAuto = True;
594
  StopAuto = True;
595
  FillVal = 0xff;
596
  DoCheckSum = False;
597
  last_byte_no_pad = False;
598
  SizeDiv = 1;
599
  ANDEq = 0;
600
  EntryAdr = -1;
601
  EntryAdrPresent = False;
602
  AutoErase = False;
603
  StartHeader = 0;
604
  ValidSegment = SegCode;
605
 
606
  as_cmd_register(P2BINParams, as_array_size(P2BINParams));
607
  if (e_cmd_err == as_cmd_process(argc, argv, "P2BINCMD", &cmd_results))
608
  {
609
    ParamError(cmd_results.error_arg_in_env, cmd_results.error_arg);
610
    exit(1);
611
  }
612
 
613
  if ((msg_level >= e_msg_level_verbose) || cmd_results.write_version_exit)
614
  {
615
    String Ver;
616
 
617
    as_snprintf(Ver, sizeof(Ver), "P2BIN V%s", Version);
618
    WrCopyRight(Ver);
619
  }
620
 
621
  if (cmd_results.write_help_exit)
622
  {
623
    char *ph1, *ph2;
624
 
625
    chkio_printf(OutName, "%s%s%s\n", getmessage(Num_InfoMessHead1), as_cmdarg_get_executable_name(), getmessage(Num_InfoMessHead2));
626
    for (ph1 = getmessage(Num_InfoMessHelp), ph2 = strchr(ph1, '\n'); ph2; ph1 = ph2 + 1, ph2 = strchr(ph1, '\n'))
627
    {
628
      *ph2 = '\0';
629
      chkio_printf(OutName, "%s\n", ph1);
630
      *ph2 = '\n';
631
    }
632
  }
633
 
634
  if (cmd_results.write_version_exit || cmd_results.write_help_exit)
635
    exit(0);
636
 
637
  if (StringListEmpty(cmd_results.file_arg_list))
638
  {
639
    fprintf(stderr, "%s: %s\n", as_cmdarg_get_executable_name(), getmessage(Num_ErrMessNoInputFiles));
640
    exit(1);
641
  }
642
 
643
  p_target_name = MoveAndCutStringListLast(&cmd_results.file_arg_list);
644
  if (!p_target_name || !*p_target_name)
645
  {
646
    if (p_target_name) free(p_target_name);
647
    p_target_name = NULL;
648
    chkio_fprintf(stderr, OutName, "%s\n", getmessage(Num_ErrMsgTargMissing));
649
    exit(1);
650
  }
651
 
652
  strmaxcpy(TargName, p_target_name, STRINGSIZE);
653
  if (!RemoveOffset(TargName, &Dummy))
654
  {
655
    strmaxcpy(TargName, p_target_name, STRINGSIZE);
656
    free(p_target_name); p_target_name = NULL;
657
    ParamError(False, TargName);
658
  }
659
 
660
  /* special case: only one argument <name> treated like <name>.p -> <name).bin */
661
 
662
  if (StringListEmpty(cmd_results.file_arg_list))
663
  {
664
    AddStringListLast(&cmd_results.file_arg_list, p_target_name);
665
    DelSuffix(TargName);
666
  }
667
  AddSuffix(TargName, STRINGSIZE, BinSuffix);
668
  free(p_target_name); p_target_name = NULL;
669
 
670
  MaxGran = 1;
671
  if (StartAuto || StopAuto)
672
  {
673
    if (StartAuto)
674
      StartAdr = 0xfffffffful;
675
    if (StopAuto)
676
      StopAdr = 0;
677
    for (p_src_name = GetStringListFirst(cmd_results.file_arg_list, &p_src_run);
678
         p_src_name; p_src_name = GetStringListNext(&p_src_run))
679
      if (*p_src_name)
680
        ProcessGroup(p_src_name, MeasureFile);
681
    if (StartAdr > StopAdr)
682
    {
683
      chkio_fprintf(stderr, OutName, "%s\n", getmessage(Num_ErrMsgAutoFailed));
684
      exit(1);
685
    }
686
    if (msg_level >= e_msg_level_normal)
687
    {
688
      printf("%s: 0x%08lX-", getmessage(Num_InfoMessDeducedRange), LoDWord(StartAdr));
689
      printf("0x%08lX\n", LoDWord(StopAdr));
690
    }
691
  }
692
 
693
  OpenTarget();
694
 
695
  for (p_src_name = GetStringListFirst(cmd_results.file_arg_list, &p_src_run);
696
       p_src_name; p_src_name = GetStringListNext(&p_src_run))
697
    if (*p_src_name)
698
      ProcessGroup(p_src_name, ProcessFile);
699
 
700
  CloseTarget();
701
 
702
  if (AutoErase)
703
    for (p_src_name = GetStringListFirst(cmd_results.file_arg_list, &p_src_run);
704
         p_src_name; p_src_name = GetStringListNext(&p_src_run))
705
      if (*p_src_name)
706
        ProcessGroup(p_src_name, EraseFile);
707
 
708
  ClearStringList(&cmd_results.file_arg_list);
709
 
710
  return 0;
711
}