1#!/usr/bin/tclsh 2#* 3#* SRT - Secure, Reliable, Transport 4#* Copyright (c) 2020 Haivision Systems Inc. 5#* 6#* This Source Code Form is subject to the terms of the Mozilla Public 7#* License, v. 2.0. If a copy of the MPL was not distributed with this 8#* file, You can obtain one at http://mozilla.org/MPL/2.0/. 9#* 10#*/ 11# 12#***************************************************************************** 13#written by 14# Haivision Systems Inc. 15#***************************************************************************** 16 17# What fields are there in every entry 18set model { 19 longname 20 shortname 21 id 22 description 23} 24 25# Logger definitions. 26# Comments here allowed, just only for the whole line. 27 28# Use values greater than 0. Value 0 is reserved for LOGFA_GENERAL, 29# which is considered always enabled. 30set loggers { 31 GENERAL gg 0 "General uncategorized log, for serious issues only" 32 SOCKMGMT sm 1 "Socket create/open/close/configure activities" 33 CONN cn 2 "Connection establishment and handshake" 34 XTIMER xt 3 "The checkTimer and around activities" 35 TSBPD ts 4 "The TsBPD thread" 36 RSRC rs 5 "System resource allocation and management" 37 CONGEST cc 7 "Congestion control module" 38 PFILTER pf 8 "Packet filter module" 39 API_CTRL ac 11 "API part for socket and library managmenet" 40 QUE_CTRL qc 13 "Queue control activities" 41 EPOLL_UPD ei 16 "EPoll, internal update activities" 42 43 API_RECV ar 21 "API part for receiving" 44 BUF_RECV br 22 "Buffer, receiving side" 45 QUE_RECV qr 23 "Queue, receiving side" 46 CHN_RECV kr 24 "CChannel, receiving side" 47 GRP_RECV gr 25 "Group, receiving side" 48 49 API_SEND as 31 "API part for sending" 50 BUF_SEND bs 32 "Buffer, sending side" 51 QUE_SEND qs 33 "Queue, sending side" 52 CHN_SEND ks 34 "CChannel, sending side" 53 GRP_SEND gs 35 "Group, sending side" 54 55 INTERNAL in 41 "Internal activities not connected directly to a socket" 56 QUE_MGMT qm 43 "Queue, management part" 57 CHN_MGMT km 44 "CChannel, management part" 58 GRP_MGMT gm 45 "Group, management part" 59 EPOLL_API ea 46 "EPoll, API part" 60} 61 62set hidden_loggers { 63 # Haicrypt logging - usually off. 64 HAICRYPT hc 6 "Haicrypt module area" 65 66 # defined in apps, this is only a stub to lock the value 67 APPLOG ap 10 "Applications" 68} 69 70set globalheader { 71 /* 72 WARNING: Generated from ../scripts/generate-logging-defs.tcl 73 74 DO NOT MODIFY. 75 76 Copyright applies as per the generator script. 77 */ 78 79} 80 81 82# This defines, what kind of definition will be generated 83# for a given file out of the log FA entry list. 84 85# Fields: 86# - prefix/postfix model 87# - logger_format 88# - hidden_logger_format 89 90# COMMENTS NOT ALLOWED HERE! Only as C++ comments inside C++ model code. 91set special { 92 srtcore/logger_default.cpp { 93 if {"$longname" == "HAICRYPT"} { 94 puts $od " 95#if ENABLE_HAICRYPT_LOGGING 96 allfa.set(SRT_LOGFA_HAICRYPT, true); 97#endif" 98 } 99 } 100} 101 102proc GenerateModelForSrtH {} { 103 104 # `path` will be set to the git top path 105 global path 106 107 set fd [open [file join $path srtcore/srt.h] r] 108 109 set contents "" 110 111 set state read 112 set pass looking 113 114 while { [gets $fd line] != -1 } { 115 if { $state == "read" } { 116 117 if { $pass != "passed" } { 118 119 set re [regexp {SRT_LOGFA BEGIN GENERATED SECTION} $line] 120 if {$re} { 121 set state skip 122 set pass found 123 } 124 125 } 126 127 append contents "$line\n" 128 continue 129 } 130 131 if {$state == "skip"} { 132 if { [string trim $line] == "" } { 133 # Empty line, continue skipping 134 continue 135 } 136 137 set re [regexp {SRT_LOGFA END GENERATED SECTION} $line] 138 if {!$re} { 139 # Still SRT_LOGFA definitions 140 continue 141 } 142 143 # End of generated section. Switch back to pass-thru. 144 145 # First fill the gap 146 append contents "\n\$entries\n\n" 147 148 append contents "$line\n" 149 set state read 150 set pass passed 151 } 152 } 153 154 close $fd 155 156 # Sanity check 157 if {$pass != "passed"} { 158 error "Invalid contents of `srt.h` file, can't find '#define SRT_LOGFA_' phrase" 159 } 160 161 return $contents 162} 163 164# COMMENTS NOT ALLOWED HERE! Only as C++ comments inside C++ model code. 165# (NOTE: Tcl syntax highlighter will likely falsely highlight # as comment here) 166# 167# Model: TARGET-NAME { format-model logger-pattern hidden-logger-pattern } 168# 169# Special syntax: 170# 171# %<command> : a high-level command execution. This declares a command that 172# must be executed to GENERATE the model. Then, [subst] is executed 173# on the results. 174# 175# = : when placed as the hidden-logger-pattern, it's equal to logger-pattern. 176# 177set generation { 178 srtcore/srt.h { 179 180 {%GenerateModelForSrtH} 181 182 {#define [format "%-20s %-3d" SRT_LOGFA_${longname} $id] // ${shortname}log: $description} 183 184 = 185 } 186 187 srtcore/logger_default.cpp { 188 189 { 190 $globalheader 191 #include "srt.h" 192 #include "logging.h" 193 #include "logger_defs.h" 194 195 namespace srt_logging 196 { 197 AllFaOn::AllFaOn() 198 { 199 $entries 200 } 201 } // namespace srt_logging 202 203 } 204 205 { 206 allfa.set(SRT_LOGFA_${longname}, true); 207 } 208 } 209 210 srtcore/logger_defs.cpp { 211 212 { 213 $globalheader 214 #include "srt.h" 215 #include "logging.h" 216 #include "logger_defs.h" 217 218 namespace srt_logging { AllFaOn logger_fa_all; } 219 // We need it outside the namespace to preserve the global name. 220 // It's a part of "hidden API" (used by applications) 221 SRT_API srt_logging::LogConfig srt_logger_config(srt_logging::logger_fa_all.allfa); 222 223 namespace srt_logging 224 { 225 $entries 226 } // namespace srt_logging 227 } 228 229 { 230 Logger ${shortname}log(SRT_LOGFA_${longname}, srt_logger_config, "SRT.${shortname}"); 231 } 232 } 233 234 srtcore/logger_defs.h { 235 { 236 $globalheader 237 #ifndef INC_SRT_LOGGER_DEFS_H 238 #define INC_SRT_LOGGER_DEFS_H 239 240 #include "srt.h" 241 #include "logging.h" 242 243 namespace srt_logging 244 { 245 struct AllFaOn 246 { 247 LogConfig::fa_bitset_t allfa; 248 AllFaOn(); 249 }; 250 251 $entries 252 253 } // namespace srt_logging 254 255 #endif 256 } 257 258 { 259 extern Logger ${shortname}log; 260 } 261 } 262 263 apps/logsupport_appdefs.cpp { 264 { 265 $globalheader 266 #include "logsupport.hpp" 267 268 LogFANames::LogFANames() 269 { 270 $entries 271 } 272 } 273 274 { 275 Install("$longname", SRT_LOGFA_${longname}); 276 } 277 278 { 279 Install("$longname", SRT_LOGFA_${longname}); 280 } 281 } 282} 283 284# EXECUTION 285 286set here [file dirname [file normalize $argv0]] 287 288if {[lindex [file split $here] end] != "scripts"} { 289 puts stderr "The script is in weird location." 290 exit 1 291} 292 293set path [file join {*}[lrange [file split $here] 0 end-1]] 294 295# Utility. Allows to put line-oriented comments and have empty lines 296proc no_comments {input} { 297 set output "" 298 foreach line [split $input \n] { 299 set nn [string trim $line] 300 if { $nn == "" || [string index $nn 0] == "#" } { 301 continue 302 } 303 append output $line\n 304 } 305 306 return $output 307} 308 309proc generate_file {od target} { 310 311 global globalheader 312 lassign [dict get $::generation $target] format_model pattern hpattern 313 314 set ptabprefix "" 315 316 if {[string index $format_model 0] == "%"} { 317 set command [string range $format_model 1 end] 318 set format_model [eval $command] 319 } 320 321 if {$format_model != ""} { 322 set beginindex 0 323 while { [string index $format_model $beginindex] == "\n" } { 324 incr beginindex 325 } 326 327 set endindex $beginindex 328 while { [string is space [string index $format_model $endindex]] } { 329 incr endindex 330 } 331 332 set tabprefix [string range $pattern $beginindex $endindex-1] 333 334 set newformat "" 335 foreach line [split $format_model \n] { 336 if {[string trim $line] == ""} { 337 append newformat "\n" 338 continue 339 } 340 341 if {[string first $tabprefix $line] == 0} { 342 set line [string range $line [string length $tabprefix] end] 343 } 344 append newformat $line\n 345 346 set ie [string first {$} $line] 347 if {$ie != -1} { 348 if {[string range $line $ie end] == {$entries}} { 349 set ptabprefix "[string range $line 0 $ie-1]" 350 } 351 } 352 } 353 354 set format_model $newformat 355 unset newformat 356 } 357 358 set entries "" 359 360 if {[string trim $pattern] != "" } { 361 362 set prevval 0 363 set pattern [string trim $pattern] 364 365 # The first "$::model" will expand into variable names 366 # as defined there. 367 foreach [list {*}$::model] [no_comments $::loggers] { 368 if {$prevval + 1 != $id} { 369 append entries "\n" 370 } 371 372 append entries "${ptabprefix}[subst -nobackslashes $pattern]\n" 373 set prevval $id 374 } 375 } 376 377 if {$hpattern != ""} { 378 if {$hpattern == "="} { 379 set hpattern $pattern 380 } else { 381 set hpattern [string trim $hpattern] 382 } 383 384 # Extra line to separate from the normal entries 385 append entries "\n" 386 foreach [list {*}$::model] [no_comments $::hidden_loggers] { 387 append entries "${ptabprefix}[subst -nobackslashes $hpattern]\n" 388 } 389 } 390 391 if { [dict exists $::special $target] } { 392 set code [subst [dict get $::special $target]] 393 394 # The code should contain "append entries" ! 395 eval $code 396 } 397 398 set entries [string trim $entries] 399 400 if {$format_model == ""} { 401 set format_model $entries 402 } 403 404 # For any case, cut external spaces 405 puts $od [string trim [subst -nocommands -nobackslashes $format_model]] 406} 407 408proc debug_vars {list} { 409 set output "" 410 foreach name $list { 411 upvar $name _${name} 412 lappend output "${name}=[set _${name}]" 413 } 414 415 return $output 416} 417 418# MAIN 419 420set entryfiles $argv 421 422if {$entryfiles == ""} { 423 set entryfiles [dict keys $generation] 424} else { 425 foreach ef $entryfiles { 426 if { $ef ni [dict keys $generation] } { 427 error "Unknown generation target: $entryfiles" 428 } 429 } 430} 431 432foreach f $entryfiles { 433 434 # Set simple relative path, if the file isn't defined as path. 435 if { [llength [file split $f]] == 1 } { 436 set filepath $f 437 } else { 438 set filepath [file join $path $f] 439 } 440 441 puts stderr "Generating '$filepath'" 442 set od [open $filepath.tmp w] 443 generate_file $od $f 444 close $od 445 if { [file exists $filepath] } { 446 puts "WARNING: will overwrite exiting '$f'. Hit ENTER to confirm, or Control-C to stop" 447 gets stdin 448 } 449 450 file rename -force $filepath.tmp $filepath 451} 452 453puts stderr Done. 454 455