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

$PART3:
$ CALL UNPACK [.NOTICE]HG$PUT_OUTPUT.MAR;1 2002938325
$ create 'f'
XMACRO errchk(variable) =`09`09`09!Signal any errors
X`09IF NOT (.variable) THEN SIGNAL (.variable)%;
X
XMACRO reterrchk(variable) =`09`09`09!Return any errors
X`09IF NOT (.variable) THEN RETURN (.variable)%;
X
XMACRO retnosignal(variable) =`09`09`09!Return an error, inhibiting
X`09RETURN (.variable OR STS$M_INHIB_MSG)%;`09!... signalling
X
XLITERAL
X`09true`09= 1,
X`09false`09= 0;
X
X!
X! MACROS
X!
XMACRO`09`09`09`09`09!Static and dynamic descriptor macros
X`09$DYNDESC =`09`09`09!Dynamic descriptor declaration
X`09`09$BBLOCK`5BDSC$C_S_BLN`5D
X`09`09PRESET`09(`5BDSC$W_LENGTH`5D = 0,
X`09`09`09 `5BDSC$B_DTYPE`5D`09= DSC$K_DTYPE_T,
X`09`09`09 `5BDSC$B_CLASS`5D`09= DSC$K_CLASS_D,
X`09`09`09 `5BDSC$A_POINTER`5D= 0)
X`09%,
X`09$STATICDESC (len, addr) =`09!Static descriptor declaration
X`09`09$BBLOCK`5BDSC$C_S_BLN`5D
X`09`09PRESET`09(`5BDSC$W_LENGTH`5D = len,
X`09`09`09 `5BDSC$B_DTYPE`5D`09= DSC$K_DTYPE_T,
X`09`09`09 `5BDSC$B_CLASS`5D`09= DSC$K_CLASS_S,
X`09`09`09 `5BDSC$A_POINTER`5D= addr)
X`09%;
$ CALL UNPACK [.NOTICE]HGMACROS.REQ;1 2015681188
$ create 'f'
X%TITLE`09'NOTICE'
XMODULE NOTICE (MAIN = main, IDENT = '01-004') =`20
XBEGIN
X!++
X!
X!  Facility:`09NOTICE
X!
X!  Author:`09Hunter Goatley
X!
X!  Date:`09February 13, 1992
X!
X!  Abstract:
X!
X!`09This program displays notices when a user logs in.  It scans
X!`09a text library looking for topics added after a user's last
X!`09interactive login date and displays a notice about each one.
X!
X!`09When invoked with a subject, it displays the text for that
X!`09subject.
X!
X!  Modified by:
X!
X!`0901-004`09`09Hunter Goatley`09`09 6-MAY-1992 08:09
X!`09`09Fixed stupid omission of BEGIN-END when checking new
X!`09`09notices that caused headers to be printed when they
X!`09`09weren't supposed to be.  Also added a couple of
X!`09`09NOTICE error messages.
X!
X!`0901-003`09`09Hunter Goatley`09`0923-APR-1992 09:12
X!`09`09Modified so that the "$" in permanent notices is not
X!`09`09displayed.  Essentially, the "$" is only visible to
X!`09`09someone using the DCL command LIBRARY/LIST.
X!
X!`09`09Also reworked the format of the new notices so that it
X!`09`09looks more like NOTICE/LIST output (except that SMG is
X!`09`09not used for the output to avoid clearing the screen).
X!
X!`0901-002`09`09Hunter Goatley`09`0913-MAR-1992 09:06
X!`09`09Moved output routines to external module.  Cleaned up
X!`09`09code some.
X!
X!`0901-001`09`09Hunter Goatley`09`0910-MAR-1992 15:54
X!`09`09Added routine put_output, support for sorting notices
X!`09`09based on insertion time, and the /LIST qualifier.
X!
X!`0901-000`09`09Hunter Goatley`09`0913-FEB-1992 10:39
X!`09`09Original version.
X!
X!--
XLIBRARY 'SYS$LIBRARY:STARLET';`09`09`09!Pull stuff from STARLET
X
XREQUIRE 'HGMACROS.REQ';
X
XSWITCHES ADDRESSING_MODE (EXTERNAL = GENERAL, NONEXTERNAL = WORD_RELATIVE);
X
XFORWARD ROUTINE
X`09main,`09`09`09`09`09!Main entry point
X`09display_new_notices,`09`09`09!Display any new notices
X`09display_all_notices,`09`09`09!Display any new notices
X`09display_topics,`09`09`09`09!Display a topic header
X`09display_notice_text,`09`09`09!Display text for a notice
X`09sort_notices,`09`09`09`09!Sort notices by date
X`09alloc_node,`09`09`09`09!Support routines for
X`09compare_node,`09`09`09`09!... LIB$INSERT_TREE and
X`09print_node,`09`09`09`09!... LIB$TRAVERSE_TREE
X`09print_node_smg`09`09`09`09!...
X`09;
X
XEXTERNAL ROUTINE
X`09hg$put_output,`09`09`09`09!Write line to SYS$OUTPUT
X`09CLI$DCL_PARSE,`09`09`09`09!Parse a DCL command line
X`09CLI$GET_VALUE,`09`09`09`09!Get value from command line
X`09CLI$PRESENT,`09`09`09`09!Check presence on command line
X`09LIB$GET_FOREIGN,`09`09`09!Get foreign command line
X`09LIB$GET_INPUT,`09`09`09`09!Read from SYS$INPUT
X`09LIB$GET_VM,`09`09`09`09!Allocate virtual memory
X`09LIB$INSERT_TREE,`09`09`09!Insert into the b-tree
X`09LIB$PUT_OUTPUT,`09`09`09`09!Write to SYS$OUTPUT
X`09LIB$SUB_TIMES,`09`09`09`09!Subtract two times
X`09LIB$TRAVERSE_TREE,`09`09`09!Traverse a b-tree
X`09LBR$CLOSE,`09`09`09`09!Close a library
X`09LBR$FIND,`09`09`09`09!Find a library module
X`09LBR$GET_INDEX,`09`09`09`09!Lookup keys in index
X`09LBR$GET_RECORD,`09`09`09`09!Get record from library
X`09LBR$INI_CONTROL,`09`09`09!Initialize library control
X`09LBR$LOOKUP_KEY,`09`09`09`09!Look up key in library
X`09LBR$OPEN,`09`09`09`09!Open a library
X`09LBR$SET_MODULE,`09`09`09`09!Set a module
X`09LBR$SET_MOVE,`09`09`09`09!Set move mode
X`09STR$CONCAT`09`09`09`09!Concatenate
X`09;
X
XEXTERNAL
X`09notice_tables,`09`09`09`09!The CDU command table
X`09notice$_nosuchtopic,`09`09`09!<no such topic in library>
X`09notice$_lbrfnf,`09`09`09`09!<NOTICE library file not found>
X`09CLI$_PRESENT,`09`09`09`09!Status indicating present
X`09LBR$_KEYNOTFND;`09`09`09`09!Library key not found
X
XMACRO`09`09`09`09`09`09!Error macro---return on error
X`09errret (val)`09=
X`09IF NOT(.val) THEN RETURN (.val)%;
X
XLITERAL
X`09txt$c_bufsiz`09= 256,
X`09node$c_length`09= 12,`09`09`09!length of the b-tree stuff
X`09node$s_abstim`09= 8,`09`09`09!length of a username
X`09node$s_data`09= 80,`09`09`09!length of the rest
X`09node$c_totlength= node$c_length+`09!the total length of a node
X`09`09`09  node$s_abstim+`09!...
X`09`09`09  node$s_data+2;`09!...
X
XMACRO
X`09node$q_abstim`09= node$c_length, 0, 0, 0%,
X`09node$w_datalen`09= node$c_length+node$s_abstim,0,16,0%,
X`09node$t_data`09= node$c_length+node$s_abstim+2,0,0,0%;
X
X
XOWN
X`09header_buff`09: $BBLOCK`5Btxt$c_bufsiz`5D,`09!Module headers buffer
X`09module_header`09: $staticdesc(txt$c_bufsiz,`09!Descriptor for
X`09`09`09`09      header_buff),`09!... header_buff
X`09line_buff`09: $BBLOCK`5Btxt$c_bufsiz`5D,`09!Buffer for records
X`09line`09`09: $staticdesc(txt$c_bufsiz,`09!Descriptor for module
X`09`09`09`09      line_buff),`09!... records
X`09fao_buff`09: $BBLOCK`5Btxt$c_bufsiz`5D,`09!$FAO output buffer
X`09fao_out`09`09: $staticdesc(txt$c_bufsiz,`09!Descriptor for $FAO
X`09`09`09`09      fao_buff),`09!... output buffer
X`09lastlogin_i`09: VECTOR`5B2,LONG`5D,`09`09!Last interactive login
X`09notice_count`09: LONG,`09`09`09`09!Count of new notices
X`09treehead`09: LONG,`09`09`09`09!Pointer to head of tree
X`09lib_index_ptr`09: UNSIGNED LONG;`09`09!Library context index
X
XBIND
X`09library_file`09= %ASCID'NOTICE_LIBRARY',
X`09null_line`09= %ASCID'',
X`09dollar_sign_d`09= %ASCID'$',
X`09libindex`09= UPLIT(1);
X!
X!  Header output stuff
X!
XBIND
X`09header1_bell`09= %ASCID %STRING(%CHAR(7),
X`09`09`09`09'NOTICE topics.  Type NOTICE ',
X`09`09`09`09'<topic-name> for more information.'),
X`09header1`09`09= %ASCID %STRING('NOTICE topics.  Type NOTICE ',
X`09`09`09`09'<topic-name> for more information.'),
X`09header2`09`09= %ASCID'Topic      Date         Description',
X`09header_lines`09= %ASCID'---------  -----------  -----------';
X
X!
X!  CLI stuff
X!
XBIND
X`09list`09`09= %ASCID'LIST',
X`09module_name`09= %ASCID'MODULE',
X`09verb`09`09= %ASCID'NOTICE ';
X`0C
X%SBTTL`09'MAIN'
XROUTINE main =
XBEGIN
X!++
X!
X!  Routine:`09MAIN
X!
X!  Abstract:
X!
X!`09This is the main routine for NOTICE.  It uses LIB$GET_FOREIGN to
X!`09get the foreign command line and the calls CLI$DCL_PARSE to parse
X!`09the line.
X!
X!--
XOWN
X`09topic`09`09: $dyndesc,`09`09`09!Descriptor for topic
X`09cmd_line`09: $dyndesc;`09`09`09!The command line
X
XREGISTER
X`09status`09`09: UNSIGNED LONG;`09`09!Routine status
X
X  status = LIB$GET_FOREIGN (topic);`09`09`09!Get foreign command
X  errret(status);`09`09`09`09`09!... line
X
X  STR$CONCAT (cmd_line, verb, topic);`09`09`09!Make one command line
X  status = CLI$DCL_PARSE (cmd_line, notice_tables);`09!Parse the command lin
Ve
X  errret(status);
X `20
X  !
X  !  Before calling the appropriate routine, go ahead and open the library.
X  !  The index pointer will be passed to the other routines.
X  ! `20
X
X  !
X  !  Initialize the library routines
X  !
X  status = LBR$INI_CONTROL (lib_index_ptr,`09`09!Context pointer
X`09`09`09    UPLIT(LBR$C_READ),`09`09!Read-only access
X`09`09`09    UPLIT(LBR$C_TYP_TXT));`09!Type is text library
X  errret(status);
X
X  !
X  !  Open the NOTICE library
X  !
X  status = LBR$OPEN (lib_index_ptr, library_file);
X  IF NOT(.status)
X  THEN
X      IF (.status EQLU RMS$_FNF)
X      THEN
X`09  RETURN (notice$_lbrfnf)
X      ELSE
X`09  RETURN (.status);
X
X  IF (CLI$PRESENT(module_name))`09`09`09`09!If a module name was
X  THEN`09`09`09`09`09`09`09!... given, get it
X     status = CLI$GET_VALUE(module_name, topic)`09`09!...
X  ELSE`09`09`09`09`09`09`09!Otherwise, initialize
X     topic`5BDSC$W_LENGTH`5D = 0;`09`09`09`09!... descriptor with 0
X
X  IF (CLI$PRESENT(list) EQLU CLI$_PRESENT)`09`09!If /LIST was specified,
X  THEN`09`09`09`09`09`09`09!... then call the
X     BEGIN`09`09`09`09`09`09!... listing routines
X     status = display_all_notices (lib_index_ptr,
X`09`09`09(IF .topic`5BDSC$W_LENGTH`5D EQLU 0
X`09`09`09 THEN
X`09`09`09    %ASCID'*'
X`09`09`09 ELSE
X`09`09`09    topic));
X     LBR$CLOSE (lib_index_ptr);`09`09`09`09!Close the library
X     RETURN (.status);`09`09`09`09`09!Return to VMS
X     END;
X
X  IF (.topic`5BDSC$W_LENGTH`5D EQLU 0)`09`09`09!If a topic was not
X  THEN`09`09`09`09`09`09`09!... specified, then
X     status = display_new_notices (lib_index_ptr,0)`09!... show new ones
X  ELSE`09`09`09`09`09`09`09!Otherwise, display text
X     status = display_notice_text (lib_index_ptr, topic);
X
X  IF (.status EQLU LBR$_KEYNOTFND)
X  THEN
X      status = notice$_nosuchtopic;
X
X  LBR$CLOSE (lib_index_ptr);`09`09`09!Close the library
X
X  RETURN (.status);`09`09`09`09!Return the status
X
XEND;`09`09`09`09`09`09!End of routine
X
X`0C
X%SBTTL`09'DISPLAY_NEW_NOTICES'
XROUTINE display_new_notices (index_a, time_a) =
XBEGIN
X!+
X!
X!  Routine:`09DISPLAY_NEW_NOTICES
X!
X!  Functional Description:
X!
X!`09This routine is called to display new notices that were added to
X!`09the text library since the last time the user logged in.
X!
X!`09This routine simply gets the last login time and calls LBR$GET_INDEX
X!`09to search through the modules.
X!
X!  Environment:
X!
X!`09User mode.
X!
X!  Formal parameters:
X!
X!`09index_a`09`09- Address of library index pointer
X!`09time_a`09`09- Address of quadword holding time to use for compares
X!
X!  Implicit inputs:
X!
X!`09lastlogin_i, notice_count, header1_bell, header2, header_lines,
X!`09null_line, treehead
X!
X!  Outputs:
X!
X!`09None.
X!
X!  Returns:
X!
X!`09R0`09- Status
X!
X!-
XBIND
X`09lib_index_ptr`09= .index_a : UNSIGNED LONG,
X`09time`09`09= .time_a  : VECTOR`5B2,LONG`5D;
X
XLOCAL
X`09jpi_itmlst`09: $ITMLST_DECL(ITEMS=1),
X`09jpi_iosb`09: VECTOR`5B2,LONG`5D;
X
X
XREGISTER
X`09status`09`09: UNSIGNED LONG;
X
X  IF (time EQLU 0)
X  THEN
X     BEGIN
X     $ITMLST_INIT (ITMLST = jpi_itmlst,`09`09`09!Initialize the $GETJPI
X`09          (ITMCOD = JPI$_LAST_LOGIN_I,`09`09!... item list
X`09 `09   BUFSIZ = 8,
X`09`09   BUFADR = lastlogin_i));
X
X     status = $GETJPIW (ITMLST = jpi_itmlst,`09!Get the last interactive log
Vin
X`09`09`09IOSB   = jpi_iosb);`09!... time for this process
X     errret(status);`09`09`09`09!Return on error
X     END
X  ELSE
X     BEGIN
X     lastlogin_i`5B0`5D = .time`5B0`5D;
X     lastlogin_i`5B1`5D = .time`5B1`5D;
X     END;
X
X  notice_count = 0;`09`09`09`09!Initialize notice count
X
X  status = LBR$GET_INDEX (lib_index_ptr,`09!Call LBR$GET_INDEX to look
X`09`09`09  libindex,`09`09!... through *all* of the
X`09`09`09  display_topics);`09!... key names
X
X  IF (.notice_count NEQU 0)`09`09`09!If there's anything to
X  THEN`09`09`09`09`09`09!... display, do it using
X     BEGIN
X     LIB$PUT_OUTPUT (null_line);`09`09!... LIB$PUT_OUTPUT so we
X     LIB$PUT_OUTPUT (header1_bell);`09`09!... don't clear the screen
X     LIB$PUT_OUTPUT (null_line);`09`09!... with SMG
X     LIB$PUT_OUTPUT (header2);`09`09`09!...
X     LIB$PUT_OUTPUT (header_lines);`09`09!...
X`09`09`09`09`09`09!And traverse the tree....
X     status = LIB$TRAVERSE_TREE (treehead, print_node, 0);
X     LIB$PUT_OUTPUT (null_line);`09`09!... one more blank line
X     END;
X
X  RETURN (SS$_NORMAL);`09`09`09`09!Return status to our caller
X
XEND;
X
X`0C
X%SBTTL`09'DISPLAY_ALL_NOTICES'
XROUTINE display_all_notices (index_a, module_a) =
XBEGIN
X!+
X!
X!  Routine:`09DISPLAY_ALL_NOTICES
X!
X!  Functional Description:
X!
X!`09This routine is called to list all notices that match an optional
X!`09wildcard specification.
X!
X!`09This routine calls LBR$GET_INDEX to search through the modules.
X!
X!  Environment:
X!
X!`09User mode.
X!
X!  Formal parameters:
X!
X!`09index_a`09`09- Address of library index pointer
X!`09module_a`09- Address of descriptor pointing to the module name
X!
X!  Implicit inputs:
X!
X!`09lastlogin_i, header1, header2, header_lines, null_line, treehead
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`09module_name`09= .module_a`09: $BBLOCK;
X
XLOCAL
X`09temp_desc`09: $dyndesc;
X
XREGISTER
X`09status2,
X`09status;
X
X  status = LBR$GET_INDEX (lib_index_ptr,`09!Call LBR$GET_INDEX to look
X`09`09`09  libindex,`09`09!... through the key names
X`09`09`09  sort_notices,`09`09!...
X`09`09`09  module_name);`09`09!...
X
X  !
X  !  Now add a dollar sign to the beginning to look for any modules
X  !  that are always displayed.
X  !
X  STR$CONCAT (temp_desc, dollar_sign_d, module_name);
X  status2 = LBR$GET_INDEX (lib_index_ptr,`09!Call LBR$GET_INDEX to look
X`09`09`09  libindex,`09`09!... through the key names
X`09`09`09  sort_notices,`09`09!...
X`09`09`09  temp_desc);`09`09!...
X
X  IF (.status OR .status2)`09`09`09!If there were any matches
X  THEN`09`09`09`09`09`09!... with the module name,
X     BEGIN`09`09`09`09`09!... then print out all the
X     hg$put_output (header1);`09`09`09!... headers for the list
X     hg$put_output (null_line);`09`09`09!...
X     hg$put_output (header2);`09`09`09!...
X     hg$put_output (header_lines);`09`09!...
X`09`09`09`09`09`09!And traverse the tree....
X     status = LIB$TRAVERSE_TREE (treehead, print_node_smg, 0);
X     END;
X
X  IF (.status)`09`09`09`09`09!If something was printed,
X  THEN`09`09`09`09`09`09!... go ahead and print
X     hg$put_output (null_line);`09`09`09!... one more blank line
X
X  RETURN (.status);`09`09`09`09!Return status to our caller
X
XEND;
X
+-+-+-+-+-+-+-+-  END  OF PART 3 +-+-+-+-+-+-+-+-
