mana.c

Go to the documentation of this file.
00001 /********************************************************************\
00002 
00003   Name:         mana.c
00004   Created by:   Stefan Ritt
00005 
00006   Contents:     The system part of the MIDAS analyzer. Has to be
00007                 linked with analyze.c to form a complete analyzer
00008 
00009   $Id: mana.c 4840 2010-09-27 22:45:45Z amaudruz $
00010 
00011 \********************************************************************/
00012 
00013 #include <assert.h>
00014 #include "midas.h"
00015 #include "msystem.h"
00016 #include "hardware.h"
00017 
00018 #include "mdsupport.h"
00019 
00020 #ifdef HAVE_ZLIB
00021 #include "zlib.h"
00022 #endif
00023 
00024 /*------------------------------------------------------------------*/
00025 
00026 /* cernlib includes */
00027 #ifdef OS_WINNT
00028 #define VISUAL_CPLUSPLUS
00029 #endif
00030 
00031 #ifdef OS_LINUX
00032 #define f2cFortran
00033 #endif
00034 
00035 #ifdef HAVE_HBOOK
00036 
00037 #include <cfortran.h>
00038 #include <hbook.h>
00039 
00040 /* missing in hbook.h */
00041 #ifndef HFNOV
00042 #define HFNOV(A1,A2)  CCALLSFSUB2(HFNOV,hfnov,INT,FLOATV,A1,A2)
00043 #endif
00044 
00045 #ifndef HMERGE
00046 #define HMERGE(A1,A2,A3)  CCALLSFSUB3(HMERGE,hmerge,INT,STRINGV,STRING,A1,A2,A3)
00047 #endif
00048 
00049 #endif                          /* HAVE_HBOOK */
00050 
00051 ANA_OUTPUT_INFO out_info;
00052 
00053 /*------------------------------------------------------------------*/
00054 
00055 #ifdef USE_ROOT
00056 
00057 #undef abs
00058 
00059 #include <assert.h>
00060 #include <TApplication.h>
00061 #include <TKey.h>
00062 #include <TROOT.h>
00063 #include <TH1.h>
00064 #include <TH2.h>
00065 #include <TFile.h>
00066 #include <TTree.h>
00067 #include <TLeaf.h>
00068 #include <TSocket.h>
00069 #include <TServerSocket.h>
00070 #include <TMessage.h>
00071 #include <TObjString.h>
00072 #include <TSystem.h>
00073 #include <TFolder.h>
00074 #include <TRint.h>
00075 #include <TCutG.h>
00076 
00077 #ifdef OS_LINUX
00078 #include <TThread.h>
00079 #endif
00080 
00081 /* Our own ROOT global objects */
00082 
00083 TApplication *manaApp;
00084 TFolder *gManaHistosFolder = NULL;      // Container for all histograms
00085 TFile *gManaOutputFile = NULL;  // MIDAS output file
00086 TObjArray *gHistoFolderStack = NULL;    //
00087 
00088 /* MIDAS output tree structure holing one tree per event type */
00089 
00090 typedef struct {
00091    int event_id;
00092    TTree *tree;
00093    int n_branch;
00094    char *branch_name;
00095    int *branch_filled;
00096    int *branch_len;
00097    TBranch **branch;
00098 } EVENT_TREE;
00099 
00100 typedef struct {
00101    TFile *f;
00102    int n_tree;
00103    EVENT_TREE *event_tree;
00104 } TREE_STRUCT;
00105 
00106 TREE_STRUCT tree_struct;
00107 
00108 #endif                          /* USE_ROOT */
00109 
00110 /*------------------------------------------------------------------*/
00111 
00112 /* PVM include */
00113 
00114 #ifdef HAVE_PVM
00115 
00116 INT pvm_start_time = 0;
00117 
00118 extern BOOL disable_shm_write;
00119 
00120 void pvm_debug(char *format, ...)
00121 {
00122    va_list argptr;
00123    char msg[256], str[256];
00124 
00125    if (pvm_start_time == 0)
00126       pvm_start_time = ss_millitime();
00127 
00128    va_start(argptr, format);
00129    vsprintf(msg, (char *) format, argptr);
00130    va_end(argptr);
00131    sprintf(str, "%1.3lf:  %s", (ss_millitime() - pvm_start_time) / 1000.0, msg);
00132    puts(str);
00133 #ifdef OS_LINUX
00134    {
00135       char cmd[256];
00136 
00137       sprintf(cmd, "echo > /dev/console \"%s\"", str);
00138       system(cmd);
00139    }
00140 #endif
00141 }
00142 
00143 #undef STRICT
00144 #include <pvm3.h>
00145 #endif
00146 
00147 /*----- PVM TAGS and data ------------------------------------------*/
00148 
00149 /* buffer size must be larger than largest event (ODB dump!) */
00150 #define PVM_BUFFER_SIZE (1024*1024)
00151 
00152 #ifdef HAVE_PVM
00153 #define TAG_DATA  1
00154 #define TAG_BOR   2
00155 #define TAG_EOR   3
00156 #define TAG_EXIT  4
00157 #define TAG_INIT  5
00158 
00159 int pvm_n_task;
00160 int pvm_myparent;
00161 int pvm_client_index;
00162 
00163 typedef struct {
00164    int tid;
00165    char host[80];
00166    char *buffer;
00167    int wp;
00168    DWORD n_events;
00169    DWORD time;
00170    BOOL eor_sent;
00171 } PVM_CLIENT;
00172 
00173 PVM_CLIENT *pvmc;
00174 
00175 int pvm_eor(int);
00176 int pvm_merge(void);
00177 void pvm_debug(char *format, ...);
00178 int pvm_distribute(ANALYZE_REQUEST * par, EVENT_HEADER * pevent);
00179 
00180 //#define PVM_DEBUG pvm_debug
00181 #define PVM_DEBUG
00182 
00183 #endif                          /* PVM */
00184 
00185 BOOL pvm_master = FALSE, pvm_slave = FALSE;
00186 
00187 char *bstr = " ";
00188 
00189 /*------------------------------------------------------------------*/
00190 
00191 /* items defined in analyzer.c */
00192 extern char *analyzer_name;
00193 extern INT analyzer_loop_period;
00194 extern INT analyzer_init(void);
00195 extern INT analyzer_exit(void);
00196 extern INT analyzer_loop(void);
00197 extern INT ana_begin_of_run(INT run_number, char *error);
00198 extern INT ana_end_of_run(INT run_number, char *error);
00199 extern INT ana_pause_run(INT run_number, char *error);
00200 extern INT ana_resume_run(INT run_number, char *error);
00201 extern INT odb_size;
00202 
00203 /*---- globals -----------------------------------------------------*/
00204 
00205 /* ODB handle */
00206 HNDLE hDB;
00207 
00208 /* run number */
00209 DWORD current_run_number;
00210 
00211 /* analyze_request defined in analyze.c or anasys.c */
00212 extern ANALYZE_REQUEST analyze_request[];
00213 
00214 /* N-tupel booking and filling flag */
00215 BOOL ntuple_flag;
00216 
00217 /* list of locked histos (won't get cleared) */
00218 INT lock_list[10000];
00219 
00220 #ifdef extname
00221 int quest_[100];
00222 #else
00223 extern int QUEST[100];
00224 #endif
00225 
00226 extern INT pawc_size;
00227 
00228 /* default HBOOK record size */
00229 #define HBOOK_LREC 8190
00230 
00231 /* maximum extended event size */
00232 #ifndef EXT_EVENT_SIZE
00233 #define EXT_EVENT_SIZE (2*(MAX_EVENT_SIZE+sizeof(EVENT_HEADER)))
00234 #endif
00235 
00236 /* command line parameters */
00237 static struct {
00238    INT online;
00239    char host_name[HOST_NAME_LENGTH];
00240    char exp_name[NAME_LENGTH];
00241    char input_file_name[10][256];
00242    char output_file_name[256];
00243    INT run_number[2];
00244    DWORD n[4];
00245    BOOL filter;
00246    char config_file_name[10][256];
00247    char param[10][256];
00248    char protect[10][256];
00249    BOOL rwnt;
00250    INT lrec;
00251    BOOL debug;
00252    BOOL verbose;
00253    BOOL quiet;
00254    BOOL no_load;
00255    BOOL daemon;
00256    INT n_task;
00257    INT pvm_buf_size;
00258    INT root_port;
00259    BOOL start_rint;
00260 } clp;
00261 
00262 static struct {
00263    char flag_char;
00264    char description[1000];
00265    void *data;
00266    INT type;
00267    INT n;
00268    INT index;
00269 } clp_descrip[] = {
00270 
00271    {
00272    'c', "<filename1>   Configuration file name(s). May contain a '%05d' to be\n\
00273      <filename2>   replaced by the run number. Up to ten files can be\n\
00274          ...       specified in one \"-c\" statement", clp.config_file_name, TID_STRING, 10}, {
00275    'd', "              Debug flag when started the analyzer fron a debugger.\n\
00276                    Prevents the system to kill the analyzer when the\n\
00277                    debugger stops at a breakpoint", &clp.debug, TID_BOOL, 0}, {
00278    'D', "              Start analyzer as a daemon in the background (UNIX only).",
00279           &clp.daemon, TID_BOOL, 0}, {
00280    'e', "<experiment>  MIDAS experiment to connect to", clp.exp_name, TID_STRING, 1}, {
00281    'f', "              Filter mode. Write original events to output file\n\
00282                    only if analyzer accepts them (doesn't return ANA_SKIP).\n", &clp.filter, TID_BOOL, 0}, {
00283    'h', "<hostname>    MIDAS host to connect to when running the analyzer online",
00284           clp.host_name, TID_STRING, 1}, {
00285    'i', "<filename1>   Input file name. May contain a '%05d' to be replaced by\n\
00286      <filename2>   the run number. Up to ten input files can be specified\n\
00287          ...       in one \"-i\" statement", clp.input_file_name, TID_STRING, 10}, {
00288    'l', "              If set, don't load histos from last histo file when\n\
00289                    running online.", &clp.no_load, TID_BOOL, 0}, {
00290    'L', "              HBOOK LREC size. Default is 8190.", &clp.lrec, TID_INT, 0}, {
00291    'n', "<count>       Analyze only \"count\" events.\n\
00292      <first> <last>\n\
00293                    Analyze only events from \"first\" to \"last\".\n\
00294      <first> <last> <n>\n\
00295                    Analyze every n-th event from \"first\" to \"last\".", clp.n, TID_INT, 4}, {
00296    'o', "<filename>    Output file name. Extension may be .mid (MIDAS binary),\n\
00297                    .asc (ASCII) or .rz (HBOOK). If the name contains a '%05d',\n\
00298                    one output file is generated for each run. Use \"OFLN\" as\n\
00299                    output file name to creaate a HBOOK shared memory instead\n\
00300                    of a file.", clp.output_file_name, TID_STRING, 1}, {
00301    'p', "<param=value> Set individual parameters to a specific value.\n\
00302                    Overrides any setting in configuration files", clp.param, TID_STRING, 10}, {
00303    'P', "<ODB tree>    Protect an ODB subtree from being overwritten\n\
00304                    with the online data when ODB gets loaded from .mid file", clp.protect, TID_STRING, 10}, {
00305    'q', "              Quiet flag. If set, don't display run progress in\n\
00306                    offline mode.", &clp.quiet, TID_BOOL, 0}, {
00307    'r', "<range>       Range of run numbers to analyzer like \"-r 120 125\"\n\
00308                    to analyze runs 120 to 125 (inclusive). The \"-r\"\n\
00309                    flag must be used with a '%05d' in the input file name.", clp.run_number, TID_INT, 2},
00310 #ifdef HAVE_PVM
00311    {
00312    't', "<n>           Parallelize analyzer using <n> tasks with PVM.", &clp.n_task,
00313           TID_INT, 1}, {
00314    'b', "<n>           Buffer size for parallelization in kB.", &clp.pvm_buf_size,
00315           TID_INT, 1},
00316 #endif
00317 #ifdef USE_ROOT
00318    {
00319    's', "<port>        Start ROOT histo server under <port>. If port==0, don't start server.", &clp.root_port, TID_INT, 1}, {
00320    'R', "              Start ROOT interpreter after analysis has finished.",
00321           &clp.start_rint, TID_BOOL, 0},
00322 #endif
00323    {
00324    'v', "              Verbose output.", &clp.verbose, TID_BOOL, 0}, {
00325    'w', "              Produce row-wise N-tuples in outpur .rz file. By\n\
00326                    default, column-wise N-tuples are used.", &clp.rwnt, TID_BOOL, 0}, {
00327    0}
00328 };
00329 
00330 FILE *out_file;
00331 #ifdef HAVE_ZLIB
00332 BOOL out_gzip;
00333 #endif
00334 INT out_format;
00335 BOOL out_append;
00336 
00337 void update_stats();
00338 void odb_load(EVENT_HEADER * pevent);
00339 
00340 /*---- ODB records -------------------------------------------------*/
00341 
00342 #define ANALYZER_REQUEST_STR "\
00343 Event ID = INT : 0\n\
00344 Trigger mask = INT : -1\n\
00345 Sampling type = INT : 1\n\
00346 Buffer = STRING : [32] SYSTEM\n\
00347 Enabled = BOOL : 1\n\
00348 Client name = STRING : [32] \n\
00349 Host = STRING : [32] \n\
00350 "
00351 
00352 #define ANALYZER_STATS_STR "\
00353 Events received = DOUBLE : 0\n\
00354 Events per sec. = DOUBLE : 0\n\
00355 Events written = DOUBLE : 0\n\
00356 "
00357 
00358 /*-- interprete command line parameters ----------------------------*/
00359 
00360 INT getparam(int argc, char **argv)
00361 {
00362    INT index, i, j, size;
00363 
00364    /* parse command line parameters */
00365    for (index = 1; index < argc;) {
00366       /* search flag in parameter description */
00367       if (argv[index][0] == '-') {
00368          for (j = 0; clp_descrip[j].flag_char; j++)
00369             if (argv[index][1] == clp_descrip[j].flag_char)
00370                break;
00371 
00372          if (!clp_descrip[j].flag_char)
00373             goto usage;
00374 
00375          if (clp_descrip[j].n > 0 && index >= argc - 1)
00376             goto usage;
00377          index++;
00378 
00379          if (clp_descrip[j].type == TID_BOOL) {
00380             *((BOOL *) clp_descrip[j].data) = TRUE;
00381             continue;
00382          }
00383 
00384          do {
00385             if (clp_descrip[j].type == TID_STRING)
00386                strcpy((char *) clp_descrip[j].data + clp_descrip[j].index * 256,
00387                       argv[index]);
00388             else
00389                db_sscanf(argv[index], clp_descrip[j].data, &size, clp_descrip[j].index,
00390                          clp_descrip[j].type);
00391 
00392             if (clp_descrip[j].n > 1)
00393                clp_descrip[j].index++;
00394 
00395             if (clp_descrip[j].index > clp_descrip[j].n) {
00396                printf("Note more than %d options possible for flag -%c\n",
00397                       clp_descrip[j].n, clp_descrip[j].flag_char);
00398                return 0;
00399             }
00400 
00401             index++;
00402 
00403          } while (index < argc && argv[index][0] != '-');
00404 
00405       } else
00406          goto usage;
00407    }
00408 
00409    return SUCCESS;
00410 
00411  usage:
00412 
00413    printf("usage: analyzer [options]\n\n");
00414    printf("valid options are:\n");
00415    for (i = 0; clp_descrip[i].flag_char; i++)
00416       printf("  -%c %s\n", clp_descrip[i].flag_char, clp_descrip[i].description);
00417 
00418    return 0;
00419 }
00420 
00421 /*-- add </logger/data dir> before filename ------------------------*/
00422 
00423 void add_data_dir(char *result, char *file)
00424 {
00425    HNDLE hDB, hkey;
00426    char str[256];
00427    int size;
00428 
00429    cm_get_experiment_database(&hDB, NULL);
00430    db_find_key(hDB, 0, "/Logger/Data dir", &hkey);
00431 
00432    if (hkey) {
00433       size = sizeof(str);
00434       db_get_data(hDB, hkey, str, &size, TID_STRING);
00435       if (str[strlen(str) - 1] != DIR_SEPARATOR)
00436          strcat(str, DIR_SEPARATOR_STR);
00437       strcat(str, file);
00438       strcpy(result, str);
00439    } else
00440       strcpy(result, file);
00441 }
00442 
00443 /*-- db_get_event_definition ---------------------------------------*/
00444 
00445 typedef struct {
00446    short int event_id;
00447    int type;
00448    WORD format;
00449    HNDLE hDefKey;
00450    BOOL disabled;
00451 } EVENT_DEF;
00452 
00453 EVENT_DEF *db_get_event_definition(short int event_id)
00454 {
00455    INT i, index, status, size, type;
00456    char str[80];
00457    HNDLE hKey, hKeyRoot;
00458    WORD id;
00459    static EVENT_DEF *event_def = NULL;
00460    static int n_cache = 0;
00461 
00462    /* search free cache entry */
00463    for (index = 0; index < n_cache; index++)
00464       if (event_def[index].event_id == event_id)
00465          return &event_def[index];
00466 
00467    /* If we get here, we have an undefined ID;
00468       allocate memory for it, zero it, then cache the ODB data */
00469    n_cache = index + 1;
00470 
00471    event_def = (EVENT_DEF *) realloc(event_def, (n_cache) * sizeof(EVENT_DEF));
00472    assert(event_def);
00473 
00474    memset(&event_def[index], 0, sizeof(EVENT_DEF));
00475 
00476    /* check for system events */
00477    if (event_id < 0) {
00478       event_def[index].event_id = event_id;
00479       event_def[index].format = FORMAT_ASCII;
00480       event_def[index].hDefKey = 0;
00481       event_def[index].disabled = FALSE;
00482       return &event_def[index];
00483    }
00484 
00485    status = db_find_key(hDB, 0, "/equipment", &hKeyRoot);
00486    if (status != DB_SUCCESS) {
00487       cm_msg(MERROR, "db_get_event_definition", "cannot find /equipment entry in ODB");
00488       return NULL;
00489    }
00490 
00491    for (i = 0;; i++) {
00492       /* search for equipment with specific name */
00493       status = db_enum_key(hDB, hKeyRoot, i, &hKey);
00494       if (status == DB_NO_MORE_SUBKEYS) {
00495          sprintf(str, "Cannot find event id %d under /equipment", event_id);
00496          cm_msg(MERROR, "db_get_event_definition", str);
00497          return NULL;
00498       }
00499 
00500       size = sizeof(id);
00501       status = db_get_value(hDB, hKey, "Common/Event ID", &id, &size, TID_WORD, TRUE);
00502       if (status != DB_SUCCESS)
00503          continue;
00504 
00505       size = sizeof(type);
00506       status = db_get_value(hDB, hKey, "Common/Type", &type, &size, TID_INT, TRUE);
00507       if (status != DB_SUCCESS)
00508          continue;
00509 
00510       if (id == event_id) {
00511          /* set cache entry */
00512          event_def[index].event_id = id;
00513          event_def[index].type = type;
00514 
00515          size = sizeof(str);
00516          str[0] = 0;
00517          db_get_value(hDB, hKey, "Common/Format", str, &size, TID_STRING, TRUE);
00518 
00519          if (equal_ustring(str, "Fixed"))
00520             event_def[index].format = FORMAT_FIXED;
00521          else if (equal_ustring(str, "ASCII"))
00522             event_def[index].format = FORMAT_ASCII;
00523          else if (equal_ustring(str, "MIDAS"))
00524             event_def[index].format = FORMAT_MIDAS;
00525          else if (equal_ustring(str, "YBOS"))
00526             event_def[index].format = FORMAT_YBOS;
00527          else if (equal_ustring(str, "DUMP"))
00528             event_def[index].format = FORMAT_DUMP;
00529          else {
00530             cm_msg(MERROR, "db_get_event_definition", "unknown data format");
00531             event_def[index].event_id = 0;
00532             return NULL;
00533          }
00534 
00535          db_find_key(hDB, hKey, "Variables", &event_def[index].hDefKey);
00536          return &event_def[index];
00537       }
00538    }
00539 }
00540 
00541 /*-- functions for internal tests ----------------------------------*/
00542 
00543 ANA_TEST **tl;
00544 int n_test = 0;
00545 
00546 void test_register(ANA_TEST * t)
00547 {
00548    int i;
00549 
00550    /* check if test already registered */
00551    for (i = 0; i < n_test; i++)
00552       if (tl[i] == t)
00553          break;
00554    if (i < n_test) {
00555       t->registered = TRUE;
00556       return;
00557    }
00558 
00559    /* allocate space for pointer to test */
00560    if (n_test == 0) {
00561       tl = (ANA_TEST **) malloc(2 * sizeof(void *));
00562 
00563       /* define "always true" test */
00564       tl[0] = (ANA_TEST *) malloc(sizeof(ANA_TEST));
00565       strcpy(tl[0]->name, "Always true");
00566       tl[0]->count = 0;
00567       tl[0]->previous_count = 0;
00568       tl[0]->value = TRUE;
00569       tl[0]->registered = TRUE;
00570       n_test++;
00571    } else
00572       tl = (ANA_TEST **) realloc(tl, (n_test + 1) * sizeof(void *));
00573 
00574    tl[n_test] = t;
00575    t->count = 0;
00576    t->value = FALSE;
00577    t->registered = TRUE;
00578 
00579    n_test++;
00580 }
00581 
00582 void test_clear()
00583 {
00584    int i;
00585 
00586    /* clear all tests in interal list */
00587    for (i = 0; i < n_test; i++) {
00588       tl[i]->count = 0;
00589       tl[i]->value = FALSE;
00590    }
00591 
00592    /* set "always true" test */
00593    if (n_test > 0)
00594       tl[0]->value = TRUE;
00595 }
00596 
00597 void test_increment()
00598 {
00599    int i;
00600 
00601    /* increment test counters based on their value and reset them */
00602    for (i = 0; i < n_test; i++) {
00603       if (tl[i]->value)
00604          tl[i]->count++;
00605       if (i > 0)
00606          tl[i]->value = FALSE;
00607    }
00608 }
00609 
00610 void test_write(int delta_time)
00611 {
00612    int i;
00613    char str[256];
00614    float rate;
00615 
00616    /* write all test counts to /analyzer/tests/<name> */
00617    for (i = 0; i < n_test; i++) {
00618       sprintf(str, "/%s/Tests/%s/Count", analyzer_name, tl[i]->name);
00619       db_set_value(hDB, 0, str, &tl[i]->count, sizeof(DWORD), 1, TID_DWORD);
00620 
00621       /* calcluate rate */
00622       if (delta_time > 0) {
00623          rate = (float) ((tl[i]->count - tl[i]->previous_count) / (delta_time / 1000.0));
00624          tl[i]->previous_count = tl[i]->count;
00625          sprintf(str, "/%s/Tests/%s/Rate [Hz]", analyzer_name, tl[i]->name);
00626          db_set_value(hDB, 0, str, &rate, sizeof(float), 1, TID_FLOAT);
00627       }
00628    }
00629 }
00630 
00631 /*-- load parameters specified on command line ---------------------*/
00632 
00633 INT load_parameters(INT run_number)
00634 {
00635    INT i, size, index, status;
00636    HNDLE hkey;
00637    char file_name[256], str[80], value_string[80], param_string[80];
00638    char data[32];
00639    KEY key;
00640 
00641    /* loop over configutation file names */
00642    for (i = 0; clp.config_file_name[i][0] && i < 10; i++) {
00643       if (strchr(clp.config_file_name[i], '%') != NULL)
00644          sprintf(file_name, clp.config_file_name[i], run_number);
00645       else
00646          strcpy(file_name, clp.config_file_name[i]);
00647 
00648       /* load file under "/" */
00649       if (db_load(hDB, 0, file_name, FALSE) == DB_SUCCESS)
00650          printf("Configuration file \"%s\" loaded\n", file_name);
00651    }
00652 
00653    /* loop over parameters */
00654    for (i = 0; clp.param[i][0] && i < 10; i++) {
00655       if (strchr(clp.param[i], '=') == NULL) {
00656          printf("Error: parameter %s contains no value\n", clp.param[i]);
00657       } else {
00658          strcpy(value_string, strchr(clp.param[i], '=') + 1);
00659          strcpy(param_string, clp.param[i]);
00660          *strchr(param_string, '=') = 0;
00661 
00662          index = 0;
00663          if (strchr(param_string, '[') != NULL) {
00664             index = atoi(strchr(param_string, '[') + 1);
00665             *strchr(param_string, '[') = 0;
00666          }
00667 
00668          if (param_string[0] == '/')
00669             strcpy(str, param_string);
00670          else
00671             sprintf(str, "/%s/Parameters/%s", analyzer_name, param_string);
00672          db_find_key(hDB, 0, str, &hkey);
00673          if (hkey == 0) {
00674             printf("Error: cannot find parameter %s in ODB\n", str);
00675          } else {
00676             db_get_key(hDB, hkey, &key);
00677             db_sscanf(value_string, data, &size, 0, key.type);
00678 
00679             status = db_set_data_index(hDB, hkey, data, size, index, key.type);
00680             if (status == DB_SUCCESS)
00681                printf("Parameter %s changed to %s\n", str, value_string);
00682             else
00683                printf("Cannot change parameter %s\n", str);
00684          }
00685       }
00686    }
00687 
00688    /* let parameter changes propagate to modules */
00689    cm_yield(0);
00690 
00691    return SUCCESS;
00692 }
00693 
00694 /*-- book N-tuples from ODB bank structures ------------------------*/
00695 
00696 char hbook_types[][8] = {
00697    "",
00698    ":U:8",                      /* TID_BYTE      */
00699    ":I:8",                      /* TID_SBYTE     */
00700    ":I:8",                      /* TID_CHAR      */
00701    ":U:16",                     /* TID_WORD      */
00702    ":I:16",                     /* TID_SHORT     */
00703    ":U*4",                      /* TID_DWORD     */
00704    ":I*4",                      /* TID_INT       */
00705    ":I*4",                      /* TID_BOOL      */
00706    ":R*4",                      /* TID_FLOAT     */
00707    ":R*8",                      /* TID_DOUBLE    */
00708    ":U:8",                      /* TID_BITFIELD  */
00709    ":C:32",                     /* TID_STRING    */
00710    "",                          /* TID_ARRAY     */
00711    "",                          /* TID_STRUCT    */
00712    "",                          /* TID_KEY       */
00713    "",                          /* TID_LINK      */
00714    "",                          /* TID_LAST      */
00715 
00716 };
00717 
00718 INT book_ntuples(void);
00719 INT book_ttree(void);
00720 
00721 void banks_changed(INT hDB, INT hKey, void *info)
00722 {
00723    char str[80];
00724    HNDLE hkey;
00725 
00726    /* close previously opened hot link */
00727    sprintf(str, "/%s/Bank switches", analyzer_name);
00728    db_find_key(hDB, 0, str, &hkey);
00729    db_close_record(hDB, hkey);
00730 
00731 #ifdef HAVE_HBOOK
00732    book_ntuples();
00733    printf("N-tuples rebooked\n");
00734 #endif
00735 #ifdef USE_ROOT
00736    book_ttree();
00737    printf("ROOT TTree rebooked\n");
00738 #endif
00739 }
00740 
00741 #ifdef HAVE_HBOOK
00742 INT book_ntuples(void)
00743 {
00744    INT index, i, j, status, n_tag, size, id;
00745    HNDLE hkey;
00746    KEY key;
00747    int *t;
00748    char ch_tags[2000];
00749    char rw_tag[512][8];
00750    char str[80], str2[80], key_name[NAME_LENGTH], block_name[NAME_LENGTH];
00751    BANK_LIST *bank_list;
00752    EVENT_DEF *event_def;
00753 
00754    /* check global N-tuple flag */
00755    ntuple_flag = 1;
00756    size = sizeof(ntuple_flag);
00757    sprintf(str, "/%s/Book N-tuples", analyzer_name);
00758    db_get_value(hDB, 0, str, &ntuple_flag, &size, TID_BOOL, TRUE);
00759 
00760    if (!ntuple_flag)
00761       return SUCCESS;
00762 
00763    /* copy output flag from ODB to bank_list */
00764    for (i = 0; analyze_request[i].event_name[0]; i++) {
00765       bank_list = analyze_request[i].bank_list;
00766 
00767       if (bank_list != NULL)
00768          for (; bank_list->name[0]; bank_list++) {
00769             sprintf(str, "/%s/Bank switches/%s", analyzer_name, bank_list->name);
00770             bank_list->output_flag = FALSE;
00771             size = sizeof(DWORD);
00772             db_get_value(hDB, 0, str, &bank_list->output_flag, &size, TID_DWORD, TRUE);
00773          }
00774    }
00775 
00776    /* hot link bank switches to N-tuple re-booking */
00777    sprintf(str, "/%s/Bank switches", analyzer_name);
00778    status = db_find_key(hDB, 0, str, &hkey);
00779    if (status != DB_SUCCESS) {
00780       cm_msg(MERROR, "book_ntuples", "Cannot find key \'%s\', status %d", str, status);
00781       return SUCCESS;
00782    }
00783 
00784    db_open_record(hDB, hkey, NULL, 0, MODE_READ, banks_changed, NULL);
00785 
00786    if (!clp.rwnt) {
00787       /* book CW N-tuples */
00788 
00789       /* go through all analyzer requests (events) */
00790       for (index = 0; analyze_request[index].event_name[0]; index++) {
00791          /* book N-tuple with evend ID */
00792          HBNT(analyze_request[index].ar_info.event_id, analyze_request[index].event_name,
00793               bstr);
00794 
00795          /* book run number/event number/time */
00796          strcpy(str, "Number");
00797          strcpy(str2, "Run:U*4,Number:U*4,Time:U*4");
00798          t = (int *) (&analyze_request[index].number.run);
00799          HBNAME(analyze_request[index].ar_info.event_id, str, t, str2);
00800 
00801          bank_list = analyze_request[index].bank_list;
00802          if (bank_list == NULL) {
00803             /* book fixed event */
00804             event_def =
00805                 db_get_event_definition((short int) analyze_request[index].ar_info.
00806                                         event_id);
00807             if (event_def == NULL) {
00808                cm_msg(MERROR, "book_ntuples", "Cannot find definition of event %s in ODB",
00809                       analyze_request[index].event_name);
00810                return 0;
00811             }
00812 
00813             ch_tags[0] = 0;
00814             for (i = 0;; i++) {
00815                status = db_enum_key(hDB, event_def->hDefKey, i, &hkey);
00816                if (status == DB_NO_MORE_SUBKEYS)
00817                   break;
00818 
00819                db_get_key(hDB, hkey, &key);
00820 
00821                /* convert blanks etc to '_' */
00822                strcpy(str, key.name);
00823                for (j = 0; str[j]; j++) {
00824                   if (!(str[j] >= 'a' && str[j] <= 'z') &&
00825                       !(str[j] >= 'A' && str[j] <= 'Z') && !(str[j] >= '0'
00826                                                              && str[j] <= '9'))
00827                      str[j] = '_';
00828                }
00829                strcat(ch_tags, str);
00830                str[0] = 0;
00831 
00832                if (key.num_values > 1)
00833                   sprintf(str, "(%d)", key.num_values);
00834 
00835                if (hbook_types[key.type] != NULL)
00836                   strcat(str, hbook_types[key.type]);
00837                else {
00838                   cm_msg(MERROR, "book_ntuples",
00839                          "Key %s in event %s is of type %s with no HBOOK correspondence",
00840                          key.name, analyze_request[index].event_name,
00841                          rpc_tid_name(key.type));
00842                   return 0;
00843                }
00844                strcat(ch_tags, str);
00845                strcat(ch_tags, ",");
00846             }
00847 
00848             ch_tags[strlen(ch_tags) - 1] = 0;
00849             db_get_record_size(hDB, event_def->hDefKey, 0, &size);
00850             analyze_request[index].addr = calloc(1, size);
00851 
00852             strcpy(block_name, analyze_request[index].event_name);
00853             block_name[8] = 0;
00854 
00855             HBNAME(analyze_request[index].ar_info.event_id, block_name,
00856                    analyze_request[index].addr, ch_tags);
00857          } else {
00858             /* go thorough all banks in bank_list */
00859             for (; bank_list->name[0]; bank_list++) {
00860                if (bank_list->output_flag == 0)
00861                   continue;
00862 
00863                if (bank_list->type != TID_STRUCT) {
00864                   sprintf(str, "N%s[0,%d]", bank_list->name, bank_list->size);
00865                   INT *t = (INT *) & bank_list->n_data;
00866                   HBNAME(analyze_request[index].ar_info.event_id,
00867                          bank_list->name, t, str);
00868 
00869                   sprintf(str, "%s(N%s)", bank_list->name, bank_list->name);
00870 
00871                   /* define variable length array */
00872                   if (hbook_types[bank_list->type] != NULL)
00873                      strcat(str, hbook_types[bank_list->type]);
00874                   else {
00875                      cm_msg(MERROR, "book_ntuples",
00876                             "Bank %s is of type %s with no HBOOK correspondence",
00877                             bank_list->name, rpc_tid_name(bank_list->type));
00878                      return 0;
00879                   }
00880 
00881                   if (rpc_tid_size(bank_list->type) == 0) {
00882                      cm_msg(MERROR, "book_ntuples",
00883                             "Bank %s is of type with unknown size", bank_list->name);
00884                      return 0;
00885                   }
00886 
00887                   bank_list->addr =
00888                       calloc(bank_list->size, MAX(4, rpc_tid_size(bank_list->type)));
00889 
00890                   HBNAME(analyze_request[index].ar_info.event_id, bank_list->name,
00891                          bank_list->addr, str);
00892                } else {
00893                   /* define structured bank */
00894                   ch_tags[0] = 0;
00895                   for (i = 0;; i++) {
00896                      status = db_enum_key(hDB, bank_list->def_key, i, &hkey);
00897                      if (status == DB_NO_MORE_SUBKEYS)
00898                         break;
00899 
00900                      db_get_key(hDB, hkey, &key);
00901 
00902                      /* convert blanks etc to '_' */
00903                      strcpy(str, key.name);
00904                      for (j = 0; str[j]; j++) {
00905                         if (!(str[j] >= 'a' && str[j] <= 'z') &&
00906                             !(str[j] >= 'A' && str[j] <= 'Z') && !(str[j] >= '0'
00907                                                                    && str[j] <= '9'))
00908                            str[j] = '_';
00909                      }
00910                      strcat(ch_tags, str);
00911                      str[0] = 0;
00912 
00913                      if (key.num_values > 1)
00914                         sprintf(str, "(%d)", key.num_values);
00915 
00916                      if (hbook_types[key.type] != NULL)
00917                         strcat(str, hbook_types[key.type]);
00918                      else {
00919                         cm_msg(MERROR, "book_ntuples",
00920                                "Key %s in bank %s is of type %s with no HBOOK correspondence",
00921                                key.name, bank_list->name, rpc_tid_name(key.type));
00922                         return 0;
00923                      }
00924                      strcat(ch_tags, str);
00925                      strcat(ch_tags, ",");
00926                   }
00927 
00928                   ch_tags[strlen(ch_tags) - 1] = 0;
00929                   bank_list->addr = calloc(1, bank_list->size);
00930 
00931                   HBNAME(analyze_request[index].ar_info.event_id, bank_list->name,
00932                          bank_list->addr, ch_tags);
00933                }
00934             }
00935          }
00936 
00937          /* HPRNT(analyze_request[index].ar_info.event_id); */
00938       }
00939    } else {
00940       /* book RW N-tuples */
00941 
00942       /* go through all analyzer requests (events) */
00943       for (index = 0; analyze_request[index].event_name[0]; index++) {
00944          /* get pointer to event definition */
00945          event_def =
00946              db_get_event_definition((short int) analyze_request[index].ar_info.event_id);
00947 
00948          /* skip if not found */
00949          if (!event_def)
00950             continue;
00951 
00952          /* don't book NT if not requested */
00953          if (analyze_request[index].rwnt_buffer_size == 0) {
00954             event_def->disabled = TRUE;
00955             continue;
00956          }
00957 
00958          n_tag = 0;
00959 
00960          strcpy(rw_tag[n_tag++], "Run");
00961          strcpy(rw_tag[n_tag++], "Number");
00962          strcpy(rw_tag[n_tag++], "Time");
00963 
00964          if (clp.verbose) {
00965             printf("NT #%d-1: Run\n", analyze_request[index].ar_info.event_id);
00966             printf("NT #%d-2: Number\n", analyze_request[index].ar_info.event_id);
00967             printf("NT #%d-3: Time\n", analyze_request[index].ar_info.event_id);
00968          }
00969 
00970          bank_list = analyze_request[index].bank_list;
00971          if (bank_list == NULL) {
00972             /* book fixed event */
00973 
00974             for (i = 0;; i++) {
00975                status = db_enum_key(hDB, event_def->hDefKey, i, &hkey);
00976                if (status == DB_NO_MORE_SUBKEYS)
00977                   break;
00978 
00979                db_get_key(hDB, hkey, &key);
00980 
00981                /* convert blanks etc to '_' */
00982                strcpy(key_name, key.name);
00983                for (j = 0; key_name[j]; j++) {
00984                   if (!(key_name[j] >= 'a' && key_name[j] <= 'z') &&
00985                       !(key_name[j] >= 'A' && key_name[j] <= 'Z') &&
00986                       !(key_name[j] >= '0' && key_name[j] <= '9'))
00987                      key_name[j] = '_';
00988                }
00989 
00990                if (key.num_values > 1)
00991                   for (j = 0; j < key.num_values; j++) {
00992                      sprintf(str, "%s%d", key_name, j);
00993                      strncpy(rw_tag[n_tag++], str, 8);
00994 
00995                      if (clp.verbose)
00996                         printf("NT #%d-%d: %s\n", analyze_request[index].ar_info.event_id,
00997                                n_tag + 1, str);
00998 
00999                      if (n_tag >= 512) {
01000                         cm_msg(MERROR, "book_ntuples",
01001                                "Too much tags for RW N-tupeles (512 maximum)");
01002                         return 0;
01003                      }
01004                } else {
01005                   strncpy(rw_tag[n_tag++], key_name, 8);
01006 
01007                   if (clp.verbose)
01008                      printf("NT #%d-%d: %s\n", analyze_request[index].ar_info.event_id,
01009                             n_tag, key_name);
01010                }
01011 
01012                if (n_tag >= 512) {
01013                   cm_msg(MERROR, "book_ntuples",
01014                          "Too much tags for RW N-tupeles (512 maximum)");
01015                   return 0;
01016                }
01017             }
01018          } else {
01019             /* go through all banks in bank_list */
01020             for (; bank_list->name[0]; bank_list++) {
01021                /* remember tag offset in n_data variable */
01022                bank_list->n_data = n_tag;
01023 
01024                if (bank_list->output_flag == 0)
01025                   continue;
01026 
01027                if (bank_list->type != TID_STRUCT) {
01028                   for (i = 0; i < (INT) bank_list->size; i++) {
01029                      sprintf(str, "%s%d", bank_list->name, i);
01030                      strncpy(rw_tag[n_tag++], str, 8);
01031 
01032                      if (clp.verbose)
01033                         printf("NT #%d-%d: %s\n", analyze_request[index].ar_info.event_id,
01034                                n_tag, str);
01035                      if (n_tag >= 512) {
01036                         cm_msg(MERROR, "book_ntuples",
01037                                "Too much tags for RW N-tupeles (512 maximum)");
01038                         return 0;
01039                      }
01040                   }
01041                } else {
01042                   /* define structured bank */
01043                   for (i = 0;; i++) {
01044                      status = db_enum_key(hDB, bank_list->def_key, i, &hkey);
01045                      if (status == DB_NO_MORE_SUBKEYS)
01046                         break;
01047 
01048                      db_get_key(hDB, hkey, &key);
01049 
01050                      /* convert blanks etc to '_' */
01051                      strcpy(key_name, key.name);
01052                      for (j = 0; key_name[j]; j++) {
01053                         if (!(key_name[j] >= 'a' && key_name[j] <= 'z') &&
01054                             !(key_name[j] >= 'A' && key_name[j] <= 'Z') &&
01055                             !(key_name[j] >= '0' && key_name[j] <= '9'))
01056                            key_name[j] = '_';
01057                      }
01058 
01059                      if (key.num_values > 1)
01060                         for (j = 0; j < key.num_values; j++) {
01061                            sprintf(str, "%s%d", key_name, j);
01062                            strncpy(rw_tag[n_tag++], str, 8);
01063 
01064                            if (clp.verbose)
01065                               printf("NT #%d-%d: %s\n",
01066                                      analyze_request[index].ar_info.event_id, n_tag, str);
01067 
01068                            if (n_tag >= 512) {
01069                               cm_msg(MERROR, "book_ntuples",
01070                                      "Too much tags for RW N-tupeles (512 maximum)");
01071                               return 0;
01072                            }
01073                      } else {
01074                         strncpy(rw_tag[n_tag++], key_name, 8);
01075                         if (clp.verbose)
01076                            printf("NT #%d-%d: %s\n",
01077                                   analyze_request[index].ar_info.event_id, n_tag,
01078                                   key_name);
01079                      }
01080 
01081                      if (n_tag >= 512) {
01082                         cm_msg(MERROR, "book_ntuples",
01083                                "Too much tags for RW N-tupeles (512 maximum)");
01084                         return 0;
01085                      }
01086                   }
01087                }
01088             }
01089          }
01090 
01091          /* book N-tuple with evend ID */
01092          strcpy(block_name, analyze_request[index].event_name);
01093          block_name[8] = 0;
01094 
01095          id = analyze_request[index].ar_info.event_id;
01096          if (HEXIST(id))
01097             HDELET(id);
01098 
01099          if (clp.online || equal_ustring(clp.output_file_name, "OFLN"))
01100             HBOOKN(id, block_name, n_tag, bstr,
01101                    n_tag * analyze_request[index].rwnt_buffer_size, rw_tag);
01102          else {
01103             strcpy(str, "//OFFLINE");
01104             HBOOKN(id, block_name, n_tag, str, 5120, rw_tag);
01105          }
01106 
01107          if (!HEXIST(id)) {
01108             printf("\n");
01109             cm_msg(MINFO, "book_ntuples",
01110                    "Cannot book N-tuple #%d. Increase PAWC size via the -s flag or switch off banks",
01111                    id);
01112          }
01113       }
01114    }
01115 
01116    return SUCCESS;
01117 }
01118 #endif                          /* HAVE_HBOOK */
01119 
01120 /*-- book TTree from ODB bank structures ---------------------------*/
01121 
01122 #ifdef USE_ROOT
01123 
01124 char ttree_types[][8] = {
01125    "",
01126    "b",                         /* TID_BYTE      */
01127    "B",                         /* TID_SBYTE     */
01128    "b",                         /* TID_CHAR      */
01129    "s",                         /* TID_WORD      */
01130    "S",                         /* TID_SHORT     */
01131    "i",                         /* TID_DWORD     */
01132    "I",                         /* TID_INT       */
01133    "I",                         /* TID_BOOL      */
01134    "F",                         /* TID_FLOAT     */
01135    "D",                         /* TID_DOUBLE    */
01136    "b",                         /* TID_BITFIELD  */
01137    "C",                         /* TID_STRING    */
01138    "",                          /* TID_ARRAY     */
01139    "",                          /* TID_STRUCT    */
01140    "",                          /* TID_KEY       */
01141    "",                          /* TID_LINK      */
01142    "",                          /* TID_LAST      */
01143 
01144 };
01145 
01146 INT book_ttree()
01147 {
01148    INT index, i, status, size;
01149    HNDLE hkey;
01150    KEY key;
01151    char leaf_tags[2000];
01152    char str[80];
01153    BANK_LIST *bank_list;
01154    EVENT_DEF *event_def;
01155    EVENT_TREE *et;
01156 
01157    /* check global N-tuple flag */
01158    ntuple_flag = 1;
01159    size = sizeof(ntuple_flag);
01160    sprintf(str, "/%s/Book TTree", analyzer_name);
01161    db_get_value(hDB, 0, str, &ntuple_flag, &size, TID_BOOL, TRUE);
01162 
01163    if (!ntuple_flag)
01164       return SUCCESS;
01165 
01166    /* copy output flag from ODB to bank_list */
01167    for (i = 0; analyze_request[i].event_name[0]; i++) {
01168       bank_list = analyze_request[i].bank_list;
01169 
01170       if (bank_list != NULL)
01171          for (; bank_list->name[0]; bank_list++) {
01172             sprintf(str, "/%s/Bank switches/%s", analyzer_name, bank_list->name);
01173             bank_list->output_flag = FALSE;
01174             size = sizeof(DWORD);
01175             db_get_value(hDB, 0, str, &bank_list->output_flag, &size, TID_DWORD, TRUE);
01176          }
01177    }
01178 
01179    /* hot link bank switches to N-tuple re-booking */
01180    sprintf(str, "/%s/Bank switches", analyzer_name);
01181    status = db_find_key(hDB, 0, str, &hkey);
01182    if (status != DB_SUCCESS) {
01183       cm_msg(MERROR, "book_ttree", "Cannot find key \'%s\', status %d", str, status);
01184       return SUCCESS;
01185    }
01186 
01187    db_open_record(hDB, hkey, NULL, 0, MODE_READ, banks_changed, NULL);
01188 
01189    /* go through all analyzer requests (events) */
01190    for (index = 0; analyze_request[index].event_name[0]; index++) {
01191       /* create tree */
01192       tree_struct.n_tree++;
01193       if (tree_struct.n_tree == 1)
01194          tree_struct.event_tree = (EVENT_TREE *) malloc(sizeof(EVENT_TREE));
01195       else
01196          tree_struct.event_tree =
01197              (EVENT_TREE *) realloc(tree_struct.event_tree,
01198                                     sizeof(EVENT_TREE) * tree_struct.n_tree);
01199 
01200       et = tree_struct.event_tree + (tree_struct.n_tree - 1);
01201 
01202       et->event_id = analyze_request[index].ar_info.event_id;
01203       et->n_branch = 0;
01204 
01205       /* create tree */
01206       sprintf(str, "Event \"%s\", ID %d", analyze_request[index].event_name,
01207               et->event_id);
01208       et->tree = new TTree(analyze_request[index].event_name, str);
01209 #if (ROOT_VERSION_CODE >= 262401)
01210       et->tree->SetCircular(analyze_request[index].rwnt_buffer_size);
01211 #endif
01212 
01213       /* book run number/event number/time */
01214       et->branch = (TBranch **) malloc(sizeof(TBranch *));
01215       et->branch_name = (char *) malloc(NAME_LENGTH);
01216       et->branch_filled = (int *) malloc(sizeof(int));
01217       et->branch_len = (int *) malloc(sizeof(int));
01218 
01219       et->branch[et->n_branch] =
01220           et->tree->Branch("Number", &analyze_request[index].number,
01221                            "Run/I:Number/I:Time/i");
01222       strcpy(et->branch_name, "Number");
01223       et->n_branch++;
01224 
01225       bank_list = analyze_request[index].bank_list;
01226       if (bank_list == NULL) {
01227          /* book fixed event */
01228          event_def =
01229              db_get_event_definition((short int) analyze_request[index].ar_info.event_id);
01230          if (event_def == NULL) {
01231             cm_msg(MERROR, "book_ttree", "Cannot find definition of event %s in ODB",
01232                    analyze_request[index].event_name);
01233             return 0;
01234          }
01235 
01236          leaf_tags[0] = 0;
01237          for (i = 0;; i++) {
01238             status = db_enum_key(hDB, event_def->hDefKey, i, &hkey);
01239             if (status == DB_NO_MORE_SUBKEYS)
01240                break;
01241 
01242             db_get_key(hDB, hkey, &key);
01243 
01244             strcat(leaf_tags, key.name);
01245 
01246             if (key.num_values > 1)
01247                sprintf(leaf_tags + strlen(leaf_tags), "[%d]", key.num_values);
01248 
01249             strcat(leaf_tags, "/");
01250 
01251             if (ttree_types[key.type] != NULL)
01252                strcat(leaf_tags, ttree_types[key.type]);
01253             else {
01254                cm_msg(MERROR, "book_ttree",
01255                       "Key %s in event %s is of type %s with no TTREE correspondence",
01256                       key.name, analyze_request[index].event_name,
01257                       rpc_tid_name(key.type));
01258                return 0;
01259             }
01260             strcat(leaf_tags, ":");
01261          }
01262 
01263          leaf_tags[strlen(leaf_tags) - 1] = 0;  /* delete last ':' */
01264 
01265          et->branch =
01266              (TBranch **) realloc(et->branch, sizeof(TBranch *) * (et->n_branch + 1));
01267          et->branch_name =
01268              (char *) realloc(et->branch_name, NAME_LENGTH * (et->n_branch + 1));
01269          et->branch_filled =
01270              (int *) realloc(et->branch_filled, sizeof(int) * (et->n_branch + 1));
01271          et->branch_len =
01272              (int *) realloc(et->branch_len, sizeof(int) * (et->n_branch + 1));
01273 
01274          et->branch[et->n_branch] =
01275              et->tree->Branch(analyze_request[index].event_name, NULL, leaf_tags);
01276          strcpy(&et->branch_name[et->n_branch * NAME_LENGTH],
01277                 analyze_request[index].event_name);
01278          et->n_branch++;
01279       } else {
01280          /* go thorough all banks in bank_list */
01281          for (; bank_list->name[0]; bank_list++) {
01282             if (bank_list->output_flag == 0)
01283                continue;
01284 
01285             if (bank_list->type != TID_STRUCT) {
01286                sprintf(leaf_tags, "n%s/I:%s[n%s]/", bank_list->name, bank_list->name,
01287                        bank_list->name);
01288 
01289                /* define variable length array */
01290                if (ttree_types[bank_list->type] != NULL)
01291                   strcat(leaf_tags, ttree_types[bank_list->type]);
01292                else {
01293                   cm_msg(MERROR, "book_ttree",
01294                          "Bank %s is of type %s with no TTREE correspondence",
01295                          bank_list->name, rpc_tid_name(bank_list->type));
01296                   return 0;
01297                }
01298 
01299                if (rpc_tid_size(bank_list->type) == 0) {
01300                   cm_msg(MERROR, "book_ttree", "Bank %s is of type with unknown size",
01301                          bank_list->name);
01302                   return 0;
01303                }
01304 
01305                et->branch =
01306                    (TBranch **) realloc(et->branch,
01307                                         sizeof(TBranch *) * (et->n_branch + 1));
01308                et->branch_name =
01309                    (char *) realloc(et->branch_name, NAME_LENGTH * (et->n_branch + 1));
01310                et->branch_filled =
01311                    (int *) realloc(et->branch_filled, sizeof(int) * (et->n_branch + 1));
01312                et->branch_len =
01313                    (int *) realloc(et->branch_len, sizeof(int) * (et->n_branch + 1));
01314 
01315                et->branch[et->n_branch] =
01316                    et->tree->Branch(bank_list->name, NULL, leaf_tags);
01317                strcpy(&et->branch_name[et->n_branch * NAME_LENGTH], bank_list->name);
01318                et->n_branch++;
01319             } else {
01320                /* define structured bank */
01321                leaf_tags[0] = 0;
01322                for (i = 0;; i++) {
01323                   status = db_enum_key(hDB, bank_list->def_key, i, &hkey);
01324                   if (status == DB_NO_MORE_SUBKEYS)
01325                      break;
01326 
01327                   db_get_key(hDB, hkey, &key);
01328 
01329                   strcat(leaf_tags, key.name);
01330 
01331                   if (key.num_values > 1)
01332                      sprintf(leaf_tags + strlen(leaf_tags), "[%d]", key.num_values);
01333 
01334                   strcat(leaf_tags, "/");
01335 
01336                   if (ttree_types[key.type] != NULL)
01337                      strcat(leaf_tags, ttree_types[key.type]);
01338                   else {
01339                      cm_msg(MERROR, "book_ttree",
01340                             "Key %s in bank %s is of type %s with no HBOOK correspondence",
01341                             key.name, bank_list->name, rpc_tid_name(key.type));
01342                      return 0;
01343                   }
01344                   strcat(leaf_tags, ":");
01345                }
01346 
01347                leaf_tags[strlen(leaf_tags) - 1] = 0;
01348 
01349                et->branch =
01350                    (TBranch **) realloc(et->branch,
01351                                         sizeof(TBranch *) * (et->n_branch + 1));
01352                et->branch_name =
01353                    (char *) realloc(et->branch_name, NAME_LENGTH * (et->n_branch + 1));
01354                et->branch_filled =
01355                    (int *) realloc(et->branch_filled, sizeof(int) * (et->n_branch + 1));
01356                et->branch_len =
01357                    (int *) realloc(et->branch_len, sizeof(int) * (et->n_branch + 1));
01358 
01359                et->branch[et->n_branch] =
01360                    et->tree->Branch(bank_list->name, NULL, leaf_tags);
01361                strcpy(&et->branch_name[et->n_branch * NAME_LENGTH], bank_list->name);
01362                et->n_branch++;
01363             }
01364          }
01365       }
01366    }
01367 
01368    return SUCCESS;
01369 }
01370 
01371 /*-- root histogram routines ---------------------------------------*/
01372 
01373 // Save all objects from given directory into given file
01374 INT SaveRootHistograms(TFolder * folder, const char *filename)
01375 {
01376    TDirectory *savedir = gDirectory;
01377    TFile *outf = new TFile(filename, "RECREATE", "Midas Analyzer Histograms");
01378    if (outf == 0) {
01379       cm_msg(MERROR, "SaveRootHistograms", "Cannot create output file %s", filename);
01380       return 0;
01381    }
01382 
01383    outf->cd();
01384    folder->Write();
01385    outf->Close();
01386    delete outf;
01387    // restore current directory
01388    savedir->cd();
01389    return SUCCESS;
01390 }
01391 
01392 /*------------------------------------------------------------------*/
01393 
01394 // copy object from a last folder, to an online folder,
01395 // and call itself to handle subfolders
01396 void copy_from_last(TFolder * lastFolder, TFolder * onlineFolder)
01397 {
01398 
01399    TIter next(lastFolder->GetListOfFolders());
01400    while (TObject * obj = next()) {
01401       const char *name = obj->GetName();
01402 
01403       if (obj->InheritsFrom("TFolder")) {
01404 
01405          TFolder *onlineSubfolder = (TFolder *) onlineFolder->FindObject(name);
01406          if (onlineSubfolder)
01407             copy_from_last((TFolder *) obj, onlineSubfolder);
01408 
01409       } else if (obj->InheritsFrom("TH1")) {
01410 
01411          // still don't know how to do TH1s
01412 
01413       } else if (obj->InheritsFrom("TCutG")) {
01414 
01415          TCutG *onlineObj = (TCutG *) onlineFolder->FindObject(name);
01416          if (onlineObj) {
01417             TCutG *lastObj = (TCutG *) obj;
01418 
01419             lastObj->TAttMarker::Copy(*onlineObj);
01420             lastObj->TAttFill::Copy(*onlineObj);
01421             lastObj->TAttLine::Copy(*onlineObj);
01422             lastObj->TNamed::Copy(*onlineObj);
01423             onlineObj->Set(lastObj->GetN());
01424             for (int i = 0; i < lastObj->GetN(); ++i) {
01425                onlineObj->SetPoint(i, lastObj->GetX()[i], lastObj->GetY()[i]);
01426             }
01427          }
01428       }
01429    }
01430    return;
01431 }
01432 
01433 /*------------------------------------------------------------------*/
01434 
01435 // Load all objects from given file into given directory
01436 INT LoadRootHistograms(TFolder * folder, const char *filename)
01437 {
01438    TFile *inf = TFile::Open(filename, "READ");
01439    if (inf == NULL)
01440       printf("Error: File \"%s\" not found\n", filename);
01441    else {
01442 
01443       TFolder *lastHistos = (TFolder *) inf->Get("histos");
01444       if (lastHistos) {
01445          // copy histos to online folder
01446          copy_from_last(lastHistos, folder);
01447          inf->Close();
01448       }
01449    }
01450    return SUCCESS;
01451 }
01452 
01453 /*------------------------------------------------------------------*/
01454 
01455 // Clear all TH1 objects in the given directory,
01456 // and it's subdirectories
01457 INT ClearRootHistograms(TFolder * folder)
01458 {
01459    TIter next(folder->GetListOfFolders());
01460    while (TObject * obj = next())
01461       if (obj->InheritsFrom("TH1"))
01462          ((TH1 *) obj)->Reset();
01463       else if (obj->InheritsFrom("TFolder"))
01464          ClearRootHistograms((TFolder *) obj);
01465    return SUCCESS;
01466 }
01467 
01468 /*------------------------------------------------------------------*/
01469 
01470 INT CloseRootOutputFile()
01471 {
01472    int i;
01473 
01474    // ensure that we do have an open file
01475    assert(gManaOutputFile != NULL);
01476 
01477    // save the histograms
01478    gManaOutputFile->cd();
01479    gManaHistosFolder->Write();
01480 
01481    // close the output file
01482    gManaOutputFile->Write();
01483    gManaOutputFile->Close();
01484    delete gManaOutputFile;
01485    gManaOutputFile = NULL;
01486 
01487    // delete the output trees
01488    for (i = 0; i < tree_struct.n_tree; i++)
01489       if (tree_struct.event_tree[i].branch) {
01490          free(tree_struct.event_tree[i].branch);
01491          free(tree_struct.event_tree[i].branch_name);
01492          free(tree_struct.event_tree[i].branch_filled);
01493          free(tree_struct.event_tree[i].branch_len);
01494          tree_struct.event_tree[i].branch = NULL;
01495       }
01496 
01497    /* delete event tree */
01498    free(tree_struct.event_tree);
01499    tree_struct.event_tree = NULL;
01500    tree_struct.n_tree = 0;
01501 
01502    // go to ROOT root directory
01503    gROOT->cd();
01504 
01505    return SUCCESS;
01506 }
01507 
01508 #endif                          /* USE_ROOT */
01509 
01510 /*-- analyzer init routine -----------------------------------------*/
01511 
01512 INT mana_init()
01513 {
01514    ANA_MODULE **module;
01515    INT i, j, status, size;
01516    HNDLE hkey;
01517    char str[256], block_name[32];
01518    BANK_LIST *bank_list;
01519    double dummy;
01520 
01521    sprintf(str, "/%s/Output", analyzer_name);
01522    db_find_key(hDB, 0, str, &hkey);
01523 
01524    if (clp.online) {
01525       status =
01526           db_open_record(hDB, hkey, &out_info, sizeof(out_info), MODE_READ, NULL, NULL);
01527       if (status != DB_SUCCESS) {
01528          cm_msg(MERROR, "bor", "Cannot read output info record");
01529          return 0;
01530       }
01531    }
01532 
01533    /* create ODB structures for banks */
01534    for (i = 0; analyze_request[i].event_name[0]; i++) {
01535       bank_list = analyze_request[i].bank_list;
01536 
01537       if (bank_list == NULL)
01538          continue;
01539 
01540       for (; bank_list->name[0]; bank_list++) {
01541          strncpy(block_name, bank_list->name, 4);
01542          block_name[4] = 0;
01543 
01544          if (bank_list->type == TID_STRUCT) {
01545             sprintf(str, "/Equipment/%s/Variables/%s", analyze_request[i].event_name,
01546                     block_name);
01547             db_check_record(hDB, 0, str, strcomb((const char **)bank_list->init_str), TRUE);
01548             db_find_key(hDB, 0, str, &hkey);
01549             bank_list->def_key = hkey;
01550          } else {
01551             sprintf(str, "/Equipment/%s/Variables/%s", analyze_request[i].event_name,
01552                     block_name);
01553             status = db_find_key(hDB, 0, str, &hkey);
01554             if (status != DB_SUCCESS) {
01555                dummy = 0;
01556                db_set_value(hDB, 0, str, &dummy, rpc_tid_size(bank_list->type), 1,
01557                             bank_list->type);
01558             }
01559             bank_list->def_key = hkey;
01560          }
01561       }
01562    }
01563 
01564    /* create ODB structures for fixed events */
01565    for (i = 0; analyze_request[i].event_name[0]; i++) {
01566       if (analyze_request[i].init_string) {
01567          sprintf(str, "/Equipment/%s/Variables", analyze_request[i].event_name);
01568          db_check_record(hDB, 0, str, strcomb((const char **)analyze_request[i].init_string), TRUE);
01569       }
01570    }
01571 
01572    /* delete tests in ODB */
01573    sprintf(str, "/%s/Tests", analyzer_name);
01574    db_find_key(hDB, 0, str, &hkey);
01575    if (hkey)
01576       db_delete_key(hDB, hkey, FALSE);
01577 
01578 #ifdef HAVE_HBOOK
01579    /* create global memory */
01580    if (clp.online) {
01581       /* book online N-tuples only once when online */
01582       status = book_ntuples();
01583       if (status != SUCCESS)
01584          return status;
01585    } else {
01586       if (equal_ustring(clp.output_file_name, "OFLN")) {
01587          /* book online N-tuples only once when online */
01588          status = book_ntuples();
01589          if (status != SUCCESS)
01590             return status;
01591       }
01592    }
01593 #endif                          /* HAVE_HBOOK */
01594 
01595 #ifdef USE_ROOT
01596    if (clp.online) {
01597       /* book online N-tuples only once when online */
01598       status = book_ttree();
01599       if (status != SUCCESS)
01600          return status;
01601    }
01602 #endif
01603 
01604    /* call main analyzer init routine */
01605    status = analyzer_init();
01606    if (status != SUCCESS)
01607       return status;
01608 
01609    /* initialize modules */
01610    for (i = 0; analyze_request[i].event_name[0]; i++) {
01611       module = analyze_request[i].ana_module;
01612       for (j = 0; module != NULL && module[j] != NULL; j++) {
01613 
01614          /* copy module enabled flag to ana_module */
01615          sprintf(str, "/%s/Module switches/%s", analyzer_name, module[j]->name);
01616          module[j]->enabled = TRUE;
01617          size = sizeof(BOOL);
01618          db_get_value(hDB, 0, str, &module[j]->enabled, &size, TID_BOOL, TRUE);
01619 
01620          if (module[j]->init != NULL && module[j]->enabled) {
01621 
01622 #ifdef USE_ROOT
01623             /* create histo subfolder for module */
01624             sprintf(str, "Histos for module %s", module[j]->name);
01625             module[j]->histo_folder = (TFolder *) gROOT->FindObjectAny(module[j]->name);
01626             if (!module[j]->histo_folder)
01627                module[j]->histo_folder =
01628                    gManaHistosFolder->AddFolder(module[j]->name, str);
01629             else if (strcmp(((TObject *) module[j]->histo_folder)->ClassName(), "TFolder")
01630                      != 0) {
01631                cm_msg(MERROR, "mana_init",
01632                       "Fatal error: ROOT Object \"%s\" of class \"%s\" exists but it is not a TFolder, exiting!",
01633                       module[j]->name,
01634                       ((TObject *) module[j]->histo_folder)->ClassName());
01635                exit(1);
01636             }
01637             gHistoFolderStack->Clear();
01638             gHistoFolderStack->Add((TObject *) module[j]->histo_folder);
01639 #endif
01640 
01641             module[j]->init();
01642          }
01643       }
01644    }
01645 
01646    return SUCCESS;
01647 }
01648 
01649 /*-- exit routine --------------------------------------------------*/
01650 
01651 INT mana_exit()
01652 {
01653    ANA_MODULE **module;
01654    INT i, j;
01655 
01656    /* call exit routines from modules */
01657    for (i = 0; analyze_request[i].event_name[0]; i++) {
01658       module = analyze_request[i].ana_module;
01659       for (j = 0; module != NULL && module[j] != NULL; j++)
01660          if (module[j]->exit != NULL && module[j]->enabled) {
01661             module[j]->exit();
01662          }
01663    }
01664 
01665    /* call main analyzer exit routine */
01666    return analyzer_exit();
01667 }
01668 
01669 /*-- BOR routine ---------------------------------------------------*/
01670 
01671 INT bor(INT run_number, char *error)
01672 {
01673    ANA_MODULE **module;
01674    INT i, j, size;
01675    char str[256], file_name[256], *ext_str;
01676    BANK_LIST *bank_list;
01677 
01678    /* load parameters */
01679    load_parameters(run_number);
01680 
01681    for (i = 0; analyze_request[i].event_name[0]; i++) {
01682       /* copy output flag from ODB to bank_list */
01683       bank_list = analyze_request[i].bank_list;
01684 
01685       if (bank_list != NULL)
01686          for (; bank_list->name[0]; bank_list++) {
01687             sprintf(str, "/%s/Bank switches/%s", analyzer_name, bank_list->name);
01688             bank_list->output_flag = FALSE;
01689             size = sizeof(DWORD);
01690             db_get_value(hDB, 0, str, &bank_list->output_flag, &size, TID_DWORD, TRUE);
01691          }
01692 
01693       /* copy module enabled flag to ana_module */
01694       module = analyze_request[i].ana_module;
01695       for (j = 0; module != NULL && module[j] != NULL; j++) {
01696          sprintf(str, "/%s/Module switches/%s", analyzer_name, module[j]->name);
01697          module[j]->enabled = TRUE;
01698          size = sizeof(BOOL);
01699          db_get_value(hDB, 0, str, &module[j]->enabled, &size, TID_BOOL, TRUE);
01700       }
01701    }
01702 
01703    /* clear histos, N-tuples and tests */
01704    if (clp.online && out_info.clear_histos) {
01705 #ifdef HAVE_HBOOK
01706       int hid[10000];
01707       int n;
01708 
01709       for (i = 0; analyze_request[i].event_name[0]; i++)
01710          if (analyze_request[i].bank_list != NULL)
01711             if (HEXIST(analyze_request[i].ar_info.event_id))
01712                HRESET(analyze_request[i].ar_info.event_id, bstr);
01713 
01714       /* get list of all histos */
01715       HIDALL(hid, n);
01716       for (i = 0; i < n; i++) {
01717          for (j = 0; j < 10000; j++)
01718             if (lock_list[j] == 0 || lock_list[j] == hid[i])
01719                break;
01720 
01721          /* clear histo if not locked */
01722          if (lock_list[j] != hid[i])
01723             HRESET(hid[i], bstr);
01724       }
01725 #endif                          /* HAVE_HBOOK */
01726 
01727 #ifdef USE_ROOT
01728       /* clear histos */
01729       if (clp.online && out_info.clear_histos)
01730          ClearRootHistograms(gManaHistosFolder);
01731 #endif                          /* USE_ROOT */
01732 
01733       /* clear tests */
01734       test_clear();
01735    }
01736 #ifdef USE_ROOT
01737    if (clp.online) {
01738       /* clear all trees when online */
01739       for (i = 0; i < tree_struct.n_tree; i++)
01740          tree_struct.event_tree[i].tree->Reset();
01741    }
01742 #endif
01743 
01744    /* open output file if not already open (append mode) and in offline mode */
01745    if (!clp.online && out_file == NULL && !pvm_master
01746        && !equal_ustring(clp.output_file_name, "OFLN")) {
01747       if (out_info.filename[0]) {
01748          strcpy(str, out_info.filename);
01749          if (strchr(str, '%') != NULL)
01750             sprintf(file_name, str, run_number);
01751          else
01752             strcpy(file_name, str);
01753 
01754          /* check output file extension */
01755 #ifdef HAVE_ZLIB
01756          out_gzip = FALSE;
01757 #endif
01758          if (strchr(file_name, '.')) {
01759             ext_str = file_name + strlen(file_name) - 1;
01760             while (*ext_str != '.')
01761                ext_str--;
01762 
01763             if (strncmp(ext_str, ".gz", 3) == 0) {
01764 #ifdef HAVE_ZLIB
01765                out_gzip = TRUE;
01766                ext_str--;
01767                while (*ext_str != '.' && ext_str > file_name)
01768                   ext_str--;
01769 #else
01770                strcpy(error,
01771                       ".gz extension not possible because zlib support is not compiled in.\n");
01772                cm_msg(MERROR, "bor", error);
01773                return 0;
01774 #endif
01775             }
01776 
01777             if (strncmp(ext_str, ".asc", 4) == 0)
01778                out_format = FORMAT_ASCII;
01779             else if (strncmp(ext_str, ".mid", 4) == 0)
01780                out_format = FORMAT_MIDAS;
01781             else if (strncmp(ext_str, ".rz", 3) == 0)
01782                out_format = FORMAT_HBOOK;
01783             else if (strncmp(ext_str, ".root", 5) == 0)
01784                out_format = FORMAT_ROOT;
01785             else {
01786                strcpy(error,
01787                       "Unknown output data format. Please use file extension .asc, .mid, .rz or .root.\n");
01788                cm_msg(MERROR, "bor", error);
01789                return 0;
01790             }
01791          } else
01792             out_format = FORMAT_ASCII;
01793 
01794 #ifdef HAVE_PVM
01795          /* use node name as filename if PVM slave */
01796          if (pvm_slave) {
01797             /* extract extension */
01798             if (strchr(file_name, '.')) {
01799                strcpy(str, strchr(file_name, '.') + 1);
01800                sprintf(file_name, "n%d", pvm_client_index);
01801                strcat(file_name, ".");
01802                strcat(file_name, str);
01803             } else {
01804                sprintf(file_name, "n%d", pvm_client_index);
01805             }
01806 
01807             PVM_DEBUG("BOR: file_name = %s", file_name);
01808          }
01809 #endif
01810 
01811          /* open output file */
01812          if (out_format == FORMAT_HBOOK) {
01813 #ifdef HAVE_HBOOK
01814             int status, lrec;
01815             char str2[80];
01816 
01817             lrec = clp.lrec;
01818 #ifdef extname
01819             quest_[9] = 65000;
01820 #else
01821             QUEST[9] = 65000;
01822 #endif
01823 
01824             strcpy(str, "BSIZE");
01825             HBSET(str, HBOOK_LREC, status);
01826             strcpy(str, "OFFLINE");
01827             strcpy(str2, "NQP");
01828             HROPEN(1, str, file_name, str2, lrec, status);
01829             if (status != 0) {
01830                sprintf(error, "Cannot open output file %s", out_info.filename);
01831                cm_msg(MERROR, "bor", error);
01832                out_file = NULL;
01833                return 0;
01834             } else
01835                out_file = (FILE *) 1;
01836 #else
01837             cm_msg(MERROR, "bor", "HBOOK support is not compiled in");
01838 #endif                          /* HAVE_HBOOK */
01839          }
01840 
01841          else if (out_format == FORMAT_ROOT) {
01842 #ifdef USE_ROOT
01843             // ensure the output file is closed
01844             assert(gManaOutputFile == NULL);
01845 
01846             gManaOutputFile =
01847                 new TFile(file_name, "RECREATE", "Midas Analyzer output file");
01848             if (gManaOutputFile == NULL) {
01849                sprintf(error, "Cannot open output file %s", out_info.filename);
01850                cm_msg(MERROR, "bor", error);
01851                out_file = NULL;
01852                return 0;
01853             }
01854             // make all ROOT objects created by user module bor() functions
01855             // go into the output file
01856             gManaOutputFile->cd();
01857 
01858             out_file = (FILE *) 1;
01859 #else
01860             cm_msg(MERROR, "bor", "ROOT support is not compiled in");
01861 #endif                          /* USE_ROOT */
01862          }
01863 
01864          else {
01865 #ifdef HAVE_ZLIB
01866             if (out_gzip)
01867                out_file = (FILE *) gzopen(file_name, "wb");
01868             else
01869 #endif
01870             if (out_format == FORMAT_ASCII)
01871                out_file = fopen(file_name, "wt");
01872             else
01873                out_file = fopen(file_name, "wb");
01874             if (out_file == NULL) {
01875                sprintf(error, "Cannot open output file %s", file_name);
01876                cm_msg(MERROR, "bor", error);
01877                return 0;
01878             }
01879          }
01880       } else
01881          out_file = NULL;
01882 
01883 #ifdef HAVE_HBOOK
01884       /* book N-tuples */
01885       if (out_format == FORMAT_HBOOK) {
01886          int status = book_ntuples();
01887          if (status != SUCCESS)
01888             return status;
01889       }
01890 #endif                          /* HAVE_HBOOK */
01891 
01892 #ifdef USE_ROOT
01893       /* book ROOT TTree */
01894       if (out_format == FORMAT_ROOT) {
01895          int status = book_ttree();
01896          if (status != SUCCESS)
01897             return status;
01898       }
01899 #endif                          /* USE_ROOT */
01900 
01901    }
01902 
01903    /* if (out_file == NULL) */
01904    /* save run number */
01905    current_run_number = run_number;
01906 
01907    /* call bor for modules */
01908    for (i = 0; analyze_request[i].event_name[0]; i++) {
01909       module = analyze_request[i].ana_module;
01910       for (j = 0; module != NULL && module[j] != NULL; j++)
01911          if (module[j]->bor != NULL && module[j]->enabled) {
01912             module[j]->bor(run_number);
01913          }
01914    }
01915 
01916    /* call main analyzer BOR routine */
01917    return ana_begin_of_run(run_number, error);
01918 }
01919 
01920 /*-- EOR routine ---------------------------------------------------*/
01921 
01922 INT eor(INT run_number, char *error)
01923 {
01924    ANA_MODULE **module;
01925    BANK_LIST *bank_list;
01926    INT i, j, status;
01927    char str[256], file_name[256];
01928 
01929    /* call EOR routines modules */
01930    for (i = 0; analyze_request[i].event_name[0]; i++) {
01931       module = analyze_request[i].ana_module;
01932       for (j = 0; module != NULL && module[j] != NULL; j++)
01933          if (module[j]->eor != NULL && module[j]->enabled) {
01934             module[j]->eor(run_number);
01935          }
01936    }
01937 
01938    /* call main analyzer BOR routine */
01939    status = ana_end_of_run(run_number, error);
01940 
01941    /* save histos if requested */
01942    if (out_info.histo_dump && clp.online) {
01943       strcpy(str, out_info.histo_dump_filename);
01944       if (strchr(str, '%') != NULL)
01945          sprintf(file_name, str, run_number);
01946       else
01947          strcpy(file_name, str);
01948 
01949       add_data_dir(str, file_name);
01950 #ifdef HAVE_HBOOK
01951       for (i = 0; i < (int) strlen(str); i++)
01952          if (isupper(str[i]))
01953             break;
01954 
01955       if (i < (int) strlen(str)) {
01956          printf
01957              ("Error: Due to a limitation in HBOOK, directoy names may not contain uppercase\n");
01958          printf("       characters. Histogram saving to %s will not work.\n", str);
01959       } else {
01960          char str2[256];
01961          strcpy(str2, "NT");
01962          HRPUT(0, str, str2);
01963       }
01964 #endif                          /* HAVE_HBOOK */
01965 
01966 #ifdef USE_ROOT
01967       SaveRootHistograms(gManaHistosFolder, str);
01968 #endif                          /* USE_ROOT */
01969    }
01970 
01971    /* close output file */
01972    if (out_file && !out_append) {
01973       if (out_format == FORMAT_HBOOK) {
01974 #ifdef HAVE_HBOOK
01975          HROUT(0, i, bstr);
01976          strcpy(str, "OFFLINE");
01977          HREND(str);
01978 #else
01979          cm_msg(MERROR, "eor", "HBOOK support is not compiled in");
01980 #endif                          /* HAVE_HBOOK */
01981       } else if (out_format == FORMAT_ROOT) {
01982 #ifdef USE_ROOT
01983          CloseRootOutputFile();
01984 #else
01985          cm_msg(MERROR, "eor", "ROOT support is not compiled in");
01986 #endif                          /* USE_ROOT */
01987       } else {
01988 #ifdef HAVE_ZLIB
01989          if (out_gzip)
01990             gzclose(out_file);
01991          else
01992 #endif
01993             fclose(out_file);
01994       }
01995 
01996       out_file = NULL;
01997 
01998       /* free CWNT buffer */
01999       for (i = 0; analyze_request[i].event_name[0]; i++) {
02000          bank_list = analyze_request[i].bank_list;
02001 
02002          if (bank_list == NULL) {
02003             if (analyze_request[i].addr) {
02004                free(analyze_request[i].addr);
02005                analyze_request[i].addr = NULL;
02006             }
02007          } else {
02008             for (; bank_list->name[0]; bank_list++)
02009                if (bank_list->addr) {
02010                   free(bank_list->addr);
02011                   bank_list->addr = NULL;
02012                }
02013          }
02014       }
02015    }
02016 
02017    return status;
02018 }
02019 
02020 /*-- transition callbacks ------------------------------------------*/
02021 
02022 /*-- start ---------------------------------------------------------*/
02023 
02024 INT tr_start(INT rn, char *error)
02025 {
02026    INT status, i;
02027 
02028    /* reset counters */
02029    for (i = 0; analyze_request[i].event_name[0]; i++) {
02030       analyze_request[i].ar_stats.events_received = 0;
02031       analyze_request[i].ar_stats.events_per_sec = 0;
02032       analyze_request[i].ar_stats.events_written = 0;
02033       analyze_request[i].events_received = 0;
02034       analyze_request[i].events_written = 0;
02035    }
02036 
02037    status = bor(rn, error);
02038    if (status != SUCCESS)
02039       return status;
02040 
02041    return SUCCESS;
02042 }
02043 
02044 /*-- stop ----------------------------------------------------------*/
02045 
02046 INT tr_stop(INT rn, char *error)
02047 {
02048    INT i, status, n_bytes;
02049 
02050    /* wait until all events in buffers are analyzed */
02051 
02052    if (rpc_is_remote())
02053       while (bm_poll_event(TRUE));
02054    else
02055       for (i = 0; analyze_request[i].event_name[0]; i++) {
02056          do {
02057             bm_get_buffer_level(analyze_request[i].buffer_handle, &n_bytes);
02058             if (n_bytes > 0)
02059                cm_yield(100);
02060          } while (n_bytes > 0);
02061       }
02062 
02063    /* update statistics */
02064    update_stats();
02065 
02066    status = eor(rn, error);
02067    if (status != SUCCESS)
02068       return status;
02069 
02070    return CM_SUCCESS;
02071 }
02072 
02073 /*-- pause ---------------------------------------------------------*/
02074 
02075 INT tr_pause(INT rn, char *error)
02076 {
02077    INT status;
02078 
02079    status = ana_pause_run(rn, error);
02080    if (status != CM_SUCCESS)
02081       return status;
02082 
02083    return CM_SUCCESS;
02084 }
02085 
02086 /*-- resume --------------------------------------------------------*/
02087 
02088 INT tr_resume(INT rn, char *error)
02089 {
02090    INT status;
02091 
02092    status = ana_resume_run(rn, error);
02093    if (status != CM_SUCCESS)
02094       return status;
02095 
02096    return CM_SUCCESS;
02097 }
02098 
02099 /*---- ASCII output ------------------------------------------------*/
02100 
02101 #define STR_INC(p,base) { p+=strlen(p); \
02102                           if (p > base+sizeof(base)) \
02103                             cm_msg(MERROR, "STR_INC", "ASCII buffer too small"); }
02104 
02105 
02106 INT write_event_ascii(FILE * file, EVENT_HEADER * pevent, ANALYZE_REQUEST * par)
02107 {
02108    INT status, size, i, j, count;
02109    BOOL exclude;
02110    BANK_HEADER *pbh;
02111    BANK_LIST *pbl;
02112    EVENT_DEF *event_def;
02113    BANK *pbk;
02114    BANK32 *pbk32;
02115    void *pdata;
02116    char *pbuf, name[5], type_name[10];
02117    LRS1882_DATA *lrs1882;
02118    LRS1877_DATA *lrs1877;
02119    LRS1877_HEADER *lrs1877_header;
02120    HNDLE hKey;
02121    KEY key;
02122    char buffer[100000];
02123    DWORD bkname;
02124    WORD bktype;
02125 
02126    event_def = db_get_event_definition(pevent->event_id);
02127    if (event_def == NULL)
02128       return SS_SUCCESS;
02129 
02130    /* write event header */
02131    pbuf = buffer;
02132    name[4] = 0;
02133 
02134    if (pevent->event_id == EVENTID_BOR)
02135       sprintf(pbuf, "%%ID BOR NR %d\n", (int) pevent->serial_number);
02136    else if (pevent->event_id == EVENTID_EOR)
02137       sprintf(pbuf, "%%ID EOR NR %d\n", (int) pevent->serial_number);
02138    else
02139       sprintf(pbuf, "%%ID %d TR %d NR %d\n", pevent->event_id, pevent->trigger_mask,
02140               (int) pevent->serial_number);
02141    STR_INC(pbuf, buffer);
02142 
02143   /*---- MIDAS format ----------------------------------------------*/
02144    if (event_def->format == FORMAT_MIDAS) {
02145       pbh = (BANK_HEADER *) (pevent + 1);
02146       pbk = NULL;
02147       pbk32 = NULL;
02148       do {
02149          /* scan all banks */
02150          if (bk_is32(pbh)) {
02151             size = bk_iterate32(pbh, &pbk32, &pdata);
02152             if (pbk32 == NULL)
02153                break;
02154             bkname = *((DWORD *) pbk32->name);
02155             bktype = (WORD) pbk32->type;
02156          } else {
02157             size = bk_iterate(pbh, &pbk, &pdata);
02158             if (pbk == NULL)
02159                break;
02160             bkname = *((DWORD *) pbk->name);
02161             bktype = (WORD) pbk->type;
02162          }
02163 
02164          /* look if bank is in exclude list */
02165          exclude = FALSE;
02166          pbl = NULL;
02167          if (par->bank_list != NULL)
02168             for (i = 0; par->bank_list[i].name[0]; i++)
02169                if (*((DWORD *) par->bank_list[i].name) == bkname) {
02170                   pbl = &par->bank_list[i];
02171                   exclude = (pbl->output_flag == 0);
02172                   break;
02173                }
02174 
02175          if (!exclude) {
02176             if (rpc_tid_size(bktype & 0xFF))
02177                size /= rpc_tid_size(bktype & 0xFF);
02178 
02179             lrs1882 = (LRS1882_DATA *) pdata;
02180             lrs1877 = (LRS1877_DATA *) pdata;
02181 
02182             /* write bank header */
02183             *((DWORD *) name) = bkname;
02184 
02185             if ((bktype & 0xFF00) == 0)
02186                strcpy(type_name, rpc_tid_name(bktype & 0xFF));
02187             else if ((bktype & 0xFF00) == TID_LRS1882)
02188                strcpy(type_name, "LRS1882");
02189             else if ((bktype & 0xFF00) == TID_LRS1877)
02190                strcpy(type_name, "LRS1877");
02191             else if ((bktype & 0xFF00) == TID_PCOS3)
02192                strcpy(type_name, "PCOS3");
02193             else
02194                strcpy(type_name, "unknown");
02195 
02196             sprintf(pbuf, "BK %s TP %s SZ %d\n", name, type_name, size);
02197             STR_INC(pbuf, buffer);
02198 
02199             if (bktype == TID_STRUCT) {
02200                if (pbl == NULL)
02201                   cm_msg(MERROR, "write_event_ascii", "received unknown bank %s", name);
02202                else
02203                   /* write structured bank */
02204                   for (i = 0;; i++) {
02205                      status = db_enum_key(hDB, pbl->def_key, i, &hKey);
02206                      if (status == DB_NO_MORE_SUBKEYS)
02207                         break;
02208 
02209                      db_get_key(hDB, hKey, &key);
02210                      sprintf(pbuf, "%s:\n", key.name);
02211                      STR_INC(pbuf, buffer);
02212 
02213                      /* adjust for alignment */
02214                      pdata =
02215                          (void *) VALIGN(pdata,
02216                                          MIN(ss_get_struct_align(), key.item_size));
02217 
02218                      for (j = 0; j < key.num_values; j++) {
02219                         db_sprintf(pbuf, pdata, key.item_size, j, key.type);
02220                         strcat(pbuf, "\n");
02221                         STR_INC(pbuf, buffer);
02222                      }
02223 
02224                      /* shift data pointer to next item */
02225                      pdata = (char *) pdata + key.item_size * key.num_values;
02226                   }
02227             } else {
02228                /* write variable length bank  */
02229                if ((bktype & 0xFF00) == TID_LRS1877) {
02230                   for (i = 0; i < size;) {
02231                      lrs1877_header = (LRS1877_HEADER *) & lrs1877[i];
02232 
02233                      /* print header */
02234                      sprintf(pbuf, "GA %d BF %d CN %d",
02235                              lrs1877_header->geo_addr, lrs1877_header->buffer,
02236                              lrs1877_header->count);
02237                      strcat(pbuf, "\n");
02238                      STR_INC(pbuf, buffer);
02239 
02240                      count = lrs1877_header->count;
02241                      if (count == 0)
02242                         break;
02243                      for (j = 1; j < count; j++) {
02244                         /* print data */
02245                         sprintf(pbuf, "GA %d CH %02d ED %d DA %1.1lf",
02246                                 lrs1877[i].geo_addr, lrs1877[i + j].channel,
02247                                 lrs1877[i + j].edge, lrs1877[i + j].data * 0.5);
02248                         strcat(pbuf, "\n");
02249                         STR_INC(pbuf, buffer);
02250                      }
02251 
02252                      i += count;
02253                   }
02254                } else
02255                   for (i = 0; i < size; i++) {
02256                      if ((bktype & 0xFF00) == 0)
02257                         db_sprintf(pbuf, pdata, size, i, bktype & 0xFF);
02258 
02259                      else if ((bktype & 0xFF00) == TID_LRS1882)
02260                         sprintf(pbuf, "GA %d CH %02d DA %d",
02261                                 lrs1882[i].geo_addr, lrs1882[i].channel, lrs1882[i].data);
02262 
02263                      else if ((bktype & 0xFF00) == TID_PCOS3)
02264                         sprintf(pbuf, "TBD");
02265                      else
02266                         db_sprintf(pbuf, pdata, size, i, bktype & 0xFF);
02267 
02268                      strcat(pbuf, "\n");
02269                      STR_INC(pbuf, buffer);
02270                   }
02271             }
02272          }
02273 
02274       } while (1);
02275    }
02276 
02277   /*---- FIXED format ----------------------------------------------*/
02278    if (event_def->format == FORMAT_FIXED) {
02279       if (event_def->hDefKey == 0)
02280          cm_msg(MERROR, "write_event_ascii", "cannot find event definition");
02281       else {
02282          pdata = (char *) (pevent + 1);
02283          for (i = 0;; i++) {
02284             status = db_enum_key(hDB, event_def->hDefKey, i, &hKey);
02285             if (status == DB_NO_MORE_SUBKEYS)
02286                break;
02287 
02288             db_get_key(hDB, hKey, &key);
02289             sprintf(pbuf, "%s\n", key.name);
02290             STR_INC(pbuf, buffer);
02291 
02292             /* adjust for alignment */
02293             pdata = (void *) VALIGN(pdata, MIN(ss_get_struct_align(), key.item_size));
02294 
02295             for (j = 0; j < key.num_values; j++) {
02296                db_sprintf(pbuf, pdata, key.item_size, j, key.type);
02297                strcat(pbuf, "\n");
02298                STR_INC(pbuf, buffer);
02299             }
02300 
02301             /* shift data pointer to next item */
02302             pdata = (char *) pdata + key.item_size * key.num_values;
02303          }
02304       }
02305    }
02306 
02307    /* insert empty line after each event */
02308    strcat(pbuf, "\n");
02309    size = strlen(buffer);
02310 
02311    /* write record to device */
02312 #ifdef HAVE_ZLIB
02313    if (out_gzip)
02314       status = gzwrite(file, buffer, size) == size ? SS_SUCCESS : SS_FILE_ERROR;
02315    else
02316 #endif
02317       status =
02318           fwrite(buffer, 1, size, file) == (size_t) size ? SS_SUCCESS : SS_FILE_ERROR;
02319 
02320    return status;
02321 }
02322 
02323 /*---- MIDAS output ------------------------------------------------*/
02324 
02325 INT write_event_midas(FILE * file, EVENT_HEADER * pevent, ANALYZE_REQUEST * par)
02326 {
02327    INT status, size = 0, i;
02328    BOOL exclude;
02329    BANK_HEADER *pbh;
02330    BANK_LIST *pbl;
02331    EVENT_DEF *event_def;
02332    BANK *pbk;
02333    BANK32 *pbk32;
02334    char *pdata, *pdata_copy;
02335    char *pbuf;
02336    EVENT_HEADER *pevent_copy;
02337    DWORD bkname, bksize;
02338    WORD bktype;
02339    static char *buffer = NULL;
02340 
02341    if (buffer == NULL)
02342       buffer = (char *) malloc(MAX_EVENT_SIZE);
02343 
02344    pevent_copy = (EVENT_HEADER *) ALIGN8((POINTER_T) buffer);
02345 
02346    if (clp.filter) {
02347       /* use original event */
02348       size = pevent->data_size + sizeof(EVENT_HEADER);
02349       memcpy(pevent_copy, pevent, size);
02350    } else {
02351       /* copy only banks which are turned on via /analyzer/bank switches */
02352 
02353     /*---- MIDAS format ----------------------------------------------*/
02354 
02355       event_def = db_get_event_definition(pevent->event_id);
02356       if (event_def == NULL)
02357          return SUCCESS;
02358 
02359       if (event_def->format == FORMAT_MIDAS) {
02360          /* copy event header */
02361          pbuf = (char *) pevent_copy;
02362          memcpy(pbuf, pevent, sizeof(EVENT_HEADER));
02363          pbuf += sizeof(EVENT_HEADER);
02364 
02365          pbh = (BANK_HEADER *) (pevent + 1);
02366 
02367          if (bk_is32(pbh))
02368             bk_init32(pbuf);
02369          else
02370             bk_init(pbuf);
02371 
02372          pbk = NULL;
02373          pbk32 = NULL;
02374          pdata_copy = pbuf;
02375          do {
02376             /* scan all banks */
02377             if (bk_is32(pbh)) {
02378                size = bk_iterate32(pbh, &pbk32, &pdata);
02379                if (pbk32 == NULL)
02380                   break;
02381                bkname = *((DWORD *) pbk32->name);
02382                bktype = (WORD) pbk32->type;
02383                bksize = pbk32->data_size;
02384             } else {
02385                size = bk_iterate(pbh, &pbk, &pdata);
02386                if (pbk == NULL)
02387                   break;
02388                bkname = *((DWORD *) pbk->name);
02389                bktype = (WORD) pbk->type;
02390                bksize = pbk->data_size;
02391             }
02392 
02393             /* look if bank is in exclude list */
02394             exclude = FALSE;
02395             pbl = NULL;
02396             if (par->bank_list != NULL)
02397                for (i = 0; par->bank_list[i].name[0]; i++)
02398                   if (*((DWORD *) par->bank_list[i].name) == bkname) {
02399                      pbl = &par->bank_list[i];
02400                      exclude = (pbl->output_flag == 0);
02401                      break;
02402                   }
02403 
02404             if (!exclude) {
02405                /* copy bank */
02406                bk_create(pbuf, (char *) (&bkname), bktype, &pdata_copy);
02407                memcpy(pdata_copy, pdata, bksize);
02408                pdata_copy += bksize;
02409                bk_close(pbuf, pdata_copy);
02410             }
02411 
02412          } while (1);
02413 
02414          /* set event size in header */
02415          size = ALIGN8((POINTER_T) pdata_copy - (POINTER_T) pbuf);
02416          pevent_copy->data_size = size;
02417          size += sizeof(EVENT_HEADER);
02418       }
02419 
02420     /*---- FIXED format ----------------------------------------------*/
02421       if (event_def->format == FORMAT_FIXED) {
02422          size = pevent->data_size + sizeof(EVENT_HEADER);
02423          memcpy(pevent_copy, pevent, size);
02424       }
02425 
02426       if (pevent_copy->data_size == 0)
02427          return SUCCESS;
02428    }
02429 
02430    /* write record to device */
02431 #ifdef HAVE_ZLIB
02432    if (out_gzip)
02433       status = gzwrite(file, pevent_copy, size) == size ? SUCCESS : SS_FILE_ERROR;
02434    else
02435 #endif
02436       status =
02437           fwrite(pevent_copy, 1, size, file) == (size_t) size ? SUCCESS : SS_FILE_ERROR;
02438 
02439    return status;
02440 }
02441 
02442 /*---- HBOOK output ------------------------------------------------*/
02443 
02444 #ifdef HAVE_HBOOK
02445 
02446 INT write_event_hbook(FILE * file, EVENT_HEADER * pevent, ANALYZE_REQUEST * par)
02447 {
02448    INT i, j, k, n, size, item_size, status;
02449    BANK *pbk;
02450    BANK32 *pbk32;
02451    BANK_LIST *pbl;
02452    BANK_HEADER *pbh;
02453    char *pdata;
02454    BOOL exclude, exclude_all;
02455    char block_name[5], str[80];
02456    float rwnt[512];
02457    EVENT_DEF *event_def;
02458    HNDLE hkey;
02459    KEY key;
02460    DWORD bkname;
02461    WORD bktype;
02462 
02463    /* return if N-tuples are disabled */
02464    if (!ntuple_flag)
02465       return SS_SUCCESS;
02466 
02467    event_def = db_get_event_definition(pevent->event_id);
02468    if (event_def == NULL)
02469       return SS_SUCCESS;
02470 
02471    if (event_def->disabled)
02472       return SS_SUCCESS;
02473 
02474    /* fill number info */
02475    if (clp.rwnt) {
02476       memset(rwnt, 0, sizeof(rwnt));
02477       rwnt[0] = (float) current_run_number;
02478       rwnt[1] = (float) pevent->serial_number;
02479       rwnt[2] = (float) pevent->time_stamp;
02480    } else {
02481       par->number.run = current_run_number;
02482       par->number.serial = pevent->serial_number;
02483       par->number.time = pevent->time_stamp;
02484    }
02485 
02486   /*---- MIDAS format ----------------------------------------------*/
02487 
02488    if (event_def->format == FORMAT_MIDAS) {
02489       /* first fill number block */
02490       strcpy(str, "Number");
02491       if (!clp.rwnt)
02492          HFNTB(pevent->event_id, str);
02493 
02494       pbk = NULL;
02495       pbk32 = NULL;
02496       exclude_all = TRUE;
02497       do {
02498          pbh = (BANK_HEADER *) (pevent + 1);
02499          /* scan all banks */
02500          if (bk_is32(pbh)) {
02501             size = bk_iterate32(pbh, &pbk32, &pdata);
02502             if (pbk32 == NULL)
02503                break;
02504             bkname = *((DWORD *) pbk32->name);
02505             bktype = (WORD) pbk32->type;
02506          } else {
02507             size = bk_iterate(pbh, &pbk, &pdata);
02508             if (pbk == NULL)
02509                break;
02510             bkname = *((DWORD *) pbk->name);
02511             bktype = (WORD) pbk->type;
02512          }
02513 
02514          /* look if bank is in exclude list */
02515          *((DWORD *) block_name) = bkname;
02516          block_name[4] = 0;
02517 
02518          exclude = FALSE;
02519          pbl = NULL;
02520          if (par->bank_list != NULL) {
02521             for (i = 0; par->bank_list[i].name[0]; i++)
02522                if (*((DWORD *) par->bank_list[i].name) == bkname) {
02523                   pbl = &par->bank_list[i];
02524                   exclude = (pbl->output_flag == 0);
02525                   break;
02526                }
02527             if (par->bank_list[i].name[0] == 0)
02528                cm_msg(MERROR, "write_event_hbook", "Received unknown bank %s",
02529                       block_name);
02530          }
02531 
02532          /* fill CW N-tuple */
02533          if (!exclude && pbl != NULL && !clp.rwnt) {
02534             /* set array size in bank list */
02535             if ((bktype & 0xFF) != TID_STRUCT) {
02536                item_size = rpc_tid_size(bktype & 0xFF);
02537                if (item_size == 0) {
02538                   cm_msg(MERROR, "write_event_hbook",
02539                          "Received bank %s with unknown item size", block_name);
02540                   continue;
02541                }
02542 
02543                pbl->n_data = size / item_size;
02544 
02545                /* check bank size */
02546                if (pbl->n_data > pbl->size) {
02547                   cm_msg(MERROR, "write_event_hbook",
02548                          "Bank %s has more (%d) entries than maximum value (%d)",
02549                          block_name, pbl->n_data, pbl->size);
02550                   continue;
02551                }
02552 
02553                /* copy bank to buffer in bank list, DWORD aligned */
02554                if (item_size >= 4) {
02555                   size = MIN((INT) pbl->size * item_size, size);
02556                   memcpy(pbl->addr, pdata, size);
02557                } else if (item_size == 2)
02558                   for (i = 0; i < (INT) pbl->n_data; i++)
02559                      *((DWORD *) pbl->addr + i) = (DWORD) * ((WORD *) pdata + i);
02560                else if (item_size == 1)
02561                   for (i = 0; i < (INT) pbl->n_data; i++)
02562                      *((DWORD *) pbl->addr + i) = (DWORD) * ((BYTE *) pdata + i);
02563             } else {
02564                /* hope that structure members are aligned as HBOOK thinks ... */
02565                memcpy(pbl->addr, pdata, size);
02566             }
02567 
02568             /* fill N-tuple */
02569             HFNTB(pevent->event_id, block_name);
02570          }
02571 
02572          /* fill RW N-tuple */
02573          if (!exclude && pbl != NULL && clp.rwnt) {
02574             exclude_all = FALSE;
02575 
02576             item_size = rpc_tid_size(bktype & 0xFF);
02577             /* set array size in bank list */
02578             if ((bktype & 0xFF) != TID_STRUCT) {
02579                n = size / item_size;
02580 
02581                /* check bank size */
02582                if (n > (INT) pbl->size) {
02583                   cm_msg(MERROR, "write_event_hbook",
02584                          "Bank %s has more (%d) entries than maximum value (%d)",
02585                          block_name, n, pbl->size);
02586                   continue;
02587                }
02588 
02589                /* convert bank to float values */
02590                for (i = 0; i < n; i++) {
02591                   switch (bktype & 0xFF) {
02592                   case TID_BYTE:
02593                      rwnt[pbl->n_data + i] = (float) (*((BYTE *) pdata + i));
02594                      break;
02595                   case TID_WORD:
02596                      rwnt[pbl->n_data + i] = (float) (*((WORD *) pdata + i));
02597                      break;
02598                   case TID_DWORD:
02599                      rwnt[pbl->n_data + i] = (float) (*((DWORD *) pdata + i));
02600                      break;
02601                   case TID_FLOAT:
02602                      rwnt[pbl->n_data + i] = (float) (*((float *) pdata + i));
02603                      break;
02604                   case TID_DOUBLE:
02605                      rwnt[pbl->n_data + i] = (float) (*((double *) pdata + i));
02606                      break;
02607                   }
02608                }
02609 
02610                /* zero padding */
02611                for (; i < (INT) pbl->size; i++)
02612                   rwnt[pbl->n_data + i] = 0.f;
02613             } else {
02614                /* fill N-tuple from structured bank */
02615                k = pbl->n_data;
02616 
02617                for (i = 0;; i++) {
02618                   status = db_enum_key(hDB, pbl->def_key, i, &hkey);
02619                   if (status == DB_NO_MORE_SUBKEYS)
02620                      break;
02621 
02622                   db_get_key(hDB, hkey, &key);
02623 
02624                   /* align data pointer */
02625                   pdata =
02626                       (void *) VALIGN(pdata, MIN(ss_get_struct_align(), key.item_size));
02627 
02628                   for (j = 0; j < key.num_values; j++) {
02629                      switch (key.type & 0xFF) {
02630                      case TID_BYTE:
02631                         rwnt[k++] = (float) (*((BYTE *) pdata + j));
02632                         break;
02633                      case TID_WORD:
02634                         rwnt[k++] = (float) (*((WORD *) pdata + j));
02635                         break;
02636                      case TID_SHORT:
02637                         rwnt[k++] = (float) (*((short int *) pdata + j));
02638                         break;
02639                      case TID_INT:
02640                         rwnt[k++] = (float) (*((INT *) pdata + j));
02641                         break;
02642                      case TID_DWORD:
02643                         rwnt[k++] = (float) (*((DWORD *) pdata + j));
02644                         break;
02645                      case TID_BOOL:
02646                         rwnt[k++] = (float) (*((BOOL *) pdata + j));
02647                         break;
02648                      case TID_FLOAT:
02649                         rwnt[k++] = (float) (*((float *) pdata + j));
02650                         break;
02651                      case TID_DOUBLE:
02652                         rwnt[k++] = (float) (*((double *) pdata + j));
02653                         break;
02654                      }
02655                   }
02656 
02657                   /* shift data pointer to next item */
02658                   pdata += key.item_size * key.num_values * sizeof(char);
02659                }
02660             }
02661          }
02662 
02663       } while (TRUE);
02664 
02665       /* fill RW N-tuple */
02666       if (clp.rwnt && file != NULL && !exclude_all)
02667          HFN(pevent->event_id, rwnt);
02668 
02669       /* fill shared memory */
02670       if (file == NULL)
02671          HFNOV(pevent->event_id, rwnt);
02672 
02673    }
02674 
02675 
02676    /* if (event_def->format == FORMAT_MIDAS) */
02677  /*---- YBOS format ----------------------------------------------*/
02678    else if (event_def->format == FORMAT_YBOS) {
02679      assert(!"YBOS not supported anymore");
02680    }
02681 
02682 
02683  /*---- FIXED format ----------------------------------------------*/
02684    if (event_def->format == FORMAT_FIXED) {
02685       if (clp.rwnt) {
02686          /* fill N-tuple from structured bank */
02687          pdata = (char *) (pevent + 1);
02688          k = 3;                 /* index 0..2 for run/serial/time */
02689 
02690          for (i = 0;; i++) {
02691             status = db_enum_key(hDB, event_def->hDefKey, i, &hkey);
02692             if (status == DB_NO_MORE_SUBKEYS)
02693                break;
02694 
02695             db_get_key(hDB, hkey, &key);
02696 
02697             /* align data pointer */
02698             pdata = (void *) VALIGN(pdata, MIN(ss_get_struct_align(), key.item_size));
02699 
02700             for (j = 0; j < key.num_values; j++) {
02701                switch (key.type & 0xFF) {
02702                case TID_BYTE:
02703                   rwnt[k++] = (float) (*((BYTE *) pdata + j));
02704                   break;
02705                case TID_WORD:
02706                   rwnt[k++] = (float) (*((WORD *) pdata + j));
02707                   break;
02708                case TID_SHORT:
02709                   rwnt[k++] = (float) (*((short int *) pdata + j));
02710                   break;
02711                case TID_INT:
02712                   rwnt[k++] = (float) (*((INT *) pdata + j));
02713                   break;
02714                case TID_DWORD:
02715                   rwnt[k++] = (float) (*((DWORD *) pdata + j));
02716                   break;
02717                case TID_BOOL:
02718                   rwnt[k++] = (float) (*((BOOL *) pdata + j));
02719                   break;
02720                case TID_FLOAT:
02721                   rwnt[k++] = (float) (*((float *) pdata + j));
02722                   break;
02723                case TID_DOUBLE:
02724                   rwnt[k++] = (float) (*((double *) pdata + j));
02725                   break;
02726                }
02727             }
02728 
02729             /* shift data pointer to next item */
02730             pdata += key.item_size * key.num_values * sizeof(char);
02731          }
02732 
02733          /* fill RW N-tuple */
02734          if (file != NULL)
02735             HFN(pevent->event_id, rwnt);
02736 
02737          /* fill shared memory */
02738          if (file == NULL)
02739             HFNOV(pevent->event_id, rwnt);
02740       } else {
02741          memcpy(par->addr, pevent + 1, pevent->data_size);
02742 
02743          /* fill N-tuple */
02744          HFNT(pevent->event_id);
02745       }
02746 
02747    }
02748 
02749    return SUCCESS;
02750 }
02751 #endif                          /* HAVE_HBOOK */
02752 
02753 /*---- ROOT output -------------------------------------------------*/
02754 
02755 #ifdef USE_ROOT
02756 
02757 INT write_event_ttree(FILE * file, EVENT_HEADER * pevent, ANALYZE_REQUEST * par)
02758 {
02759    INT i, bklen;
02760    BANK *pbk;
02761    BANK32 *pbk32;
02762    BANK_LIST *pbl;
02763    BANK_HEADER *pbh;
02764    void *pdata;
02765    BOOL exclude, exclude_all;
02766    char bank_name[5];
02767    EVENT_DEF *event_def;
02768    DWORD bkname;
02769    WORD bktype;
02770    EVENT_TREE *et;
02771    TBranch *branch;
02772 
02773    /* return if N-tuples are disabled */
02774    if (!ntuple_flag)
02775       return SS_SUCCESS;
02776 
02777    event_def = db_get_event_definition(pevent->event_id);
02778    if (event_def == NULL)
02779       return SS_SUCCESS;
02780 
02781    if (event_def->disabled)
02782       return SS_SUCCESS;
02783 
02784    /* fill number info */
02785    par->number.run = current_run_number;
02786    par->number.serial = pevent->serial_number;
02787    par->number.time = pevent->time_stamp;
02788 
02789   /*---- MIDAS format ----------------------------------------------*/
02790 
02791    if (event_def->format == FORMAT_MIDAS) {
02792       /* find event in tree structure */
02793       for (i = 0; i < tree_struct.n_tree; i++)
02794          if (tree_struct.event_tree[i].event_id == pevent->event_id)
02795             break;
02796 
02797       if (i == tree_struct.n_tree) {
02798          cm_msg(MERROR, "write_event_ttree", "Event #%d not booked by book_ttree()",
02799                 pevent->event_id);
02800          return SS_INVALID_FORMAT;
02801       }
02802 
02803       et = tree_struct.event_tree + i;
02804 
02805       /* first mark all banks non-filled */
02806       for (i = 0; i < et->n_branch; i++)
02807          et->branch_filled[i] = FALSE;
02808 
02809       /* first fill number block */
02810       et->branch_filled[0] = TRUE;
02811 
02812       pbk = NULL;
02813       pbk32 = NULL;
02814       exclude_all = TRUE;
02815       do {
02816          pbh = (BANK_HEADER *) (pevent + 1);
02817          /* scan all banks */
02818          if (bk_is32(pbh)) {
02819             bklen = bk_iterate32(pbh, &pbk32, &pdata);
02820             if (pbk32 == NULL)
02821                break;
02822             bkname = *((DWORD *) pbk32->name);
02823             bktype = (WORD) pbk32->type;
02824          } else {
02825             bklen = bk_iterate(pbh, &pbk, &pdata);
02826             if (pbk == NULL)
02827                break;
02828             bkname = *((DWORD *) pbk->name);
02829             bktype = (WORD) pbk->type;
02830          }
02831 
02832          if (rpc_tid_size(bktype & 0xFF))
02833             bklen /= rpc_tid_size(bktype & 0xFF);
02834 
02835          /* look if bank is in exclude list */
02836          *((DWORD *) bank_name) = bkname;
02837          bank_name[4] = 0;
02838 
02839          exclude = FALSE;
02840          pbl = NULL;
02841          if (par->bank_list != NULL) {
02842             for (i = 0; par->bank_list[i].name[0]; i++)
02843                if (*((DWORD *) par->bank_list[i].name) == bkname) {
02844                   pbl = &par->bank_list[i];
02845                   exclude = (pbl->output_flag == 0);
02846                   break;
02847                }
02848             if (par->bank_list[i].name[0] == 0) {
02849                cm_msg(MERROR, "write_event_ttree", "Received unknown bank %s", bank_name);
02850                continue;
02851             }
02852          }
02853 
02854          /* fill leaf */
02855          if (!exclude && pbl != NULL) {
02856             for (i = 0; i < et->n_branch; i++)
02857                if (*((DWORD *) (&et->branch_name[i * NAME_LENGTH])) == bkname)
02858                   break;
02859 
02860             if (i == et->n_branch) {
02861                cm_msg(MERROR, "write_event_ttree", "Received unknown bank %s", bank_name);
02862                continue;
02863             }
02864 
02865             exclude_all = FALSE;
02866             branch = et->branch[i];
02867             et->branch_filled[i] = TRUE;
02868             et->branch_len[i] = bklen;
02869 
02870             /* structured bank */
02871             if ((bktype & 0xFF) != TID_STRUCT) {
02872                TIter next(branch->GetListOfLeaves());
02873                TLeaf *leaf = (TLeaf *) next();
02874 
02875                /* varibale length array */
02876                leaf->SetAddress(&et->branch_len[i]);
02877 
02878                leaf = (TLeaf *) next();
02879                leaf->SetAddress(pdata);
02880             } else {
02881                /* hope that structure members are aligned as TTREE thinks ... */
02882                branch->SetAddress(pdata);
02883             }
02884          }
02885 
02886       } while (TRUE);
02887 
02888       /* check if all branches have been filled */
02889       for (i = 0; i < et->n_branch; i++)
02890          if (!et->branch_filled[i])
02891             cm_msg(MERROR, "root_write",
02892                    "Bank %s booked but not received, tree cannot be filled",
02893                    et->branch_name + (i * NAME_LENGTH));
02894 
02895       /* delete tree if too many entries, will be obsolete with cyglic trees later */
02896 #if (ROOT_VERSION_CODE < 262401)
02897       if (clp.online && et->tree->GetEntries() > par->rwnt_buffer_size)
02898          et->tree->Reset();
02899 #endif
02900 
02901       /* fill tree both online and offline */
02902       if (!exclude_all)
02903          et->tree->Fill();
02904 
02905    }                            // if (event_def->format == FORMAT_MIDAS)
02906 
02907    /*---- FIXED format ----------------------------------------------*/
02908 
02909    if (event_def->format == FORMAT_FIXED) {
02910       /* find event in tree structure */
02911       for (i = 0; i < tree_struct.n_tree; i++)
02912          if (tree_struct.event_tree[i].event_id == pevent->event_id)
02913             break;
02914 
02915       if (i == tree_struct.n_tree) {
02916          cm_msg(MERROR, "write_event_ttree", "Event #%d not booked by book_ttree()",
02917                 pevent->event_id);
02918          return SS_INVALID_FORMAT;
02919       }
02920 
02921       et = tree_struct.event_tree + i;
02922 
02923       et->tree->GetBranch(et->branch_name)->SetAddress(pevent + 1);
02924       et->tree->Fill();
02925    }
02926 
02927    return SUCCESS;
02928 }
02929 
02930 #endif                          /* USE_ROOT */
02931 
02932 /*---- ODB output --------------------------------------------------*/
02933 
02934 INT write_event_odb(EVENT_HEADER * pevent)
02935 {
02936    INT status, size, n_data, i;
02937    BANK_HEADER *pbh;
02938    EVENT_DEF *event_def;
02939    BANK *pbk;
02940    BANK32 *pbk32;
02941    void *pdata;
02942    char name[5];
02943    HNDLE hKeyRoot, hKey;
02944    KEY key;
02945    DWORD bkname;
02946    WORD bktype;
02947 
02948    event_def = db_get_event_definition(pevent->event_id);
02949    if (event_def == NULL)
02950       return SS_SUCCESS;
02951 
02952    /*---- MIDAS format ----------------------------------------------*/
02953 
02954    if (event_def->format == FORMAT_MIDAS) {
02955       pbh = (BANK_HEADER *) (pevent + 1);
02956       pbk = NULL;
02957       pbk32 = NULL;
02958       do {
02959          /* scan all banks */
02960          if (bk_is32(pbh)) {
02961             size = bk_iterate32(pbh, &pbk32, &pdata);
02962             if (pbk32 == NULL)
02963                break;
02964             bkname = *((DWORD *) pbk32->name);
02965             bktype = (WORD) pbk32->type;
02966          } else {
02967             size = bk_iterate(pbh, &pbk, &pdata);
02968             if (pbk == NULL)
02969                break;
02970             bkname = *((DWORD *) pbk->name);
02971             bktype = (WORD) pbk->type;
02972          }
02973 
02974          n_data = size;
02975          if (rpc_tid_size(bktype & 0xFF))
02976             n_data /= rpc_tid_size(bktype & 0xFF);
02977 
02978          /* get bank key */
02979          *((DWORD *) name) = bkname;
02980          name[4] = 0;
02981 
02982          status = db_find_key(hDB, event_def->hDefKey, name, &hKeyRoot);
02983          if (status != DB_SUCCESS) {
02984             cm_msg(MERROR, "write_event_odb", "received unknown bank %s", name);
02985             continue;
02986          }
02987 
02988          if (bktype == TID_STRUCT) {
02989             /* write structured bank */
02990             for (i = 0;; i++) {
02991                status = db_enum_key(hDB, hKeyRoot, i, &hKey);
02992                if (status == DB_NO_MORE_SUBKEYS)
02993                   break;
02994 
02995                db_get_key(hDB, hKey, &key);
02996 
02997                /* adjust for alignment */
02998                if (key.type != TID_STRING && key.type != TID_LINK)
02999                   pdata =
03000                       (void *) VALIGN(pdata, MIN(ss_get_struct_align(), key.item_size));
03001 
03002                status = db_set_data(hDB, hKey, pdata, key.item_size * key.num_values,
03003                                     key.num_values, key.type);
03004                if (status != DB_SUCCESS) {
03005                   cm_msg(MERROR, "write_event_odb", "cannot write %s to ODB", name);
03006                   continue;
03007                }
03008 
03009                /* shift data pointer to next item */
03010                pdata = (char *) pdata + key.item_size * key.num_values;
03011             }
03012          } else {
03013             db_get_key(hDB, hKeyRoot, &key);
03014 
03015             /* write variable length bank  */
03016             if (n_data > 0) {
03017                status = db_set_data(hDB, hKeyRoot, pdata, size, n_data, key.type);
03018                if (status != DB_SUCCESS) {
03019                   cm_msg(MERROR, "write_event_odb", "cannot write %s to ODB", name);
03020                   continue;
03021                }
03022             }
03023          }
03024       } while (1);
03025    }
03026 
03027    /*---- FIXED format ----------------------------------------------*/
03028 
03029    if (event_def->format == FORMAT_FIXED && !clp.online) {
03030       if (db_set_record
03031           (hDB, event_def->hDefKey, (char *) (pevent + 1), pevent->data_size,
03032            0) != DB_SUCCESS)
03033          cm_msg(MERROR, "write_event_odb", "event #%d size mismatch", pevent->event_id);
03034    }
03035 
03036    return SUCCESS;
03037 }
03038 
03039 /*------------------------------------------------------------------*/
03040 
03041 static struct {
03042    short int event_id;
03043    DWORD last_time;
03044 } last_time_event[50];
03045 
03046 ANALYZE_REQUEST *_current_par;
03047 
03048 void correct_num_events(INT i)
03049 {
03050    if (_current_par)
03051       _current_par->events_received += i - 1;
03052 }
03053 
03054 INT process_event(ANALYZE_REQUEST * par, EVENT_HEADER * pevent)
03055 {
03056    INT i, status = SUCCESS, ch;
03057    ANA_MODULE **module;
03058    DWORD actual_time;
03059    EVENT_DEF *event_def;
03060    static DWORD last_time_kb = 0;
03061    static char *orig_event = NULL;
03062 
03063    /* verbose output */
03064    if (clp.verbose)
03065       printf("event %d, number %d, total size %d\n",
03066              (int) pevent->event_id,
03067              (int) pevent->serial_number,
03068              (int) (pevent->data_size + sizeof(EVENT_HEADER)));
03069 
03070    /* save analyze_request for event number correction */
03071    _current_par = par;
03072 
03073    /* check keyboard once every second */
03074    actual_time = ss_millitime();
03075    if (!clp.online && actual_time - last_time_kb > 1000 && !clp.quiet && !pvm_slave) {
03076       last_time_kb = actual_time;
03077 
03078       while (ss_kbhit()) {
03079          ch = ss_getchar(0);
03080          if (ch == -1)
03081             ch = getchar();
03082 
03083          if ((char) ch == '!')
03084             return RPC_SHUTDOWN;
03085       }
03086    }
03087 
03088    if (par == NULL) {
03089       /* load ODB with BOR event */
03090       if (pevent->event_id == EVENTID_BOR) {
03091          /* get run number from BOR event */
03092          current_run_number = pevent->serial_number;
03093 
03094          cm_msg(MINFO, "process_event", "Set run number %d in ODB", current_run_number);
03095          assert(current_run_number > 0);
03096 
03097          /* set run number in ODB */
03098          status = db_set_value(hDB, 0, "/Runinfo/Run number", &current_run_number,
03099                                sizeof(current_run_number), 1, TID_INT);
03100          assert(status == SUCCESS);
03101 
03102          /* load ODB from event */
03103          odb_load(pevent);
03104 
03105 #ifdef HAVE_PVM
03106          PVM_DEBUG("process_event: ODB load");
03107 #endif
03108       }
03109    } else
03110       /* increment event counter */
03111       par->events_received++;
03112 
03113 #ifdef HAVE_PVM
03114 
03115    /* if master, distribute events to clients */
03116    if (pvm_master) {
03117       status = pvm_distribute(par, pevent);
03118       return status;
03119    }
03120 #endif
03121 
03122    /* don't analyze special (BOR,MESSAGE,...) events */
03123    if (par == NULL)
03124       return SUCCESS;
03125 
03126    /* swap event if necessary */
03127    event_def = db_get_event_definition(pevent->event_id);
03128    if (event_def == NULL)
03129       return 0;
03130 
03131    if (event_def->format == FORMAT_MIDAS)
03132       bk_swap((BANK_HEADER *) (pevent + 1), FALSE);
03133 
03134    /* keep copy of original event */
03135    if (clp.filter) {
03136       if (orig_event == NULL)
03137          orig_event = (char *) malloc(MAX_EVENT_SIZE + sizeof(EVENT_HEADER));
03138       memcpy(orig_event, pevent, pevent->data_size + sizeof(EVENT_HEADER));
03139    }
03140 
03141   /*---- analyze event ----*/
03142 
03143    /* call non-modular analyzer if defined */
03144    if (par->analyzer) {
03145       status = par->analyzer(pevent, (void *) (pevent + 1));
03146 
03147       /* don't continue if event was rejected */
03148       if (status == ANA_SKIP)
03149          return 0;
03150    }
03151 
03152    /* loop over analyzer modules */
03153    module = par->ana_module;
03154    for (i = 0; module != NULL && module[i] != NULL; i++) {
03155       if (module[i]->enabled) {
03156 
03157          status = module[i]->analyzer(pevent, (void *) (pevent + 1));
03158 
03159          /* don't continue if event was rejected */
03160          if (status == ANA_SKIP)
03161             return 0;
03162       }
03163    }
03164 
03165    if (event_def->format == FORMAT_MIDAS) {
03166       /* check if event got too large */
03167       i = bk_size(pevent + 1);
03168       if (i > MAX_EVENT_SIZE)
03169          cm_msg(MERROR, "process_event", "Event got too large (%d Bytes) in analyzer", i);
03170 
03171       /* correct for increased event size */
03172       pevent->data_size = i;
03173    }
03174 
03175    if (event_def->format == FORMAT_YBOS) {
03176      assert(!"YBOS not supported anymore");
03177    }
03178 
03179    /* increment tests */
03180    if (par->use_tests)
03181       test_increment();
03182 
03183    /* in filter mode, use original event */
03184    if (clp.filter)
03185       pevent = (EVENT_HEADER *) orig_event;
03186 
03187    /* write resulting event */
03188    if (out_file) {
03189 #ifdef HAVE_HBOOK
03190       if (out_format == FORMAT_HBOOK)
03191          status = write_event_hbook(out_file, pevent, par);
03192 #endif                          /* HAVE_HBOOK */
03193 #ifdef USE_ROOT
03194       if (out_format == FORMAT_ROOT)
03195          status = write_event_ttree(out_file, pevent, par);
03196 #endif                          /* USE_ROOT */
03197       if (out_format == FORMAT_ASCII)
03198          status = write_event_ascii(out_file, pevent, par);
03199       if (out_format == FORMAT_MIDAS)
03200          status = write_event_midas(out_file, pevent, par);
03201 
03202       if (status != SUCCESS) {
03203          cm_msg(MERROR, "process_event", "Error writing to file (Disk full?)");
03204          return -1;
03205       }
03206 
03207       par->events_written++;
03208    }
03209 #ifdef HAVE_HBOOK
03210    /* fill shared memory */
03211    if ((clp.online || equal_ustring(clp.output_file_name, "OFLN"))
03212        && par->rwnt_buffer_size > 0)
03213       write_event_hbook(NULL, pevent, par);
03214 #endif                          /* HAVE_HBOOK */
03215 #ifdef USE_ROOT
03216    /* fill tree, should later be replaced by cyclic filling once it's implemented in ROOT */
03217    if (clp.online && par->rwnt_buffer_size > 0)
03218       write_event_ttree(NULL, pevent, par);
03219 #endif
03220 
03221 
03222    /* put event in ODB once every second */
03223    if (out_info.events_to_odb)
03224       for (i = 0; i < 50; i++) {
03225          if (last_time_event[i].event_id == pevent->event_id) {
03226             if (event_def->type == EQ_PERIODIC ||
03227                 event_def->type == EQ_SLOW
03228                 || actual_time - last_time_event[i].last_time > 1000) {
03229                last_time_event[i].last_time = actual_time;
03230                write_event_odb(pevent);
03231             }
03232             break;
03233          }
03234          if (last_time_event[i].event_id == 0) {
03235             last_time_event[i].event_id = pevent->event_id;
03236             last_time_event[i].last_time = actual_time;
03237             write_event_odb(pevent);
03238             break;
03239          }
03240       }
03241 
03242    return SUCCESS;
03243 }
03244 
03245 /*------------------------------------------------------------------*/
03246 
03247 void receive_event(HNDLE buffer_handle, HNDLE request_id, EVENT_HEADER * pheader,
03248                    void *pevent)
03249 /* receive online event */
03250 {
03251    INT i;
03252    ANALYZE_REQUEST *par;
03253    static DWORD buffer_size = 0;
03254    static char *buffer = NULL;
03255    char *pb;
03256 
03257    if (buffer == NULL) {
03258       buffer = (char *) malloc(MAX_EVENT_SIZE + sizeof(EVENT_HEADER));
03259 
03260       if (buffer == NULL) {
03261          cm_msg(MERROR, "receive_event", "Not enough memory to buffer event of size %d",
03262                 buffer_size);
03263          return;
03264       }
03265    }
03266 
03267    /* align buffer */
03268    pb = (char *) ALIGN8((POINTER_T) buffer);
03269 
03270    /* copy event to local buffer */
03271    memcpy(pb, pheader, pheader->data_size + sizeof(EVENT_HEADER));
03272 
03273    par = analyze_request;
03274 
03275    for (i = 0; par->event_name[0]; par++)
03276       if (par->buffer_handle == buffer_handle && par->request_id == request_id) {
03277          process_event(par, (EVENT_HEADER *) pb);
03278       }
03279 }
03280 
03281 /*------------------------------------------------------------------*/
03282 
03283 void update_request(HNDLE hDB, HNDLE hKey, void *info)
03284 {
03285    AR_INFO *ar_info;
03286    INT i;
03287 
03288    if (!clp.online)
03289       return;
03290 
03291    /* check which request's key has changed */
03292    for (i = 0; analyze_request[i].event_name[0]; i++)
03293       if (analyze_request[i].hkey_common == hKey) {
03294          ar_info = &analyze_request[i].ar_info;
03295 
03296          /* remove previous request */
03297          if (analyze_request[i].request_id != -1)
03298             bm_delete_request(analyze_request[i].request_id);
03299 
03300          /* if enabled, add new request */
03301          if (ar_info->enabled)
03302             bm_request_event(analyze_request[i].buffer_handle, (short) ar_info->event_id,
03303                              (short) ar_info->trigger_mask, ar_info->sampling_type,
03304                              &analyze_request[i].request_id, receive_event);
03305          else
03306             analyze_request[i].request_id = -1;
03307       }
03308 
03309 }
03310 
03311 /*------------------------------------------------------------------*/
03312 
03313 void register_requests(void)
03314 {
03315    INT index, status;
03316    char str[256];
03317    AR_INFO *ar_info;
03318    AR_STATS *ar_stats;
03319    HNDLE hKey;
03320 
03321    /* scan ANALYZE_REQUEST table from ANALYZE.C */
03322    for (index = 0; analyze_request[index].event_name[0]; index++) {
03323       ar_info = &analyze_request[index].ar_info;
03324       ar_stats = &analyze_request[index].ar_stats;
03325 
03326       /* create common subtree from analyze_request table in analyze.c */
03327       sprintf(str, "/%s/%s/Common", analyzer_name, analyze_request[index].event_name);
03328       db_check_record(hDB, 0, str, ANALYZER_REQUEST_STR, TRUE);
03329       db_find_key(hDB, 0, str, &hKey);
03330       analyze_request[index].hkey_common = hKey;
03331 
03332       strcpy(ar_info->client_name, analyzer_name);
03333       gethostname(ar_info->host, sizeof(ar_info->host));
03334       db_set_record(hDB, hKey, ar_info, sizeof(AR_INFO), 0);
03335 
03336       /* open hot link to analyzer request info */
03337       db_open_record(hDB, hKey, ar_info, sizeof(AR_INFO), MODE_READ, update_request,
03338                      NULL);
03339 
03340       /* create statistics tree */
03341       sprintf(str, "/%s/%s/Statistics", analyzer_name, analyze_request[index].event_name);
03342       db_check_record(hDB, 0, str, ANALYZER_STATS_STR, TRUE);
03343       db_find_key(hDB, 0, str, &hKey);
03344       assert(hKey);
03345 
03346       ar_stats->events_received = 0;
03347       ar_stats->events_per_sec = 0;
03348       ar_stats->events_written = 0;
03349 
03350       /* open hot link to statistics tree */
03351       status =
03352           db_open_record(hDB, hKey, ar_stats, sizeof(AR_STATS), MODE_WRITE, NULL, NULL);
03353       if (status != DB_SUCCESS)
03354          printf("Cannot open statistics record, probably other analyzer is using it\n");
03355 
03356       if (clp.online) {
03357          /*---- open event buffer ---------------------------------------*/
03358          bm_open_buffer(ar_info->buffer, 2*MAX_EVENT_SIZE,
03359                         &analyze_request[index].buffer_handle);
03360 
03361          /* set the default buffer cache size */
03362          bm_set_cache_size(analyze_request[index].buffer_handle, 100000, 0);
03363 
03364          /*---- request event -------------------------------------------*/
03365          if (ar_info->enabled)
03366             bm_request_event(analyze_request[index].buffer_handle,
03367                              (short) ar_info->event_id, (short) ar_info->trigger_mask,
03368                              ar_info->sampling_type, &analyze_request[index].request_id,
03369                              receive_event);
03370          else
03371             analyze_request[index].request_id = -1;
03372       }
03373    }
03374 }
03375 
03376 /*------------------------------------------------------------------*/
03377 
03378 void update_stats()
03379 {
03380    int i;
03381    AR_STATS *ar_stats;
03382    static DWORD last_time = 0;
03383    DWORD actual_time;
03384 
03385    actual_time = ss_millitime();
03386 
03387    if (last_time == 0)
03388       last_time = actual_time;
03389 
03390    if (actual_time - last_time == 0)
03391       return;
03392 
03393    for (i = 0; analyze_request[i].event_name[0]; i++) {
03394       ar_stats = &analyze_request[i].ar_stats;
03395       ar_stats->events_received += analyze_request[i].events_received;
03396       ar_stats->events_written += analyze_request[i].events_written;
03397       ar_stats->events_per_sec =
03398           (analyze_request[i].events_received / ((actual_time - last_time) / 1000.0));
03399       analyze_request[i].events_received = 0;
03400       analyze_request[i].events_written = 0;
03401    }
03402 
03403    /* propagate new statistics to ODB */
03404    db_send_changed_records();
03405 
03406    /* save tests in ODB */
03407    test_write(actual_time - last_time);
03408 
03409    last_time = actual_time;
03410 }
03411 
03412 /*-- Book histos --------------------------------------------------*/
03413 
03414 #ifdef USE_ROOT
03415 
03416 /* h1_book and h2_book are now templates in midas.h */
03417 
03418 //==============================================================================
03419 
03420 TCutG *cut_book(const char *name)
03421 {
03422 
03423 //------------------------------------------------------------------------------
03424 
03425    open_subfolder("cuts");
03426 
03427    TFolder *folder(gHistoFolderStack->Last()? (TFolder *) gHistoFolderStack->
03428                    Last() : gManaHistosFolder);
03429 
03430    TCutG *cut((TCutG *) folder->FindObject(name));
03431 
03432    if (!cut) {
03433       cut = new TCutG();
03434       cut->SetName(name);
03435       folder->Add(cut);
03436    }
03437 
03438    close_subfolder();
03439    return cut;
03440 }
03441 
03442 void open_subfolder(char *name)
03443 {
03444 
03445    TFolder *current = (TFolder *) gHistoFolderStack->Last();
03446 
03447    if (!current)
03448       current = gManaHistosFolder;
03449 
03450    // if the subfolder already exists, use it
03451    TFolder *subfolder = 0;
03452 
03453    TCollection *listOfSubFolders = current->GetListOfFolders();
03454    TIter iter(listOfSubFolders);
03455    while (TObject * obj = iter()) {
03456       if (strcmp(obj->GetName(), name) == 0 && obj->InheritsFrom("TFolder"))
03457          subfolder = (TFolder *) obj;
03458    }
03459 
03460    if (!subfolder) {
03461       subfolder = new TFolder(name, name);
03462       current->Add(subfolder);
03463    }
03464 
03465    gHistoFolderStack->Add(subfolder);
03466 }
03467 
03468 void close_subfolder()
03469 {
03470    if (gHistoFolderStack->Last())
03471       gHistoFolderStack->Remove(gHistoFolderStack->Last());
03472 }
03473 
03474 #endif
03475 
03476 /*-- Clear histos --------------------------------------------------*/
03477 #ifdef HAVE_HBOOK
03478 INT clear_histos_hbook(INT id1, INT id2)
03479 {
03480    INT i;
03481 
03482    if (id1 != id2) {
03483       printf("Clear ID %d to ID %d\n", id1, id2);
03484       for (i = id1; i <= id2; i++)
03485          if (HEXIST(i))
03486             HRESET(i, bstr);
03487    } else {
03488       printf("Clear ID %d\n", id1);
03489       HRESET(id1, bstr);
03490    }
03491 
03492    return SUCCESS;
03493 }
03494 #endif                          /* HAVE_HBOOK */
03495 
03496 /*------------------------------------------------------------------*/
03497 
03498 void lock_histo(INT id)
03499 {
03500    INT i;
03501 
03502    for (i = 0; i < 10000; i++)
03503       if (lock_list[i] == 0)
03504          break;
03505 
03506    lock_list[i] = id;
03507 }
03508 
03509 /*------------------------------------------------------------------*/
03510 
03511 #ifdef HAVE_HBOOK
03512 INT ana_callback(INT index, void *prpc_param[])
03513 {
03514    if (index == RPC_ANA_CLEAR_HISTOS)
03515       clear_histos_hbook(CINT(0), CINT(1));
03516    return RPC_SUCCESS;
03517 }
03518 #endif
03519 
03520 /*------------------------------------------------------------------*/
03521 
03522 void load_last_histos()
03523 {
03524    char str[256];
03525 
03526    /* load previous online histos */
03527    if (!clp.no_load) {
03528       strcpy(str, out_info.last_histo_filename);
03529 
03530       if (strchr(str, DIR_SEPARATOR) == NULL)
03531          add_data_dir(str, out_info.last_histo_filename);
03532 
03533 #ifdef HAVE_HBOOK
03534       {
03535          FILE *f;
03536          char str2[256];
03537          int i;
03538 
03539          for (i = 0; i < (int) strlen(str); i++)
03540             if (isupper(str[i]))
03541                break;
03542 
03543          if (i < (int) strlen(str)) {
03544             printf
03545                 ("Error: Due to a limitation in HBOOK, directoy names may not contain uppercase\n");
03546             printf("       characters. Histogram loading from %s will not work.\n", str);
03547          } else {
03548             f = fopen(str, "r");
03549             if (f != NULL) {
03550                fclose(f);
03551                printf("Loading previous online histos from %s\n", str);
03552                strcpy(str2, "A");
03553                HRGET(0, str, str2);
03554 
03555                /* fix wrongly booked N-tuples at ID 100000 */
03556                if (HEXIST(100000))
03557                   HDELET(100000);
03558             }
03559          }
03560       }
03561 #endif                          /* HAVE_HBOOK */
03562 
03563 #ifdef USE_ROOT
03564       printf("Loading previous online histos from %s\n", str);
03565       LoadRootHistograms(gManaHistosFolder, str);
03566 #endif
03567    }
03568 }
03569 
03570 /*------------------------------------------------------------------*/
03571 
03572 void save_last_histos()
03573 {
03574    char str[256];
03575 
03576    /* save online histos */
03577    strcpy(str, out_info.last_histo_filename);
03578    if (strchr(str, DIR_SEPARATOR) == NULL)
03579       add_data_dir(str, out_info.last_histo_filename);
03580 
03581    printf("Saving current online histos to %s\n", str);
03582 
03583 #ifdef HAVE_HBOOK
03584    {
03585       int i;
03586       char str2[256];
03587 
03588       for (i = 0; i < (int) strlen(str); i++)
03589          if (isupper(str[i]))
03590             break;
03591 
03592       if (i < (int) strlen(str)) {
03593          printf
03594              ("Error: Due to a limitation in HBOOK, directoy names may not contain uppercase\n");
03595          printf("       characters. Histogram saving to %s will not work.\n", str);
03596       } else {
03597          strcpy(str2, "NT");
03598          HRPUT(0, str, str2);
03599       }
03600    }
03601 #endif
03602 
03603 #ifdef USE_ROOT
03604    SaveRootHistograms(gManaHistosFolder, str);
03605 #endif
03606 
03607 }
03608 
03609 /*------------------------------------------------------------------*/
03610 
03611 INT loop_online()
03612 {
03613    INT status = SUCCESS;
03614    DWORD last_time_loop, last_time_update, actual_time;
03615    int ch;
03616 
03617    printf("Running analyzer online. Stop with \"!\"\n");
03618 
03619    /* main loop */
03620    last_time_update = 0;
03621    last_time_loop = 0;
03622 
03623    do {
03624       /* calculate events per second */
03625       actual_time = ss_millitime();
03626 
03627       if (actual_time - last_time_update > 1000) {
03628          /* update statistics */
03629          update_stats();
03630          last_time_update = actual_time;
03631 
03632          /* check keyboard */
03633          ch = 0;
03634          while (ss_kbhit()) {
03635             ch = ss_getchar(0);
03636             if (ch == -1)
03637                ch = getchar();
03638 
03639             if ((char) ch == '!')
03640                break;
03641          }
03642 
03643          if ((char) ch == '!')
03644             break;
03645       }
03646 
03647       if (analyzer_loop_period == 0)
03648          status = cm_yield(1000);
03649       else {
03650          if (actual_time - last_time_loop > (DWORD) analyzer_loop_period) {
03651             last_time_loop = actual_time;
03652             analyzer_loop();
03653          }
03654 
03655          status = cm_yield(analyzer_loop_period);
03656       }
03657 
03658    } while (status != RPC_SHUTDOWN && status != SS_ABORT);
03659 
03660    /* update statistics */
03661    update_stats();
03662 
03663    return status;
03664 }
03665 
03666 /*------------------------------------------------------------------*/
03667 
03668 INT init_module_parameters(BOOL bclose)
03669 {
03670    INT i, j, status, size;
03671    ANA_MODULE **module;
03672    char str[80];
03673    HNDLE hkey;
03674 
03675    for (i = 0; analyze_request[i].event_name[0]; i++) {
03676       module = analyze_request[i].ana_module;
03677       for (j = 0; module != NULL && module[j] != NULL; j++) {
03678          if (module[j]->parameters != NULL) {
03679             sprintf(str, "/%s/Parameters/%s", analyzer_name, module[j]->name);
03680 
03681             if (bclose) {
03682                db_find_key(hDB, 0, str, &hkey);
03683                db_close_record(hDB, hkey);
03684             } else {
03685                status = db_find_key(hDB, 0, str, &hkey);
03686                if (status == DB_SUCCESS) {
03687                   db_get_record_size(hDB, hkey, 0, &size);
03688                   if (size != module[j]->param_size)
03689                      status = 0;
03690                }
03691                if (status != DB_SUCCESS && module[j]->init_str) {
03692                   if (db_check_record(hDB, 0, str, strcomb((const char **)module[j]->init_str), TRUE) !=
03693                       DB_SUCCESS) {
03694                      cm_msg(MERROR, "init_module_parameters",
03695                             "Cannot create/check \"%s\" parameters in ODB", str);
03696                      return 0;
03697                   }
03698                }
03699 
03700                db_find_key(hDB, 0, str, &hkey);
03701                assert(hkey);
03702 
03703                if (db_open_record(hDB, hkey, module[j]->parameters, module[j]->param_size,
03704                                   MODE_READ, NULL, NULL) != DB_SUCCESS) {
03705                   cm_msg(MERROR, "init_module_parameters",
03706                          "Cannot open \"%s\" parameters in ODB", str);
03707                   return 0;
03708                }
03709             }
03710          }
03711       }
03712    }
03713 
03714    return SUCCESS;
03715 }
03716 
03717 /*------------------------------------------------------------------*/
03718 void odb_load(EVENT_HEADER * pevent)
03719 {
03720    BOOL flag;
03721    int size, i, status;
03722    char str[256];
03723    HNDLE hKey, hKeyRoot, hKeyEq;
03724 
03725    flag = TRUE;
03726    size = sizeof(flag);
03727    sprintf(str, "/%s/ODB Load", analyzer_name);
03728    db_get_value(hDB, 0, str, &flag, &size, TID_BOOL, TRUE);
03729 
03730    if (flag) {
03731       for (i = 0; i < 10; i++)
03732          if (clp.protect[i][0] && !clp.quiet)
03733             printf("Protect ODB tree \"%s\"\n", clp.protect[i]);
03734 
03735       if (!clp.quiet)
03736          printf("Load ODB from run %d...", (int) current_run_number);
03737 
03738       if (flag == 1) {
03739          /* lock all ODB values except run parameters */
03740          db_set_mode(hDB, 0, MODE_READ, TRUE);
03741 
03742          db_find_key(hDB, 0, "/Experiment/Run Parameters", &hKey);
03743          if (hKey)
03744             db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE);
03745 
03746          /* and analyzer parameters */
03747          sprintf(str, "/%s/Parameters", analyzer_name);
03748          db_find_key(hDB, 0, str, &hKey);
03749          if (hKey)
03750             db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE);
03751 
03752          /* and equipment (except /variables) */
03753          db_find_key(hDB, 0, "/Equipment", &hKeyRoot);
03754          if (hKeyRoot) {
03755             db_set_mode(hDB, hKeyRoot, MODE_READ | MODE_WRITE | MODE_DELETE, FALSE);
03756 
03757             for (i = 0;; i++) {
03758                status = db_enum_key(hDB, hKeyRoot, i, &hKeyEq);
03759                if (status == DB_NO_MORE_SUBKEYS)
03760                   break;
03761 
03762                db_set_mode(hDB, hKeyEq, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE);
03763 
03764                db_find_key(hDB, hKeyEq, "Variables", &hKey);
03765                if (hKey)
03766                   db_set_mode(hDB, hKey, MODE_READ, TRUE);
03767             }
03768          }
03769 
03770          /* lock protected trees */
03771          for (i = 0; i < 10; i++)
03772             if (clp.protect[i][0]) {
03773                db_find_key(hDB, 0, clp.protect[i], &hKey);
03774                if (hKey)
03775                   db_set_mode(hDB, hKey, MODE_READ, TRUE);
03776             }
03777       }
03778 
03779       /* close open records to parameters */
03780       init_module_parameters(TRUE);
03781 
03782       if (strncmp((char *) (pevent + 1), "<?xml version=\"1.0\"", 19) == 0)
03783          db_paste_xml(hDB, 0, (char *) (pevent + 1));
03784       else
03785          db_paste(hDB, 0, (char *) (pevent + 1));
03786 
03787       if (flag == 1)
03788          db_set_mode(hDB, 0, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE);
03789 
03790       /* reinit structured opened by user analyzer */
03791       analyzer_init();
03792 
03793       /* reload parameter files after BOR event */
03794       if (!clp.quiet)
03795          printf("OK\n");
03796       load_parameters(current_run_number);
03797 
03798       /* open module parameters again */
03799       init_module_parameters(FALSE);
03800    }
03801 }
03802 
03803 /*------------------------------------------------------------------*/
03804 
03805 #define MA_DEVICE_DISK        1
03806 #define MA_DEVICE_TAPE        2
03807 #define MA_DEVICE_FTP         3
03808 #define MA_DEVICE_PVM         4
03809 
03810 #define MA_FORMAT_MIDAS       (1<<0)
03811 #define MA_FORMAT_YBOS        (1<<2)
03812 #define MA_FORMAT_GZIP        (1<<3)
03813 
03814 typedef struct {
03815    char file_name[256];
03816    int format;
03817    int device;
03818    int fd;
03819 #ifdef HAVE_ZLIB
03820    gzFile gzfile;
03821 #else
03822    FILE *file;
03823 #endif
03824    char *buffer;
03825    int wp, rp;
03826    /*FTP_CON ftp_con; */
03827 } MA_FILE;
03828 
03829 /*------------------------------------------------------------------*/
03830 
03831 MA_FILE *ma_open(char *file_name)
03832 {
03833    char *ext_str;
03834    int status;
03835    MA_FILE *file;
03836 
03837    /* allocate MA_FILE structure */
03838    file = (MA_FILE *) calloc(sizeof(MA_FILE), 1);
03839    if (file == NULL) {
03840       cm_msg(MERROR, "ma_open", "Cannot allocate MA file structure");
03841       return NULL;
03842    }
03843 
03844    /* save file name */
03845    strcpy(file->file_name, file_name);
03846 
03847    /* for now, just read from disk */
03848    file->device = MA_DEVICE_DISK;
03849 
03850    /* or from PVM */
03851    if (pvm_slave) {
03852       file->device = MA_DEVICE_PVM;
03853       file->buffer = (char *) malloc(PVM_BUFFER_SIZE);
03854       file->wp = file->rp = 0;
03855    }
03856 
03857    /* check input file extension */
03858    if (strchr(file_name, '.')) {
03859       ext_str = file_name + strlen(file_name) - 1;
03860       while (*ext_str != '.')
03861          ext_str--;
03862    } else
03863       ext_str = "";
03864 
03865    if (strncmp(ext_str, ".gz", 3) == 0) {
03866 #ifdef HAVE_ZLIB
03867       ext_str--;
03868       while (*ext_str != '.' && ext_str > file_name)
03869          ext_str--;
03870 #else
03871       cm_msg(MERROR, "ma_open",
03872              ".gz extension not possible because zlib support is not compiled in.\n");
03873       return NULL;
03874 #endif
03875    }
03876 
03877    if (strncmp(file_name, "/dev/", 4) == 0)     /* assume MIDAS tape */
03878       file->format = MA_FORMAT_MIDAS;
03879    else if (strncmp(ext_str, ".mid", 4) == 0)
03880       file->format = MA_FORMAT_MIDAS;
03881    else if (strncmp(ext_str, ".ybs", 4) == 0)
03882      assert(!"YBOS not supported anymore");
03883    else {
03884       printf
03885           ("Unknown input data format \"%s\". Please use file extension .mid or mid.gz.\n",
03886            ext_str);
03887       return NULL;
03888    }
03889 
03890    if (file->device == MA_DEVICE_DISK) {
03891       if (file->format == MA_FORMAT_YBOS) {
03892         assert(!"YBOS not supported anymore");
03893       } else {
03894 #ifdef HAVE_ZLIB
03895          file->gzfile = gzopen(file_name, "rb");
03896          if (file->gzfile == NULL)
03897             return NULL;
03898 #else
03899          file->file = fopen(file_name, "rb");
03900          if (file->file == NULL)
03901             return NULL;
03902 #endif
03903       }
03904    }
03905 
03906    return file;
03907 }
03908 
03909 /*------------------------------------------------------------------*/
03910 
03911 int ma_close(MA_FILE * file)
03912 {
03913    if (file->format == MA_FORMAT_YBOS)
03914      assert(!"YBOS not supported anymore");
03915    else
03916 #ifdef HAVE_ZLIB
03917       gzclose(file->gzfile);
03918 #else
03919       fclose(file->file);
03920 #endif
03921 
03922    free(file);
03923    return SUCCESS;
03924 }
03925 
03926 /*------------------------------------------------------------------*/
03927 
03928 int ma_read_event(MA_FILE * file, EVENT_HEADER * pevent, int size)
03929 {
03930    int status, n;
03931 
03932    if (file->device == MA_DEVICE_DISK) {
03933       if (file->format == MA_FORMAT_MIDAS) {
03934          if (size < (int) sizeof(EVENT_HEADER)) {
03935             cm_msg(MERROR, "ma_read_event", "Buffer size too small");
03936             return -1;
03937          }
03938 
03939          /* read event header */
03940 #ifdef HAVE_ZLIB
03941          n = gzread(file->gzfile, pevent, sizeof(EVENT_HEADER));
03942 #else
03943          n = sizeof(EVENT_HEADER)*fread(pevent, sizeof(EVENT_HEADER), 1, file->file);
03944 #endif
03945 
03946          if (n < (int) sizeof(EVENT_HEADER)) {
03947             if (n > 0)
03948                printf("Unexpected end of file %s, last event skipped\n", file->file_name);
03949             return -1;
03950          }
03951 
03952          /* swap event header if in wrong format */
03953 #ifdef SWAP_EVENTS
03954          WORD_SWAP(&pevent->event_id);
03955          WORD_SWAP(&pevent->trigger_mask);
03956          DWORD_SWAP(&pevent->serial_number);
03957          DWORD_SWAP(&pevent->time_stamp);
03958          DWORD_SWAP(&pevent->data_size);
03959 #endif
03960 
03961          /* read event */
03962          n = 0;
03963          if (pevent->data_size > 0) {
03964             if (size < (int) pevent->data_size + (int) sizeof(EVENT_HEADER)) {
03965                cm_msg(MERROR, "ma_read_event", "Buffer size too small");
03966                return -1;
03967             }
03968 #ifdef HAVE_ZLIB
03969             n = gzread(file->gzfile, pevent + 1, pevent->data_size);
03970 #else
03971             n = pevent->data_size*fread(pevent + 1, pevent->data_size, 1, file->file);
03972 #endif
03973             if (n != (INT) pevent->data_size) {
03974                printf("Unexpected end of file %s, last event skipped\n", file->file_name);
03975                return -1;
03976             }
03977          }
03978 
03979          return n + sizeof(EVENT_HEADER);
03980       } else if (file->format == MA_FORMAT_YBOS) {
03981         assert(!"YBOS not supported anymore");
03982       }
03983    } else if (file->device == MA_DEVICE_PVM) {
03984 #ifdef HAVE_PVM
03985       int bufid, len, tag, tid;
03986       EVENT_HEADER *pe;
03987       struct timeval timeout;
03988 
03989       /* check if anything in buffer */
03990       if (file->wp > file->rp) {
03991          pe = (EVENT_HEADER *) (file->buffer + file->rp);
03992          size = sizeof(EVENT_HEADER) + pe->data_size;
03993          memcpy(pevent, pe, size);
03994          file->rp += size;
03995          return size;
03996       }
03997 
03998       /* send data request */
03999       pvm_initsend(PvmDataInPlace);
04000       pvm_send(pvm_myparent, TAG_DATA);
04001 
04002       /* receive data */
04003       timeout.tv_sec = 60;
04004       timeout.tv_usec = 0;
04005 
04006       bufid = pvm_trecv(-1, -1, &timeout);
04007       if (bufid < 0) {
04008          pvm_perror("pvm_recv");
04009          return -1;
04010       }
04011       if (bufid == 0) {
04012          PVM_DEBUG("ma_read_event: timeout receiving data, aborting analyzer.\n");
04013          return -1;
04014       }
04015 
04016       status = pvm_bufinfo(bufid, &len, &tag, &tid);
04017       if (status < 0) {
04018          pvm_perror("pvm_bufinfo");
04019          return -1;
04020       }
04021 
04022       PVM_DEBUG("ma_read_event: receive tag %d, buflen %d", tag, len);
04023 
04024       if (tag == TAG_EOR || tag == TAG_EXIT)
04025          return -1;
04026 
04027       file->wp = len;
04028       file->rp = 0;
04029       status = pvm_upkbyte((char *) file->buffer, len, 1);
04030       if (status < 0) {
04031          pvm_perror("pvm_upkbyte");
04032          return -1;
04033       }
04034 
04035       /* no new data available, sleep some time to reduce network traffic */
04036       if (len == 0)
04037          ss_sleep(200);
04038 
04039       /* re-call this function */
04040       return ma_read_event(file, pevent, size);
04041 #endif
04042    }
04043 
04044    return 0;
04045 }
04046 
04047 /*------------------------------------------------------------------*/
04048 
04049 INT analyze_run(INT run_number, char *input_file_name, char *output_file_name)
04050 {
04051    EVENT_HEADER *pevent, *pevent_unaligned;
04052    ANALYZE_REQUEST *par;
04053    INT i, n, size;
04054    DWORD num_events_in, num_events_out;
04055    char error[256], str[256];
04056    INT status = SUCCESS;
04057    MA_FILE *file;
04058    BOOL skip;
04059    DWORD start_time;
04060 
04061    /* set output file name and flags in ODB */
04062    sprintf(str, "/%s/Output/Filename", analyzer_name);
04063    db_set_value(hDB, 0, str, output_file_name, 256, 1, TID_STRING);
04064 #ifdef HAVE_HBOOK
04065    sprintf(str, "/%s/Output/RWNT", analyzer_name);
04066    db_set_value(hDB, 0, str, &clp.rwnt, sizeof(BOOL), 1, TID_BOOL);
04067 #endif
04068 
04069    assert(run_number > 0);
04070 
04071    /* set run number in ODB */
04072    status =
04073        db_set_value(hDB, 0, "/Runinfo/Run number", &run_number, sizeof(run_number), 1,
04074                     TID_INT);
04075    assert(status == SUCCESS);
04076 
04077    /* set file name in out_info */
04078    strcpy(out_info.filename, output_file_name);
04079 
04080    /* let changes propagate to modules */
04081    cm_yield(0);
04082 
04083    /* open input file, will be changed to ma_open_file later... */
04084    file = ma_open(input_file_name);
04085    if (file == NULL) {
04086       printf("Cannot open input file \"%s\"\n", input_file_name);
04087       return -1;
04088    }
04089 
04090    pevent_unaligned = (EVENT_HEADER *) malloc(EXT_EVENT_SIZE);
04091    if (pevent_unaligned == NULL) {
04092       printf("Not enough memeory\n");
04093       return -1;
04094    }
04095    pevent = (EVENT_HEADER *) ALIGN8((POINTER_T) pevent_unaligned);
04096 
04097    /* call analyzer bor routines */
04098    bor(run_number, error);
04099 
04100    num_events_in = num_events_out = 0;
04101 
04102    start_time = ss_millitime();
04103 
04104    /* event loop */
04105    do {
04106       /* read next event */
04107       n = ma_read_event(file, pevent, EXT_EVENT_SIZE);
04108       if (n <= 0)
04109          break;
04110 
04111       num_events_in++;
04112 
04113       /* copy system events (BOR, EOR, MESSAGE) to output file */
04114       if (pevent->event_id < 0) {
04115          status = process_event(NULL, pevent);
04116          if (status < 0 || status == RPC_SHUTDOWN)      /* disk full/stop analyzer */
04117             break;
04118 
04119          if (out_file && out_format == FORMAT_MIDAS) {
04120             size = pevent->data_size + sizeof(EVENT_HEADER);
04121 #ifdef HAVE_ZLIB
04122             if (out_gzip)
04123                status = gzwrite(out_file, pevent, size) == size ? SUCCESS : SS_FILE_ERROR;
04124             else
04125 #endif
04126                status =
04127                    fwrite(pevent, 1, size,
04128                           out_file) == (size_t) size ? SUCCESS : SS_FILE_ERROR;
04129 
04130             if (status != SUCCESS) {
04131                cm_msg(MERROR, "analyze_run", "Error writing to file (Disk full?)");
04132                return -1;
04133             }
04134 
04135             num_events_out++;
04136          }
04137 
04138          /* reinit start time after BOR event */
04139          if (pevent->event_id == EVENTID_BOR)
04140             start_time = ss_millitime();
04141       }
04142 
04143       /* check if event is in event limit */
04144       skip = FALSE;
04145 
04146       if (!pvm_slave) {
04147          if (clp.n[0] > 0 || clp.n[1] > 0) {
04148             if (clp.n[1] == 0) {
04149                /* treat n[0] as upper limit */
04150                if (num_events_in > clp.n[0]) {
04151                   num_events_in--;
04152                   status = SUCCESS;
04153                   break;
04154                }
04155             } else {
04156                if (num_events_in > clp.n[1]) {
04157                   status = SUCCESS;
04158                   break;
04159                }
04160                if (num_events_in < clp.n[0])
04161                   skip = TRUE;
04162                else if (clp.n[2] > 0 && num_events_in % clp.n[2] != 0)
04163                   skip = TRUE;
04164             }
04165          }
04166       }
04167 
04168       if (!skip) {
04169          /* find request belonging to this event */
04170          par = analyze_request;
04171          status = SUCCESS;
04172          for (i = 0; par->event_name[0]; par++)
04173             if ((par->ar_info.event_id == EVENTID_ALL ||
04174                  par->ar_info.event_id == pevent->event_id) &&
04175                 (par->ar_info.trigger_mask == TRIGGER_ALL ||
04176                  (par->ar_info.trigger_mask & pevent->trigger_mask))
04177                 && par->ar_info.enabled) {
04178                /* analyze this event */
04179                status = process_event(par, pevent);
04180                if (status == SUCCESS)
04181                   num_events_out++;
04182                if (status < 0 || status == RPC_SHUTDOWN)        /* disk full/stop analyzer */
04183                   break;
04184 
04185                /* check for Ctrl-C */
04186                status = cm_yield(0);
04187             }
04188          if (status < 0 || status == RPC_SHUTDOWN)
04189             break;
04190       }
04191 
04192       /* update ODB statistics once every 100 events */
04193       if (num_events_in % 100 == 0) {
04194          update_stats();
04195          if (!clp.quiet) {
04196             if (out_file)
04197                printf("%s:%d  %s:%d  events\r", input_file_name, (int) num_events_in,
04198                       out_info.filename, (int) num_events_out);
04199             else
04200                printf("%s:%d  events\r", input_file_name, (int) num_events_in);
04201 
04202 #ifndef OS_WINNT
04203             fflush(stdout);
04204 #endif
04205          }
04206       }
04207    } while (1);
04208 
04209 #ifdef HAVE_PVM
04210    PVM_DEBUG("analyze_run: event loop finished, status = %d", status);
04211 #endif
04212 
04213    /* signal EOR to slaves */
04214 #ifdef HAVE_PVM
04215    if (pvm_master) {
04216       if (status == RPC_SHUTDOWN)
04217          printf("\nShutting down distributed analyzers, please wait...\n");
04218       pvm_eor(status == RPC_SHUTDOWN ? TAG_EXIT : TAG_EOR);
04219 
04220       /* merge slave output files */
04221       if (out_info.filename[0] && !out_append)
04222          status = pvm_merge();
04223 
04224       start_time = ss_millitime() - start_time;
04225 
04226       update_stats();
04227       if (!clp.quiet) {
04228          if (out_file)
04229             printf("%s:%d  %s:%d  events, %1.2lfs\n", input_file_name, num_events_in,
04230                    out_info.filename, num_events_out, start_time / 1000.0);
04231          else
04232             printf("%s:%d  events, %1.2lfs\n", input_file_name, num_events_in,
04233                    start_time / 1000.0);
04234       }
04235    } else if (pvm_slave) {
04236       start_time = ss_millitime() - start_time;
04237 
04238       update_stats();
04239       if (!clp.quiet) {
04240          if (out_file)
04241             printf("%s:%d  %s:%d  events, %1.2lfs\n", input_file_name, num_events_in,
04242                    out_info.filename, num_events_out, start_time / 1000.0);
04243          else
04244             printf("%s:%d  events, %1.2lfs\n", input_file_name, num_events_in,
04245                    start_time / 1000.0);
04246       }
04247 
04248       eor(current_run_number, error);
04249 
04250       /* send back tests */
04251       pvm_initsend(PvmDataInPlace);
04252 
04253       for (i = 0; i < n_test; i++)
04254          pvm_pkbyte((char *) tl[i], sizeof(ANA_TEST), 1);
04255 
04256       PVM_DEBUG("analyze_run: send %d tests back to master", n_test);
04257 
04258       status = pvm_send(pvm_myparent, TAG_EOR);
04259       if (status < 0) {
04260          pvm_perror("pvm_send");
04261          return RPC_SHUTDOWN;
04262       }
04263    } else {
04264       start_time = ss_millitime() - start_time;
04265 
04266       update_stats();
04267       if (!clp.quiet) {
04268          if (out_file)
04269             printf("%s:%d  %s:%d  events, %1.2lfs\n", input_file_name, num_events_in,
04270                    out_info.filename, num_events_out, start_time / 1000.0);
04271          else
04272             printf("%s:%d  events, %1.2lfs\n", input_file_name, num_events_in,
04273                    start_time / 1000.0);
04274       }
04275 
04276       /* call analyzer eor routines */
04277       eor(current_run_number, error);
04278    }
04279 #else
04280 
04281    start_time = ss_millitime() - start_time;
04282 
04283    update_stats();
04284    if (!clp.quiet) {
04285       if (out_file)
04286          printf("%s:%d  %s:%d  events, %1.2lfs\n", input_file_name, (int) num_events_in,
04287                 out_info.filename, (int) num_events_out, start_time / 1000.0);
04288       else
04289          printf("%s:%d  events, %1.2lfs\n", input_file_name, (int) num_events_in,
04290                 start_time / 1000.0);
04291    }
04292 
04293    /* call analyzer eor routines */
04294    eor(current_run_number, error);
04295 
04296 #endif
04297 
04298    ma_close(file);
04299 
04300    free(pevent_unaligned);
04301 
04302    return status;
04303 }
04304 
04305 /*------------------------------------------------------------------*/
04306 
04307 INT loop_runs_offline()
04308 {
04309    INT i, status, run_number;
04310    char input_file_name[256], output_file_name[256], *prn;
04311    BANK_LIST *bank_list;
04312 
04313    if (!clp.quiet)
04314       printf("Running analyzer offline. Stop with \"!\"\n");
04315 
04316    run_number = 0;
04317    out_append = ((strchr(clp.input_file_name[0], '%') != NULL) &&
04318                  (strchr(clp.output_file_name, '%') == NULL))
04319        || clp.input_file_name[1][0];
04320 
04321    /* loop over range of files */
04322    if (clp.run_number[0] > 0) {
04323       if (strchr(clp.input_file_name[0], '%') == NULL) {
04324          printf
04325              ("Input file name must contain a wildcard like \"%%05d\" when using a range.\n");
04326          return 0;
04327       }
04328 
04329       if (clp.run_number[0] == 0) {
04330          printf("End of range not specified.\n");
04331          return 0;
04332       }
04333 
04334       for (run_number = clp.run_number[0]; run_number <= clp.run_number[1]; run_number++) {
04335          sprintf(input_file_name, clp.input_file_name[0], run_number);
04336          if (strchr(clp.output_file_name, '%') != NULL)
04337             sprintf(output_file_name, clp.output_file_name, run_number);
04338          else
04339             strcpy(output_file_name, clp.output_file_name);
04340 
04341          status = analyze_run(run_number, input_file_name, output_file_name);
04342          if (status == RPC_SHUTDOWN)
04343             break;
04344       }
04345    } else {
04346       /* loop over input file names */
04347       for (i = 0; clp.input_file_name[i][0] && i < 10; i++) {
04348          strcpy(input_file_name, clp.input_file_name[i]);
04349 
04350          /* get run number from input file */
04351          prn = input_file_name;
04352          while (strchr(prn, DIR_SEPARATOR) != NULL)
04353             prn = strchr(prn, DIR_SEPARATOR) + 1;
04354 
04355          if (strpbrk(prn, "0123456789"))
04356             run_number = atoi(strpbrk(prn, "0123456789"));
04357 
04358          if (strchr(clp.output_file_name, '%') != NULL) {
04359             if (run_number == 0) {
04360                printf("Cannot extract run number from input file name.\n");
04361                return 0;
04362             }
04363             sprintf(output_file_name, clp.output_file_name, run_number);
04364          } else
04365             strcpy(output_file_name, clp.output_file_name);
04366 
04367          status = analyze_run(run_number, input_file_name, output_file_name);
04368          if (status == RPC_SHUTDOWN)
04369             break;
04370       }
04371    }
04372 
04373    /* close output file in append mode */
04374    if (out_file && out_append) {
04375       if (out_format == FORMAT_HBOOK) {
04376 #ifdef HAVE_HBOOK
04377          char str[80];
04378 
04379          HROUT(0, i, bstr);
04380          strcpy(str, "OFFLINE");
04381          HREND(str);
04382 #else
04383          cm_msg(MERROR, "loop_runs_offline", "HBOOK support is not compiled in");
04384 #endif
04385       } else if (out_format == FORMAT_ROOT) {
04386 #ifdef USE_ROOT
04387          CloseRootOutputFile();
04388 #else
04389          cm_msg(MERROR, "loop_runs_offline", "ROOT support is not compiled in");
04390 #endif                          /* USE_ROOT */
04391       } else {
04392 #ifdef HAVE_ZLIB
04393          if (out_gzip)
04394             gzclose(out_file);
04395          else
04396 #endif
04397             fclose(out_file);
04398       }
04399 
04400       /* free bank buffer */
04401       for (i = 0; analyze_request[i].event_name[0]; i++) {
04402          bank_list = analyze_request[i].bank_list;
04403 
04404          if (bank_list == NULL)
04405             continue;
04406 
04407          for (; bank_list->name[0]; bank_list++)
04408             if (bank_list->addr) {
04409                free(bank_list->addr);
04410                bank_list->addr = NULL;
04411             }
04412       }
04413    }
04414 #ifdef HAVE_PVM
04415    /* merge slave output files */
04416    if (pvm_master && out_info.filename[0] && out_append)
04417       pvm_merge();
04418 #endif
04419 
04420    return CM_SUCCESS;
04421 }
04422 
04423 /*------------------------------------------------------------------*/
04424 
04425 #ifdef HAVE_PVM
04426 
04427 int pvm_main(char *argv[])
04428 {
04429    int mytid, status, i, j, dtid, *pvm_tid, bufid;
04430    char path[256];
04431    struct timeval timeout;
04432 
04433    getcwd(path, 256);
04434 
04435    mytid = pvm_mytid();
04436    if (mytid < 0) {
04437       pvm_perror("pvm_mytid");
04438       return 0;
04439    }
04440 
04441    chdir(path);
04442 
04443    status = pvm_setopt(PvmRoute, PvmRouteDirect);
04444    if (status < 0) {
04445       pvm_perror("pvm_setopt");
04446       pvm_exit();
04447       return 0;
04448    }
04449 
04450    pvm_myparent = pvm_parent();
04451    if (pvm_myparent < 0 && pvm_myparent != PvmNoParent) {
04452       pvm_perror("pvm_parent");
04453       pvm_exit();
04454       return 0;
04455    }
04456 
04457    /* check if master */
04458    if (pvm_myparent == PvmNoParent) {
04459       struct pvmhostinfo *hostp;
04460       int n_host, n_arch;
04461 
04462 #ifdef WIN32
04463       char *p;
04464 
04465       /* use no path, executable must be under $PVM_ROOT$/bin/WIN32 */
04466       p = argv[0] + strlen(argv[0]) - 1;
04467       while (p > argv[0] && *p != '\\')
04468          p--;
04469       if (*p == '\\')
04470          p++;
04471       strcpy(path, p);
04472 #else
04473       if (strchr(argv[0], '/') == 0) {
04474          getcwd(path, 256);
04475          strcat(path, "/");
04476          strcat(path, argv[0]);
04477       } else
04478          strcpy(path, argv[0]);
04479 #endif
04480 
04481       /* return if no parallelization selected */
04482       if (clp.n_task == -1)
04483          return SUCCESS;
04484 
04485       /* Set number of slaves to start */
04486       pvm_config(&n_host, &n_arch, &hostp);
04487 
04488       pvm_n_task = n_host - 1;
04489       if (clp.n_task != 0)
04490          pvm_n_task = clp.n_task;
04491 
04492       if (clp.n_task != 1 && pvm_n_task > n_host - 1)
04493          pvm_n_task = n_host - 1;
04494 
04495       if (pvm_n_task == 0)
04496          return SUCCESS;
04497 
04498       pvm_master = TRUE;
04499 
04500       pvm_tid = malloc(sizeof(int) * pvm_n_task);
04501       pvmc = malloc(sizeof(PVM_CLIENT) * pvm_n_task);
04502 
04503       if (pvm_tid == NULL || pvmc == NULL) {
04504          free(pvm_tid);
04505          printf("Not enough memory to allocate PVM structures.\n");
04506          pvm_exit();
04507          return 0;
04508       }
04509 
04510       memset(pvmc, 0, sizeof(PVM_CLIENT) * pvm_n_task);
04511 
04512       for (i = 0; i < pvm_n_task; i++) {
04513          pvmc[i].buffer = malloc(PVM_BUFFER_SIZE);
04514          if (pvmc[i].buffer == NULL) {
04515             free(pvm_tid);
04516             free(pvmc);
04517             printf("Not enough memory to allocate PVM buffers.\n");
04518             pvm_exit();
04519             return 0;
04520          }
04521       }
04522 
04523       /* spawn slaves */
04524       printf("Parallelizing analyzer on %d machines\n", pvm_n_task);
04525       if (pvm_n_task == 1)
04526          status = pvm_spawn(path, argv + 1, PvmTaskDefault, NULL, pvm_n_task, pvm_tid);
04527       else
04528          status =
04529              pvm_spawn(path, argv + 1, PvmTaskHost | PvmHostCompl, ".", pvm_n_task,
04530                        pvm_tid);
04531       if (status == 0) {
04532          pvm_perror("pvm_spawn");
04533          pvm_exit();
04534          free(pvm_tid);
04535          free(pvmc);
04536          return 0;
04537       }
04538 
04539       for (i = 0; i < pvm_n_task; i++) {
04540          pvmc[i].tid = pvm_tid[i];
04541          pvmc[i].wp = 0;
04542          pvmc[i].n_events = 0;
04543          pvmc[i].time = 0;
04544          dtid = pvm_tidtohost(pvm_tid[i]);
04545          for (j = 0; j < n_host; j++)
04546             if (dtid == hostp[j].hi_tid)
04547                strcpy(pvmc[i].host, hostp[j].hi_name);
04548       }
04549 
04550       PVM_DEBUG("Spawing on hosts:");
04551       for (i = 0; i < pvm_n_task; i++)
04552          PVM_DEBUG("%s", pvmc[i].host);
04553 
04554       if (status < pvm_n_task) {
04555          printf("Trouble spawning slaves. Aborting. Error codes are:\n");
04556          for (i = 0; i < pvm_n_task; i++)
04557             printf("TID %d %d\n", i, pvm_tid[i]);
04558 
04559          pvm_exit();
04560          free(pvm_tid);
04561          free(pvmc);
04562          return 0;
04563       }
04564 
04565       /* send slave index */
04566       for (i = 0; i < pvm_n_task; i++) {
04567          pvm_initsend(PvmDataDefault);
04568 
04569          pvm_pkint(&i, 1, 1);
04570 
04571          PVM_DEBUG("pvm_main: send index to client %d", i);
04572 
04573          status = pvm_send(pvmc[i].tid, TAG_INIT);
04574          if (status < 0) {
04575             pvm_perror("pvm_send");
04576             return 0;
04577          }
04578       }
04579 
04580       free(pvm_tid);
04581    } else {
04582       char path[256];
04583 
04584       pvm_master = FALSE;
04585       pvm_slave = TRUE;
04586 
04587       /* go to path from argv[0] */
04588       strcpy(path, argv[0]);
04589       for (i = strlen(path); i > 0 && path[i] != DIR_SEPARATOR; i--)
04590          path[i] = 0;
04591       if (i > 0)
04592          path[i] = 0;
04593 
04594       chdir(path);
04595       PVM_DEBUG("PATH=%s", path);
04596 
04597       /* receive slave index */
04598       timeout.tv_sec = 10;
04599       timeout.tv_usec = 0;
04600 
04601       bufid = pvm_trecv(-1, -1, &timeout);
04602       if (bufid < 0) {
04603          pvm_perror("pvm_recv");
04604          return 0;
04605       }
04606       if (bufid == 0) {
04607          PVM_DEBUG("pvm_main: timeout receiving index, aborting analyzer.\n");
04608          return 0;
04609       }
04610 
04611       status = pvm_upkint(&pvm_client_index, 1, 1);
04612       if (status < 0) {
04613          pvm_perror("pvm_upkint");
04614          return 0;
04615       }
04616 
04617       PVM_DEBUG("Received client ID %d", pvm_client_index);
04618    }
04619 
04620    return SUCCESS;
04621 }
04622 
04623 /*------------------------------------------------------------------*/
04624 
04625 int pvm_send_event(int index, EVENT_HEADER * pevent)
04626 {
04627    struct timeval timeout;
04628    int bufid, len, tag, tid, status;
04629 
04630    if (pevent->data_size + sizeof(EVENT_HEADER) >= PVM_BUFFER_SIZE) {
04631       printf("Event too large (%d) for PVM buffer (%d), analyzer aborted\n",
04632              pevent->data_size + sizeof(EVENT_HEADER), PVM_BUFFER_SIZE);
04633       return RPC_SHUTDOWN;
04634    }
04635 
04636    /* wait on event request */
04637    timeout.tv_sec = 60;
04638    timeout.tv_usec = 0;
04639 
04640    bufid = pvm_trecv(pvmc[index].tid, -1, &timeout);
04641    if (bufid < 0) {
04642       pvm_perror("pvm_recv");
04643       return RPC_SHUTDOWN;
04644    }
04645    if (bufid == 0) {
04646       printf("Timeout receiving data requests from %s, aborting analyzer.\n",
04647              pvmc[index].host);
04648       return RPC_SHUTDOWN;
04649    }
04650 
04651    status = pvm_bufinfo(bufid, &len, &tag, &tid);
04652    if (status < 0) {
04653       pvm_perror("pvm_bufinfo");
04654       return RPC_SHUTDOWN;
04655    }
04656 
04657    PVM_DEBUG("pvm_send_event: received request from client %d", index);
04658 
04659    /* send event */
04660    pvm_initsend(PvmDataInPlace);
04661 
04662    pvm_pkbyte((char *) pevent, pevent->data_size + sizeof(EVENT_HEADER), 1);
04663 
04664    PVM_DEBUG("pvm_send_event: send events to client %d", index);
04665 
04666    status = pvm_send(tid, TAG_DATA);
04667    if (status < 0) {
04668       pvm_perror("pvm_send");
04669       return RPC_SHUTDOWN;
04670    }
04671 
04672    pvmc[index].time = ss_millitime();
04673 
04674    return SUCCESS;
04675 }
04676 
04677 /*------------------------------------------------------------------*/
04678 
04679 int pvm_send_buffer(int index)
04680 {
04681    struct timeval timeout;
04682    int i, bufid, len, tag, tid, status;
04683 
04684    PVM_DEBUG("pvm_send_buffer: index %d", index);
04685 
04686    if (index == -2) {
04687       bufid = pvm_nrecv(-1, -1);
04688    } else {
04689       /* wait on event request with timeout */
04690       timeout.tv_sec = 60;
04691       timeout.tv_usec = 0;
04692 
04693       bufid = pvm_trecv(-1, -1, &timeout);
04694    }
04695 
04696    if (bufid < 0) {
04697       pvm_perror("pvm_recv");
04698       return RPC_SHUTDOWN;
04699    }
04700    if (bufid == 0) {
04701       if (index == -2)
04702          return SUCCESS;
04703 
04704       printf("Timeout receiving data requests, aborting analyzer.\n");
04705       return RPC_SHUTDOWN;
04706    }
04707 
04708    status = pvm_bufinfo(bufid, &len, &tag, &tid);
04709    if (status < 0) {
04710       pvm_perror("pvm_bufinfo");
04711       return RPC_SHUTDOWN;
04712    }
04713 
04714    /* find index of that client */
04715    for (i = 0; i < pvm_n_task; i++)
04716       if (pvmc[i].tid == tid)
04717          break;
04718 
04719    if (i == pvm_n_task) {
04720       cm_msg(MERROR, "pvm_send_buffer", "received message from unknown client %d", tid);
04721       return RPC_SHUTDOWN;
04722    }
04723 
04724    PVM_DEBUG("pvm_send_buffer: received request from client %d", i);
04725 
04726    /* send event */
04727    pvm_initsend(PvmDataInPlace);
04728 
04729    pvm_pkbyte((char *) pvmc[i].buffer, pvmc[i].wp, 1);
04730 
04731    PVM_DEBUG("pvm_send_buffer: send %d events (%1.1lfkB) to client %d",
04732              pvmc[i].n_events, pvmc[i].wp / 1024.0, i);
04733 
04734    status = pvm_send(tid, TAG_DATA);
04735    if (status < 0) {
04736       pvm_perror("pvm_send");
04737       return RPC_SHUTDOWN;
04738    }
04739 
04740    pvmc[i].wp = 0;
04741    pvmc[i].n_events = 0;
04742    pvmc[i].time = ss_millitime();
04743 
04744    /* if specific client is requested and not emptied, try again */
04745    if (index >= 0 && index != i)
04746       return pvm_send_buffer(index);
04747 
04748    return SUCCESS;
04749 }
04750 
04751 /*------------------------------------------------------------------*/
04752 
04753 int pvm_distribute(ANALYZE_REQUEST * par, EVENT_HEADER * pevent)
04754 {
04755    char str[256];
04756    int i, index, size, status, min, max;
04757 
04758    if (par == NULL && pevent->event_id == EVENTID_BOR) {
04759       /* distribute ODB dump */
04760       for (i = 0; i < pvm_n_task; i++) {
04761          status = pvm_send_event(i, pevent);
04762          if (status != SUCCESS)
04763             return status;
04764       }
04765 
04766       return SUCCESS;
04767    }
04768 
04769    size = sizeof(EVENT_HEADER) + pevent->data_size;
04770 
04771    if (par == NULL || (par->ar_info.sampling_type & GET_FARM) == 0) {
04772       /* if not farmed, copy to all client buffers */
04773       for (i = 0; i < pvm_n_task; i++) {
04774          /* if buffer full, empty it */
04775          if (pvmc[i].wp + size >= clp.pvm_buf_size) {
04776             status = pvm_send_buffer(i);
04777             if (status != SUCCESS)
04778                return status;
04779          }
04780 
04781          if (size >= PVM_BUFFER_SIZE) {
04782             printf("Event too large (%d) for PVM buffer (%d), analyzer aborted\n", size,
04783                    PVM_BUFFER_SIZE);
04784             return RPC_SHUTDOWN;
04785          }
04786 
04787          memcpy(pvmc[i].buffer + pvmc[i].wp, pevent, size);
04788          pvmc[i].wp += size;
04789          pvmc[i].n_events++;
04790       }
04791    } else {
04792       /* farmed: look for buffer with lowest level */
04793       min = PVM_BUFFER_SIZE;
04794       index = 0;
04795       for (i = 0; i < pvm_n_task; i++)
04796          if (pvmc[i].wp < min) {
04797             min = pvmc[i].wp;
04798             index = i;
04799          }
04800 
04801       /* if buffer full, empty it */
04802       if (pvmc[index].wp + size >= clp.pvm_buf_size) {
04803          status = pvm_send_buffer(index);
04804          if (status != SUCCESS)
04805             return status;
04806       }
04807 
04808       if (pvmc[index].wp + size >= PVM_BUFFER_SIZE) {
04809          printf("Event too large (%d) for PVM buffer (%d), analyzer aborted\n", size,
04810                 PVM_BUFFER_SIZE);
04811          return RPC_SHUTDOWN;
04812       }
04813 
04814       /* copy to "index" buffer */
04815       memcpy(pvmc[index].buffer + pvmc[index].wp, pevent, size);
04816       pvmc[index].wp += size;
04817       pvmc[index].n_events++;
04818    }
04819 
04820    sprintf(str, "%1.3lf:  ", (ss_millitime() - pvm_start_time) / 1000.0);
04821    for (i = 0; i < pvm_n_task; i++)
04822       if (i == index)
04823          sprintf(str + strlen(str), "#%d# ", pvmc[i].wp);
04824       else
04825          sprintf(str + strlen(str), "%d ", pvmc[i].wp);
04826    //PVM_DEBUG(str);
04827 
04828    /* find min/max buffer level */
04829    min = PVM_BUFFER_SIZE;
04830    max = 0;
04831    for (i = 0; i < pvm_n_task; i++) {
04832       if (pvmc[i].wp > max)
04833          max = pvmc[i].wp;
04834       if (pvmc[i].wp < min)
04835          min = pvmc[i].wp;
04836    }
04837 
04838    /* don't send events if all buffers are less than half full */
04839    if (max < clp.pvm_buf_size / 2)
04840       return SUCCESS;
04841 
04842    /* if all buffer are more than half full, wait for next request */
04843    if (min > clp.pvm_buf_size / 2) {
04844       status = pvm_send_buffer(-1);
04845       return status;
04846    }
04847 
04848    /* probe new requests */
04849    status = pvm_send_buffer(-2);
04850 
04851    return status;
04852 }
04853 
04854 /*------------------------------------------------------------------*/
04855 
04856 int pvm_eor(int eor_tag)
04857 {
04858    struct timeval timeout;
04859    int bufid, len, tag, tid, i, j, status, size;
04860    ANA_TEST *tst_buf;
04861    DWORD count;
04862    char str[256];
04863 
04864    printf("\n");
04865 
04866    for (i = 0; i < pvm_n_task; i++)
04867       pvmc[i].eor_sent = FALSE;
04868 
04869    do {
04870       /* flush remaining buffers */
04871       timeout.tv_sec = 60;
04872       timeout.tv_usec = 0;
04873 
04874       bufid = pvm_trecv(-1, -1, &timeout);
04875       if (bufid < 0) {
04876          pvm_perror("pvm_recv");
04877          return RPC_SHUTDOWN;
04878       }
04879       if (bufid == 0) {
04880          printf("Timeout receiving data request, aborting analyzer.\n");
04881          return RPC_SHUTDOWN;
04882       }
04883 
04884       status = pvm_bufinfo(bufid, &len, &tag, &tid);
04885       if (status < 0) {
04886          pvm_perror("pvm_bufinfo");
04887          return RPC_SHUTDOWN;
04888       }
04889 
04890       /* find index of that client */
04891       for (j = 0; j < pvm_n_task; j++)
04892          if (pvmc[j].tid == tid)
04893             break;
04894 
04895       if (j == pvm_n_task) {
04896          cm_msg(MERROR, "pvm_eor", "received message from unknown client %d", tid);
04897          return RPC_SHUTDOWN;
04898       }
04899 
04900       PVM_DEBUG("pvm_eor: received request from client %d", j);
04901 
04902       /* send remaining buffer if data available */
04903       if (eor_tag == TAG_EOR && pvmc[j].wp > 0) {
04904          pvm_initsend(PvmDataInPlace);
04905 
04906          pvm_pkbyte((char *) pvmc[j].buffer, pvmc[j].wp, 1);
04907 
04908          PVM_DEBUG("pvm_eor: send %d events (%1.1lfkB) to client %d",
04909                    pvmc[j].n_events, pvmc[j].wp / 1024.0, j);
04910 
04911          status = pvm_send(tid, TAG_DATA);
04912          if (status < 0) {
04913             pvm_perror("pvm_send");
04914             return RPC_SHUTDOWN;
04915          }
04916 
04917          pvmc[j].wp = 0;
04918          pvmc[j].n_events = 0;
04919          pvmc[j].time = ss_millitime();
04920       } else {
04921          /* send EOR */
04922          pvm_initsend(PvmDataDefault);
04923 
04924          if (eor_tag == TAG_EOR)
04925             PVM_DEBUG("pvm_eor: send EOR to client %d", j);
04926          else
04927             PVM_DEBUG("pvm_eor: send EXIT to client %d", j);
04928 
04929          printf("Shutting down %s               \r", pvmc[j].host);
04930          fflush(stdout);
04931 
04932          status = pvm_send(tid, eor_tag);
04933          if (status < 0) {
04934             pvm_perror("pvm_send");
04935             return RPC_SHUTDOWN;
04936          }
04937 
04938          pvmc[j].eor_sent = TRUE;
04939 
04940          /* wait for EOR reply */
04941          timeout.tv_sec = 60;
04942          timeout.tv_usec = 0;
04943 
04944          bufid = pvm_trecv(tid, -1, &timeout);
04945          if (bufid < 0) {
04946             pvm_perror("pvm_recv");
04947             return RPC_SHUTDOWN;
04948          }
04949          if (bufid == 0) {
04950             printf("Timeout receiving EOR request, aborting analyzer.\n");
04951             return RPC_SHUTDOWN;
04952          }
04953 
04954          status = pvm_bufinfo(bufid, &len, &tag, &tid);
04955          if (status < 0) {
04956             pvm_perror("pvm_bufinfo");
04957             return RPC_SHUTDOWN;
04958          }
04959 
04960          PVM_DEBUG("\nGot %d bytes", len);
04961 
04962          tst_buf = malloc(len);
04963          pvm_upkbyte((char *) tst_buf, len, 1);
04964 
04965          /* write tests to ODB */
04966          for (i = 0; i < (int) (len / sizeof(ANA_TEST)); i++) {
04967             sprintf(str, "/%s/Tests/%s", analyzer_name, tst_buf[i].name);
04968             count = 0;
04969             size = sizeof(DWORD);
04970             db_get_value(hDB, 0, str, &count, &size, TID_DWORD, TRUE);
04971             count += tst_buf[i].count;
04972 
04973             db_set_value(hDB, 0, str, &count, sizeof(DWORD), 1, TID_DWORD);
04974          }
04975 
04976          free(tst_buf);
04977       }
04978 
04979       /* check if EOR sent to all clients */
04980       for (j = 0; j < pvm_n_task; j++)
04981          if (!pvmc[j].eor_sent)
04982             break;
04983 
04984    } while (j < pvm_n_task);
04985 
04986    printf("\n");
04987 
04988    return SUCCESS;
04989 }
04990 
04991 /*------------------------------------------------------------------*/
04992 
04993 int pvm_merge()
04994 {
04995    int i, j;
04996    char fn[10][8], str[256], file_name[256], error[256];
04997    char ext[10], *p;
04998 
04999    strcpy(str, out_info.filename);
05000    if (strchr(str, '%') != NULL)
05001       sprintf(file_name, str, current_run_number);
05002    else
05003       strcpy(file_name, str);
05004 
05005    /* check output file extension */
05006    out_gzip = FALSE;
05007    ext[0] = 0;
05008    if (strchr(file_name, '.')) {
05009       p = file_name + strlen(file_name) - 1;
05010       while (*p != '.')
05011          p--;
05012       strcpy(ext, p);
05013    }
05014    if (strncmp(ext, ".gz", 3) == 0) {
05015       out_gzip = TRUE;
05016       *p = 0;
05017       p--;
05018       while (*p != '.' && p > file_name)
05019          p--;
05020       strcpy(ext, p);
05021    }
05022 
05023    if (strncmp(ext, ".asc", 4) == 0)
05024       out_format = FORMAT_ASCII;
05025    else if (strncmp(ext, ".mid", 4) == 0)
05026       out_format = FORMAT_MIDAS;
05027    else if (strncmp(ext, ".rz", 3) == 0)
05028       out_format = FORMAT_HBOOK;
05029    else {
05030       strcpy(error,
05031              "Unknown output data format. Please use file extension .asc, .mid or .rz.\n");
05032       cm_msg(MERROR, "pvm_merge", error);
05033       return 0;
05034    }
05035 
05036    if (out_format == FORMAT_HBOOK) {
05037       if (pvm_n_task <= 10) {
05038          for (i = 0; i < pvm_n_task; i++)
05039             sprintf(fn[i], "n%d.rz", i);
05040 
05041          HMERGE(pvm_n_task, fn, file_name);
05042       } else {
05043          for (i = 0; i <= pvm_n_task / 10; i++) {
05044             for (j = 0; j < 10 && j + i * 10 < pvm_n_task; j++)
05045                sprintf(fn[j], "n%d.rz", j + i * 10);
05046 
05047             sprintf(str, "t%d.rz", i);
05048             printf("Merging %d files to %s:\n", j, str);
05049             HMERGE(j, fn, str);
05050          }
05051          for (i = 0; i <= pvm_n_task / 10; i++)
05052             sprintf(fn[i], "t%d.rz", i);
05053 
05054          printf("Merging %d files to %s:\n", i, file_name);
05055          HMERGE(i, fn, file_name);
05056       }
05057    }
05058 
05059    return SUCCESS;
05060 }
05061 
05062 #endif                          /* PVM */
05063 
05064 /*------------------------------------------------------------------*/
05065 
05066 #ifdef USE_ROOT
05067 
05068 /*==== ROOT socket histo server ====================================*/
05069 
05070 #if defined ( OS_UNIX )
05071 #define THREADRETURN
05072 #define THREADTYPE void
05073 #endif
05074 #if defined( OS_WINNT )
05075 #define THREADRETURN 0
05076 #define THREADTYPE DWORD WINAPI
05077 #endif
05078 
05079 /*------------------------------------------------------------------*/
05080 
05081 TFolder *ReadFolderPointer(TSocket * fSocket)
05082 {
05083    //read pointer to current folder
05084    TMessage *m = 0;
05085    fSocket->Recv(m);
05086    POINTER_T p;
05087    *m >> p;
05088    return (TFolder *) p;
05089 }
05090 
05091 /*------------------------------------------------------------------*/
05092 
05093 THREADTYPE root_server_thread(void *arg)
05094 /*
05095   Serve histograms over TCP/IP socket link
05096 */
05097 {
05098    char request[256];
05099 
05100    TSocket *sock = (TSocket *) arg;
05101 
05102    do {
05103 
05104       /* close connection if client has disconnected */
05105       if (sock->Recv(request, sizeof(request)) <= 0) {
05106          // printf("Closed connection to %s\n", sock->GetInetAddress().GetHostName());
05107          sock->Close();
05108          delete sock;
05109          return THREADRETURN;
05110 
05111       } else {
05112 
05113          TMessage *message = new TMessage(kMESS_OBJECT);
05114 
05115          if (strcmp(request, "GetListOfFolders") == 0) {
05116 
05117             TFolder *folder = ReadFolderPointer(sock);
05118             if (folder == NULL) {
05119                message->Reset(kMESS_OBJECT);
05120                message->WriteObject(NULL);
05121                sock->Send(*message);
05122                delete message;
05123                continue;
05124             }
05125             //get folder names
05126             TObject *obj;
05127             TObjArray *names = new TObjArray(100);
05128 
05129             TCollection *folders = folder->GetListOfFolders();
05130             TIterator *iterFolders = folders->MakeIterator();
05131             while ((obj = iterFolders->Next()) != NULL)
05132                names->Add(new TObjString(obj->GetName()));
05133 
05134             //write folder names
05135             message->Reset(kMESS_OBJECT);
05136             message->WriteObject(names);
05137             sock->Send(*message);
05138 
05139             for (int i = 0; i < names->GetLast() + 1; i++)
05140                delete(TObjString *) names->At(i);
05141 
05142             delete names;
05143 
05144             delete message;
05145 
05146          } else if (strncmp(request, "FindObject", 10) == 0) {
05147 
05148             TFolder *folder = ReadFolderPointer(sock);
05149 
05150             //get object
05151             TObject *obj;
05152             if (strncmp(request + 10, "Any", 3) == 0)
05153                obj = folder->FindObjectAny(request + 14);
05154             else
05155                obj = folder->FindObject(request + 11);
05156 
05157             //write object
05158             if (!obj)
05159                sock->Send("Error");
05160             else {
05161                message->Reset(kMESS_OBJECT);
05162                message->WriteObject(obj);
05163                sock->Send(*message);
05164             }
05165             delete message;
05166 
05167          } else if (strncmp(request, "FindFullPathName", 16) == 0) {
05168 
05169             TFolder *folder = ReadFolderPointer(sock);
05170 
05171             //find path
05172             const char *path = folder->FindFullPathName(request + 17);
05173 
05174             //write path
05175             if (!path) {
05176                sock->Send("Error");
05177             } else {
05178                TObjString *obj = new TObjString(path);
05179                message->Reset(kMESS_OBJECT);
05180                message->WriteObject(obj);
05181                sock->Send(*message);
05182                delete obj;
05183             }
05184             delete message;
05185 
05186          } else if (strncmp(request, "Occurence", 9) == 0) {
05187 
05188             TFolder *folder = ReadFolderPointer(sock);
05189 
05190             //read object
05191             TMessage *m = 0;
05192             sock->Recv(m);
05193             TObject *obj = ((TObject *) m->ReadObject(m->GetClass()));
05194 
05195             //get occurence
05196             Int_t retValue = folder->Occurence(obj);
05197 
05198             //write occurence
05199             message->Reset(kMESS_OBJECT);
05200             *message << retValue;
05201             sock->Send(*message);
05202 
05203             delete message;
05204 
05205          } else if (strncmp(request, "GetPointer", 10) == 0) {
05206 
05207             //find object
05208             TObject *obj = gROOT->FindObjectAny(request + 11);
05209 
05210             //write pointer
05211             message->Reset(kMESS_ANY);
05212             POINTER_T p = (POINTER_T) obj;
05213             *message << p;
05214             sock->Send(*message);
05215 
05216             delete message;
05217 
05218          } else if (strncmp(request, "Command", 7) == 0) {
05219             char objName[100], method[100];
05220             sock->Recv(objName, sizeof(objName));
05221             sock->Recv(method, sizeof(method));
05222             TObject *object = gROOT->FindObjectAny(objName);
05223             if (object && object->InheritsFrom(TH1::Class())
05224                 && strcmp(method, "Reset") == 0)
05225                static_cast < TH1 * >(object)->Reset();
05226 
05227          } else if (strncmp(request, "SetCut", 6) == 0) {
05228 
05229             //read new settings for a cut
05230             char name[256];
05231             sock->Recv(name, sizeof(name));
05232             TCutG *cut = (TCutG *) gManaHistosFolder->FindObjectAny(name);
05233 
05234             TMessage *m = 0;
05235             sock->Recv(m);
05236             TCutG *newc = ((TCutG *) m->ReadObject(m->GetClass()));
05237 
05238             if (cut) {
05239                cm_msg(MINFO, "root server thread", "changing cut %s", newc->GetName());
05240                newc->TAttMarker::Copy(*cut);
05241                newc->TAttFill::Copy(*cut);
05242                newc->TAttLine::Copy(*cut);
05243                newc->TNamed::Copy(*cut);
05244                cut->Set(newc->GetN());
05245                for (int i = 0; i < cut->GetN(); ++i) {
05246                   cut->SetPoint(i, newc->GetX()[i], newc->GetY()[i]);
05247                }
05248             } else {
05249                cm_msg(MERROR, "root server thread", "ignoring receipt of unknown cut %s",
05250                       newc->GetName());
05251             }
05252             delete newc;
05253 
05254          } else
05255             printf("SocketServer: Received unknown command \"%s\"\n", request);
05256       }
05257    } while (1);
05258 
05259    return THREADRETURN;
05260 }
05261 
05262 /*------------------------------------------------------------------*/
05263 
05264 THREADTYPE root_socket_server(void *arg)
05265 {
05266 // Server loop listening for incoming network connections on specified port.
05267 // Starts a searver_thread for each connection.
05268    int port;
05269 
05270    port = *(int *) arg;
05271 
05272    printf("Root server listening on port %d...\n", port);
05273    TServerSocket *lsock = new TServerSocket(port, kTRUE);
05274 
05275    do {
05276       TSocket *sock = lsock->Accept();
05277 
05278       // printf("Established connection to %s\n", sock->GetInetAddress().GetHostName());
05279 
05280 #if defined ( __linux__ )
05281       TThread *thread = new TThread("Server", root_server_thread, sock);
05282       thread->Run();
05283 #endif
05284 #if defined( _MSC_VER )
05285       LPDWORD lpThreadId = 0;
05286       CloseHandle(CreateThread(NULL, 1024, &root_server_thread, sock, 0, lpThreadId));
05287 #endif
05288    } while (1);
05289 
05290    return THREADRETURN;
05291 }
05292 
05293 /*------------------------------------------------------------------*/
05294 
05295 void start_root_socket_server(int port)
05296 {
05297    static int pport = port;
05298 #if defined ( __linux__ )
05299    TThread *thread = new TThread("server_loop", root_socket_server, &pport);
05300    thread->Run();
05301 #endif
05302 #if defined( _MSC_VER )
05303    LPDWORD lpThreadId = 0;
05304    CloseHandle(CreateThread(NULL, 1024, &root_socket_server, &pport, 0, lpThreadId));
05305 #endif
05306 }
05307 
05308 /*------------------------------------------------------------------*/
05309 
05310 void *root_event_loop(void *arg)
05311 /*
05312   Thread wrapper around main event loop
05313 */
05314 {
05315    if (clp.online)
05316       loop_online();
05317    else
05318       loop_runs_offline();
05319 
05320    gSystem->ExitLoop();
05321 
05322    return NULL;
05323 }
05324 
05325 #endif                          /* USE_ROOT */
05326 
05327 /*------------------------------------------------------------------*/
05328 
05329 int main(int argc, char *argv[])
05330 {
05331    INT status, size;
05332    char str[256];
05333    HNDLE hkey;
05334 
05335 #ifdef HAVE_PVM
05336    int i;
05337 
05338    str[0] = 0;
05339    for (i = 0; i < argc; i++) {
05340       strcat(str, argv[i]);
05341       strcat(str, " ");
05342    }
05343    PVM_DEBUG("Analyzer started: %s", str);
05344 #endif
05345 
05346 #ifdef USE_ROOT
05347    int argn = 1;
05348    char *argp = (char *) argv[0];
05349 
05350    manaApp = new TRint("ranalyzer", &argn, &argp, NULL, 0, true);
05351 
05352    /* default server port */
05353    clp.root_port = 9090;
05354 #endif
05355 
05356    /* get default from environment */
05357    cm_get_environment(clp.host_name, sizeof(clp.host_name), clp.exp_name,
05358                       sizeof(clp.exp_name));
05359 
05360 #ifdef HAVE_HBOOK
05361    /* set default lrec size */
05362    clp.lrec = HBOOK_LREC;
05363 #endif                          /* HAVE_HBOOK */
05364 
05365    /* read in command line parameters into clp structure */
05366    status = getparam(argc, argv);
05367    if (status != CM_SUCCESS)
05368       return 1;
05369 
05370    /* become a daemon */
05371    if (clp.daemon) {
05372       printf("Becoming a daemon...\n");
05373       clp.quiet = TRUE;
05374       ss_daemon_init(FALSE);
05375    }
05376 
05377    /* set default buffer size */
05378    if (clp.pvm_buf_size == 0)
05379       clp.pvm_buf_size = 512 * 1024;
05380    else
05381       clp.pvm_buf_size *= 1024;
05382    if (clp.pvm_buf_size > PVM_BUFFER_SIZE) {
05383       printf("Buffer size cannot be larger than %dkB\n", PVM_BUFFER_SIZE / 1024);
05384       return 1;
05385    }
05386 
05387    /* set online mode if no input filename is given */
05388    clp.online = (clp.input_file_name[0][0] == 0);
05389 
05390 #ifdef HAVE_HBOOK
05391    /* set Ntuple format to RWNT if online */
05392    if (clp.online || equal_ustring(clp.output_file_name, "OFLN"))
05393       clp.rwnt = TRUE;
05394 #endif                          /* HAVE_HBOOK */
05395 
05396 #ifdef HAVE_PVM
05397    status = pvm_main(argv);
05398    if (status != CM_SUCCESS)
05399       return 1;
05400 #endif
05401 
05402 #ifdef USE_ROOT
05403    /* workaround for multi-threading with midas system calls */
05404    ss_force_single_thread();
05405 #endif
05406 
05407    /* now connect to server */
05408    if (clp.online) {
05409       if (clp.host_name[0])
05410          printf("Connect to experiment %s on host %s...", clp.exp_name, clp.host_name);
05411       else
05412          printf("Connect to experiment %s...", clp.exp_name);
05413    }
05414 
05415    status =
05416        cm_connect_experiment1(clp.host_name, clp.exp_name, analyzer_name, NULL, odb_size,
05417                               DEFAULT_WATCHDOG_TIMEOUT);
05418 
05419    if (status == CM_UNDEF_EXP) {
05420       printf("\nError: Experiment \"%s\" not defined.\n", clp.exp_name);
05421       if (getenv("MIDAS_DIR")) {
05422          printf
05423              ("Note that \"MIDAS_DIR\" is defined, which results in a single experiment\n");
05424          printf
05425              ("called \"Default\". If you want to use the \"exptab\" file, undefine \"MIDAS_DIR\".\n");
05426       }
05427       return 1;
05428    } else if (status != CM_SUCCESS) {
05429       cm_get_error(status, str);
05430       printf("\nError: %s\n", str);
05431       return 1;
05432    }
05433 
05434    if (clp.online)
05435       printf("OK\n");
05436 
05437    /* set online/offline mode */
05438    cm_get_experiment_database(&hDB, NULL);
05439    db_set_value(hDB, 0, "/Runinfo/Online Mode", &clp.online, sizeof(clp.online), 1,
05440                 TID_INT);
05441 
05442    if (clp.online) {
05443       /* check for duplicate name */
05444       status = cm_exist(analyzer_name, FALSE);
05445       if (status == CM_SUCCESS) {
05446          cm_disconnect_experiment();
05447          printf("An analyzer named \"%s\" is already running in this experiment.\n",
05448                 analyzer_name);
05449          printf
05450              ("Please select another analyzer name in analyzer.c or stop other analyzer.\n");
05451          return 1;
05452       }
05453 
05454       /* register transitions if started online */
05455       if (cm_register_transition(TR_START, tr_start, 300) != CM_SUCCESS ||
05456           cm_register_transition(TR_STOP, tr_stop, 700) != CM_SUCCESS ||
05457           cm_register_transition(TR_PAUSE, tr_pause, 700) != CM_SUCCESS ||
05458           cm_register_transition(TR_RESUME, tr_resume, 300) != CM_SUCCESS) {
05459          printf("Failed to start local RPC server");
05460          return 1;
05461       }
05462    } else {
05463       if (!pvm_slave) {         /* slave could run on same machine... */
05464          status = cm_exist(analyzer_name, FALSE);
05465          if (status == CM_SUCCESS) {
05466             /* kill hanging previous analyzer */
05467             cm_cleanup(analyzer_name, FALSE);
05468 
05469             status = cm_exist(analyzer_name, FALSE);
05470             if (status == CM_SUCCESS) {
05471                /* analyzer may only run once if offline */
05472                status = cm_shutdown(analyzer_name, FALSE);
05473                if (status == CM_SHUTDOWN)
05474                   printf("Previous analyzer stopped\n");
05475             }
05476          }
05477       }
05478    }
05479 
05480 #ifdef HAVE_HBOOK
05481    /* register callback for clearing histos */
05482    cm_register_function(RPC_ANA_CLEAR_HISTOS, ana_callback);
05483 #endif
05484 
05485    /* turn on keepalive messages */
05486    cm_set_watchdog_params(TRUE, DEFAULT_RPC_TIMEOUT);
05487 
05488    /* decrease watchdog timeout in offline mode */
05489    if (!clp.online)
05490       cm_set_watchdog_params(TRUE, 2000);
05491 
05492    /* turn off watchdog if in debug mode */
05493    if (clp.debug)
05494       cm_set_watchdog_params(0, 0);
05495 
05496    /* initialize module parameters */
05497    if (init_module_parameters(FALSE) != CM_SUCCESS) {
05498       cm_disconnect_experiment();
05499       return 1;
05500    }
05501 
05502    /* create ODB structure for output */
05503    sprintf(str, "/%s/Output", analyzer_name);
05504    db_check_record(hDB, 0, str, ANA_OUTPUT_INFO_STR, TRUE);
05505    db_find_key(hDB, 0, str, &hkey);
05506    assert(hkey);
05507    size = sizeof(out_info);
05508    db_get_record(hDB, hkey, &out_info, &size, 0);
05509 
05510 #ifdef USE_ROOT
05511    /* create the folder for analyzer histograms */
05512    gManaHistosFolder =
05513        gROOT->GetRootFolder()->AddFolder("histos", "MIDAS Analyzer Histograms");
05514    gHistoFolderStack = new TObjArray();
05515    gROOT->GetListOfBrowsables()->Add(gManaHistosFolder, "histos");
05516 
05517    /* convert .rz names to .root names */
05518    if (strstr(out_info.last_histo_filename, ".rz"))
05519       strcpy(out_info.last_histo_filename, "last.root");
05520 
05521    if (strstr(out_info.histo_dump_filename, ".rz"))
05522       strcpy(out_info.histo_dump_filename, "his%05d.root");
05523 
05524    db_set_record(hDB, hkey, &out_info, sizeof(out_info), 0);
05525 
05526    /* start socket server */
05527    if (clp.root_port)
05528       start_root_socket_server(clp.root_port);
05529 
05530 #endif                          /* USE_ROOT */
05531 
05532 #ifdef HAVE_HBOOK
05533    /* convert .root names to .rz names */
05534    if (strstr(out_info.last_histo_filename, ".root"))
05535       strcpy(out_info.last_histo_filename, "last.rz");
05536 
05537    if (strstr(out_info.histo_dump_filename, ".root"))
05538       strcpy(out_info.histo_dump_filename, "his%05d.rz");
05539 
05540    db_set_record(hDB, hkey, &out_info, sizeof(out_info), 0);
05541 #endif
05542 
05543 #ifdef HAVE_HBOOK
05544    /* create global memory */
05545    if (clp.online) {
05546       HLIMAP(pawc_size / 4, out_info.global_memory_name);
05547       printf("\nGLOBAL MEMORY NAME = %s\n", out_info.global_memory_name);
05548    } else {
05549       if (equal_ustring(clp.output_file_name, "OFLN")) {
05550          strcpy(str, "OFLN");
05551          HLIMAP(pawc_size / 4, str);
05552          printf("\nGLOBAL MEMORY NAME = %s\n", "OFLN");
05553       } else
05554          HLIMIT(pawc_size / 4);
05555    }
05556 #endif                          /* HAVE_HBOOK */
05557 
05558    /* analyzer init function */
05559    if (mana_init() != CM_SUCCESS) {
05560       cm_disconnect_experiment();
05561       return 1;
05562    }
05563 
05564    /* load histos from last.xxx */
05565    if (clp.online)
05566       load_last_histos();
05567 
05568    /* reqister event requests */
05569    register_requests();
05570 
05571    /* initialize ss_getchar */
05572    if (!clp.quiet && !pvm_slave)
05573       ss_getchar(0);
05574 
05575    /*---- start main loop ----*/
05576 
05577    if (clp.online)
05578       loop_online();
05579    else
05580       loop_runs_offline();
05581 
05582    /* reset terminal */
05583    if (!clp.quiet && !pvm_slave)
05584       ss_getchar(TRUE);
05585 
05586    /* call exit function */
05587    mana_exit();
05588 
05589    /* save histos to last.xxx */
05590    if (clp.online)
05591       save_last_histos();
05592 
05593 #ifdef HAVE_PVM
05594 
05595    PVM_DEBUG("Analyzer stopped");
05596 
05597    /* exit PVM */
05598    pvm_exit();
05599 
05600    /* if PVM slave, don't write *SHM file back */
05601    if (pvm_slave)
05602       disable_shm_write = TRUE;
05603 
05604 #endif
05605 
05606    /* disconnect from experiment */
05607    cm_disconnect_experiment();
05608 
05609 #ifdef USE_ROOT
05610    if (clp.start_rint)
05611       manaApp->Run(true);
05612    printf("\r               \n");       /* overwrite superflous ROOT prompt */
05613 #endif
05614 
05615    return 0;
05616 }
05617 
05618 #ifdef LINK_TEST
05619 int   odb_size;
05620 char* analyzer_name;
05621 int   analyzer_loop_period;
05622 ANALYZE_REQUEST analyze_request[1];
05623 int analyzer_init(void) { return 0; }
05624 int analyzer_loop(void) { return 0; }
05625 int analyzer_exit(void) { return 0; }
05626 int ana_end_of_run(INT run_number, char *error) { return 0; }
05627 int ana_begin_of_run(INT run_number, char *error) { return 0; }
05628 int ana_resume_run(INT run_number, char *error) { return 0; }
05629 int ana_pause_run(INT run_number, char *error) { return 0; }
05630 #endif

Midas DOC Version 3.0.0 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - Sergio Ballestrero - Suzannah Daviel - Doxygen - Peter Green - Qing Gu - Greg Hackman - Gertjan Hofman - Paul Knowles - Exaos Lee - Rudi Meier - Glenn Moloney - Dave Morris - John M O'Donnell - Konstantin Olchanski - Renee Poutissou - Tamsen Schurman - Andreas Suter - Jan M.Wouters - Piotr Adam Zolnierczuk