Subversion Repositories spk

Rev

Rev 46 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 SPKInstall V1.00 Created by Cycrow (Matthew Gravestock)
*/

// Main Spk File Library Include
#ifdef _WIN32
#include <spk.h>
#else
#include "../spk/spk.h"
#endif
#include <time.h>

#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#include <shlobj.h>
#endif

#define BETA 1

class CProgressConsole : public CProgressInfo
{
public:
        CProgressConsole() : CProgressInfo()
        {
                m_iCount = 0;
                m_fNextPercent = 0.0f;
        }

        void Finish(bool newline = true)
        {
                for ( int i = m_iCount; i < 20; i++ )
                        printf ( "*" );
                if ( newline )
                        printf ( "\n");
                m_fNextPercent = 0.0f;
                m_iCount = 0;
        }

protected:
        virtual void ProgressUpdated ( const long cur, const long max )
        {
                float percent = ((float)cur / (float)max) * 100.0f;
                if ( m_bDoHalf )
                {
                        percent /= 2.0f;
                        if ( m_bSecondHalf )
                                percent += 50.0f;
                        else if ( percent > 50.0f )
                                percent = 50.0f;
                }
                if ( (percent - m_fNextPercent) >= 5.0f )
                {
                        printf ( "*" );
                        m_fNextPercent += 5.0f;
                        ++m_iCount;
                }
        }
        virtual void DoingFile ( C_File *file )
        {
        }

private:
        float m_fNextPercent;
        int   m_iCount;
};

#define FLAGS "[-voctm][-d destination][-l langid]"

CyString        g_dir;
bool    g_debug = false;
bool    g_force = false;
int             g_indent = 0;
/*
        Func:   GetInput
        Desc:   Gets an input from the user, ie, any settings required to be typed in
*/
CyString GetInput ()
{
//      g_read = true;

        CyString line;
        char c = getchar();

        while ( (c != '\n') && (c != '\0') )
        {
                line += c;
                c = getchar();
        }

        return line;
}

void PrintSyntax ( CyString cmd )
{
        printf ( "Syntax: %s %s </command> [arguments]\n", cmd.c_str(), FLAGS );
        printf ( "\nCommands:\n" );
        printf ( "   /list\n\t- Lists installed packages\n" );
        printf ( "   /install <file>\n\t- Installs a package file\n" );
        printf ( "   /uninstall <package#>\n\t- Uninstalls a package, use id number from list\n" );
        printf ( "   /enable <package#>\n\t- Enables an installed package\n" );
        printf ( "   /disable <package#>\n\t- Disables an installed package\n" );
        printf ( "   /removeuninstall\n\t- Removes uninstall scripts\n" );
        printf ( "   /removeshared\n\t- Removes unused sharded files\n" );
        printf ( "\nSwitchs:\n" );
        printf ( "   -d (--directory) [directory]\n\tChange destination directory, otherwise uses current\n\n" );
        printf ( "   -v (--verbose)\n\tTurns on verbose mode\n\n" );
        printf ( "   -o (--override)\n\tOverride install warnings\n\tIE. allows you to install older scripts\n\n" );
        printf ( "   -t (--textrename)\n\tForces text file renaming for installed packages\n\n" );
        printf ( "   -l (--language) <language>\n\tSets the language id for text file renaming\n\totheriwse reads game lang.dat\n\n" );
        printf ( "   -c (--enablechild)\n\tAuto Enabled all children when parent is enabled\n\n" );
        printf ( "   -m (--forcemod\n\tForces a mod enabled even if theres one already enabled\n\n" );
}

void DisplayPackage(CBaseFile *p, int indent, int language)
{
        CyString version = p->GetVersion();
        if ( version.lower()[0] != 'v' )
                version.Prepend("v");

        printf ( "  [%5d] ", p->GetNum() + 1 );

        if ( indent > g_indent )
        {
                printf (" \\->");
        }
        for ( int i = 0; i < indent; i++ )
                printf("\t");

        g_indent = indent;

        if ( !p->IsEnabled() )
                printf("[D] ");

        printf ( "%s %s by %s\n", p->GetLanguageName(language).c_str(), version.c_str(), p->GetAuthor().c_str() );
}

