File indexing completed on 2024-06-16 11:34:36

0001 /***************************************************************************
0002  *   Copyright (C) 2005 by David Saxton                                    *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "processchain.h"
0012 #include "asmparser.h"
0013 #include "docmanager.h"
0014 #include "gplib.h"
0015 #include "ktechlab.h"
0016 #include "language.h"
0017 #include "languagemanager.h"
0018 #include "logview.h"
0019 #include "outputmethoddlg.h"
0020 #include "projectmanager.h"
0021 #include "textdocument.h"
0022 
0023 #include "flowcode.h"
0024 #include "gpasm.h"
0025 #include "gpdasm.h"
0026 #include "gplink.h"
0027 #include "microbe.h"
0028 #include "picprogrammer.h"
0029 #include "sdcc.h"
0030 
0031 #include <KLocalizedString>
0032 
0033 #include <QDir>
0034 #include <QFile>
0035 #include <QTemporaryFile>
0036 #include <QTimer>
0037 
0038 #include <ktlconfig.h>
0039 #include <ktechlab_debug.h>
0040 
0041 // BEGIN class ProcessChain
0042 ProcessChain::ProcessChain(ProcessOptions options)
0043     : QObject(KTechlab::self())
0044 {
0045     m_pFlowCode = nullptr;
0046     m_pGpasm = nullptr;
0047     m_pGpdasm = nullptr;
0048     m_pGplib = nullptr;
0049     m_pGplink = nullptr;
0050     m_pMicrobe = nullptr;
0051     m_pPicProgrammer = nullptr;
0052     m_pSDCC = nullptr;
0053     m_processOptions = options;
0054 
0055     QString target;
0056     if (ProcessOptions::ProcessPath::to(options.processPath()) == ProcessOptions::ProcessPath::Pic)
0057         target = options.m_picID;
0058     else
0059         target = options.targetFile();
0060 
0061     LanguageManager::self()->logView()->addOutput(i18n("Building: %1", target), LogView::ot_important);
0062     QTimer::singleShot(0, this, SLOT(compile()));
0063 }
0064 
0065 ProcessChain::~ProcessChain()
0066 {
0067     delete m_pFlowCode;
0068     delete m_pGpasm;
0069     delete m_pGpdasm;
0070     delete m_pGplib;
0071     delete m_pGplink;
0072     delete m_pMicrobe;
0073     delete m_pPicProgrammer;
0074     delete m_pSDCC;
0075 }
0076 
0077 // void ProcessChain::compile( ProcessOptions * options )
0078 void ProcessChain::compile()
0079 {
0080     // If the micro id in the options is empty, then attempt to get it from any
0081     // open project (it might not be necessarily...but won't hurt if it isn't).
0082     if (m_processOptions.m_picID.isEmpty()) {
0083         if (ProjectInfo *projectInfo = ProjectManager::self()->currentProject()) {
0084             ProjectItem *projectItem = projectInfo->findItem(QUrl::fromLocalFile(m_processOptions.inputFiles().first()));
0085             if (projectItem)
0086                 m_processOptions.m_picID = projectItem->microID();
0087         }
0088     }
0089 
0090     switch (m_processOptions.processPath()) {
0091 #define DIRECT_PROCESS(path, processor)                                                                                                                                                                                                        \
0092     case ProcessOptions::ProcessPath::path: {                                                                                                                                                                                                  \
0093         processor()->processInput(m_processOptions);                                                                                                                                                                                           \
0094         break;                                                                                                                                                                                                                                 \
0095     }
0096 #define INDIRECT_PROCESS(path, processor, extension)                                                                                                                                                                                           \
0097     case ProcessOptions::ProcessPath::path: {                                                                                                                                                                                                  \
0098         QTemporaryFile *f = new QTemporaryFile(QDir::tempPath() + QLatin1String("/ktechlab_XXXXXX") + QLatin1String(extension), processor());                                                                                                  \
0099         f->open();                                                                                                                                                                                                                             \
0100         f->close();                                                                                                                                                                                                                            \
0101         m_processOptions.setIntermediaryOutput(f->fileName());                                                                                                                                                                                 \
0102         processor()->processInput(m_processOptions);                                                                                                                                                                                           \
0103         break;                                                                                                                                                                                                                                 \
0104     }
0105 
0106         INDIRECT_PROCESS(AssemblyAbsolute_PIC, gpasm, ".hex")
0107         DIRECT_PROCESS(AssemblyAbsolute_Program, gpasm)
0108         INDIRECT_PROCESS(AssemblyRelocatable_Library, gpasm, ".o")
0109         DIRECT_PROCESS(AssemblyRelocatable_Object, gpasm)
0110         INDIRECT_PROCESS(AssemblyRelocatable_PIC, gpasm, ".o")
0111         INDIRECT_PROCESS(AssemblyRelocatable_Program, gpasm, ".o")
0112         DIRECT_PROCESS(C_AssemblyRelocatable, sdcc)
0113         INDIRECT_PROCESS(C_Library, sdcc, ".asm")
0114         INDIRECT_PROCESS(C_Object, sdcc, ".asm")
0115         INDIRECT_PROCESS(C_PIC, sdcc, ".asm")
0116         INDIRECT_PROCESS(C_Program, sdcc, ".asm")
0117         INDIRECT_PROCESS(FlowCode_AssemblyAbsolute, flowCode, ".microbe")
0118         DIRECT_PROCESS(FlowCode_Microbe, flowCode)
0119         INDIRECT_PROCESS(FlowCode_PIC, flowCode, ".microbe")
0120         INDIRECT_PROCESS(FlowCode_Program, flowCode, ".microbe")
0121         DIRECT_PROCESS(Microbe_AssemblyAbsolute, microbe)
0122         INDIRECT_PROCESS(Microbe_PIC, microbe, ".asm")
0123         INDIRECT_PROCESS(Microbe_Program, microbe, ".asm")
0124         DIRECT_PROCESS(Object_Disassembly, gpdasm)
0125         DIRECT_PROCESS(Object_Library, gplib)
0126         INDIRECT_PROCESS(Object_PIC, gplink, ".lib")
0127         DIRECT_PROCESS(Object_Program, gplink)
0128         DIRECT_PROCESS(PIC_AssemblyAbsolute, picProgrammer)
0129         DIRECT_PROCESS(Program_Disassembly, gpdasm)
0130         DIRECT_PROCESS(Program_PIC, picProgrammer)
0131 #undef DIRECT_PROCESS
0132 #undef INDIRECT_PROCESS
0133 
0134     case ProcessOptions::ProcessPath::Invalid:
0135         qCWarning(KTL_LOG) << "Process path is invalid";
0136         qCWarning(KTL_LOG) << "Nothing to do";
0137         break;
0138     case ProcessOptions::ProcessPath::None:
0139         qCWarning(KTL_LOG) << "Nothing to do";
0140         break;
0141     }
0142 }
0143 
0144 void ProcessChain::slotFinishedCompile(Language *language)
0145 {
0146     ProcessOptions options = language->processOptions();
0147 
0148     if (options.b_addToProject && ProjectManager::self()->currentProject())
0149         ProjectManager::self()->currentProject()->addFile(QUrl::fromLocalFile(options.targetFile()));
0150 
0151     ProcessOptions::ProcessPath::MediaType typeTo = ProcessOptions::ProcessPath::to(m_processOptions.processPath());
0152 
0153     TextDocument *editor = nullptr;
0154     if (KTLConfig::reuseSameViewForOutput()) {
0155         editor = options.textOutputTarget();
0156         if (editor && (!editor->url().isEmpty() || editor->isModified()))
0157             editor = nullptr;
0158     }
0159 
0160     switch (typeTo) {
0161     case ProcessOptions::ProcessPath::AssemblyAbsolute:
0162     case ProcessOptions::ProcessPath::AssemblyRelocatable:
0163     case ProcessOptions::ProcessPath::C:
0164     case ProcessOptions::ProcessPath::Disassembly:
0165     case ProcessOptions::ProcessPath::Library:
0166     case ProcessOptions::ProcessPath::Microbe:
0167     case ProcessOptions::ProcessPath::Object:
0168     case ProcessOptions::ProcessPath::Program: {
0169         switch (options.method()) {
0170         case ProcessOptions::Method::LoadAsNew: {
0171             if (!editor)
0172                 editor = DocManager::self()->createTextDocument();
0173 
0174             if (!editor)
0175                 break;
0176 
0177             QString text;
0178             QFile f(options.targetFile());
0179             if (!f.open(QIODevice::ReadOnly)) {
0180                 editor->deleteLater();
0181                 editor = nullptr;
0182                 break;
0183             }
0184 
0185             QTextStream stream(&f);
0186 
0187             while (!stream.atEnd())
0188                 text += stream.readLine() + '\n';
0189 
0190             f.close();
0191 
0192             editor->setText(text, true);
0193             break;
0194         }
0195 
0196         case ProcessOptions::Method::Load: {
0197             editor = dynamic_cast<TextDocument *>(DocManager::self()->openURL(QUrl::fromLocalFile(options.targetFile())));
0198             break;
0199         }
0200 
0201         case ProcessOptions::Method::Forget:
0202             break;
0203         }
0204     }
0205 
0206     case ProcessOptions::ProcessPath::FlowCode:
0207     case ProcessOptions::ProcessPath::Pic:
0208     case ProcessOptions::ProcessPath::Unknown:
0209         break;
0210     }
0211 
0212     if (editor) {
0213         switch (typeTo) {
0214         case ProcessOptions::ProcessPath::AssemblyAbsolute:
0215         case ProcessOptions::ProcessPath::AssemblyRelocatable: {
0216             if (KTLConfig::autoFormatMBOutput())
0217                 editor->formatAssembly();
0218             editor->slotInitLanguage(TextDocument::ct_asm);
0219             break;
0220         }
0221 
0222         case ProcessOptions::ProcessPath::C:
0223             editor->slotInitLanguage(TextDocument::ct_c);
0224             break;
0225 
0226         case ProcessOptions::ProcessPath::Disassembly:
0227             break;
0228 
0229         case ProcessOptions::ProcessPath::Library:
0230         case ProcessOptions::ProcessPath::Object:
0231         case ProcessOptions::ProcessPath::Program:
0232             editor->slotInitLanguage(TextDocument::ct_hex);
0233             break;
0234 
0235         case ProcessOptions::ProcessPath::Microbe:
0236             editor->slotInitLanguage(TextDocument::ct_microbe);
0237             break;
0238 
0239         case ProcessOptions::ProcessPath::FlowCode:
0240         case ProcessOptions::ProcessPath::Pic:
0241         case ProcessOptions::ProcessPath::Unknown:
0242             break;
0243         }
0244 
0245         DocManager::self()->giveDocumentFocus(editor);
0246     }
0247 
0248     options.setTextOutputtedTo(editor);
0249 
0250     emit successful(options);
0251     emit successful();
0252 }
0253 
0254 #define LanguageFunction(a, b, c)                                                                                                                                                                                                              \
0255     a *ProcessChain::b()                                                                                                                                                                                                                       \
0256     {                                                                                                                                                                                                                                          \
0257         if (!c) {                                                                                                                                                                                                                              \
0258             c = new a(this);                                                                                                                                                                                                                   \
0259             connect(c, SIGNAL(processSucceeded(Language *)), this, SLOT(slotFinishedCompile(Language *)));                                                                                                                                     \
0260             connect(c, SIGNAL(processFailed(Language *)), this, SIGNAL(failed()));                                                                                                                                                             \
0261         }                                                                                                                                                                                                                                      \
0262         return c;                                                                                                                                                                                                                              \
0263     }
0264 
0265 LanguageFunction(FlowCode, flowCode, m_pFlowCode) LanguageFunction(Gpasm, gpasm, m_pGpasm) LanguageFunction(Gpdasm, gpdasm, m_pGpdasm) LanguageFunction(Gplib, gplib, m_pGplib) LanguageFunction(Gplink, gplink, m_pGplink)
0266     LanguageFunction(Microbe, microbe, m_pMicrobe) LanguageFunction(PicProgrammer, picProgrammer, m_pPicProgrammer) LanguageFunction(SDCC, sdcc, m_pSDCC)
0267     // END class ProcessChain
0268 
0269     // BEGIN class ProcessListChain
0270     ProcessListChain::ProcessListChain(ProcessOptionsList pol)
0271     : QObject(KTechlab::self())
0272 {
0273     m_processOptionsList = pol;
0274 
0275     // Start us off...
0276     slotProcessChainSuccessful();
0277 }
0278 
0279 void ProcessListChain::slotProcessChainSuccessful()
0280 {
0281     if (m_processOptionsList.isEmpty()) {
0282         emit successful();
0283         return;
0284     }
0285 
0286     ProcessOptionsList::iterator it = m_processOptionsList.begin();
0287     ProcessOptions po = *it;
0288     m_processOptionsList.erase(it);
0289 
0290     ProcessChain *pc = LanguageManager::self()->compile(po);
0291 
0292     connect(pc, SIGNAL(successful()), this, SLOT(slotProcessChainSuccessful()));
0293     connect(pc, SIGNAL(failed()), this, SLOT(slotProcessChainFailed()));
0294 }
0295 
0296 void ProcessListChain::slotProcessChainFailed()
0297 {
0298     emit failed();
0299 }
0300 // END class ProcessListChain
0301 
0302 #include "moc_processchain.cpp"