!>
alert(3f) - [M_attr] print messages using a standard format including
time and program name
(LICENSE:MIT)
 subroutine alert(message,&
 g0,g1,g2,g3,g4,g5,g6,g7,g8,g9,ga,gb,gc,gd,ge,gf,gg,gh,gi,gj)
    character(len=*),intent(in),optional :: type
    character(len=*),intent(in),optional :: message
    class(*),intent(in),optional :: g0,g1,g2,g3,g4,g5,g6,g7,g8,g9, &
                                  & ga,gb,gc,gd,ge,gf,gg,gh,gi,gj
Display a message prefixed with a timestamp and the name
of the calling program when the TYPE is specified as any
of 'error','warn', or 'info'.
It also allows the keywords
<ARG0>,<TZ>,<YE>,<MO>,<DA>,<HR>,<MI>,<SE>,<MS> to be used in the
message (which is passed to ATTR(3f)).
Note that time stamp keywords will only be updated when using ALERT(3f)
and will only be displayed in color mode!
TYPE     if present and one of 'warn','message','info', or 'debug'
         a predefined message is written to stderr of the form
          : <HR>:<MI>:<SE>.<MS> : (<ARG0>) : TYPE -> message
MESSAGE  the user-supplied message to display via a call to ATTR(3f)
g[0-9a-j]   optional values to print after the message. May
            be of type INTEGER, LOGICAL, REAL, DOUBLEPRECISION,
            COMPLEX, or CHARACTER.
if no parameters are supplied the macros are updated but no output
is generated.
Sample program
 program demo_alert
 use M_attr, only : alert, attr, attr_mode
 implicit none
 real X
  call attr_mode(manner='plain')
  call attr_mode(manner='color')
  call alert("error",&
            "Say you didn't!")
  call alert("warn", &
            "I wouldn't if I were you, Will Robinson.")
  call alert("info", &
            "I fixed that for you, but it was a bad idea.")
  call alert("debug", &
            "Who knows what is happening now?.")
  call alert("???    ",  "not today you don't")
  ! call to just update the macros
  call alert()
  ! conventional call to ATTR(3f) using the ALERT(3f)-defined macros
  write(*,*)attr(&
          '<bo>The year was <g><YE></g>, the month was <g><MO></g>')
  ! optional arguments
  X=211.3
  call alert('error',&
          'allowed range of X is 0 <lt> X <lt> 100, X=<r>',X)
  ! up to twenty values are allowed of intrinsic type
  call alert('info','values are<g>',10,234.567,&
          cmplx(11.0,22.0),123.456d0,'</g>today')
 end program demo_alert
Results:
 00:38:30: (prg) : error    -> Say you didn't!
 00:38:30: (prg) : warning  -> I wouldn't if I were you, ...
                               Will Robinson.
 00:38:30: (prg) : info     -> I fixed that for you,  ...
                               but it was a bad idea.
 00:38:30: (prg) : debug    -> Who knows what is happening now?. ...
 00:38:30: (prg) : ???      -> not today you don't
 00:38:30: (prg) : error    -> allowed range of X is 0  X  100, ...
                               X= 211.300003
 00:38:30: (prg) : info     -> values are 10 234.567001 ...
                               (11.0000000,22.0000000) ...
                               123.45600000000000 today
John S. Urban, 2021
MIT
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in), | optional | :: | type | ||
| character(len=*), | intent(in), | optional | :: | message | ||
| class(*), | intent(in), | optional | :: | g0 | ||
| class(*), | intent(in), | optional | :: | g1 | ||
| class(*), | intent(in), | optional | :: | g2 | ||
| class(*), | intent(in), | optional | :: | g3 | ||
| class(*), | intent(in), | optional | :: | g4 | ||
| class(*), | intent(in), | optional | :: | g5 | ||
| class(*), | intent(in), | optional | :: | g6 | ||
| class(*), | intent(in), | optional | :: | g7 | ||
| class(*), | intent(in), | optional | :: | g8 | ||
| class(*), | intent(in), | optional | :: | g9 | ||
| class(*), | intent(in), | optional | :: | ga | ||
| class(*), | intent(in), | optional | :: | gb | ||
| class(*), | intent(in), | optional | :: | gc | ||
| class(*), | intent(in), | optional | :: | gd | ||
| class(*), | intent(in), | optional | :: | ge | ||
| class(*), | intent(in), | optional | :: | gf | ||
| class(*), | intent(in), | optional | :: | gg | ||
| class(*), | intent(in), | optional | :: | gh | ||
| class(*), | intent(in), | optional | :: | gi | ||
| class(*), | intent(in), | optional | :: | gj | 
subroutine alert(type,message,g0,g1,g2,g3,g4,g5,g6,g7,g8,g9,ga,gb,gc,gd,ge,gf,gg,gh,gi,gj) ! TODO: could add a warning level to ignore info, or info|warning, or all implicit none character(len=*),intent(in),optional :: type character(len=*),intent(in),optional :: message class(*),intent(in),optional :: g0,g1,g2,g3,g4,g5,g6,g7,g8,g9 class(*),intent(in),optional :: ga,gb,gc,gd,ge,gf,gg,gh,gi,gj character(len=8) :: dt character(len=10) :: tm character(len=5) :: zone integer,dimension(8) :: values character(len=4096) :: arg0 character(len=:),allocatable :: new_message character(len=:),allocatable :: other logical :: printme call date_and_time(dt,tm,zone,values) call attr_update('YE',dt(1:4),dt(1:4)) call attr_update('MO',dt(5:6),dt(5:6)) call attr_update('DA',dt(7:8),dt(7:8)) call attr_update('HR',tm(1:2),tm(1:2)) call attr_update('MI',tm(3:4),tm(3:4)) call attr_update('SE',tm(5:6),tm(5:6)) call attr_update('MS',tm(8:10),tm(8:10)) call attr_update('TZ',zone,zone) call get_command_argument(0,arg0) if(index(arg0,'/').ne.0) arg0=arg0(index(arg0,'/',back=.true.)+1:) if(index(arg0,'\').ne.0) arg0=arg0(index(arg0,'\',back=.true.)+1:) call attr_update('ARG0',arg0,arg0) printme=.true. if(present(type))then new_message= ' <b>'//tm(1:2)//':'//tm(3:4)//':'//tm(5:6)//'.'//tm(8:10)//'</b> : ('//trim(arg0)//') : ' other=message//' '//str(g0,g1,g2,g3,g4,g5,g6,g7,g8,g9,ga,gb,gc,gd,ge,gf,gg,gh,gi,gj) select case(type) case('warn','WARN','warning','WARNING') new_message= new_message//'<EBONY><bo><y>warning </y></EBONY> -<gt> ' printme=alert_warn case('info','INFO','information','INFORMATION') new_message= new_message//'<EBONY><bo><g>info </g></EBONY> -<gt> ' printme=alert_info case('error','ERROR') new_message= new_message//'<EBONY><bo><r>error </r></EBONY> -<gt> ' printme=alert_error case('debug','DEBUG') new_message= new_message//'<EBONY><white><bo>debug </white></EBONY> -<gt> ' printme=alert_debug case default new_message= new_message//'<EBONY><bo><c>'//type//' </c></EBONY> -<gt> ' printme=alert_other end select if(printme)then write(alert_unit,'(a)')attr(trim(new_message//other)) endif elseif(present(message))then write(alert_unit,'(a)')attr(trim(other)) endif end subroutine alert