void DoAllChildren(CPackages *packages, CBaseFile *p, CLinkList<CBaseFile> *doneList, int indent)
{
        CLinkList<CBaseFile> children;
        if ( packages->GetChildPackages(p, &children) )
        {
                for ( CBaseFile *child = children.First(); p; p = children.Next() )
                {
                        DisplayPackage(child, indent, packages->GetLanguage());
                        doneList->push_back(child);

                        DoAllChildren(packages, child, doneList, indent + 1);
                }
        }
}

void ListPackages(CPackages *packages)
{
        CProgressConsole progress;

        CLinkList<CBaseFile> doneList;

        g_indent = 0;
        printf ( "\nPackages:\n" );
        for ( CBaseFile *p = packages->PackageList()->First(); p; p = packages->PackageList()->Next() )
        {
                // already done?
                if ( doneList.FindData(p) )
                        continue;

                if ( p->GetType() != TYPE_SPK )
                        continue;

                DisplayPackage(p, 0, packages->GetLanguage());
                doneList.push_back(p);

                // find all children
                DoAllChildren(packages, p, &doneList, 1);
        }
}

int SplitArguments(char **argv, int argc, int start, CyStringList *argList)
{
        for ( int i = start; i < argc; i++ )
        {
                CyString arg = argv[i];
                if ( !arg.Empty() )
                        argList->PushBack(arg);
        }

        return argList->Count();
}

