Subversion Repositories pentevo

Rev

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

  1. /* alink.c */
  2. /****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                    */
  4. /*                                                                          */
  5. /* AS-Portierung                                                            */
  6. /*                                                                          */
  7. /* Linking of AS Code Files                                                 */
  8. /*                                                                          */
  9. /* History:  2. 7.2000 begun                                                */
  10. /*           4. 7.2000 read symbols                                         */
  11. /*           6. 7.2000 start real relocation                                */
  12. /*           7. 7.2000 simple relocations                                   */
  13. /*          30.10.2000 added 1-byte relocations, verbosity levels           */
  14. /*           14. 1.2001 silenced warnings about unused parameters           */
  15. /*                                                                          */
  16. /****************************************************************************/
  17.  
  18. #include "stdinc.h"
  19. #include <string.h>
  20. #include <ctype.h>
  21.  
  22. #include "version.h"
  23.  
  24. #include "be_le.h"
  25. #include "bpemu.h"
  26. #include "strutil.h"
  27. #include "nls.h"
  28. #include "nlmessages.h"
  29. #include "stringlists.h"
  30. #include "cmdarg.h"
  31. #include "msg_level.h"
  32. #include "toolutils.h"
  33.  
  34. #include "ioerrs.h"
  35.  
  36. #include "alink.rsc"
  37. #ifdef _USE_MSH
  38. # include "alink.msh"
  39. #endif
  40.  
  41. /****************************************************************************/
  42. /* Macros */
  43.  
  44. /****************************************************************************/
  45. /* Types */
  46.  
  47. typedef struct sPart
  48. {
  49.   struct sPart *Next;
  50.   int FileNum, RecNum;
  51.   LargeWord CodeStart, CodeLen;
  52.   Byte Gran, Segment;
  53.   Boolean MustReloc;
  54.   PRelocInfo RelocInfo;
  55. } TPart, *PPart;
  56.  
  57. /****************************************************************************/
  58. /* Variables */
  59.  
  60. static Boolean DoubleErr;
  61. static LongWord UndefErr;
  62.  
  63. static String TargName;
  64.  
  65. static PPart PartList, PartLast;
  66.  
  67. static FILE *TargFile;
  68.  
  69. static Byte *Buffer;
  70. LongInt BufferSize;
  71.  
  72. static LargeWord SegStarts[SegCount];
  73.  
  74. /****************************************************************************/
  75. /* increase buffer if necessary */
  76.  
  77. static void BumpBuffer(LongInt MinSize)
  78. {
  79.   if (MinSize > BufferSize)
  80.   {
  81.     Buffer = (Byte*) ((BufferSize == 0) ? malloc(sizeof(Byte) * MinSize)
  82.                                         : realloc(Buffer, sizeof(Byte) * MinSize));
  83.     BufferSize = MinSize;
  84.   }
  85. }
  86.  
  87. /****************************************************************************/
  88. /* reading/patching in buffer */
  89.  
  90. static int GetValue(LongInt Type, LargeWord Offset, LargeWord *p_result)
  91. {
  92.   switch (Type & ~(RelocFlagSUB | RelocFlagPage))
  93.   {
  94.     case RelocTypeL8:
  95.       *p_result = MRead1L(Buffer + Offset);
  96.       return 0;
  97.     case RelocTypeL16:
  98.       *p_result = MRead2L(Buffer + Offset);
  99.       return 0;
  100.     case RelocTypeB16:
  101.       *p_result = MRead2B(Buffer + Offset);
  102.       return 0;
  103.     case RelocTypeL32:
  104.       *p_result = MRead4L(Buffer + Offset);
  105.       return 0;
  106.     case RelocTypeB32:
  107.       *p_result = MRead4B(Buffer + Offset);
  108.       return 0;
  109. #ifdef HAS64
  110.     case RelocTypeL64:
  111.       *p_result = MRead8L(Buffer + Offset);
  112.       return 0;
  113.     case RelocTypeB64:
  114.       *p_result = MRead8B(Buffer + Offset);
  115.       return 0;
  116. #endif
  117.     default:
  118.       fprintf(stderr, "unknown relocation type: 0x");
  119.       fprintf(stderr, LongIntFormat, Type);
  120.       fprintf(stderr, "\n");
  121.       *p_result = 0;
  122.       return -1;
  123.   }
  124. }
  125.  
  126. static void PutValue(LargeWord Value, LongInt Type, LargeWord Offset)
  127. {
  128.   switch (Type & ~(RelocFlagSUB | RelocFlagPage))
  129.   {
  130.     case RelocTypeL8:
  131.       MWrite1L(Buffer + Offset, Value);
  132.       break;
  133.     case RelocTypeL16:
  134.       MWrite2L(Buffer + Offset, Value);
  135.       break;
  136.     case RelocTypeB16:
  137.       MWrite2B(Buffer + Offset, Value);
  138.       break;
  139.     case RelocTypeL32:
  140.       MWrite4L(Buffer + Offset, Value);
  141.       break;
  142.     case RelocTypeB32:
  143.       MWrite4B(Buffer + Offset, Value);
  144.       break;
  145. #ifdef HAS64
  146.     case RelocTypeL64:
  147.       MWrite8L(Buffer + Offset, Value);
  148.       break;
  149.     case RelocTypeB64:
  150.       MWrite8B(Buffer + Offset, Value);
  151.       break;
  152. #endif
  153.     default:
  154.       fprintf(stderr, "unknown relocation type: 0x");
  155.       fprintf(stderr, LongIntFormat, Type);
  156.       fprintf(stderr, "\n");
  157.       exit(3);
  158.   }
  159. }
  160.  
  161. /****************************************************************************/
  162. /* get the value of an exported symbol */
  163.  
  164. static Boolean GetExport(char *Name, LargeWord *Result)
  165. {
  166.   PPart PartRun;
  167.   LongInt z;
  168.  
  169.   for (PartRun = PartList; PartRun; PartRun = PartRun->Next)
  170.    for (z = 0; z < PartRun->RelocInfo->ExportCount; z++)
  171.     if (!strcmp(Name, PartRun->RelocInfo->ExportEntries[z].Name))
  172.     {
  173.       *Result = PartRun->RelocInfo->ExportEntries[z].Value;
  174.       return True;
  175.     }
  176.  
  177.   return False;
  178. }
  179.  
  180. /****************************************************************************/
  181. /* read the symbol exports/relocations from a file */
  182.  
  183. static void ReadSymbols(const char *pSrcName, int Index)
  184. {
  185.   FILE *f;
  186.   String SrcName;
  187.   Byte Header, CPU, Gran, Segment;
  188.   PPart PNew;
  189.   LongWord Addr;
  190.   Word Len;
  191.   int cnt;
  192.  
  193.   /* open this file - we're only reading */
  194.  
  195.   strmaxcpy(SrcName, pSrcName, STRINGSIZE);
  196.   DelSuffix(SrcName); AddSuffix(SrcName, STRINGSIZE, getmessage(Num_Suffix));
  197.   if (msg_level >= 3)
  198.     printf("%s '%s'...\n", getmessage(Num_InfoMsgGetSyms), SrcName);
  199.   f = fopen(SrcName, OPENRDMODE);
  200.   if (!f)
  201.     ChkIO(SrcName);
  202.  
  203.   /* check magic */
  204.  
  205.   if (!Read2(f, &Len)) ChkIO(SrcName);
  206.   if (Len != FileMagic)
  207.     FormatError(SrcName, getmessage(Num_FormatInvHeaderMsg));
  208.  
  209.   /* step through records */
  210.  
  211.   cnt = 0;
  212.   while (!feof(f))
  213.   {
  214.     /* read a record's header */
  215.  
  216.     ReadRecordHeader(&Header, &CPU, &Segment, &Gran, SrcName, f);
  217.  
  218.     /* for absolute records, only store address position */
  219.     /* for relocatable records, also read following relocation record */
  220.  
  221.     if ((Header == FileHeaderDataRec) || (Header == FileHeaderRDataRec)
  222.      || (Header == FileHeaderRelocRec) || (Header == FileHeaderRRelocRec))
  223.     {
  224.       /* build up record */
  225.  
  226.       PNew = (PPart) malloc(sizeof(TPart));
  227.       PNew->Next = NULL;
  228.       PNew->FileNum = Index;
  229.       PNew->RecNum = cnt++;
  230.       PNew->Gran = Gran;
  231.       PNew->Segment = Segment;
  232.       if (!Read4(f, &Addr))
  233.         chk_wr_read_error(SrcName);
  234.       PNew->CodeStart = Addr;
  235.       if (!Read2(f, &Len))
  236.         chk_wr_read_error(SrcName);
  237.       PNew->CodeLen = Len;
  238.       PNew->MustReloc = ((Header == FileHeaderRelocRec)
  239.                       || (Header == FileHeaderRRelocRec));
  240.  
  241.       /* skip code */
  242.  
  243.       if (fseek(f, Len, SEEK_CUR) != 0)
  244.         ChkIO(SrcName);
  245.  
  246.       /* relocatable record must be followed by relocation data */
  247.  
  248.       if ((Header == FileHeaderRDataRec) || (Header == FileHeaderRRelocRec))
  249.       {
  250.         LongInt z;
  251.         LargeWord Dummy;
  252.  
  253.         ReadRecordHeader(&Header, &CPU, &Segment, &Gran, SrcName, f);
  254.         if (Header != FileHeaderRelocInfo)
  255.           FormatError(SrcName, getmessage(Num_FormatRelocInfoMissing));
  256.         PNew->RelocInfo = ReadRelocInfo(f);
  257.         if (!PNew->RelocInfo)
  258.           ChkIO(SrcName);
  259.  
  260.         /* check for double-defined symbols */
  261.  
  262.         for (z = 0; z < PNew->RelocInfo->ExportCount; z++)
  263.           if (GetExport(PNew->RelocInfo->ExportEntries[z].Name, &Dummy))
  264.           {
  265.             fprintf(stderr, "%s: %s '%s'\n",
  266.                     SrcName, getmessage(Num_DoubleDefSymbol),
  267.                     PNew->RelocInfo->ExportEntries[z].Name);
  268.             DoubleErr = True;
  269.           }
  270.       }
  271.       else
  272.         PNew->RelocInfo = NULL;
  273.  
  274.       /* put into list */
  275.  
  276.       if (!PartList)
  277.         PartList = PNew;
  278.       else
  279.         PartLast->Next = PNew;
  280.       PartLast = PNew;
  281.     }
  282.  
  283.     /* end of file ? */
  284.  
  285.     else if (Header == FileHeaderEnd)
  286.       break;
  287.  
  288.     /* skip everything else */
  289.  
  290.     else
  291.       SkipRecord(Header, SrcName, f);
  292.   }
  293.  
  294.   /* close again */
  295.  
  296.   fclose(f);
  297. }
  298.  
  299. /****************************************************************************/
  300. /* do the relocation */
  301.  
  302. static void ProcessFile(const char *pSrcName, int Index)
  303. {
  304.   FILE *f;
  305.   String SrcName;
  306.   PPart PartRun;
  307.   Byte Header, CPU, Gran, Segment;
  308.   LongInt Addr, z;
  309.   LargeWord Value, RelocVal, NRelocVal;
  310.   Word Len, Magic;
  311.   LongWord SumLen;
  312.   PRelocEntry PReloc;
  313.   Boolean UndefFlag, Found;
  314.  
  315.   /* open this file - we're only reading */
  316.  
  317.   strmaxcpy(SrcName, pSrcName, STRINGSIZE);
  318.   DelSuffix(SrcName); AddSuffix(SrcName, STRINGSIZE, getmessage(Num_Suffix));
  319.   if (msg_level >= 3)
  320.     printf("%s '%s'...", getmessage(Num_InfoMsgOpenSrc), SrcName);
  321.   else if (msg_level >= e_msg_level_verbose)
  322.     printf("%s", SrcName);
  323.   f = fopen(SrcName, OPENRDMODE);
  324.   if (!f)
  325.     ChkIO(SrcName);
  326.  
  327.   /* check magic */
  328.  
  329.   if (!Read2(f, &Magic))
  330.     chk_wr_read_error(SrcName);
  331.   if (Magic != FileMagic)
  332.     FormatError(SrcName, getmessage(Num_FormatInvHeaderMsg));
  333.  
  334.   /* due to the way we built the part list, all parts of a file are
  335.      sequentially in the list.  Therefore we only have to look for
  336.      the first part of this file in the list and know the remainders
  337.      will follow sequentially. */
  338.  
  339.   for (PartRun = PartList; PartRun; PartRun = PartRun->Next)
  340.     if (PartRun->FileNum >= Index)
  341.       break;
  342.  
  343.   /* now step through the records */
  344.  
  345.   SumLen = 0;
  346.   while (!feof(f))
  347.   {
  348.     /* get header */
  349.  
  350.     ReadRecordHeader(&Header, &CPU, &Segment, &Gran, SrcName, f);
  351.  
  352.     /* records without relocation info do not need any processing - just
  353.        pass them through */
  354.  
  355.     if ((Header == FileHeaderDataRec) || (Header == FileHeaderRelocRec))
  356.     {
  357.       if (!Read4(f, &Addr))
  358.         chk_wr_read_error(SrcName);
  359.       if (!Read2(f, &Len))
  360.         chk_wr_read_error(SrcName);
  361.       BumpBuffer(Len);
  362.       if (fread(Buffer, 1, Len, f) != Len)
  363.         chk_wr_read_error(SrcName);
  364.       WriteRecordHeader(&Header, &CPU, &Segment, &Gran, TargName, TargFile);
  365.       if (!Write4(TargFile, &Addr))
  366.         ChkIO(TargName);
  367.       if (!Write2(TargFile, &Len))
  368.         ChkIO(TargName);
  369.       if (fwrite(Buffer, 1, Len, TargFile) != Len)
  370.         ChkIO(TargName);
  371.       if (PartRun)
  372.         PartRun = PartRun->Next;
  373.       SumLen += Len;
  374.     }
  375.  
  376.     /* records with relocation: basically the same, plus the real work...
  377.        the appended relocation info will be skipped in the next loop run. */
  378.  
  379.     else if ((Header == FileHeaderRDataRec) || (Header == FileHeaderRRelocRec))
  380.     {
  381.       if (!Read4(f, &Addr))
  382.         chk_wr_read_error(SrcName);
  383.       if (!Read2(f, &Len))
  384.         chk_wr_read_error(SrcName);
  385.       BumpBuffer(Len);
  386.       if (fread(Buffer, 1, Len, f) != Len)
  387.         chk_wr_read_error(SrcName);
  388.  
  389.       UndefFlag = False;
  390.       for (z = 0; z < PartRun->RelocInfo->RelocCount; z++)
  391.       {
  392.         PReloc = PartRun->RelocInfo->RelocEntries + z;
  393.         Found = True;
  394.         if (!strcmp(PReloc->Name, RelName_SegStart))
  395.           Value = PartRun->CodeStart;
  396.         else
  397.           Found = GetExport(PReloc->Name, &Value);
  398.         if (Found)
  399.         {
  400.           if (msg_level >= 3)
  401.             printf("%s 0x%x...", getmessage(Num_InfoMsgReading), (int)PReloc->Addr);
  402.           if (GetValue(PReloc->Type, PReloc->Addr - PartRun->CodeStart, &RelocVal))
  403.             UndefErr++;
  404.           else
  405.           {
  406.             NRelocVal = (PReloc->Type & RelocFlagSUB) ? RelocVal - Value : RelocVal + Value;
  407.             PutValue(NRelocVal, PReloc->Type, PReloc->Addr - PartRun->CodeStart);
  408.           }
  409.         }
  410.         else
  411.         {
  412.           fprintf(stderr, "%s: %s(%s)\n", getmessage(Num_UndefSymbol),
  413.                   PReloc->Name, SrcName);
  414.           UndefFlag = True;
  415.           UndefErr++;
  416.         }
  417.       }
  418.  
  419.       if (!UndefFlag)
  420.       {
  421.         Header = FileHeaderDataRec;
  422.         WriteRecordHeader(&Header, &CPU, &Segment, &Gran, TargName, TargFile);
  423.         Addr = PartRun->CodeStart;
  424.         if (!Write4(TargFile, &Addr))
  425.           ChkIO(TargName);
  426.         if (!Write2(TargFile, &Len))
  427.           ChkIO(TargName);
  428.         if (fwrite(Buffer, 1, Len, TargFile) != Len)
  429.           ChkIO(TargName);
  430.         if (PartRun)
  431.           PartRun = PartRun->Next;
  432.       }
  433.       SumLen += Len;
  434.     }
  435.  
  436.     /* all done? */
  437.  
  438.     else if (Header == FileHeaderEnd)
  439.       break;
  440.  
  441.     else
  442.       SkipRecord(Header, SrcName, f);
  443.   }
  444.  
  445.   if (msg_level >= e_msg_level_verbose)
  446.   {
  447.     printf("(");
  448.     printf(Integ32Format, SumLen);
  449.     printf(" %s)\n", getmessage((SumLen == 1) ? Num_Byte : Num_Bytes));
  450.   }
  451. }
  452.  
  453. /****************************************************************************/
  454. /* command line processing */
  455.  
  456. int main(int argc, char **argv)
  457. {
  458.   String Ver;
  459.   int file_index;
  460.   Word LMagic;
  461.   Byte LHeader;
  462.   PPart PartRun;
  463.   LargeInt Diff;
  464.   as_cmd_results_t cmd_results;
  465.   char *p_target_name;
  466.   const char *p_src_name;
  467.   StringRecPtr p_src_run;
  468.  
  469.   /* the initialization orgy... */
  470.  
  471.   nls_init();
  472.   if (!NLS_Initialize(&argc, argv))
  473.     exit(4);
  474.  
  475.   be_le_init();
  476.   bpemu_init();
  477.   strutil_init();
  478.  
  479.   Buffer = NULL;
  480.   BufferSize = 0;
  481.  
  482.   /* open message catalog */
  483.  
  484. #ifdef _USE_MSH
  485.   nlmessages_init_buffer(alink_msh_data, sizeof(alink_msh_data), MsgId1, MsgId2);
  486. #else
  487.   nlmessages_init_file("alink.msg", *argv, MsgId1, MsgId2);
  488. #endif
  489.   ioerrs_init(*argv);
  490.   as_cmdarg_init(*argv);
  491.   toolutils_init(*argv);
  492.  
  493.   /* process arguments */
  494.  
  495.   if (e_cmd_err == as_cmd_process(argc, argv, "ALINKCMD", &cmd_results))
  496.   {
  497.     printf("%s%s\n%s\n",
  498.            getmessage(cmd_results.error_arg_in_env ? Num_ErrMsgInvEnvParam : Num_ErrMsgInvParam),
  499.            cmd_results.error_arg, getmessage(Num_ErrMsgProgTerm));
  500.     exit(1);
  501.   }
  502.  
  503.   if ((msg_level >= e_msg_level_verbose) && (argc > 1))
  504.    printf("\n");
  505.  
  506.   if ((msg_level >= e_msg_level_verbose) || cmd_results.write_version_exit)
  507.   {
  508.     String Ver;
  509.  
  510.     as_snprintf(Ver, sizeof(Ver), "ALINK V%s", Version);
  511.     WrCopyRight(Ver);
  512.   }
  513.  
  514.   if (cmd_results.write_help_exit)
  515.   {
  516.     char *ph1, *ph2;
  517.  
  518.     errno = 0;
  519.     printf("%s%s%s\n", getmessage(Num_InfoMessHead1), as_cmdarg_get_executable_name(),
  520.            getmessage(Num_InfoMessHead2));
  521.     ChkIO(OutName);
  522.     for (ph1 = getmessage(Num_InfoMessHelp), ph2 = strchr(ph1,'\n'); ph2; ph1 = ph2+1, ph2 = strchr(ph1,'\n'))
  523.     {
  524.       *ph2 = '\0';
  525.       printf("%s\n", ph1);
  526.       *ph2 = '\n';
  527.     }
  528.   }
  529.  
  530.   if (cmd_results.write_version_exit || cmd_results.write_help_exit)
  531.     exit(0);
  532.  
  533.   /* no command line arguments? */
  534.  
  535.   if (StringListEmpty(cmd_results.file_arg_list))
  536.   {
  537.     fprintf(stderr, "%s: %s\n", as_cmdarg_get_executable_name(), getmessage(Num_ErrMessNoInputFiles));
  538.     exit(1);
  539.   }
  540.  
  541.   /* extract target file */
  542.  
  543.   p_target_name = MoveAndCutStringListLast(&cmd_results.file_arg_list);
  544.   strmaxcpy(TargName, p_target_name ? p_target_name : "", STRINGSIZE);
  545.   free(p_target_name); p_target_name = NULL;
  546.   if (!*TargName)
  547.   {
  548.     errno = 0;
  549.     printf("%s\n", getmessage(Num_ErrMsgTargMissing));
  550.     ChkIO(OutName);
  551.     exit(1);
  552.   }
  553.   DelSuffix(TargName);
  554.   AddSuffix(TargName, STRINGSIZE, getmessage(Num_Suffix));
  555.  
  556.   /* walk over source file(s): */
  557.  
  558.   if (StringListEmpty(cmd_results.file_arg_list))
  559.   {
  560.     errno = 0;
  561.     printf("%s\n", getmessage(Num_ErrMsgSrcMissing));
  562.     ChkIO(OutName);
  563.     exit(1);
  564.   }
  565.  
  566.   /* read symbol info from all files */
  567.  
  568.   DoubleErr = False;
  569.   PartList = NULL;
  570.   for (p_src_name = GetStringListFirst(cmd_results.file_arg_list, &p_src_run), file_index = 1;
  571.        p_src_name; p_src_name = GetStringListNext(&p_src_run), file_index++)
  572.     if (*p_src_name)
  573.       ReadSymbols(p_src_name, file_index);
  574.  
  575.   /* double-defined symbols? */
  576.  
  577.   if (DoubleErr)
  578.     return 1;
  579.  
  580.   /* arrange relocatable segments in memory, relocate global symbols */
  581.  
  582.   for (PartRun = PartList; PartRun; PartRun = PartRun->Next)
  583.     if (PartRun->MustReloc)
  584.     {
  585.       Diff = SegStarts[PartRun->Segment] - PartRun->CodeStart;
  586.       PartRun->CodeStart += Diff;
  587.       if (msg_level >= e_msg_level_verbose)
  588.         printf("%s 0x%x\n", getmessage(Num_InfoMsgLocating), (int)PartRun->CodeStart);
  589.       if (PartRun->RelocInfo)
  590.       {
  591.         PExportEntry ExpRun, ExpEnd;
  592.         PRelocEntry RelRun, RelEnd;
  593.  
  594.         ExpRun = PartRun->RelocInfo->ExportEntries;
  595.         ExpEnd = ExpRun + PartRun->RelocInfo->ExportCount;
  596.         for (; ExpRun < ExpEnd; ExpRun++)
  597.           if (ExpRun->Flags & RelFlag_Relative)
  598.             ExpRun->Value += Diff;
  599.         RelRun = PartRun->RelocInfo->RelocEntries;
  600.         RelEnd = RelRun + PartRun->RelocInfo->RelocCount;
  601.         for (; RelRun < RelEnd; RelRun++)
  602.           RelRun->Addr += Diff;
  603.       }
  604.       SegStarts[PartRun->Segment] += PartRun->CodeLen / PartRun->Gran;
  605.     }
  606.  
  607.   /* open target file */
  608.  
  609.   TargFile = fopen(TargName, OPENWRMODE);
  610.   if (!TargFile)
  611.     ChkIO(TargName);
  612.   LMagic = FileMagic;
  613.   if (!Write2(TargFile, &LMagic))
  614.     ChkIO(TargName);
  615.  
  616.   /* do relocations, underwhile write target file */
  617.  
  618.   UndefErr = 0;
  619.   for (p_src_name = GetStringListFirst(cmd_results.file_arg_list, &p_src_run), file_index = 1;
  620.        p_src_name; p_src_name = GetStringListNext(&p_src_run), file_index++)
  621.     if (*p_src_name)
  622.       ProcessFile(p_src_name, file_index);
  623.  
  624.   /* write final creator record */
  625.  
  626.   LHeader = FileHeaderEnd;
  627.   if (fwrite(&LHeader, 1, 1, TargFile) != 1)
  628.     ChkIO(TargName);
  629.   as_snprintf( Ver, sizeof(Ver), "ALINK %s/%s-%s", Version, ARCHPRNAME, ARCHSYSNAME);
  630.   if (fwrite(Ver, 1, strlen(Ver), TargFile) != strlen(Ver))
  631.     ChkIO(TargName);
  632.  
  633.   /* close target file and erase if undefined symbols */
  634.  
  635.   fclose(TargFile);
  636.   if ((UndefErr > 0) || (Magic != 0))
  637.     unlink(TargName);
  638.   if (UndefErr > 0)
  639.   {
  640.     fprintf(stderr, "\n");
  641.     fprintf(stderr, LongIntFormat, UndefErr);
  642.     fprintf(stderr, " %s\n", getmessage((UndefErr == 1) ? Num_SumUndefSymbol : Num_SumUndefSymbols));
  643.     return 1;
  644.   }
  645.  
  646.   ClearStringList(&cmd_results.file_arg_list);
  647.  
  648.   return 0;
  649. }
  650.