1
- ! > @brief Generic utilities to store and issue messages to an output unit .
1
+ ! > @brief Store and issue logging messages to output units .
2
2
module MessageModule
3
3
4
4
use KindModule, only: LGP, I4B, DP
@@ -10,128 +10,102 @@ module MessageModule
10
10
implicit none
11
11
public :: MessagesType
12
12
public :: write_message
13
- public :: write_message_counter
13
+ public :: write_message_indented
14
14
public :: write_message_centered
15
15
16
- ! > @brief Container for related messages sharing a name and title .
16
+ ! > @brief Container for related messages.
17
17
! !
18
- ! ! A maximum number of messages may be configured. Message storage
19
- ! ! arrays are dynamically reallocated up to the specified capacity.
18
+ ! ! A maximum capacity can be configured. Message storage
19
+ ! ! is dynamically resized up to the configured capacity.
20
20
! <
21
21
type :: MessagesType
22
- character (len= LINELENGTH) :: title ! < title of the message
23
- character (len= LINELENGTH) :: name ! < message name
24
- integer (I4B) :: nmessage = 0 ! < number of messages stored
25
- integer (I4B) :: max_message = 1000 ! < default maximum number of messages that can be stored
26
- integer (I4B) :: max_exceeded = 0 ! < flag indicating if the maximum number of messages has exceed the maximum number
27
- integer (I4B) :: inc_message = 100 ! < amount to increment message array by when calling ExpandArray
28
- character (len= MAXCHARLEN), allocatable , dimension (:) :: messages ! < message array
22
+ ! character(len=LINELENGTH) :: title !< message title
23
+ ! character(len=LINELENGTH) :: name !< message name
24
+ integer (I4B) :: num_messages = 0 ! < number of messages currently stored
25
+ integer (I4B) :: max_messages = 1000 ! < default max message storage capacity
26
+ integer (I4B) :: max_exceeded = 0 ! < number of messages in excess of maximum
27
+ integer (I4B) :: exp_messages = 100 ! < number of slots to expand message array
28
+ real (DP) :: exp_factor = 1.1 ! < factor to multiply the number of expansion slots
29
+ character (len= MAXCHARLEN), private , allocatable , dimension (:) :: messages
29
30
contains
30
- procedure :: init_message
31
- procedure :: count_message
32
- procedure :: set_max_message
33
- procedure :: store_message
34
- procedure :: print_message
35
- procedure :: deallocate_message
31
+ procedure :: count
32
+ procedure :: store
33
+ procedure :: write_all
34
+ procedure :: deallocate
36
35
end type MessagesType
37
36
38
37
contains
39
38
40
- ! > @brief Initialize message storage.
41
- subroutine init_message (this )
42
- class(MessagesType) :: this ! < MessageType object
43
-
44
- ! -- initialize message variables
45
- this% nmessage = 0
46
- this% max_message = 1000
47
- this% max_exceeded = 0
48
- this% inc_message = 100
49
- end subroutine init_message
50
-
51
39
! > @brief Return the number of messages currently stored.
52
- function count_message (this ) result(nmessage )
40
+ function count (this ) result(nmsg )
53
41
class(MessagesType) :: this ! < MessageType object
54
- integer (I4B) :: nmessage
55
-
56
- ! -- set nmessage
42
+ integer (I4B) :: nmsg
57
43
if (allocated (this% messages)) then
58
- nmessage = this% nmessage
44
+ nmsg = this% num_messages
59
45
else
60
- nmessage = 0
46
+ nmsg = 0
61
47
end if
62
- end function count_message
48
+ end function count
63
49
64
- ! > @brief Set the maximum number of messages.
65
- subroutine set_max_message (this , imax )
66
- class(MessagesType) :: this ! < MessageType object
67
- integer (I4B), intent (in ) :: imax ! < maximum number of messages that will be stored
68
-
69
- ! -- set max_message
70
- this% max_message = imax
71
- end subroutine set_max_message
72
-
73
- ! > @brief Store a message for printing at the end of the simulation.
74
- subroutine store_message (this , msg , substring )
50
+ ! > @brief Add a message to storage.
51
+ ! !
52
+ ! ! An optional string may be provided to filter out duplicate messages.
53
+ ! ! If any stored messages contain the string the message is not stored.
54
+ ! <
55
+ subroutine store (this , message , filter )
75
56
! -- dummy variables
76
57
class(MessagesType) :: this ! < MessageType object
77
- character (len=* ), intent (in ) :: msg ! < message
78
- character (len=* ), intent (in ), optional :: substring ! < optional string that can be used
79
- ! ! to prevent storing duplicate messages
58
+ character (len=* ), intent (in ) :: message ! < message
59
+ character (len=* ), intent (in ), optional :: filter ! < duplicate filter
80
60
! -- local variables
81
- logical (LGP) :: inc_array
82
- logical (LGP) :: increment_message
83
61
integer (I4B) :: i
84
- integer (I4B) :: idx
85
62
!
86
- ! -- determine if messages should be expanded
87
- inc_array = .TRUE.
88
- if (allocated (this% messages)) then
89
- i = this% nmessage
90
- if (i < size (this% messages)) then
91
- inc_array = .FALSE.
63
+ ! -- allocate/expand arrays if needed
64
+ if (.not. allocated (this% messages)) then
65
+ allocate (this% messages(int (this% max_messages / 10 )))
66
+ else
67
+ i = this% num_messages
68
+ if (i == size (this% messages)) then
69
+ call ExpandArray(this% messages, increment= this% exp_messages)
70
+ this% exp_messages = int (this% exp_messages * this% exp_factor)
92
71
end if
93
72
end if
94
73
!
95
- ! -- resize message
96
- if (inc_array) then
97
- call ExpandArray(this% messages, increment= this% inc_message)
98
- this% inc_message = int (this% inc_message * 1.1 )
99
- end if
100
- !
101
- ! -- Determine if the substring exists in the passed message.
102
- ! If substring is in passed message, do not add the duplicate
103
- ! passed message.
104
- increment_message = .TRUE.
105
- if (present (substring)) then
106
- do i = 1 , this% nmessage
107
- idx = index (this% messages(i), substring)
108
- if (idx > 0 ) then
109
- increment_message = .FALSE.
110
- exit
111
- end if
74
+ ! -- if a duplicate filter is provided and any message contains it, skip it
75
+ if (present (filter)) then
76
+ do i = 1 , this% num_messages
77
+ if (index (this% messages(i), filter) > 0 ) return
112
78
end do
113
79
end if
114
80
!
115
- ! -- store this message and calculate nmessage
116
- if (increment_message) then
117
- i = this% nmessage + 1
118
- if (i <= this% max_message ) then
119
- this% nmessage = i
120
- this% messages(i) = msg
121
- else
122
- this % max_exceeded = this % max_exceeded + 1
123
- end if
81
+ ! -- store message and update count unless
82
+ ! at capacity, then update excess count
83
+ i = this% num_messages + 1
84
+ if (i <= this% max_messages ) then
85
+ this% num_messages = i
86
+ this% messages(i) = message
87
+ print * , ' stored message: ' , message
88
+ else
89
+ this % max_exceeded = this % max_exceeded + 1
124
90
end if
125
- end subroutine store_message
91
+ end subroutine store
126
92
127
- ! > @brief Print stored messages.
128
- subroutine print_message (this , title , name , iunit )
93
+ ! > @brief Write all stored messages to standard output.
94
+ ! !
95
+ ! ! An optional title to precede the messages may be provided.
96
+ ! ! The title is printed on a separate line. An arbitrary kind
97
+ ! ! may be specified, e.g. 'note', 'warning' or 'error. A file
98
+ ! ! unit can also be specified to write in addition to stdout.
99
+ ! <
100
+ subroutine write_all (this , title , kind , iunit )
129
101
! -- dummy variables
130
102
class(MessagesType) :: this ! < MessageType object
131
- character (len=* ), intent (in ) :: title ! < message title
132
- character (len=* ), intent (in ) :: name ! < message name
133
- integer (I4B), intent (in ), optional :: iunit ! < optional file unit to save messages to
103
+ character (len=* ), intent (in ), optional :: title ! < message title
104
+ character (len=* ), intent (in ), optional :: kind ! < message kind (e.g. note, warning, error)
105
+ integer (I4B), intent (in ), optional :: iunit ! < optional file unit
134
106
! -- local
107
+ character (len= LINELENGTH) :: ltitle
108
+ character (len= LINELENGTH) :: lkind
135
109
character (len= LINELENGTH) :: errmsg
136
110
character (len= LINELENGTH) :: cerr
137
111
integer (I4B) :: iu
@@ -142,61 +116,76 @@ subroutine print_message(this, title, name, iunit)
142
116
character (len=* ), parameter :: stdfmt = " (/,A,/)"
143
117
!
144
118
! -- process optional variables
119
+ if (present (title)) then
120
+ ltitle = title
121
+ else
122
+ ltitle = ' '
123
+ end if
124
+ if (present (kind)) then
125
+ lkind = kind
126
+ else
127
+ lkind = ' '
128
+ end if
145
129
if (present (iunit)) then
146
130
iu = iunit
147
131
else
148
132
iu = istdout
149
133
end if
150
134
!
151
- ! -- write the title and all message entries
135
+ ! -- write messages, if any
152
136
if (allocated (this% messages)) then
153
- isize = this% nmessage
154
- if (isize > 0 ) then
155
- !
156
- ! -- calculate the maximum width of the prepended string
157
- ! for the counter
158
- write (cerr, ' (i0)' ) isize
159
- iwidth = len_trim (cerr) + 1
160
- !
161
- ! -- write title for message
137
+ isize = this% num_messages
138
+ if (isize == 0 ) return
139
+ !
140
+ ! -- calculate the maximum width of the prepended string
141
+ ! for the counter
142
+ write (cerr, ' (i0)' ) isize
143
+ iwidth = len_trim (cerr) + 1
144
+ !
145
+ ! -- write title, if provided
146
+ if (trim (ltitle) /= ' ' ) then
162
147
if (iu > 0 ) &
163
- call write_message(iunit= iu, text= title , fmt= stdfmt)
164
- call write_message(text= title , fmt= stdfmt)
165
- !
166
- ! -- write each message
167
- do i = 1 , isize
168
- if (iu > 0 ) &
169
- call write_message_counter( &
170
- iunit = iu, &
171
- text = this % messages(i) , &
172
- icount = i , &
173
- iwidth = iwidth)
174
- call write_message_counter( &
175
- text = this % messages(i), &
176
- icount = i , &
177
- iwidth = iwidth)
178
- end do
179
- !
180
- ! -- write the number of additional messages
181
- if (this % max_exceeded > 0 ) then
182
- write (errmsg, ' (i0,3(1x,a)) ' ) &
183
- this % max_exceeded , ' additional ' , trim (name), &
184
- ' detected but not printed. '
185
- if (iu > 0 ) &
186
- call write_message(iunit = iu, text = trim (errmsg), fmt = ' (/,1x,a) ' )
187
- call write_message(text= trim (errmsg), fmt= ' (/,1x,a)' )
188
- end if
148
+ call write_message(iunit= iu, text= ltitle , fmt= stdfmt)
149
+ call write_message(text= ltitle , fmt= stdfmt)
150
+ end if
151
+ !
152
+ ! -- write each message
153
+ do i = 1 , isize
154
+ if (iu > 0 ) &
155
+ call write_message_indented( &
156
+ iunit = iu , &
157
+ text = this % messages(i) , &
158
+ icount = i, &
159
+ iwidth = iwidth)
160
+ call write_message_indented( &
161
+ text = this % messages(i) , &
162
+ icount = i, &
163
+ iwidth = iwidth)
164
+ end do
165
+ !
166
+ ! -- warn about messages we couldn't save/show
167
+ if (this % max_exceeded > 0 ) then
168
+ write (errmsg , ' (i0,3(1x,a)) ' ) &
169
+ this % max_exceeded, trim (lkind), &
170
+ ' messages over capacity. '
171
+ if (iu > 0 ) &
172
+ call write_message(iunit = iu, text= trim (errmsg), fmt= ' (/,1x,a)' )
173
+ call write_message(text = trim (errmsg), fmt = ' (/,1x,a) ' )
189
174
end if
190
175
end if
191
- end subroutine print_message
176
+ end subroutine write_all
192
177
193
- ! > @ brief Deallocate message stored if needed .
194
- subroutine deallocate_message (this )
178
+ ! > @ brief Deallocate message storage .
179
+ subroutine deallocate (this )
195
180
class(MessagesType) :: this
196
181
if (allocated (this% messages)) deallocate (this% messages)
197
- end subroutine deallocate_message
182
+ end subroutine deallocate
198
183
199
- ! > @brief Configurable routine to write a message to an output unit.
184
+ ! > @brief Write a message to an output unit.
185
+ ! !
186
+ ! ! Use `advance` to toggle advancing output. Use `skipbefore/after` to
187
+ ! ! configure the number of whitespace lines before/after the message.
188
+ ! <
200
189
subroutine write_message (text , iunit , fmt , &
201
190
skipbefore , skipafter , advance )
202
191
! -- dummy
@@ -266,17 +255,16 @@ subroutine write_message(text, iunit, fmt, &
266
255
end if
267
256
end subroutine write_message
268
257
269
- ! > @brief Write a message, splitting across lines as needed .
258
+ ! > @brief Write a message with configurable indentation .
270
259
! !
271
- ! ! Subroutine that formats and writes a single message that
272
- ! ! may exceeed 78 characters in length. Messages longer than
273
- ! ! 78 characters are written across multiple lines. When a
274
- ! ! counter is passed in subsequent lines are indented .
260
+ ! ! The message may exceed 78 characters in length. Messages longer than
261
+ ! ! 78 characters are written across multiple lines. After icount lines,
262
+ ! ! subsequent lines are indented. Use skipbefore/after to configure the
263
+ ! ! number of empty lines before/after the message .
275
264
! <
276
- subroutine write_message_counter (text , iunit , icount , iwidth , &
277
- skipbefore , skipafter )
265
+ subroutine write_message_indented (text , iunit , icount , iwidth , &
266
+ skipbefore , skipafter )
278
267
! -- dummy
279
-
280
268
character (len=* ), intent (in ) :: text ! < message to be written
281
269
integer (I4B), intent (in ), optional :: iunit ! < the unit number to which the message is written
282
270
integer (I4B), intent (in ), optional :: icount ! < counter to prepended to the message
@@ -412,7 +400,7 @@ subroutine write_message_counter(text, iunit, icount, iwidth, &
412
400
call write_message(text= line, iunit= iu, fmt= fmt_cont, &
413
401
skipafter= isa)
414
402
end if
415
- end subroutine write_message_counter
403
+ end subroutine write_message_indented
416
404
417
405
! > @brief Write horizontally centered text, left-padding as needed.
418
406
subroutine write_message_centered (text , linelen , iunit )
0 commit comments