CyString InstallPackage(CyStringList *lArguments, CyStringList *errors, CPackages *packages, bool disabled)
{
        CProgressConsole progress;

        int error;

        if ( !lArguments || !lArguments->Count() )
                return NullString;

        // append spk on the end
        for ( SStringList *node = lArguments->Head(); node; node = node->next )
        {
                if ( !CFileIO(node->str).Exists() )
                {
                        if ( CFileIO(node->str).GetFileExtension().lower() != "spk" )
                                node->str += ".spk";
                }
        }

        CLinkList<CBaseFile> lPackages;

        // open the package file
        printf ( "  - Opening Package                \n" );
        for ( SStringList *node = lArguments->Head(); node; node = node->next )
        {
                CyString spkFilename = node->str;

                if ( spkFilename.Length() > 30 )
                        printf ( "    ..%28s ", spkFilename.Right(28).c_str() );
                else
                        printf ( "    %30s ", spkFilename.Right(30).c_str() );

                CLinkList<CBaseFile> lPackageList;
                CBaseFile *package = packages->OpenPackage(spkFilename, &error, &progress);

                // multi packages
                if ( !package && error == INSTALLERR_NOMULTI )
                {
                        if ( !packages->OpenMultiPackage(spkFilename, &lPackageList, &error, &progress) )
                        {
                                printf ( "Error!\n");
                                continue;
                        }
                        progress.Finish();
                }

                else if ( package )
                {
                        progress.Finish();
                        lPackageList.push_back(package);
                }
                else
                {
                        printf ( "ERROR!  " );
                        switch ( error )
                        {
                                case INSTALLERR_OLD:
                                        printf ( "File is in old format no longer supported" );
                                        break;
                                case INSTALLERR_NOEXIST:
                                        printf ( "file doesn't exist" );
                                        break;
                                case INSTALLERR_INVALID:
                                        printf ( "Invalid package file" );
                                        break;
                                case INSTALLERR_NOSHIP:
                                        printf ( "Ship Packages are currently not supported" );
                                        break;
                                case INSTALLERR_VERSION:
                                        printf ( "Package file was created in a newer version, unable to open" );
                                        break;
                        }
                        printf ( "\n");
                        continue;
                }

                for ( CListNode<CBaseFile> *pNode = lPackageList.Front(); pNode; pNode = pNode->next() )
                {
                        CBaseFile *package = pNode->Data();

                        // compare versions
                        CyString packageName = package->GetFullPackageName(packages->GetLanguage());

                        int checkFlags = IC_ALL;
                        int check = packages->PrepareInstallPackage(package, (disabled) ? true : !package->IsEnabled(), false, checkFlags);

                        switch (check)
                        {
                                case INSTALLCHECK_OLDVERSION:
                                        printf ( "Newer version of \"%s\" already installed", packageName.c_str() );
                                        if ( !g_force )
                                        {
                                                printf ( ", Unable to install older, use -o to force installation\n" );
                                                continue;
                                        }
                                        else
                                        {
                                                printf ( ", Overriding install\n" );
                                                if ( packages->PrepareInstallPackage(package, disabled, true) != INSTALLCHECK_OK )
                                                        continue;
                                                break;
                                        }
                                        break;
                                        // wait for the rest to be added
                                case INSTALLCHECK_WRONGGAME:
                                        printf ( "ERROR! \"%s\" Wrong Game (Requires: %s)", packageName.c_str(), packages->GetGameTypesString(package, false).c_str() );
                                        if ( g_force )
                                        {
                                                printf ( " [FORCED]\n" );
                                                if ( packages->PrepareInstallPackage(package, disabled, true) != INSTALLCHECK_OK )
                                                        continue;
                                        }
                                        else
                                        {
                                                printf("\n");
                                                continue;
                                        }
                                        break;

                                case INSTALLCHECK_WRONGVERSION:
                                        printf ( "ERROR! \"%s\" Wrong Game Version (Requires: %s)\n", packageName.c_str(), packages->GetGameVersionString(package).c_str() );
                                        if ( g_force )
                                        {
                                                printf ( " [FORCED]\n" );
                                                if ( packages->PrepareInstallPackage(package, disabled, true) != INSTALLCHECK_OK )
                                                        continue;
                                        }
                                        else
                                        {
                                                printf("\n");
                                                continue;
                                        }
                                        break;
                        }

                        if ( package->IsThereInstallText() )
                        {
                                CyString installtext = packages->GetInstallBeforeText(package);
                                if ( !installtext.Empty() )
                                {
                                        installtext.StripHTML();
                                        printf ( "Installing %s: %s\n", packageName.c_str(), installtext.c_str() );
                                        printf ( "Do you want to continue with the install? " );

                                        if ( g_force )
                                                printf ( "(FORCED)\n" );
                                        else
                                        {
                                                CyString input = GetInput().ToLower();

                                                if ( input != "y" && input != "yes" )
                                                {
                                                        printf ( "\nInstallion aborted!!\n\n" );
                                                        packages->RemovePreparedInstall(package);
                                                        continue;
                                                }
                                        }
                                }
                        }

                        lPackages.push_back(package);
                }
        }

        // is there any that couldn't install
        CLinkList<CBaseFile> lCheckPackages;
        if ( packages->CheckPreparedInstallRequired(&lCheckPackages) )
        {
                printf ( "\nError! Some packages are missing dependacies:\n" );
                for ( CListNode<CBaseFile> *pNode = lCheckPackages.Front(); pNode; pNode = pNode->next() )
                {
                        CSpkFile *spk = (CSpkFile *)pNode->Data();
                        printf ( "\t%s V%s by %s (Requires: %s by %s)\n", spk->GetLanguageName(packages->GetLanguage()).c_str(), spk->GetVersion().c_str(), spk->GetAuthor().c_str(), spk->GetOtherName().c_str(), spk->GetOtherAuthor().c_str());
                }
        }

        // no packages will be installed
        if ( packages->GetNumPackagesInQueue() < 1 )
                return NullString;

        // install the package file
        printf ( "  - Installing                     " );
        CLinkList<CBaseFile> erroredPackages;
        if ( packages->InstallPreparedPackages(errors, &progress, &erroredPackages) )
                progress.Finish();
        else
        {
                printf ( "ERROR!\n" );
                return NullString;
        }

        // delete any errored packages
        for ( CListNode<CBaseFile> *pNode = erroredPackages.Front(); pNode; pNode = pNode->next() )
        {
                lPackages.remove(pNode->Data());
                pNode->DeleteData();
        }

        // now display the packages
        CyString retStr = "Packages Installed:\n";
        for ( CListNode<CBaseFile> *pNode = lPackages.Front(); pNode; pNode = pNode->next() )
        {
                CBaseFile *package = pNode->Data();

                retStr += "  <> ";
                retStr += package->GetFullPackageName(packages->GetLanguage());
                retStr += "\n";

                if ( !packages->GetInstallAfterText(package).Empty() )
                {
                        CyString afterText = packages->GetInstallAfterText(package).StripHTML();
                        afterText = afterText.FindReplace("\n", "\n\t");
                        retStr += "\t";
                        retStr += afterText;
                        retStr += "\n";
                }
        }

        return retStr;
}

