int main(int argc, char **argv) { struct sigaction sa; char *LogFile; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = SIG_DFL; sa.sa_flags |= SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) != 0) { Error("sigaction(2) failure"); } gtk_init(&argc, &argv); gtk_panda_init(&argc, &argv); gtk_set_locale(); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); LogFile = getenv("GLPUSH_LOGFILE"); if (LogFile == NULL) { InitLogger("glprint"); } else { InitLogger_via_FileName(LogFile); } TempDir = getenv("GLPUSH_TEMPDIR"); if (TempDir == NULL) { InitTempDir("glprint"); } else { InitTempDir_via_Dir(TempDir); } gl_config_init(); InitDesktop(); execute(); gtk_timeout_add(30 * 1000, push_action_exit, NULL); gtk_main(); sleep(3); return 0; }
// The `main program' equivalent, creating the windows and returning the // main frame bool AudacityApp::OnInit() { // Unused strings that we want to be translated, even though // we're not using them yet... wxString future1 = _("Master Gain Control"); wxString future2 = _("Input Meter"); wxString future3 = _("Output Meter"); ::wxInitAllImageHandlers(); wxFileSystem::AddHandler(new wxZipFSHandler); InitPreferences(); #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__) this->AssociateFileTypes(); #endif // // Paths: set search path and temp dir path // wxString home = wxGetHomeDir(); mAppHomeDir = home; // On Unix systems, the default temp dir is in /tmp. // Search path (in this order): // * The AUDACITY_PATH environment variable // * The current directory // * The user's .audacity-files directory in their home directory // * The "share" and "share/doc" directories in their install path #ifdef __WXGTK__ defaultTempDir.Printf(wxT("/tmp/audacity1.2-%s"), wxGetUserId().c_str()); wxString pathVar = wxGetenv(wxT("AUDACITY_PATH")); if (pathVar != wxT("")) AddMultiPathsToPathList(pathVar, audacityPathList); AddUniquePathToPathList(FROMFILENAME(::wxGetCwd()), audacityPathList); AddUniquePathToPathList(wxString::Format(wxT("%s/.audacity-files"), home.c_str()), audacityPathList); #ifdef AUDACITY_NAME AddUniquePathToPathList(wxString::Format(wxT("%s/share/%s"), wxT(INSTALL_PREFIX), wxT(AUDACITY_NAME)), audacityPathList); AddUniquePathToPathList(wxString::Format(wxT("%s/share/doc/%s"), wxT(INSTALL_PREFIX), wxT(AUDACITY_NAME)), audacityPathList); #else AddUniquePathToPathList(wxString::Format(wxT("%s/share/audacity"), wxT(INSTALL_PREFIX)), audacityPathList); AddUniquePathToPathList(wxString::Format(wxT("%s/share/doc/audacity"), wxT(INSTALL_PREFIX)), audacityPathList); #endif AddUniquePathToPathList(wxString::Format(wxT("%s/share/locale"), wxT(INSTALL_PREFIX)), audacityPathList); #endif wxFileName tmpFile; tmpFile.AssignTempFileName(wxT("nn")); wxString tmpDirLoc = tmpFile.GetPath(wxPATH_GET_VOLUME); ::wxRemoveFile(FILENAME(tmpFile.GetFullPath())); // On Mac and Windows systems, use the directory which contains Audacity. #ifdef __WXMSW__ // On Windows, the path to the Audacity program is in argv[0] wxString progPath = wxPathOnly(argv[0]); AddUniquePathToPathList(progPath, audacityPathList); AddUniquePathToPathList(progPath+wxT("\\Languages"), audacityPathList); defaultTempDir.Printf(wxT("%s\\audacity_1_2_temp"), tmpDirLoc.c_str()); #endif #ifdef __MACOSX__ // On Mac OS X, the path to the Audacity program is in argv[0] wxString progPath = wxPathOnly(argv[0]); AddUniquePathToPathList(progPath, audacityPathList); // If Audacity is a "bundle" package, then the root directory is // the great-great-grandparent of the directory containing the executable. AddUniquePathToPathList(progPath+wxT("/../../../"), audacityPathList); AddUniquePathToPathList(progPath+wxT("/Languages"), audacityPathList); AddUniquePathToPathList(progPath+wxT("/../../../Languages"), audacityPathList); defaultTempDir.Printf(wxT("%s/audacity1.2-%s"), tmpDirLoc.c_str(), wxGetUserId().c_str()); #endif #ifdef __MACOS9__ // On Mac OS 9, the initial working directory is the one that // contains the program. wxString progPath = wxGetCwd(); AddUniquePathToPathList(progPath, audacityPathList); AddUniquePathToPathList(progPath+wxT(":Languages"), audacityPathList); defaultTempDir.Printf(wxT("%s/audacity_1_2_temp"), tmpDirLoc.c_str()); #endif // BG: Create a temporary window to set as the top window wxFrame *temporarywindow = new wxFrame(NULL, -1, wxT("temporarytopwindow")); SetTopWindow(temporarywindow); // Locale // wxWindows 2.3 has a much nicer wxLocale API. We can make this code much // better once we move to wx 2.3/2.4. wxString lang = gPrefs->Read(wxT("/Locale/Language"), wxT("")); // Pop up a dialog the first time the program is run if (lang == wxT("")) lang = ChooseLanguage(NULL); #ifdef NOT_RQD //TIDY-ME: (CleanSpeech) Language prompt?? // The prompt for language only happens ONCE on a system. // I don't think we should disable it JKC wxString lang = gPrefs->Read(wxT("/Locale/Language"), "en"); //lda // Pop up a dialog the first time the program is run //lda if (lang == "") //lda lang = ChooseLanguage(NULL); #endif gPrefs->Write(wxT("/Locale/Language"), lang); if (lang != wxT("en")) { wxLogNull nolog; mLocale = new wxLocale(wxT(""), lang, wxT(""), true, true); for(unsigned int i=0; i<audacityPathList.GetCount(); i++) mLocale->AddCatalogLookupPathPrefix(audacityPathList[i]); #ifdef AUDACITY_NAME mLocale->AddCatalog(wxT(AUDACITY_NAME)); #else mLocale->AddCatalog(wxT("audacity")); #endif } else mLocale = NULL; // Initialize internationalisation (number formats etc.) // // This must go _after_ creating the wxLocale instance because // creating the wxLocale instance sets the application-wide locale. Internat::Init(); // Init DirManager, which initializes the temp directory // If this fails, we must exit the program. if (!InitTempDir()) { FinishPreferences(); return false; } // More initialization InitCleanSpeech(); InitDitherers(); InitAudioIO(); LoadEffects(); #ifdef __WXMAC__ // On the Mac, users don't expect a program to quit when you close the last window. // Create an offscreen frame with a menu bar. The frame should never // be visible, but when all other windows are closed, this menu bar should // become visible. gParentFrame = new wxFrame(NULL, -1, wxT("invisible"), wxPoint(5000, 5000), wxSize(100, 100)); wxMenu *fileMenu = new wxMenu(); fileMenu->Append(wxID_NEW, wxT("&New\tCtrl+N")); fileMenu->Append(wxID_OPEN, wxT("&Open...\tCtrl+O")); /* i18n-hint: Mac OS X shortcut should be Ctrl+, */ fileMenu->Append(wxID_PREFERENCES, _("&Preferences...\tCtrl+,")); wxMenuBar *menuBar = new wxMenuBar(); menuBar->Append(fileMenu, wxT("&File")); gParentFrame->SetMenuBar(menuBar); gParentFrame->Show(); SetTopWindow(gParentFrame); #endif SetExitOnFrameDelete(true); /////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// //Initiate pointers to toolbars here, and create //the toolbars that should be loaded at startup. gControlToolBarStub = LoadToolBar( wxT(""),true, gParentWindow,ControlToolBarID); gMixerToolBarStub = LoadToolBar( wxT("/GUI/EnableMixerToolBar"),true, gParentWindow,MixerToolBarID); gMeterToolBarStub = LoadToolBar( wxT("/GUI/EnableMeterToolBar"),true, gParentWindow,MeterToolBarID); gEditToolBarStub = LoadToolBar( wxT("/GUI/EnableEditToolBar"),true, gParentWindow,EditToolBarID); gTranscriptionToolBarStub = LoadToolBar( wxT("/GUI/EnableTranscriptionToolBar"),false, gParentWindow,TranscriptionToolBarID); /// ToolBar Initiation Complete. //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// AudacityProject *project = CreateNewAudacityProject(gParentWindow); SetTopWindow(project); delete temporarywindow; // Can't handle command-line args on Mac OS X yet... // Cygwin command-line parser below... #if !defined(__MACOSX__) && !defined(__CYGWIN__) // Parse command-line arguments if (argc > 1) { for (int option = 1; option < argc; option++) { if (!argv[option]) continue; bool handled = false; if (!wxString(wxT("-help")).CmpNoCase(argv[option])) { wxPrintf(/* i18n-hint: '-help', '-test' and '-blocksize' need to stay in English. */ _("Command-line options supported:\n -help (this message)\n -test (run self diagnostics)\n -blocksize ### (set max disk block size in bytes)\n\nIn addition, specify the name of an audio file or Audacity project\nto open it.\n\n")); exit(0); } if (option < argc - 1 && argv[option + 1] && !wxString(wxT("-blocksize")).CmpNoCase(argv[option])) { long theBlockSize; if (wxString(argv[option + 1]).ToLong(&theBlockSize)) { if (theBlockSize >= 256 && theBlockSize < 100000000) { wxFprintf(stderr, _("Using block size of %ld\n"), theBlockSize); Sequence::SetMaxDiskBlockSize(theBlockSize); } } option++; handled = true; } if (!handled && !wxString(wxT("-test")).CmpNoCase(argv[option])) { RunBenchmark(NULL); exit(0); } if (argv[option][0] == wxT('-') && !handled) { wxPrintf(_("Unknown command line option: %s\n"), argv[option]); exit(0); } if (!handled) project->OpenFile(argv[option]); } // for option... } // if (argc>1) #endif // not Mac OS X // Cygwin command line parser (by Dave Fancella) #if defined(__CYGWIN__) if (argc > 1) { int optionstart = 1; bool startAtOffset = false; // Scan command line arguments looking for trouble for (int option = 1; option < argc; option++) { if (!argv[option]) continue; // Check to see if argv[0] is copied across other arguments. // This is the reason Cygwin gets its own command line parser. if (wxString(argv[option]).Lower().Contains(wxString(wxT("audacity.exe")))) { startAtOffset = true; optionstart = option + 1; } } for (int option = optionstart; option < argc; option++) { if (!argv[option]) continue; bool handled = false; bool openThisFile = false; wxString fileToOpen; if (!wxString(wxT("-help")).CmpNoCase(argv[option])) { wxPrintf(/* i18n-hint: '-help', '-test' and '-blocksize' need to stay in English. */ _("Command-line options supported:\n" " -help (this message)\n" " -test (run self diagnostics)\n" " -blocksize ### (set max disk block size in bytes)\n" "\n" "In addition, specify the name of an audio file or " "Audacity project\n" "to open it.\n" "\n")); exit(0); } if (option < argc - 1 && argv[option + 1] && !wxString(wxT("-blocksize")).CmpNoCase(argv[option])) { long theBlockSize; if (wxString(argv[option + 1]).ToLong(&theBlockSize)) { if (theBlockSize >= 256 && theBlockSize < 100000000) { wxFprintf(stderr, _("Using block size of %ld\n"), theBlockSize); Sequence::SetMaxDiskBlockSize(theBlockSize); } } option++; handled = true; } if (!handled && !wxString(wxT("-test")).CmpNoCase(argv[option])) { RunBenchmark(NULL); exit(0); } if (argv[option][0] == wxT('-') && !handled) { wxPrintf(_("Unknown command line option: %s\n"), argv[option]); exit(0); } if(handled) fileToOpen.Clear(); if (!handled) fileToOpen = fileToOpen + wxT(" ") + argv[option]; if(wxString(argv[option]).Lower().Contains(wxT(".aup"))) openThisFile = true; if(openThisFile) { openThisFile = false; project->OpenFile(fileToOpen); } } // for option... } // if (argc>1) #endif // Cygwin command-line parser gInited = true; return TRUE; }
void setup_Rmainloop(void) { volatile int doneit; volatile SEXP baseEnv; SEXP cmd; char deferred_warnings[11][250]; volatile int ndeferred_warnings = 0; /* In case this is a silly limit: 2^32 -3 has been seen and * casting to intptr_r relies on this being smaller than 2^31 on a * 32-bit platform. */ if(R_CStackLimit > 100000000U) R_CStackLimit = (uintptr_t)-1; /* make sure we have enough head room to handle errors */ if(R_CStackLimit != -1) R_CStackLimit = (uintptr_t)(0.95 * R_CStackLimit); InitConnections(); /* needed to get any output at all */ /* Initialize the interpreter's internal structures. */ #ifdef HAVE_LOCALE_H #ifdef Win32 { char *p, Rlocale[1000]; /* Windows' locales can be very long */ p = getenv("LC_ALL"); strncpy(Rlocale, p ? p : "", 1000); Rlocale[1000 - 1] = '\0'; if(!(p = getenv("LC_CTYPE"))) p = Rlocale; /* We'd like to use warning, but need to defer. Also cannot translate. */ if(!setlocale(LC_CTYPE, p)) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_CTYPE=%s failed\n", p); if((p = getenv("LC_COLLATE"))) { if(!setlocale(LC_COLLATE, p)) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_COLLATE=%s failed\n", p); } else setlocale(LC_COLLATE, Rlocale); if((p = getenv("LC_TIME"))) { if(!setlocale(LC_TIME, p)) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_TIME=%s failed\n", p); } else setlocale(LC_TIME, Rlocale); if((p = getenv("LC_MONETARY"))) { if(!setlocale(LC_MONETARY, p)) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_MONETARY=%s failed\n", p); } else setlocale(LC_MONETARY, Rlocale); /* Windows does not have LC_MESSAGES */ /* We set R_ARCH here: Unix does it in the shell front-end */ char Rarch[30]; strcpy(Rarch, "R_ARCH=/"); strcat(Rarch, R_ARCH); putenv(Rarch); } #else /* not Win32 */ if(!setlocale(LC_CTYPE, "")) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_CTYPE failed, using \"C\"\n"); if(!setlocale(LC_COLLATE, "")) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_COLLATE failed, using \"C\"\n"); if(!setlocale(LC_TIME, "")) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_TIME failed, using \"C\"\n"); #ifdef ENABLE_NLS if(!setlocale(LC_MESSAGES, "")) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_MESSAGES failed, using \"C\"\n"); #endif /* NB: we do not set LC_NUMERIC */ #ifdef LC_MONETARY if(!setlocale(LC_MONETARY, "")) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_MONETARY failed, using \"C\"\n"); #endif #ifdef LC_PAPER if(!setlocale(LC_PAPER, "")) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_PAPER failed, using \"C\"\n"); #endif #ifdef LC_MEASUREMENT if(!setlocale(LC_MEASUREMENT, "")) snprintf(deferred_warnings[ndeferred_warnings++], 250, "Setting LC_MEASUREMENT failed, using \"C\"\n"); #endif #endif /* not Win32 */ #endif /* make sure srand is called before R_tmpnam, PR#14381 */ srand(TimeToSeed()); InitArithmetic(); InitParser(); InitTempDir(); /* must be before InitEd */ InitMemory(); InitStringHash(); /* must be before InitNames */ InitNames(); InitBaseEnv(); InitGlobalEnv(); InitDynload(); InitOptions(); InitEd(); InitGraphics(); InitTypeTables(); /* must be before InitS3DefaultTypes */ InitS3DefaultTypes(); R_Is_Running = 1; R_check_locale(); /* Initialize the global context for error handling. */ /* This provides a target for any non-local gotos */ /* which occur during error handling */ R_Toplevel.nextcontext = NULL; R_Toplevel.callflag = CTXT_TOPLEVEL; R_Toplevel.cstacktop = 0; R_Toplevel.promargs = R_NilValue; R_Toplevel.callfun = R_NilValue; R_Toplevel.call = R_NilValue; R_Toplevel.cloenv = R_BaseEnv; R_Toplevel.sysparent = R_BaseEnv; R_Toplevel.conexit = R_NilValue; R_Toplevel.vmax = NULL; R_Toplevel.nodestack = R_BCNodeStackTop; #ifdef BC_INT_STACK R_Toplevel.intstack = R_BCIntStackTop; #endif R_Toplevel.cend = NULL; R_Toplevel.intsusp = FALSE; R_Toplevel.handlerstack = R_HandlerStack; R_Toplevel.restartstack = R_RestartStack; R_Toplevel.srcref = R_NilValue; R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel; R_ExitContext = NULL; R_Warnings = R_NilValue; /* This is the same as R_BaseEnv, but this marks the environment of functions as the namespace and not the package. */ baseEnv = R_BaseNamespace; /* Set up some global variables */ Init_R_Variables(baseEnv); /* On initial entry we open the base language package and begin by running the repl on it. If there is an error we pass on to the repl. Perhaps it makes more sense to quit gracefully? */ #ifdef RMIN_ONLY /* This is intended to support a minimal build for experimentation. */ if (R_SignalHandlers) init_signal_handlers(); #else FILE *fp = R_OpenLibraryFile("base"); if (fp == NULL) R_Suicide(_("unable to open the base package\n")); doneit = 0; SETJMP(R_Toplevel.cjmpbuf); R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel; if (R_SignalHandlers) init_signal_handlers(); if (!doneit) { doneit = 1; R_ReplFile(fp, baseEnv); } fclose(fp); #endif /* This is where we source the system-wide, the site's and the user's profile (in that order). If there is an error, we drop through to further processing. */ R_IoBufferInit(&R_ConsoleIob); R_LoadProfile(R_OpenSysInitFile(), baseEnv); /* These are the same bindings, so only lock them once */ R_LockEnvironment(R_BaseNamespace, TRUE); #ifdef NOTYET /* methods package needs to trample here */ R_LockEnvironment(R_BaseEnv, TRUE); #endif /* At least temporarily unlock some bindings used in graphics */ R_unLockBinding(R_DeviceSymbol, R_BaseEnv); R_unLockBinding(R_DevicesSymbol, R_BaseEnv); R_unLockBinding(install(".Library.site"), R_BaseEnv); /* require(methods) if it is in the default packages */ doneit = 0; SETJMP(R_Toplevel.cjmpbuf); R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel; if (!doneit) { doneit = 1; PROTECT(cmd = install(".OptRequireMethods")); R_CurrentExpr = findVar(cmd, R_GlobalEnv); if (R_CurrentExpr != R_UnboundValue && TYPEOF(R_CurrentExpr) == CLOSXP) { PROTECT(R_CurrentExpr = lang1(cmd)); R_CurrentExpr = eval(R_CurrentExpr, R_GlobalEnv); UNPROTECT(1); } UNPROTECT(1); } if (strcmp(R_GUIType, "Tk") == 0) { char buf[PATH_MAX]; snprintf(buf, PATH_MAX, "%s/library/tcltk/exec/Tk-frontend.R", R_Home); R_LoadProfile(R_fopen(buf, "r"), R_GlobalEnv); } /* Print a platform and version dependent greeting and a pointer to * the copyleft. */ if(!R_Quiet) PrintGreeting(); R_LoadProfile(R_OpenSiteFile(), baseEnv); R_LockBinding(install(".Library.site"), R_BaseEnv); R_LoadProfile(R_OpenInitFile(), R_GlobalEnv); /* This is where we try to load a user's saved data. The right thing to do here is very platform dependent. E.g. under Unix we look in a special hidden file and on the Mac we look in any documents which might have been double clicked on or dropped on the application. */ doneit = 0; SETJMP(R_Toplevel.cjmpbuf); R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel; if (!doneit) { doneit = 1; R_InitialData(); } else { if (! SETJMP(R_Toplevel.cjmpbuf)) { warning(_("unable to restore saved data in %s\n"), get_workspace_name()); } } /* Initial Loading is done. At this point we try to invoke the .First Function. If there is an error we continue. */ doneit = 0; SETJMP(R_Toplevel.cjmpbuf); R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel; if (!doneit) { doneit = 1; PROTECT(cmd = install(".First")); R_CurrentExpr = findVar(cmd, R_GlobalEnv); if (R_CurrentExpr != R_UnboundValue && TYPEOF(R_CurrentExpr) == CLOSXP) { PROTECT(R_CurrentExpr = lang1(cmd)); R_CurrentExpr = eval(R_CurrentExpr, R_GlobalEnv); UNPROTECT(1); } UNPROTECT(1); } /* Try to invoke the .First.sys function, which loads the default packages. If there is an error we continue. */ doneit = 0; SETJMP(R_Toplevel.cjmpbuf); R_GlobalContext = R_ToplevelContext = R_SessionContext = &R_Toplevel; if (!doneit) { doneit = 1; PROTECT(cmd = install(".First.sys")); R_CurrentExpr = findVar(cmd, baseEnv); if (R_CurrentExpr != R_UnboundValue && TYPEOF(R_CurrentExpr) == CLOSXP) { PROTECT(R_CurrentExpr = lang1(cmd)); R_CurrentExpr = eval(R_CurrentExpr, R_GlobalEnv); UNPROTECT(1); } UNPROTECT(1); } { int i; for(i = 0 ; i < ndeferred_warnings; i++) warning(deferred_warnings[i]); } if (R_CollectWarnings) { REprintf(_("During startup - ")); PrintWarnings(); } /* trying to do this earlier seems to run into bootstrapping issues. */ R_init_jit_enabled(); R_Is_Running = 2; }
extern int main(int argc, char **argv) { GOptionContext *goctx; char *command; GLProtocol *ctx; setlocale(LC_CTYPE, "ja_JP.UTF-8"); AUTHURI = NULL; RPCURI = NULL; RESTURI = NULL; SESSIONID = NULL; RPCID = 0; USER = NULL; PASS = NULL; #ifdef USE_SSL CERTFILE = NULL; KEYFILE = NULL; KEYPASS = NULL; CAFILE = NULL; #endif goctx = g_option_context_new(""); g_option_context_add_main_entries(goctx, entries, NULL); g_option_context_parse(goctx, &argc, &argv, NULL); if (argc < 2) { PrintArgError(); exit(1); } command = argv[1]; InitTempDir(); ctx = InitProtocol(AUTHURI, USER, PASS); if (RPCURI != NULL) { GLP_SetRPCURI(ctx, RPCURI); } if (RESTURI != NULL) { GLP_SetRESTURI(ctx, RESTURI); } if (SESSIONID != NULL) { GLP_SetSessionID(ctx, SESSIONID); } if (RPCID != 0) { GLP_SetRPCID(ctx, RPCID); } #ifdef USE_SSL if (CERTFILE != NULL && KEYFILE != NULL && KEYPASS != NULL && CAFILE != NULL) { GLP_SetSSL(ctx, CERTFILE, KEYFILE, KEYPASS, CAFILE); } #endif if (!strcmp(command, "start_session")) { StartSession(ctx); } else if (!strcmp(command, "get_window")) { GetWindow(ctx); } else if (!strcmp(command, "send_event")) { if (argc < 3) { fprintf(stderr, "start_session need param.json\n"); exit(1); } SendEvent(ctx, argv[2]); } else if (!strcmp(command, "end_session")) { EndSession(ctx); } else if (!strcmp(command, "list_downloads")) { ListDownloads(ctx); } else if (!strcmp(command, "get_message")) { GetMessage(ctx); } else { PrintArgError(); exit(1); } FinalProtocol(ctx); return 0; }