From:	MERC::"uunet!WKUVX1.BITNET!FILESERV-Mgr"  6-MAY-1992 20:46:09.72
To:	galaxy::gleeve
CC:	
Subj:	NOTICE.04_OF_06

-+-+-+-+-+-+-+-+ START OF PART 4 -+-+-+-+-+-+-+-+
X`0C
X%SBTTL`09'DISPLAY_TOPICS'
XROUTINE display_topics (key_name_a, rfa_a) =
XBEGIN
X!+
X!
X!  Routine:`09DISPLAY_TOPICS
X!
X!  Functional Description:
X!
X!`09This routine is called by LBR$GET_INDEX to display the first line
X!`09and module name for a given module.  This routine compares the
X!`09module's insertion date with the login time and only displays those
X!`09modules that have been added since the user's last interactive login.
X!
X!  Environment:
X!
X!`09User mode.
X!
X!  Formal parameters:
X!
X!`09key_name_a`09- Address of descriptor for the module's key
X!`09rfa_a`09`09- Address of the record's RFA
X!
X!  Implicit inputs:
X!
X!`09lastlogin_i, notice_count, module_header, header_buff, line, fao_out,
X!`09null_line
X!
X!  Outputs:
X!
X!`09None.
X!
X!  Returns:
X!
X!`09R0`09- Status
X!
X!-
XBIND
X`09key_name`09= .key_name_a`09: $BBLOCK,
X`09rfa`09`09= .rfa_a`09: VECTOR`5B2,LONG`5D;
X
XOWN
X`09temp`09`09: VECTOR`5B2,LONG`5D;
X
XLOCAL
X`09always_display`09: INITIAL(false);
X
XREGISTER
X`09status`09`09: UNSIGNED LONG;
X
XEXTERNAL
X`09LIB$_NEGTIM`09: ADDRESSING_MODE(ABSOLUTE);
X
X  !
X  !  Check the key name to see if this topic should always be displayed.
X  !
X  IF (CH$RCHAR(.key_name`5BDSC$A_POINTER`5D) NEQU %C'$')
X  THEN
X     BEGIN
X     status = LBR$SET_MODULE (lib_index_ptr, rfa, module_header, module_head
Ver);
X     IF NOT(.status) OR
X`09(LIB$SUB_TIMES(header_buff`5BMHD$L_DATIM`5D, lastlogin_i, temp) EQLU
X`09 LIB$_NEGTIM)
X     THEN
X`09RETURN (.status);
X     END;
X
X  !
X  !  Here, either the module should always be displayed or the insertion
X  !  date is more recent than the user's last login.  We need to look up
X  !  the first line and display that on the screen.
X  !
X  notice_count = .notice_count + 1;
X  RETURN (sort_notices(key_name, rfa));
X
XEND;
X
X`0C
X%SBTTL`09'DISPLAY_NOTICE_TEXT'
XROUTINE display_notice_text (index_a, topic_a) =
XBEGIN
X!+
X!
X!  Routine:`09DISPLAY_NOTICE_TEXT
X!
X!  Functional Description:
X!
X!`09This routine is called to display the text of a particular notice.
X!
X!  Environment:
X!
X!`09User mode.
X!
X!  Formal parameters:
X!
X!`09index_a`09`09- Address of library index pointer
X!`09topic_a`09`09- Address of string descriptor for the topic name
X!
X!  Implicit inputs:
X!
X!`09fao_out, line, module_header, header_buff, null_line
X!
X!  Outputs:
X!
X!`09None.
X!
X!  Returns:
X!
X!`09R0`09- Status
X!
X!-
XBIND
X`09lib_index_ptr`09= .index_a`09: UNSIGNED LONG,
X`09topic`09`09= .topic_a`09: $BBLOCK;
X
XOWN
X`09rfa`09`09: VECTOR`5B2,LONG`5D;`09!Module's Record file address
X
XREGISTER
X`09status`09`09: UNSIGNED LONG;
X
X  !
X  !  Reset descriptor lengths for buffers
X  !
X  module_header`5BDSC$W_LENGTH`5D = fao_out`5BDSC$W_LENGTH`5D = txt$c_bufsiz
V;
X
X  !
X  !  Now lookup the module using the key, setting the rfa for that module.
X  !
X  status = LBR$LOOKUP_KEY (lib_index_ptr, topic, rfa);`09!Lookup the module
X  IF (.status EQLU LBR$_KEYNOTFND)`09`09`09!If the key was not
X  THEN`09`09`09`09`09`09`09!... found, slap a
X     BEGIN`09`09`09`09`09`09!... "$" at the front
X     LOCAL`09`09`09`09`09`09!... and look again
X`09temp_desc : $dyndesc;
X     STR$CONCAT (temp_desc, dollar_sign_d, topic);
X     status = LBR$LOOKUP_KEY (lib_index_ptr, temp_desc, rfa);
X     END;
X  errret(status);
X
X  !
X  !  Get the module header so we can display the date.
X  !
X  status = LBR$SET_MODULE (lib_index_ptr, rfa, module_header, module_header)
V;
X  errret(status);
X
X  !
X  !  Format the header and print it out.
X  !
X  $FAO (%ASCID'Notice !AS, dated !%D', fao_out, fao_out, topic,
X`09`09 header_buff`5BMHD$L_DATIM`5D);
X  hg$put_output (fao_out);
X  hg$put_output (null_line);
X
X  !
X  !  Call LBR$GET_RECORD and display each record until EOF is returned.
X  !
X  WHILE (BEGIN`09`09`09`09`09!Loop while more records....
X`09 line`5BDSC$W_LENGTH`5D = txt$c_bufsiz;`09!Reset descriptor length
X`09 status = LBR$GET_RECORD (lib_index_ptr, line, line)`09!Get record
X`09 END)
X  DO`09`09`09`09`09`09!While there are more records,
X    hg$put_output (line);`09`09`09`09!... write them to SYS$OUTPUT
X
X  hg$put_output (null_line);`09`09`09!Print blank line
X  RETURN ((IF (.status EQLU RMS$_EOF)`09`09!If error was EOF, then return
X`09   THEN`09`09`09`09`09!.... normal success status
X`09      SS$_NORMAL`09`09`09!....
X`09   ELSE`09`09`09`09`09!Otherwise, return whatever
X`09      .status));`09`09`09!.... the status is
X
XEND;
X
X`0C
X%SBTTL`09'SORT_NOTICES'
XROUTINE sort_notices (key_name_a, rfa_a) =
XBEGIN
X!+
X!
X!  Routine:`09SORT_NOTICES
X!
X!  Functional Description:
X!
X!`09This routine is called by LBR$GET_INDEX for each module that is found.
X!`09It then calls LIB$INSERT_TREE to insert the module info into a b-tree.
X!
X!  Formal parameters:
X!
X!`09key_name_a`09= Address of descriptor for the key name
X!`09rfa_a`09`09= Address of RFA for the module
X!
X!  Implicit Inputs:
X!
X!`09treehead
X!
X!  Returns:
X!
X!`09R0`09- Status
X!
X!  Side effects:
X!
X!`09Allocates memory via LIB$GET_VM.
X!
X!-
XBIND
X`09key_name`09= .key_name_a`09: $BBLOCK,
X`09rfa`09`09= .rfa_a`09: VECTOR`5B2,LONG`5D;
X
XBIND
X`09fao_data`09= %ASCID'!10AD !11%D  !55AS';
X
XLOCAL
X`09always_display`09: INITIAL (false),
X`09temp_node`09: LONG;
X
XREGISTER
X`09status`09: UNSIGNED LONG;
X
X  status = LBR$SET_MODULE (lib_index_ptr, rfa, module_header, module_header)
V;
X
X  !
X  !  Here, we have the module header.  Format the topic name and the date.
X  !
X
X  status = LBR$FIND (lib_index_ptr, rfa);`09!Find the right module
X  errret(status);`09`09`09`09!Return any error
X
X  line`5BDSC$W_LENGTH`5D = txt$c_bufsiz;`09`09!Reset descriptor length
X  status = LBR$GET_RECORD (lib_index_ptr, line, line);`09!Get the first line
X  errret(status);`09`09`09`09!Return any error
X
X  IF CH$RCHAR(.key_name`5BDSC$A_POINTER`5D) EQLU %C'$'
X  THEN
X      always_display = true;
X
X  fao_out`5BDSC$W_LENGTH`5D = txt$c_bufsiz;
X  status = $FAO (fao_data, fao_out, fao_out,
X`09`09(IF .always_display`09`09`09!Skip over the dollar
X`09`09 THEN`09`09`09`09`09!... sign if it's
X`09`09    .key_name`5BDSC$W_LENGTH`5D - 1`09`09!... there
X`09`09 ELSE
X`09`09    .key_name`5BDSC$W_LENGTH`5D),
X`09`09(IF .always_display
X`09`09 THEN
X`09`09    .key_name`5BDSC$A_POINTER`5D + 1
X`09`09 ELSE
X`09`09    .key_name`5BDSC$A_POINTER`5D),
X`09`09 header_buff`5BMHD$L_DATIM`5D, line);
X  errret(status);`09`09`09`09!Return any error
X
X  RETURN (LIB$INSERT_TREE (`09`09`09!Insert this line into the
X`09`09`09treehead,`09`09!...tree, to be sorted by
X`09`09`09header_buff`5BMHD$L_DATIM`5D,`09!...insertion date
X`09`09`09%REF(0),`09`09!...don't allow duplicates
X`09`09`09compare_node,`09`09!...the comparison routine
X`09`09`09alloc_node,`09`09!...the VM allocation routine
X`09`09`09temp_node,`09`09!...the node allocated
X`09`09`09fao_out));`09`09!...
X
XEND;`09`09`09`09`09`09!End of alloc_node
X
X`0C
X%SBTTL`09'ALLOC_NODE'
XROUTINE alloc_node (key_a, retdesc_a, data_a) =
XBEGIN
X!+
X!
X!  Routine:`09ALLOC_NODE
X!
X!  Functional Description:
X!
X!`09This routine is called by LIB$INSERT_TREE to allocate memory for
X!`09the node; the username is used as the key for sorting the tree.
X!
X!  Formal parameters:
X!
X!`09key_a`09`09= Address of descriptor for the key
X!`09retdesc_a`09= Address of longword to receive address of memory
X!`09data_a`09`09= Address of descriptor for user data
X!
X!  Implicit Inputs:
X!
X!`09sysuaf_fab, sysuaf_rab, sysuaf_buffer
X!
X!  Returns:
X!
X!`09R0`09- Status
X!
X!  Side effects:
X!
X!`09Allocates memory via LIB$GET_VM.
X!
X!-
XREGISTER
X`09status`09: UNSIGNED LONG;
X
XBIND
X`09key`09= .key_a`09: VECTOR`5B2,LONG`5D,
X`09retdesc = .retdesc_a`09: LONG,
X`09data`09= .data_a`09: $BBLOCK;
X
XOWN
X`09noderef`09: REF $BBLOCK;`09!points to the node allocated
X
X  status = LIB$GET_VM (`09`09`09`09!allocate some memory
X`09%REF(NODE$C_TOTLENGTH), `09`09!...the length
X`09noderef);`09`09`09`09!...where to put the address
X  IF (.status)`09`09`09`09`09!successful allocation?
X  THEN`09`09`09`09`09`09!Yes,
X     BEGIN
X     LOCAL ptr : REF VECTOR`5B2,LONG`5D;
X     ptr = noderef`5Bnode$q_abstim`5D;`09`09!Get pointer
X     ptr`5B0`5D = .key`5B0`5D;
X     ptr`5B1`5D = .key`5B1`5D;
X
X     noderef`5Bnode$w_datalen`5D = `09`09`09!Copy the length of the user
X`09`09.data`5BDSC$W_LENGTH`5D;`09`09!...data
X     CH$MOVE (`09`09`09`09`09!Copy the user data
X`09.data`5BDSC$W_LENGTH`5D, `09`09`09!...
X`09.data`5BDSC$A_POINTER`5D,`09`09`09!...
X`09noderef`5Bnode$t_data`5D);`09`09`09!...
X     retdesc = .noderef;`09`09`09!Return address of the node
X
X     END;
X
X  RETURN (.status);`09`09`09`09!Return the final status
X
XEND;`09`09`09`09`09`09!End of alloc_node
X
X`0C
X%SBTTL`09'COMPARE_NODE'
XROUTINE compare_node (key_a, node_a, data_a) =
XBEGIN
X!+
X!
X!  Routine:`09COMPARE_NODE
X!
X!  Functional Description:
X!
X!`09This routine is called by LIB$INSERT_TREE to compare two nodes.
X!
X!  Formal parameters:
X!
X!`09key_a`09`09= Address of quadword time value
X!`09node_a`09`09= Address of node to compare
X!`09data_a`09`09= Address of descriptor for user data
X!
X!  Implicit Inputs:
X!
X!`09sysuaf_fab, sysuaf_rab, sysuaf_buffer
X!
X!  Returns:
X!
X!`09R0`09- -1`09- First is less than second
X!`09`09   0`09- Two are equal
X!`09`09   1`09- First is greater than second
X!
X!-
X  BIND
X`09key`09= .key_a`09: VECTOR`5B2,LONG`5D,
X`09node`09= .node_a`09: $BBLOCK,
X`09data`09= .data_a`09: $BBLOCK;
X
X  LOCAL
X`09work`09: VECTOR`5B2,LONG`5D;
X
XEXTERNAL
X`09LIB$_NEGTIM`09: ADDRESSING_MODE(ABSOLUTE);
X
X  IF (LIB$SUB_TIMES (key, node`5Bnode$q_abstim`5D, work) EQLU LIB$_NEGTIM)
X  THEN
X     RETURN 1
X  ELSE
X     !
X     !  If the two times are equal, LIB$SUB_TIMES returns .1 instead of
X     !  0., because a 0 time is invalid in VMS.  .1 is represented as
X     !  -1 in both longwords.
X     !
X     IF (.work`5B0`5D EQLU -1) AND (.work`5B1`5D EQLU -1)`09!Were they equal
V?
X     THEN`09`09`09`09`09`09!If so, return 0
X`09RETURN 0
X     ELSE
X`09RETURN -1;
X
XEND;`09`09`09`09`09`09!End of compare_node
X
X`0C
X%SBTTL`09'PRINT_NODE'
XROUTINE print_node (node_a, data_a) =
XBEGIN
X!+
X!
X!  Routine:`09PRINT_NODE
X!
X!  Functional Description:
X!
X!`09This routine is called by LIB$TRAVERSE_TREE to write node information
X!`09to the output file.  It is called once for each node in the tree.
X!
X!`09The output routine used is LIB$PUT_OUTPUT.
X!
X!  Inputs:
X!
X!`09node_a`09`09= Address of longword containing the node address
X!`09data_a`09`09= Address of descriptor for user data
X!
X!  Implicit Inputs:
X!
X!
X!  Returns:
X!
X!`09R0`09- Status
X!
X!-
XBIND
X`09node`09= .node_a`09: $BBLOCK,
X`09data`09= .data_a`09: $BBLOCK;
X
XLOCAL
X`09ptr`09`09: REF $BBLOCK,
X`09work_desc`09: $staticdesc(0,0);
X
X  ptr = work_desc`5BDSC$A_POINTER`5D = node`5Bnode$t_data`5D;
X
X  ptr = .ptr + .node`5Bnode$w_datalen`5D;`09`09!Point to last byte
X  WHILE (CH$RCHAR(.ptr) EQLU %C' ') DO`09`09!Trim any blanks off end by
X     ptr = .ptr - 1;`09`09`09`09!... decrementing the pointer
X
X  work_desc`5BDSC$W_LENGTH`5D = CH$DIFF(.ptr, .work_desc`5BDSC$A_POINTER`5D)
V;
X
X  RETURN (LIB$PUT_OUTPUT(work_desc));
X
XEND;`09`09`09`09`09`09!end of print_node
X`0C
X%SBTTL`09'PRINT_NODE_SMG'
XROUTINE print_node_smg (node_a, data_a) =
XBEGIN
X!+
X!
X!  Routine:`09PRINT_NODE_SMG
X!
X!  Functional Description:
X!
X!`09This routine is called by LIB$TRAVERSE_TREE to write node information
X!`09to the output file.  It is called once for each node in the tree.
X!
X!`09The output routine is hg$put_output, which uses SMG$.
X!
X!  Inputs:
X!
X!`09node_a`09`09= Address of longword containing the node address
X!`09data_a`09`09= Address of descriptor for user data
X!
X!  Implicit Inputs:
X!
X!
X!  Returns:
X!
X!`09R0`09- Status
X!
X!-
XBIND
X`09node`09= .node_a`09: $BBLOCK,
X`09data`09= .data_a`09: $BBLOCK;
X
XLOCAL
X`09ptr`09`09: REF $BBLOCK,
X`09work_desc`09: $staticdesc(0,0);
X
X  ptr = work_desc`5BDSC$A_POINTER`5D = node`5Bnode$t_data`5D;
X
X  ptr = .ptr + .node`5Bnode$w_datalen`5D;`09`09!Point to last byte
X  WHILE (CH$RCHAR(.ptr) EQLU %C' ') DO`09`09!Trim any blanks off end by
X     ptr = .ptr - 1;`09`09`09`09!... decrementing the pointer
X
X  work_desc`5BDSC$W_LENGTH`5D = CH$DIFF(.ptr, .work_desc`5BDSC$A_POINTER`5D)
V;
X
X  RETURN (hg$put_output(work_desc));
X
XEND;`09`09`09`09`09`09!end of print_node
X
XEND`09`09`09`09`09`09!End of module BEGIN
XELUDOM`09`09`09`09`09`09!End of module
$ CALL UNPACK [.NOTICE]NOTICE.B32;1 1043602417
$ create 'f'
X.!
X.!  File:       NOTICE.HELP
X.!
X.!  Author:     Hunter Goatley
X.!
X.!  Date:       March 10, 1992
X.!
X.!  Abstract:   Source file to build RUNOFF .RNH file for NOTICE on-line hel
Vp
X.!
X.!
X<INIT>
X<MAIN>
XNOTICE
X
XNOTICE informs users of important (?) notices when they log in to VMS.
XWhen you log in, any notices that have been added since the last time you
Xlogged in are displayed.  For more information on a given topic, just type
XNOTICE followed by the topic name.
X
XIf you type NOTICE without any parameters, any notices displayed upon login
V are
Xdisplayed again.  The /LIST qualifier can be used to list all notices in the
Xdatabase.
X
X<FORMAT>
X$ NOTICE `5Btopic`5D
X
X<TOPIC>
XParameter
X
XA topic name may be specified on the command line to display the complete te
Vxt
Xof any notice in the database.  If the topic is omitted, NOTICE checks the
Xdatabase for messages added since your last interactive login.
X
X<QUALIFIER>
X/LIST
X
X/LIST
X
XDisplays all of the notices stored in the NOTICE database.  The topic keywor
Vd
Xfor the notice, its creation date, and a one-line description are displayed.
$ CALL UNPACK [.NOTICE]NOTICE.HELP;1 740385021
$ create 'f'
X;MACRO-32 source generated by BLISS-32 compiler
X`09.TITLE  NOTICE NOTICE
X`09.IDENT  \01-004\
X`09.PSECT  $OWN$,NOEXE,2
XU.11:`09.BLKB   256
XU.12:`09.WORD   256
X`09.BYTE   14, 1
X`09.ADDRESS U.11
XU.13:`09.BLKB   256
XU.14:`09.WORD   256
X`09.BYTE   14, 1
X`09.ADDRESS U.13
XU.15:`09.BLKB   256
XU.16:`09.WORD   256
X`09.BYTE   14, 1
X`09.ADDRESS U.15
XU.17:`09.BLKB   8
XU.18:`09.BLKB   4
XU.19:`09.BLKB   4
+-+-+-+-+-+-+-+-  END  OF PART 4 +-+-+-+-+-+-+-+-