CBaseFile *FindPackage(int packageNum, CPackages *packages)
{
        for ( CBaseFile *p = packages->PackageList()->First(); p; p = packages->PackageList()->Next() )
        {
                if ( p->GetNum() == (packageNum - 1) )
                        return p;
        }

        return 0;
}

bool UninstallPackage(int uninstallNum, CyStringList *errors, CPackages *packages, CyString *endMessage)
{
        CBaseFile *p = FindPackage(uninstallNum, packages);
        if ( !p )
                return false;

        // lets check for the uninstall text
        CyString uText = packages->GetUninstallBeforeText(p).StripHTML();
        if ( !uText.Empty() )
        {
                printf ( "Uninstalling: %s\n", uText.c_str() );
                printf ( "Do you wish to continue with the uninstall? " );
                if ( g_force )
                        printf ( "(FORCED)\n" );
                else
                {
                        CyString input = GetInput().ToLower();
                        if ( input != "y" && input != "yes" )
                        {
                                printf ( "\nUninstallation has been aborted!!\n" );
                                return false;
                        }
                }
        }

        CProgressConsole progress;

        (*endMessage) = CyString("Uninstalled: ") + p->GetFullPackageName(packages->GetLanguage());
        // add the uninstall after text
        uText = packages->GetUninstallAfterText(p).StripHTML();
        if ( !uText.Empty() )
        {
                (*endMessage) += "\n\n";
                (*endMessage) += uText;
                (*endMessage) += "\n";
        }

        printf ( "  - Unistalling                    " );
        packages->PrepareUninstallPackage(p);
        if ( packages->UninstallPreparedPackages(errors, &progress) )
        {
                progress.Finish();
        }
        else
        {
                (*endMessage) = "";
                printf ( "ERROR!\n" );
                return false;
        }


        return true;
}

bool EnablePackage(int uninstallNum, CyStringList *errors, CPackages *packages, CyString *endMessage)
{
        CBaseFile *p = FindPackage(uninstallNum, packages);
        if ( !p )
                return false;

        CProgressConsole progress;

        (*endMessage) = CyString("Enabled: ") + p->GetFullPackageName(packages->GetLanguage());

        printf ( "  - Enabling                       " );
        if ( packages->EnablePackage(p, errors, &progress) )
        {
                progress.Finish();
        }
        else
        {
                int error = packages->GetError();
                (*endMessage) = "";
                printf ( "ERROR! " );
                if ( error == PKERR_NOPARENT )
                        printf ( "Parent package is disabled" );
                printf ( "\n" );
                return false;
        }
        return true;
}

bool DisablePackage(int uninstallNum, CyStringList *errors, CPackages *packages, CyString *endMessage)
{
        CBaseFile *p = FindPackage(uninstallNum, packages);
        if ( !p )
                return false;

        CProgressConsole progress;

        (*endMessage) = CyString("Disabled: ") + p->GetFullPackageName(packages->GetLanguage());

        printf ( "  - Disabling                      " );
        if ( packages->DisablePackage(p, errors, &progress) )
        {
                progress.Finish();
        }
        else
        {
                (*endMessage) = "";
                printf ( "ERROR!\n" );
                return false;
        }
        return true;
}

void RemoveUninstallScripts(CPackages *packages, CyStringList *errors)
{
        CProgressConsole progress;
        printf ( "  - Removing uninstall scripts     " );
        packages->RemoveUninstallScripts(errors, &progress);
        progress.Finish();
}

void RemoveUnusedShared(CPackages *packages, CyStringList *errors)
{
        CProgressConsole progress;
        printf ( "  - Removing unused shared files   " );
        packages->RemoveUnusedSharedFiles(errors, &progress);
        progress.Finish();
}


void PrintDebug(CyStringList *errors)
{
        if ( !g_debug )
                return;

        if ( errors && errors->Count() )
                printf ( "\n");

        for ( SStringList *str = errors->Head(); str; str = str->next )
        {
                int errornum = str->str.ToInt();
                CyString rest = str->str.GetToken(" ", 2);

                CyString err = FormatErrorString(errornum, rest);
                printf ( "  * %s\n", err.c_str() );
        }

        if ( errors && errors->Count() )
                printf ( "\n");
}




