Module: Remind::Runtime
- Defined in:
- lib/remind/runtime.rb
Overview
The startup Remind does before it looks at its command line.
InitRemind is one function with two jobs: it brings the interpreter up
-- hash tables, dynamic buffers, the translation table, today's date --
and then it parses argv, opens files and, on bad input, exits the process.
A library wants the first job and never the second, so this repeats the
first rather than calling the function that does both.
Skipping it is not an option. Remind's tables are static storage with null
function pointers in them until something initialises them, so the first
expression that takes an error path -- where GetErr translates the
message -- walks into a null pointer and takes the process with it.
It runs once per process, because the state is process-wide.
Constant Summary collapse
- LOCK =
Mutex.new
- TABLES =
In the order InitRemind does them.
%i[ init_variables init_user_functions init_translation_table init_files init_dedupe_table ].freeze
- DEVNULL =
Remind reports a parse error by printing the line with a caret under the offending character. A library raises instead, so by default the printing goes nowhere and the exception carries the message; a caller who wants the caret can ask for it.
"/dev/null"
Class Method Summary collapse
- .boot(native, diagnostics: false) ⇒ Object
- .booted ⇒ Object
-
.discard(native) ⇒ Object
One stream per process, held open: reopening it per expression would leak a descriptor every time.
-
.point_errors(native, diagnostics) ⇒ Object
ErrFp starts as a null FILE *, and main() is what points it at stderr.
-
.read_the_clock(native) ⇒ Object
SystemDate answers today as a day count and fills in the year, month and day Remind completes partial dates with.
- .start(native, diagnostics) ⇒ Object
Class Method Details
.boot(native, diagnostics: false) ⇒ Object
44 45 46 47 48 49 50 51 52 |
# File 'lib/remind/runtime.rb', line 44 def boot(native, diagnostics: false) LOCK.synchronize do if booted[native.path] false else start(native, diagnostics) end end end |
.booted ⇒ Object
40 41 42 |
# File 'lib/remind/runtime.rb', line 40 def booted @booted ||= {} end |
.discard(native) ⇒ Object
One stream per process, held open: reopening it per expression would leak a descriptor every time.
76 77 78 79 80 81 |
# File 'lib/remind/runtime.rb', line 76 def discard(native) @discard ||= native.open_stream( Fiddle::Pointer["#{DEVNULL}\0"], Fiddle::Pointer["w\0"], ).to_i end |
.point_errors(native, diagnostics) ⇒ Object
ErrFp starts as a null FILE *, and main() is what points it at stderr. Everything that reports an error writes through it, including the paths that would otherwise dereference the null.
66 67 68 69 70 71 72 |
# File 'lib/remind/runtime.rb', line 66 def point_errors(native, diagnostics) if diagnostics native.write_pointer(Native::ERROR_STREAM, native.standard_error) else native.write_pointer(Native::ERROR_STREAM, discard(native)) end end |
.read_the_clock(native) ⇒ Object
SystemDate answers today as a day count and fills in the year, month and day Remind completes partial dates with.
85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/remind/runtime.rb', line 85 def read_the_clock(native) year = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE) month = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE) day = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE) today = native.system_date(year, month, day) native.write_global("RealToday", today) native.write_global("DSEToday", today) native.write_global("LocalDSEToday", today) native.write_global("CurYear", year[0, Fiddle::SIZEOF_INT].unpack1("i!")) native.write_global("LocalSysTime", native.system_time(0)) end |
.start(native, diagnostics) ⇒ Object
54 55 56 57 58 59 60 61 |
# File 'lib/remind/runtime.rb', line 54 def start(native, diagnostics) point_errors(native, diagnostics) TABLES.each { |name| native.public_send(name) } Native::BUFFERS.each { |name| native.init_buffer(native.address_of(name)) } read_the_clock(native) booted[native.path] = true end |