=========================== start of opcom_catcher.opt ===================== ! Command line: LINK [/NOTRACE] OPCOM_CATCHER /OPT ! opcom_catcher poke_pcb sys$library:vaxcrtl/share =========================== start of opcom_catcher.c ======================= /* * OPCOM_CATCHER.C - catch OPCOM messages. */ #include ctype /* character type */ #include descrip /* definitions for the descriptor structure */ #include iodef /* definitions for the function codes */ #include opcdef /* sndopr message fields */ #include stsdef /* VMS status code definitions */ #include ttdef /* terminal characteristics */ #include tt2def /* extended terminal characteristics */ typedef struct { unsigned short status; unsigned short len; unsigned long devinfo; } IOSB; static char dev_name_str [] = " "; static $DESCRIPTOR(device_name, dev_name_str); #define DEVICE_TYPE "LTA" #define DEVICE_NUM 4444 /* * Minimum size of a "real" operator message. */ #define MSG_MIN 22 /* * Structure of an operator message. * Last byte of message is typically (without ) */ typedef struct { char junk [MSG_MIN]; char bell [1]; char percents_1 [11]; char spaces_opcom_spaces [9]; char date_time [23]; char spaces_after_date_time [2]; char percents_2 [11]; char crlf [2]; char rest [1]; /* actually longer ! */ } OPERATOR_MSG; static readonly $DESCRIPTOR(mailbox_name, "OPCOM_catcher_mailbox"); #define check(status) {if (! ((status) & STS$M_SUCCESS)) exit(status);} /* * Simplified layout of operator terminal request, which allows us to * fill in everything at compile time. */ typedef struct { char type; char enable; short unused; long mask; short unit; char name_len; char name [15]; } MY_OPC; static readonly MY_OPC buffer = { OPC$_RQ_TERME, /* request type */ 1, /* enable flag */ 0, /* unused */ -1, /* mask for all messages */ DEVICE_NUM, /* unit number */ sizeof(DEVICE_TYPE) - 1, DEVICE_TYPE }; extern poke_pcb (); main () { char inbuf [256]; struct dsc$descriptor_s oprdesc = { (&buffer.name - &buffer.type) + buffer.name_len, DSC$K_DTYPE_T, DSC$K_CLASS_S, &buffer }; IOSB iosb; int chan; int mbchan; int status; char *arglist [2] = { 1, &device_name }; int chars [3]; /* terminal characteristics */ /* * Encode the device type and number to form a valid device name. */ sprintf(device_name.dsc$a_pointer, "%s%d:", DEVICE_TYPE, DEVICE_NUM); device_name.dsc$w_length = strlen(device_name.dsc$a_pointer); status = sys$alloc(&device_name, 0, 0, 0, 0); check(status); status = sys$crembx(0, &mbchan, 0, 0, 0, 0, &mailbox_name); check(status); /* * Assign mailbox channel to terminal. */ status = sys$assign(&device_name, &chan, 0, &mailbox_name); check(status); /* * Get the current terminal characteristics, and modify them. */ status = sys$qiow(0, chan, IO$_SENSEMODE, &iosb, 0, 0, chars, sizeof(chars), 0, 0, 0, 0); check(status); check(iosb.status); chars[1] &= ~(TT$M_NOBRDCST); /* Allow broadcast */ chars[2] |= TT2$M_BRDCSTMBX; /* Specify broadcast mailbox */ status = sys$qiow(0, chan, IO$_SETMODE, &iosb, 0, 0, chars, sizeof(chars), 0, 0, 0, 0); check(status); check(iosb.status); /* * Hack the process's terminal in the PCB. */ sys$cmkrnl(&poke_pcb, &arglist); status = sys$sndopr(&oprdesc, 0); check(status); while (1) { status = sys$qiow(0, mbchan, IO$_READVBLK, &iosb, 0, 0, inbuf, sizeof(inbuf), 0, 0, 0, 0); check(status); check(iosb.status); if (iosb.len > MSG_MIN) { OPERATOR_MSG *msg = (OPERATOR_MSG *)inbuf; inbuf[iosb.len] = '\0'; /* * Here, we can filter the message; it starts at msg->bell. * The following code just outputs it. */ { struct dsc$descriptor_s outbuf = { strlen(msg->bell), DSC$K_DTYPE_T, DSC$K_CLASS_S, &msg->bell }; status = lib$put_output(&outbuf); check(status); } } } } =========================== start of poke_pcb.mar ========================== ; POKE_PCB.MAR - fudge terminal name in PCB for OPCOM_CATCHER. ; .title poke_pcb .library "sys$share:lib.mlb" $pcbdef .psect code .entry poke_pcb, 0 movl 4(ap), r0 ;get descriptor to r0 movzbl (r0), r1 ;get string length to r1 cmpb r1, #pcb$s_terminal ;must be less than field size blss len_ok movb #pcb$s_terminal-1, r1 ;maximum possible size len_ok: movl 4(r0), r0 ;get string address to r0 movb r1, pcb$t_terminal(r4) ;store length movc3 r1, (r0), pcb$t_terminal+1(r4) ;copy terminal name movl #ss$_normal, r0 ret .end =========================== start of opcom_catcher.com ===================== $! Do MC LATCP CRE PORT LTA4444 (etc) before running this. $ run /detach - /buffer=20000 - /page_file=10000 - /priv=all - /proc="OPCOM catcher" - /input=nl: - /output=opcom_catcher.log - /error=opcom_catcher.log - /uic=[1,4] - opcom_catcher.exe