void Pause()
{
#ifdef _DEBUG
        char pause;
        scanf ( "%s", &pause );
#endif
}


int ParseCommandSwitchs(char c, CyString *destination, CPackages *packages, int start, int *arg, char **argv)
{
        switch ( c )
        {
                case 'o':
                        g_force = true;
                        break;
                case 'v':
                        g_debug = true;
                        break;
                case 'd':
                        *destination = argv[*arg];
                        *destination = destination->FindReplace("\\", "/");
                        ++(*arg);
                        ++start;
                        break;
                case 't':
                        packages->SetRenameText(true);
                        break;
                case 'l':
                        packages->SetLanguage(CyString(argv[*arg]).ToInt());
                        ++(*arg);
                        ++start;
                        break;
                case 'c':
                        packages->SetAutoEnable(true);
                        break;
                case 'm':
                        packages->SetForceModInstall(true);
                        break;
        }

        return start;
}

/*
TODO:
Additional Features
        Patch Mods
        Update Packages
*/

/*
        Main entry point to program
*/
int main ( int argc, char **argv )
{
        // display program header to command prompt
        printf ( "\nSPKInstall V0.90 (SPK Library Version %.2f) 18/10/2009 Created by Cycrow\n\n", GetLibraryVersion() );

        // parse the cmd name
        CyString cmd (argv[0]);

        cmd = cmd.FindReplace ( "\\", "/" );
        g_dir = cmd.GetToken ( 0, cmd.NumToken('/') - 1, '/' );
        cmd = cmd.GetToken ( cmd.NumToken('/'), '/' );

        if ( g_dir.Empty() )
        {
            #ifdef _WIN32
                g_dir = CyString(_getcwd(NULL, 0));
                #else
                g_dir = CyString(getcwd(NULL, 0));
                #endif
                if ( g_dir.Empty() )
                        g_dir = "./";
        }

        // not enough arguments, display the syntax and exit
        if ( argc < 2 )
        {
                PrintSyntax(cmd);
                Pause();
                exit ( 1 );
        }

        CyString destination = g_dir;
        CyStringList errors;

        // get the command flag
        CyString command(argv[1]);
        command = command.lower();

        CPackages packages;
        CyString myDoc = g_dir;
#ifdef _WIN32
        TCHAR pszPath[MAX_PATH];
        if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, pszPath)))
                myDoc = (char *)pszPath;
