Subversion Repositories pentevo

Rev

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

  1. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  2. #include "stdinc.h"
  3. #include "nlmessages.h"
  4. #include "stringlists.h"
  5. #include "codechunks.h"
  6. #include "entryaddress.h"
  7. #include "invaddress.h"
  8. #include "strutil.h"
  9. #include "cmdarg.h"
  10. #include "msg_level.h"
  11. #include "dasmdef.h"
  12. #include "cpulist.h"
  13. #include "console.h"
  14. #include "nls.h"
  15. #include "version.h"
  16. #include "das.rsc"
  17.  
  18. #include "deco68.h"
  19. #include "deco87c800.h"
  20. #include "deco4004.h"
  21.  
  22. #define TABSIZE 8
  23.  
  24. char *pEnvName = "DASCMD";
  25.  
  26. void WrCopyRight(const char *Msg)
  27. {
  28.   printf("%s\n%s\n", Msg, InfoMessCopyright);
  29. }
  30.  
  31. typedef void (*tChunkCallback)(const OneChunk *pChunk, Boolean IsData, void *pUser);
  32.  
  33. static void IterateChunks(tChunkCallback Callback, void *pUser)
  34. {
  35.   Word NextCodeChunk, NextDataChunk;
  36.   const OneChunk *pChunk;
  37.   Boolean IsData;
  38.  
  39.   NextCodeChunk = NextDataChunk = 0;
  40.   while ((NextCodeChunk < UsedCodeChunks.RealLen) || (NextDataChunk < UsedDataChunks.RealLen))
  41.   {
  42.     if (NextCodeChunk >= UsedCodeChunks.RealLen)
  43.     {
  44.       pChunk = UsedDataChunks.Chunks + (NextDataChunk++);
  45.       IsData = True;
  46.     }
  47.     else if (NextDataChunk >= UsedDataChunks.RealLen)
  48.     {
  49.       pChunk = UsedCodeChunks.Chunks + (NextCodeChunk++);
  50.       IsData = False;
  51.     }
  52.     else if (UsedDataChunks.Chunks[NextDataChunk].Start < UsedCodeChunks.Chunks[NextCodeChunk].Start)
  53.     {
  54.       pChunk = UsedDataChunks.Chunks + (NextDataChunk++);
  55.       IsData = True;
  56.     }
  57.     else
  58.     {
  59.       pChunk = UsedCodeChunks.Chunks + (NextCodeChunk++);
  60.       IsData = False;
  61.     }
  62.  
  63.     Callback(pChunk, IsData, pUser);
  64.   }
  65. }
  66.  
  67. typedef struct
  68. {
  69.   FILE *pDestFile;
  70.   LargeWord Sum;
  71. } tDumpIteratorData;
  72.  
  73. static void DumpIterator(const OneChunk *pChunk, Boolean IsData, void *pUser)
  74. {
  75.   String Str;
  76.   tDumpIteratorData *pData = (tDumpIteratorData*)pUser;
  77.  
  78.   HexString(Str, sizeof(Str), pChunk->Start, 0);
  79.   fprintf(pData->pDestFile, "\t\t; %s...", Str);
  80.   HexString(Str, sizeof(Str), pChunk->Start + pChunk->Length - 1, 0);
  81.   fprintf(pData->pDestFile, "%s (%s)\n", Str, IsData ? "data" :"code");
  82.   pData->Sum += pChunk->Length;
  83. }
  84.  
  85. static void DumpChunks(const ChunkList *NChunk, FILE *pDestFile)
  86. {
  87.   tDumpIteratorData Data;
  88.   String Str;
  89.  
  90.   UNUSED(NChunk);
  91.  
  92.   Data.pDestFile = pDestFile;
  93.   Data.Sum = 0;
  94.   fprintf(pDestFile, "\t\t; disassembled area:\n");
  95.   IterateChunks(DumpIterator, &Data);
  96.   as_snprintf(Str, sizeof(Str), "\t\t; %lllu/%lllu bytes disassembled", Data.Sum, GetCodeChunksStored(&CodeChunks));
  97.   fprintf(pDestFile, "%s\n", Str);
  98. }
  99.  
  100. static int tabbedstrlen(const char *s)
  101. {
  102.   int Result = 0;
  103.  
  104.   for (; *s; s++)
  105.   {
  106.     if (*s == '\t')
  107.       Result += TABSIZE - (Result % TABSIZE);
  108.     else
  109.       Result++;
  110.   }
  111.   return Result;
  112. }
  113.  
  114. static void PrTabs(FILE *pDestFile, int TargetLen, int ThisLen)
  115. {
  116.   while (ThisLen < TargetLen)
  117.   {
  118.     fputc('\t', pDestFile);
  119.     ThisLen += TABSIZE - (ThisLen % TABSIZE);
  120.   }
  121. }
  122.  
  123. static as_cmd_result_t ArgError(int MsgNum, const char *pArg)
  124. {
  125.   if (pArg)
  126.     fprintf(stderr, "%s:", pArg);
  127.   fprintf(stderr, "%s\n", getmessage(MsgNum));
  128.  
  129.   return e_cmd_err;
  130. }
  131.  
  132. static as_cmd_result_t CMD_BinFile(Boolean Negate, const char *pArg)
  133. {
  134.   LargeWord Start = 0, Len = 0, Gran = 1;
  135.   char *pStart = NULL, *pLen = NULL, *pGran = NULL;
  136.   String Arg;
  137.   Boolean OK;
  138.   tCodeChunk Chunk;
  139.  
  140.   if (Negate || !*pArg)
  141.     return ArgError(Num_ErrMsgFileArgumentMissing, NULL);
  142.  
  143.   strmaxcpy(Arg, pArg, sizeof(Arg));
  144.   if ((pStart = strchr(Arg, '@')))
  145.   {
  146.     *pStart++ = '\0';
  147.     if ((pLen = strchr(pStart, ',')))
  148.     {
  149.       *pLen++ = '\0';
  150.       if ((pGran = strchr(pLen, ',')))
  151.         *pGran++ = '\0';
  152.     }
  153.   }
  154.  
  155.   if (pStart && *pStart)
  156.   {
  157.     Start = ConstLongInt(pStart, &OK, 10);
  158.     if (!OK)
  159.       return ArgError(Num_ErrMsgInvalidNumericValue, pStart);
  160.   }
  161.   else
  162.     Start = 0;
  163.  
  164.   if (pLen && *pLen)
  165.   {
  166.     Len = ConstLongInt(pLen, &OK, 10);
  167.     if (!OK)
  168.       return ArgError(Num_ErrMsgInvalidNumericValue, pLen);
  169.   }
  170.   else
  171.     Len = 0;
  172.  
  173.   if (pGran && *pGran)
  174.   {
  175.     Gran = ConstLongInt(pGran, &OK, 10);
  176.     if (!OK)
  177.       return ArgError(Num_ErrMsgInvalidNumericValue, pGran);
  178.   }
  179.   else
  180.     Gran = 1;
  181.  
  182.   InitCodeChunk(&Chunk);
  183.   if (ReadCodeChunk(&Chunk, Arg, Start, Len, Gran))
  184.     return ArgError(Num_ErrMsgCannotReadBinaryFile, Arg);
  185.   MoveCodeChunkToList(&CodeChunks, &Chunk, TRUE);
  186.  
  187.   return e_cmd_arg;
  188. }
  189.  
  190. static void ResizeBuffer(Byte* *ppBuffer, LargeWord *pAllocLen, LargeWord ReqLen)
  191. {
  192.   if (ReqLen > *pAllocLen)
  193.   {
  194.     Byte *pNew = *ppBuffer ? realloc(*ppBuffer, ReqLen) : malloc(ReqLen);
  195.     if (pNew)
  196.     {
  197.       *ppBuffer = pNew;
  198.       *pAllocLen = ReqLen;
  199.     }
  200.   }
  201. }
  202.  
  203. static Boolean GetByte(char* *ppLine, Byte *pResult)
  204. {
  205.   if (!as_isxdigit(**ppLine))
  206.     return False;
  207.   *pResult = isdigit(**ppLine) ? (**ppLine - '0') : (as_toupper(**ppLine) - 'A' + 10);
  208.   (*ppLine)++;
  209.   if (!as_isxdigit(**ppLine))
  210.     return False;
  211.   *pResult = (*pResult << 4) | (isdigit(**ppLine) ? (**ppLine - '0') : (as_toupper(**ppLine) - 'A' + 10));
  212.   (*ppLine)++;
  213.   return True;
  214. }
  215.  
  216. static void FlushChunk(tCodeChunk *pChunk)
  217. {
  218.   pChunk->Granularity = 1;
  219.   pChunk->pLongCode = (LongWord*)pChunk->pCode;
  220.   pChunk->pWordCode = (Word*)pChunk->pCode;
  221.   MoveCodeChunkToList(&CodeChunks, pChunk, TRUE);
  222.   InitCodeChunk(pChunk);
  223. }
  224.  
  225. /* ------------------------------------------------------- */
  226.  
  227. static Boolean write_version_exit, write_help_exit, write_cpu_list_exit;
  228.  
  229. static int screen_height = 0;
  230.  
  231. static void write_console_next(const char *p_line)
  232. {
  233.   static int LineZ;
  234.  
  235.   WrConsoleLine(p_line, True);
  236.   if (screen_height && (++LineZ >= screen_height))
  237.   {
  238.     LineZ = 0;
  239.     WrConsoleLine(getmessage(Num_KeyWaitMsg), False);
  240.     fflush(stdout);
  241.     while (getchar() != '\n');
  242.   }
  243. }
  244.  
  245. static as_cmd_result_t CMD_HexFile(Boolean Negate, const char *pArg)
  246. {
  247.   FILE *pFile;
  248.   char Line[300], *pLine;
  249.   size_t Len;
  250.   Byte *pLineBuffer = NULL, *pDataBuffer = 0, RecordType, Tmp;
  251.   LargeWord LineBufferStart = 0, LineBufferAllocLen = 0, LineBufferLen = 0,
  252.             Sum;
  253.   tCodeChunk Chunk;
  254.   unsigned z;
  255.  
  256.   if (Negate || !*pArg)
  257.     return ArgError(Num_ErrMsgFileArgumentMissing, NULL);
  258.  
  259.   pFile = fopen(pArg, "r");
  260.   if (!pFile)
  261.   {
  262.     return ArgError(Num_ErrMsgCannotReadHexFile, pArg);
  263.   }
  264.  
  265.   InitCodeChunk(&Chunk);
  266.   while (!feof(pFile))
  267.   {
  268.     fgets(Line, sizeof(Line), pFile);
  269.     Len = strlen(Line);
  270.     if ((Len > 0) && (Line[Len -1] == '\n'))
  271.       Line[--Len] = '\0';
  272.     if ((Len > 0) && (Line[Len -1] == '\r'))
  273.       Line[--Len] = '\0';
  274.     if (*Line != ':')
  275.       continue;
  276.  
  277.     Sum = 0;
  278.     pLine = Line + 1;
  279.     if (!GetByte(&pLine, &Tmp))
  280.       return ArgError(Num_ErrMsgInvalidHexData, pArg);
  281.     ResizeBuffer(&pLineBuffer, &LineBufferAllocLen, Tmp);
  282.     LineBufferLen = Tmp;
  283.     Sum += Tmp;
  284.  
  285.     LineBufferStart = 0;
  286.     for (z = 0; z < 2; z++)
  287.     {
  288.       if (!GetByte(&pLine, &Tmp))
  289.         return ArgError(Num_ErrMsgInvalidHexData, pArg);
  290.       LineBufferStart = (LineBufferStart << 8) | Tmp;
  291.       Sum += Tmp;
  292.     }
  293.  
  294.     if (!GetByte(&pLine, &RecordType))
  295.       return ArgError(Num_ErrMsgInvalidHexData, pArg);
  296.     Sum += RecordType;
  297.     if (RecordType != 0)
  298.       continue;
  299.  
  300.     for (z = 0; z < LineBufferLen; z++)
  301.     {
  302.       if (!GetByte(&pLine, &pLineBuffer[z]))
  303.         return ArgError(Num_ErrMsgInvalidHexData, pArg);
  304.       Sum += pLineBuffer[z];
  305.     }
  306.  
  307.     if (!GetByte(&pLine, &Tmp))
  308.       return ArgError(Num_ErrMsgInvalidHexData, pArg);
  309.     Sum += Tmp;
  310.     if (Sum & 0xff)
  311.       return ArgError(Num_ErrMsgHexDataChecksumError, pArg);
  312.  
  313.     if (Chunk.Start + Chunk.Length == LineBufferStart)
  314.     {
  315.       ResizeBuffer(&Chunk.pCode, &Chunk.Length, Chunk.Length + LineBufferLen);
  316.       memcpy(&Chunk.pCode[Chunk.Length - LineBufferLen], pLineBuffer, LineBufferLen);
  317.     }
  318.     else
  319.     {
  320.       if (Chunk.Length)
  321.         FlushChunk(&Chunk);
  322.       ResizeBuffer(&Chunk.pCode, &Chunk.Length, LineBufferLen);
  323.       memcpy(Chunk.pCode, pLineBuffer, LineBufferLen);
  324.       Chunk.Start = LineBufferStart;
  325.     }
  326.   }
  327.   if (Chunk.Length)
  328.     FlushChunk(&Chunk);
  329.  
  330.   if (pLineBuffer)
  331.     free(pLineBuffer);
  332.   if (pDataBuffer)
  333.     free(pDataBuffer);
  334.   fclose(pFile);
  335.   return e_cmd_ok;
  336. }
  337.  
  338. static as_cmd_result_t CMD_EntryAddress(Boolean Negate, const char *pArg)
  339. {
  340.   LargeWord Address;
  341.   char *pName = NULL;
  342.   String Arg, Str;
  343.   Boolean OK;
  344.  
  345.   if (Negate || !*pArg)
  346.     return ArgError(Num_ErrMsgAddressArgumentMissing, NULL);
  347.  
  348.   strmaxcpy(Arg, pArg, sizeof(Arg));
  349.   if ((pName = ParenthPos(Arg, ',')))
  350.     *pName++ = '\0';
  351.  
  352.   if (*Arg)
  353.   {
  354.     if (*Arg == '(')
  355.     {
  356.       Byte Vector[8];
  357.       char *pVectorAddress = NULL, *pAddrLen = NULL, *pEndianess = NULL;
  358.       LargeWord AddrLen, VectorAddress = 0, z;
  359.       Boolean VectorMSB;
  360.       int l;
  361.  
  362.       pVectorAddress = Arg + 1;
  363.       l = strlen(pVectorAddress);
  364.       if (pVectorAddress[l - 1] != ')')
  365.         return ArgError(Num_ErrMsgClosingPatentheseMissing, pVectorAddress);
  366.       pVectorAddress[l - 1] = '\0';
  367.  
  368.       if ((pAddrLen = strchr(pVectorAddress, ',')))
  369.       {
  370.         *pAddrLen++ = '\0';
  371.         if ((pEndianess = strchr(pAddrLen, ',')))
  372.           *pEndianess++ = '\0';
  373.       }
  374.  
  375.       if (pVectorAddress && *pVectorAddress)
  376.       {
  377.         VectorAddress = ConstLongInt(pVectorAddress, &OK, 10);
  378.         if (!OK)
  379.           return ArgError(Num_ErrMsgInvalidNumericValue, pVectorAddress);
  380.       }
  381.       else
  382.         pVectorAddress = 0;
  383.  
  384.       if (pAddrLen && *pAddrLen)
  385.       {
  386.         AddrLen = ConstLongInt(pAddrLen, &OK, 10);
  387.         if (!OK || (AddrLen > sizeof(Vector)))
  388.           return ArgError(Num_ErrMsgInvalidNumericValue, pAddrLen);
  389.       }
  390.       else
  391.         AddrLen = 1;
  392.  
  393.       if (pEndianess && *pEndianess)
  394.       {
  395.         if (!as_strcasecmp(pEndianess, "MSB"))
  396.           VectorMSB = True;
  397.         else if (!as_strcasecmp(pEndianess, "LSB"))
  398.           VectorMSB = False;
  399.         else
  400.           return ArgError(Num_ErrMsgInvalidEndinaness, pEndianess);
  401.       }
  402.       else
  403.         VectorMSB = True; /* TODO: depend on CPU */
  404.  
  405.       if (!RetrieveCodeFromChunkList(&CodeChunks, VectorAddress, Vector, AddrLen))
  406.         return ArgError(Num_ErrMsgCannotRetrieveEntryAddressData, NULL);
  407.  
  408.       Address = 0;
  409.       for (z = 0; z < AddrLen; z++)
  410.       {
  411.         Address <<= 8;
  412.         Address |= VectorMSB ? Vector[z] : Vector[AddrLen - 1 - z];
  413.       }
  414.       as_snprintf(Str, sizeof Str, "indirect address @ %lllx -> 0x%lllx", VectorAddress, Address);
  415.       printf("%s\n", Str);
  416.       AddChunk(&UsedDataChunks, VectorAddress, AddrLen, True);
  417.  
  418.       if (pName && *pName)
  419.       {
  420.         String Str;
  421.  
  422.         as_snprintf(Str, sizeof(Str), "Vector_2_%s", pName);
  423.         AddInvSymbol(Str, VectorAddress);
  424.       }
  425.     }
  426.     else
  427.     {
  428.       Address = ConstLongInt(pArg, &OK, 10);
  429.       if (!OK)
  430.         return ArgError(Num_ErrMsgInvalidNumericValue, pArg);
  431.     }
  432.   }
  433.   else
  434.     Address = 0;
  435.  
  436.   if (pName && *pName)
  437.     AddInvSymbol(pName, Address);
  438.   AddEntryAddress(Address);
  439.  
  440.   return e_cmd_arg;
  441. }
  442.  
  443. static as_cmd_result_t CMD_Symbol(Boolean Negate, const char *pArg)
  444. {
  445.   LargeWord Address;
  446.   char *pName = NULL;
  447.   String Arg;
  448.   Boolean OK;
  449.  
  450.   if (Negate || !*pArg)
  451.     return ArgError(Num_ErrMsgSymbolArgumentMissing, NULL);
  452.  
  453.   strmaxcpy(Arg, pArg, sizeof(Arg));
  454.   if ((pName = strchr(Arg, '=')))
  455.     *pName++ = '\0';
  456.  
  457.   if (*Arg)
  458.   {
  459.     Address = ConstLongInt(Arg, &OK, 10);
  460.     if (!OK)
  461.       return ArgError(Num_ErrMsgInvalidNumericValue, Arg);
  462.   }
  463.   else
  464.     Address = 0;
  465.  
  466.   if (pName && *pName)
  467.     AddInvSymbol(pName, Address);
  468.  
  469.   return e_cmd_arg;
  470. }
  471.  
  472. static as_cmd_result_t CMD_CPU(Boolean Negate, const char *pArg)
  473. {
  474.   const tCPUDef *pCPUDef;
  475.  
  476.   if (Negate || !*pArg)
  477.     return ArgError(Num_ErrMsgCPUArgumentMissing, NULL);
  478.  
  479.   if (!as_strcasecmp(pArg, "?") || !as_strcasecmp(pArg, "LIST"))
  480.   {
  481.     write_cpu_list_exit = True;
  482.     return e_cmd_ok;
  483.   }
  484.  
  485.   pCPUDef = LookupCPUDefByName(pArg);
  486.   if (!pCPUDef)
  487.     return ArgError(Num_ErrMsgUnknownCPU, pArg);
  488.  
  489.   pCPUDef->SwitchProc(pCPUDef->pUserData);
  490.  
  491.   return e_cmd_arg;
  492. }
  493.  
  494. static as_cmd_result_t CMD_HexLowerCase(Boolean Negate, const char *Arg)
  495. {
  496.   UNUSED(Arg);
  497.  
  498.   HexStartCharacter = Negate ? 'A' : 'a';
  499.   return e_cmd_ok;
  500. }
  501.  
  502. static as_cmd_result_t CMD_PrintVersion(Boolean Negate, const char *Arg)
  503. {
  504.   UNUSED(Arg);
  505.  
  506.   if (Negate)
  507.     return e_cmd_err;
  508.  
  509.   write_version_exit = True;
  510.   return e_cmd_ok;
  511. }
  512.  
  513. static as_cmd_result_t CMD_PrintHelp(Boolean Negate, const char *Arg)
  514. {
  515.   UNUSED(Arg);
  516.  
  517.   if (Negate)
  518.     return e_cmd_err;
  519.  
  520.   write_help_exit = True;
  521.   return e_cmd_ok;
  522. }
  523.  
  524. static as_cmd_result_t CMD_screen_height(Boolean negate, const char *p_arg)
  525. {
  526.   Boolean ok;
  527.   int new_screen_height;
  528.  
  529.   if (negate)
  530.   {
  531.     screen_height = 0;
  532.     return e_cmd_ok;
  533.   }
  534.   new_screen_height = ConstLongInt(p_arg, &ok, 10);
  535.   if (!ok)
  536.     return e_cmd_err;
  537.   screen_height = new_screen_height;
  538.   return e_cmd_arg;
  539. }
  540.  
  541. static as_cmd_rec_t DASParams[] =
  542. {
  543.   { "CPU"             , CMD_CPU             },
  544.   { "BINFILE"         , CMD_BinFile         },
  545.   { "HEXFILE"         , CMD_HexFile         },
  546.   { "ENTRYADDRESS"    , CMD_EntryAddress    },
  547.   { "SCREENHEIGHT"    , CMD_screen_height   },
  548.   { "SYMBOL"          , CMD_Symbol          },
  549.   { "h"               , CMD_HexLowerCase    },
  550.   { "HELP"            , CMD_PrintHelp       },
  551.   { "VERSION"         , CMD_PrintVersion    }
  552. };
  553.  
  554. typedef struct
  555. {
  556.   FILE *pDestFile;
  557.   int MaxSrcLineLen, MaxLabelLen;
  558. } tDisasmData;
  559.  
  560. static void DisasmIterator(const OneChunk *pChunk, Boolean IsData, void *pUser)
  561. {
  562.   LargeWord Address;
  563.   char NumString[50];
  564.   tDisassInfo Info;
  565.   tDisasmData *pData = (tDisasmData*)pUser;
  566.   const char *pLabel;
  567.   Byte Code[100];
  568.   unsigned z;
  569.   int DataSize = -1;
  570.  
  571.   Address = pChunk->Start;
  572.   HexString(NumString, sizeof(NumString), Address, 0);
  573.   fprintf(pData->pDestFile, "\n");
  574.   PrTabs(pData->pDestFile, pData->MaxLabelLen, 0);
  575.   fprintf(pData->pDestFile, "org\t$%s\n", NumString);
  576.   while (Address < pChunk->Start + pChunk->Length)
  577.   {
  578.     pLabel = LookupInvSymbol(Address);
  579.     if (pLabel && !strncmp(pLabel, "Vector_", 7) && IsData)
  580.     {
  581.       String Num;
  582.       char *pEnd = strchr(pLabel + 7, '_');
  583.  
  584.       if (pEnd)
  585.       {
  586.         int l = pEnd - (pLabel + 7);
  587.  
  588.         memcpy(Num, pLabel + 7, l);
  589.         Num[l] = '\0';
  590.         DataSize = strtol(Num, &pEnd, 10);
  591.         if (*pEnd)
  592.           DataSize = -1;
  593.       }
  594.     }
  595.  
  596.     Disassemble(Address, &Info, IsData, DataSize);
  597.     if (Info.pRemark)
  598.     {
  599.       PrTabs(pData->pDestFile, pData->MaxLabelLen, 0);
  600.       fprintf(pData->pDestFile, "; %s\n", Info.pRemark);
  601.     }
  602.  
  603.     if (pLabel)
  604.     {
  605.       fprintf(pData->pDestFile, "%s:", pLabel);
  606.       PrTabs(pData->pDestFile, pData->MaxLabelLen, tabbedstrlen(pLabel) + 1);
  607.     }
  608.     else
  609.       PrTabs(pData->pDestFile, pData->MaxLabelLen, 0);
  610.     fprintf(pData->pDestFile, "%s", Info.SrcLine);
  611.  
  612.     PrTabs(pData->pDestFile, pData->MaxSrcLineLen, tabbedstrlen(Info.SrcLine));
  613.     fprintf(pData->pDestFile, ";");
  614.     RetrieveCodeFromChunkList(&CodeChunks, Address, Code, Info.CodeLen);
  615.     for (z = 0; z < Info.CodeLen; z++)
  616.     {
  617.       HexString(NumString, sizeof(NumString),  Code[z], 2);
  618.       fprintf(pData->pDestFile, " %s", NumString);
  619.     }
  620.     fputc('\n', pData->pDestFile);
  621.  
  622.     Address += Info.CodeLen;
  623.   }
  624. }
  625.  
  626. int main(int argc, char **argv)
  627. {
  628.   LargeWord Address, NextAddress;
  629.   Boolean NextAddressValid;
  630.   tDisassInfo Info;
  631.   unsigned z;
  632.   tDisasmData Data;
  633.   int ThisSrcLineLen;
  634.   as_cmd_results_t cmd_results;
  635.  
  636.   strutil_init();
  637.   nls_init();
  638.   NLS_Initialize(&argc, argv);
  639.   dasmdef_init();
  640.   cpulist_init();
  641.   msg_level_init();
  642.   nlmessages_init("das.msg", *argv, MsgId1, MsgId2);
  643.   deco68_init();
  644.   deco87c800_init();
  645.   deco4004_init();
  646.   write_version_exit = write_help_exit = write_cpu_list_exit = False;
  647.  
  648.   as_cmd_register(DASParams, as_array_size(DASParams));
  649.   if (e_cmd_err == as_cmd_process(argc, argv, pEnvName, &cmd_results))
  650.   {
  651.     fprintf(stderr, "%s%s\n", getmessage(cmd_results.error_arg_in_env ? Num_ErrMsgInvEnvParam : Num_ErrMsgInvParam), cmd_results.error_arg);
  652.     exit(4);
  653.   }
  654.  
  655.   if ((msg_level >= e_msg_level_verbose) || write_version_exit)
  656.   {
  657.     String Ver;
  658.  
  659.     as_snprintf(Ver, sizeof(Ver), "DAS V%s", Version);
  660.     WrCopyRight(Ver);
  661.   }
  662.  
  663.   if (write_help_exit)
  664.   {
  665.     char *ph1, *ph2;
  666.     String Tmp;
  667.     as_snprintf(Tmp, sizeof(Tmp), "%s%s%s", getmessage(Num_InfoMessHead1), as_cmdarg_get_executable_name(), getmessage(Num_InfoMessHead2));
  668.     write_console_next(Tmp);
  669.     for (ph1 = getmessage(Num_InfoMessHelp), ph2 = strchr(ph1, '\n'); ph2; ph1 = ph2 + 1, ph2 = strchr(ph1, '\n'))
  670.     {
  671.       *ph2 = '\0';
  672.       write_console_next(ph1);
  673.       *ph2 = '\n';
  674.     }
  675.   }
  676.  
  677.   if (write_cpu_list_exit)
  678.   {
  679.     printf("%s\n", getmessage(Num_InfoMessCPUList));
  680.     PrintCPUList(write_console_next);
  681.   }
  682.  
  683.   if (write_version_exit || write_help_exit || write_cpu_list_exit)
  684.     exit(0);
  685.  
  686.   if (!Disassemble)
  687.   {
  688.     fprintf(stderr, "no CPU set, aborting\n");
  689.     exit(3);
  690.   }
  691.  
  692.   /* walk through code */
  693.  
  694.   NextAddress = 0;
  695.   NextAddressValid = False;
  696.   Data.MaxSrcLineLen = 0;
  697.   while (EntryAddressAvail())
  698.   {
  699.     Address = GetEntryAddress(NextAddressValid, NextAddress);
  700.     Disassemble(Address, &Info, False, -1);
  701.     AddChunk(&UsedCodeChunks, Address, Info.CodeLen, True);
  702.     if ((ThisSrcLineLen = tabbedstrlen(Info.SrcLine)) > Data.MaxSrcLineLen)
  703.       Data.MaxSrcLineLen = ThisSrcLineLen;
  704.     for (z = 0; z < Info.NextAddressCount; z++)
  705.       if (!AddressInChunk(&UsedCodeChunks, Info.NextAddresses[z]))
  706.         AddEntryAddress(Info.NextAddresses[z]);
  707.     NextAddress = Address + Info.CodeLen;
  708.     NextAddressValid = True;
  709.   }
  710.  
  711.   /* round up src line & symbol length to next multiple of tabs */
  712.  
  713.   Data.MaxSrcLineLen += TABSIZE - (Data.MaxSrcLineLen % TABSIZE);
  714.   Data.MaxLabelLen = GetMaxInvSymbolNameLen() + 1;
  715.   Data.MaxLabelLen += TABSIZE - (Data.MaxLabelLen % TABSIZE);
  716.   Data.pDestFile = stdout;
  717.  
  718.   /* bring areas into order */
  719.  
  720.   SortChunks(&UsedCodeChunks);
  721.   SortChunks(&UsedDataChunks);
  722.  
  723.   /* dump them out */
  724.  
  725.   IterateChunks(DisasmIterator, &Data);
  726.  
  727.   /* summary */
  728.  
  729.   DumpChunks(&UsedCodeChunks, Data.pDestFile);
  730.  
  731.   return 0;
  732. }
  733.