#endif
        packages.Startup(g_dir, g_dir, myDoc);

        int start = 2;
        // check for switchs
        while ( command[0] == '-' )
        {
                if ( argc < (start + 1) )
                {
                        PrintSyntax(cmd);
                        Pause();
                        exit ( 1 );
                }
                ++start;

                // single long commands
                int arg = 2;
                if ( command.Left(2) == "--" )
                {
                        CyString cmd = command.Right(-2);
                        cmd = cmd.ToLower();

                        char c = 0;
                        if ( cmd == "override" )
                                c = 'o';
                        else if ( cmd == "verbose" )
                                c = 'v';
                        else if ( cmd == "directory" )
                                c = 'd';
                        else if ( cmd == "textrename" )
                                c = 't';
                        else if ( cmd == "enablechild" )
                                c = 'c';
                        else if ( cmd == "language" )
                                c = 'l';
                        else if ( cmd == "forcemod" )
                                c = 'm';

                        if ( c )
                                start = ParseCommandSwitchs(c, &destination, &packages, start, &arg, argv);
                }
                else
                {
                        // now parse arguments
                        for ( int i = 1; i < (int)command.Length(); i++ )
                                start = ParseCommandSwitchs(command[i], &destination, &packages, start, &arg, argv);
                }

                if ( argc < start )
                {
                        PrintSyntax(cmd);
                        exit( 1 );
                }
                command = argv[start - 1];
        }

        if ( command[0] == '/' )
        {
                char c = command[1];

                bool disabled = false;

                CyString checkCmd = command.ToLower();
                if ( checkCmd == "/install" )
                        c = 'i';
                else if ( checkCmd == "/installdisable" )
                {
                        c = 'i';
                        disabled = true;
                }
                else if ( checkCmd == "/uninstall" )
                        c = 'u';
                else if ( checkCmd == "/enable" )
                        c = 'e';
                else if ( checkCmd == "/disable" )
                        c = 'd';
                else if ( checkCmd == "/list" )
                        c = 'l';
                else if ( checkCmd == "/removeshared" )
                        c = 's';
                else if ( checkCmd == "/removeunisntall" )
                        c = 'r';

                if ( c == 'i' || c == 'l' || c == 'u' || c == 'e' || c == 'd' || c == 'r' || c == 's' )
                {
                        CyString endMessage;

                        printf ( "                                   |0              100|\n\n");
                        printf ( "  - Reading game directory         " );

                        CProgressConsole progress;

                        if ( packages.Read(destination, &progress) )
                        {
                                packages.UpdatePackages();
                                packages.ReadGameLanguage(false);
                                progress.Finish(false);

                                CyString gameName = packages.GetGameName();
                                if ( packages.GetLanguage() || !gameName.Empty())
                                {
                                        printf ( "\n\t" );
                                        if ( !gameName.Empty() )
                                                printf ( "Game: %s ", gameName.c_str());
                                        if ( packages.GetLanguage() )
                                                printf ( "(Language: %d)", packages.GetLanguage() );
                                }
                                printf ( "\n" );
                        }
                        else
                        {
                                printf ( "ERROR!\n" );
                                exit(1);
                        }

                        bool prepare = false;

                        packages.AssignPackageNumbers();

                        CyStringList lArguments;
                        SplitArguments(argv, argc, start, &lArguments);

                        switch ( c )
                        {
                                case 'i':
                                        if ( argc <= start )
                                                printf ( "Syntax: %s [flags] /i <file>\n\tInstalls a package to the destination\n", cmd.c_str() );
                                        else
                                        {
                                                CyString aftertext = InstallPackage(&lArguments, &errors, &packages, disabled);
                                                if ( !aftertext.Empty() )
                                                {
                                                        prepare = true;
                                                        endMessage = aftertext;
                                                }
                                                PrintDebug(&errors);
                                        }
                                        break;

                                case 'u':
                                        if ( argc <= start )
                                                printf ( "Syntax: %s [flags] /u <package#\n\tUninstalls a package, package# is from the /l list command\n", cmd.c_str() );
                                        else
                                        {
                                                prepare = UninstallPackage(CyString(argv[start]).ToInt(), &errors, &packages, &endMessage);
                                                PrintDebug(&errors);
                                        }
                                        break;

                                case 'e':
                                        if ( argc <= start )
                                                printf ( "Syntax: %s [flags] /u <package#\n\tEnabled an installed package thats been disabled\n", cmd.c_str() );
                                        else
                                        {
                                                prepare = EnablePackage(CyString(argv[start]).ToInt(), &errors, &packages, &endMessage);
                                                PrintDebug(&errors);
                                        }
                                        break;

                                case 'd':
                                        if ( argc <= start )
                                                printf ( "Syntax: %s [flags] /u <package#\n\tDisabled an installed package\n", cmd.c_str() );
                                        else
                                        {
                                                prepare = DisablePackage(CyString(argv[start]).ToInt(), &errors, &packages, &endMessage);
                                                PrintDebug(&errors);
                                        }
                                        break;

                                case 'l':
                                        ListPackages(&packages);
                                        break;

                                case 'r':
                                        RemoveUninstallScripts(&packages, &errors);
                                        endMessage = "Removed all unused uninstall scripts";
                                        break;

                                case 's':
                                        RemoveUnusedShared(&packages, &errors);
                                        endMessage = "Removed all unused shared files";
                                        break;
                        }

                        if ( prepare )
                        {
                                errors.Clear();
                                printf ( "  - Preparing game directory       " );
                                if ( packages.CloseDir(&errors, &progress, true) )
                                        progress.Finish();
                                else
                                {
                                        printf ( "ERROR!\n" );
                                        Pause();
                                        exit(1);
                                }

                                PrintDebug(&errors);
                        }
                        else
                                packages.RestoreFakePatch();

                        printf ( "\nDone!\n" );
                        if ( !endMessage.Empty() )
                                printf ( "\n%s\n", endMessage.c_str() );
                }
                else
                        printf ( "Unknown Command: %c\n", c );
        }

        Pause();

        return 0;
}