suitcase

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 91954e159ec6549ee9d8fed662bb87a6b93ae99c
parent 2037fe5694a4821f3029e051d5a667de85b42037
Author: Ellenor Bjornsdottir <ellenor@umbrellix.net>
Date:   Wed, 19 Oct 2022 06:20:40 +0000

add gitignore and progression on djb library imports

Diffstat:
M.gitignore | 6++++++
Adoc/io/QUELLE | 1+
Adoc/io/README.md | 3+++
Adoc/io/io.html | 702+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdoc/npthread/README.md | 6+++---
Ahead/io/io.h | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahead/npthread/npthread.h | 42++++++++++++++++++++++++++++++++++++++++++
Ahead/tai/caldate.h | 19+++++++++++++++++++
Ahead/tai/caltime.h | 20++++++++++++++++++++
Ahead/tai/leapsecs.h | 10++++++++++
Ahead/tai/tai.h | 22++++++++++++++++++++++
Ahead/tai/taia.h | 31+++++++++++++++++++++++++++++++
Ahead/tai/uint64.h | 6++++++
Asrc/configlib.sh | 21+++++++++++++++++++++
Msrc/eloop/QUELLE | 2+-
Asrc/io/QUELLE | 3+++
Asrc/tai/QUELLE | 5+++++
Asrc/tai/caldate_fmjd.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/tai/caldate_fmt.c | 23+++++++++++++++++++++++
Asrc/tai/caldate_mjd.c | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/tai/caldate_norm.c | 6++++++
Asrc/tai/caldate_scan.c | 23+++++++++++++++++++++++
Asrc/tai/caldate_ster.c | 23+++++++++++++++++++++++
Asrc/tai/caltime_fmt.c | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/tai/caltime_scan.c | 38++++++++++++++++++++++++++++++++++++++
Asrc/tai/caltime_tai.c | 23+++++++++++++++++++++++
Asrc/tai/caltime_utc.c | 31+++++++++++++++++++++++++++++++
Asrc/tai/check.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/tai/easter.c | 28++++++++++++++++++++++++++++
Asrc/tai/leapsecs.c | 28++++++++++++++++++++++++++++
Asrc/tai/leapsecs_add.c | 24++++++++++++++++++++++++
Asrc/tai/leapsecs_init.c | 11+++++++++++
Asrc/tai/leapsecs_read.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/tai/leapsecs_sub.c | 28++++++++++++++++++++++++++++
Asrc/tai/nowutc.c | 37+++++++++++++++++++++++++++++++++++++
Asrc/tai/tai_add.c | 6++++++
Asrc/tai/tai_now.c | 7+++++++
Asrc/tai/tai_pack.c | 16++++++++++++++++
Asrc/tai/tai_sub.c | 6++++++
Asrc/tai/tai_unpack.c | 16++++++++++++++++
Asrc/tai/taia_add.c | 18++++++++++++++++++
Asrc/tai/taia_approx.c | 6++++++
Asrc/tai/taia_fmtfrac.c | 31+++++++++++++++++++++++++++++++
Asrc/tai/taia_frac.c | 6++++++
Asrc/tai/taia_half.c | 12++++++++++++
Asrc/tai/taia_less.c | 12++++++++++++
Asrc/tai/taia_now.c | 14++++++++++++++
Asrc/tai/taia_pack.c | 20++++++++++++++++++++
Asrc/tai/taia_sub.c | 21+++++++++++++++++++++
Asrc/tai/taia_tai.c | 6++++++
Asrc/tai/taia_unpack.c | 20++++++++++++++++++++
Asrc/tai/trycpp.c | 7+++++++
Asrc/tai/yearcal.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
53 files changed, 1832 insertions(+), 4 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,6 @@ +*.obj +*.exe +.dep.* +.lock.* +build/ +!build/*.do diff --git a/doc/io/QUELLE b/doc/io/QUELLE @@ -0,0 +1 @@ +Sun 13 Jul 2003 16:43:42 UTC diff --git a/doc/io/README.md b/doc/io/README.md @@ -0,0 +1,3 @@ +# The io library - notes + +This copy of io.html was last modified Sun 13 Jul 2003 16:43:42 UTC (Epoch +1058114622) diff --git a/doc/io/io.html b/doc/io/io.html @@ -0,0 +1,702 @@ +<html> +<body> +<a href="../djb.html">D. J. Bernstein</a> +<h1>The io library interface</h1> +This page starts with +<a href="#intro">an introduction to the io library</a>. +It continues by describing the io functions for +<a href="#create">creating descriptors</a>, +<a href="#read">reading data</a>, +<a href="#write">writing data</a>, +<a href="#timeout">setting time limits on descriptors</a>, +<a href="#wait">waiting for ready descriptors</a>, +and +<a href="#absorb">using descriptors created in other ways</a>. +<h2><a name="intro">Introduction to the io library</a></h2> +A UNIX program receives information from external sources +through ``file descriptors.'' +Despite the word ``file,'' +these sources are not necessarily files on disk; +a file descriptor might be a ``socket'' +receiving information from the <tt>cnn.com</tt> web server, +for example, +or a ``tty'' receiving information from the user's keyboard. +<p> +Similarly, +a UNIX program provides information to external sinks +through file descriptors. +<p> +The io (input/output) library manages file descriptors. +It can +<ul> +<li>create descriptors talking to disk files, other programs, etc.; +<li>receive (``read'') data from a descriptor, +if the descriptor has data to provide; +<li>provide (``write'') data to a descriptor, +if the descriptor has space for data; +<li>if no descriptors are ready for reading or writing, +pause until the situation changes; and +<li>identify the descriptors that are ready +for reading or writing. +</ul> +The descriptors are identified by nonnegative integers (0, 1, 2, etc.) +stored in <tt>int64</tt> variables. +<p> +For example, a program that wants to read a file from disk +can use <tt>io_readfile()</tt> to create a descriptor for the file, +<tt>io_tryread()</tt> repeatedly to receive information from the file, +and then <tt>io_close()</tt> to eliminate the descriptor. +<p> +The following program uses the io library +to copy standard input (descriptor 0) +to standard output (descriptor 1), +with a 65536-byte buffer in the middle: +<pre> + #include "io.h" + + char buf[65536]; + int64 readpos = 0; + int64 writepos = 0; + int flageof = 0; + + int main() + { + int64 r; + + if (!io_fd(0)) return 111; + if (!io_fd(1)) return 111; + + for (;;) { + if (flageof && writepos &gt;= readpos) return 0; + + if (!flageof && readpos &lt; sizeof buf) { + r = io_tryread(0,buf + readpos,sizeof buf - readpos); + if (r &lt;= -2) return 111; /* read error other than <tt>EAGAIN</tt> */ + if (r == 0) flageof = 1; + if (r &gt; 0) readpos += r; + } + + if (writepos &lt; readpos) { + r = io_trywrite(1,buf + writepos,readpos - writepos); + if (r &lt;= -2) return 111; /* write error other than <tt>EAGAIN</tt> */ + if (r &gt; 0) { + writepos += r; + if (writepos == readpos) readpos = writepos = 0; + /* if writepos is big, might want to left-shift buffer here */ + } + } + } + } +</pre> +<tt>io_fd</tt> makes file descriptors 0 and 1 visible to the io library. +<tt>io_tryread(0,...)</tt> +reads data if descriptor 0 is readable, +and <tt>io_trywrite(1,...)</tt> +writes data if descriptor 1 is writable. +If the buffer is partially full, +the program will check both descriptors, +rather than delaying further reads until the current data is written. +<p> +If descriptor 0 is unreadable (or there is no space in the buffer for new data) +and descriptor 1 is unwritable (or the buffer is empty), +the above program busy-loops: +it calls <tt>io_tryread()</tt> and <tt>io_trywrite()</tt> repeatedly, +making no progress until the situation changes. +Here is a smarter program +that instead goes to sleep until the situation changes, +leaving the CPU free for other programs: +<pre> + #include "io.h" + + char buf[65536]; + int64 readpos = 0; + int64 writepos = 0; + int flageof = 0; + + int main() + { + int64 r; + + if (!io_fd(0)) return 111; + if (!io_fd(1)) return 111; + + for (;;) { + if (flageof && writepos &gt;= readpos) return 0; + + if (!flageof && readpos &lt; sizeof buf) io_wantread(0); + if (writepos &lt; readpos) io_wantwrite(1); + io_wait(); + if (!flageof && readpos &lt; sizeof buf) io_dontwantread(0); + if (writepos &lt; readpos) io_dontwantwrite(1); + + if (!flageof && readpos &lt; sizeof buf) { + r = io_tryread(0,buf + readpos,sizeof buf - readpos); + if (r &lt;= -2) return 111; /* read error other than <tt>EAGAIN</tt> */ + if (r == 0) flageof = 1; + if (r &gt; 0) readpos += r; + } + + if (writepos &lt; readpos) { + r = io_trywrite(1,buf + writepos,readpos - writepos); + if (r &lt;= -2) return 111; /* write error other than <tt>EAGAIN</tt> */ + if (r &gt; 0) { + writepos += r; + if (writepos == readpos) readpos = writepos = 0; + /* if writepos is big, might want to left-shift buffer here */ + } + } + } + } +</pre> +<tt>io_wait</tt> watches the descriptors previously indicated by +<tt>io_wantread</tt> and <tt>io_wantwrite</tt>. +<hr> +<h2><a name="create">Creating descriptors</a></h2> +<pre> + #include "io.h" + char <i>s</i>[]; + int64 <i>d</i>; + io_readfile(&amp;<i>d</i>,<i>s</i>); +</pre> +<tt>io_readfile</tt> sets <tt><i>d</i></tt> to the number of a new descriptor +reading from the disk file named <tt><i>s</i></tt>, +and returns 1. +<p> +If something goes wrong, +<tt>io_readfile</tt> sets <tt>errno</tt> to indicate the error, +and returns 0; +it does not create a new descriptor, +and it does not touch <tt><i>d</i></tt>. +<hr> +<pre> + #include "io.h" + char <i>s</i>[]; + int64 <i>d</i>; + io_createfile(&amp;<i>d</i>,<i>s</i>); +</pre> +<tt>io_createfile</tt> sets <tt><i>d</i></tt> to the number of a new descriptor +writing to the disk file named <tt><i>s</i></tt>, +and returns 1. +If <tt><i>s</i></tt> already existed, it is truncated to length 0; +otherwise, it is created, with mode 0600. +<p> +If something goes wrong, +<tt>io_createfile</tt> sets <tt>errno</tt> to indicate the error, +and returns 0; +it does not create a new descriptor, +and it does not touch <tt><i>d</i></tt>. +(However, it may have truncated or created the file.) +<hr> +<pre> + #include "io.h" + int64 <i>d</i>[2]; + io_pipe(<i>d</i>); +</pre> +<tt>io_pipe</tt> creates a new UNIX ``pipe.'' +The pipe can receive data and provide data; +any bytes written to the pipe +can then be read from the pipe in the same order. +<p> +A pipe is typically stored in an 8192-byte memory buffer; +the exact number depends on the UNIX kernel. +Bytes are written to the end of the buffer +and read from the beginning of the buffer. +Once a byte has been read, it is eliminated from the buffer, +making space for another byte to be written; +readers cannot ``rewind'' a pipe to read old data. +Once 8192 bytes have been written to the buffer, +the pipe will not be ready for further writing +until some of the bytes have been read. +Once all the bytes written have been read, +the pipe will not be ready for further reading +until more bytes are written. +<p> +<tt>io_pipe</tt> sets <tt><i>d</i>[0]</tt> +to the number of a new descriptor reading from the pipe, +and sets <tt><i>d</i>[1]</tt> +to the number of a new descriptor writing to the pipe. +It then returns 1 to indicate success. +If something goes wrong, +<tt>io_pipe</tt> returns 0, setting <tt>errno</tt> to indicate the error; +in this case +it frees any memory that it allocated for the new pipe, +and it leaves <tt><i>d</i></tt> alone. +<hr> +<pre> + #include "io.h" + int64 <i>d</i>; + io_close(<i>d</i>); +</pre> +<tt>io_close</tt> eliminates the descriptor numbered <tt><i>d</i></tt>. +This usually does not mean eliminating the object that the descriptor +is talking to. +(For example, if a descriptor writes to a named disk file, +closing the descriptor will not remove the file; +it simply removes one way of writing to the file. +On the other hand, a pipe disappears as soon as no descriptors refer to it.) +<p> +<tt>io_close</tt> has no return value; +it always succeeds in deallocating the memory used for the descriptor. +If <tt><i>d</i></tt> is not the number of a descriptor, +<tt>io_close</tt> has no effect. +<hr> +<h2><a name="read">Reading data</a></h2> +<pre> + #include "io.h" + int64 <i>d</i>; + char <i>buf</i>[]; + int64 <i>len</i>; + int64 <i>result</i>; + <i>result</i> = io_tryread(<i>d</i>,<i>buf</i>,<i>len</i>); +</pre> +<tt>io_tryread</tt> tries to read <tt><i>len</i></tt> bytes of data +from descriptor <tt><i>d</i></tt> +into +<tt><i>buf</i>[0]</tt>, +<tt><i>buf</i>[1]</tt>, +..., +<tt><i>buf</i>[<i>len</i>-1]</tt>. +(The effects are undefined if <tt><i>len</i></tt> is 0 or smaller.) +There are several possible results: +<ul> +<li><tt>io_tryread</tt> returns an integer between 1 and <tt><i>len</i></tt>: +This number of bytes was available for immediate reading; +the bytes were read into the beginning of <tt><i>buf</i></tt>. +Note that this number can be, and often is, smaller than <tt><i>len</i></tt>; +you must not assume that <tt>io_tryread</tt> +always succeeds in reading exactly <tt><i>len</i></tt> bytes. +<li><tt>io_tryread</tt> returns 0: +No bytes were read, +because the descriptor is at end of file. +For example, +this descriptor has reached the end of a disk file, +or is reading an empty pipe that has been closed by all writers. +<li><tt>io_tryread</tt> returns -1, +setting <tt>errno</tt> to <tt>EAGAIN</tt>: +No bytes were read, +because the descriptor is not ready. +For example, the descriptor is reading an empty pipe +that could still be written to. +<li><tt>io_tryread</tt> returns -3, +setting <tt>errno</tt> to something other than <tt>EAGAIN</tt>: +No bytes were read, +because the read attempt encountered a persistent error, +such as a serious disk failure (<tt>EIO</tt>), +an unreachable network (<tt>ENETUNREACH</tt>), +or an invalid descriptor number (<tt>EBADF</tt>). +</ul> +<tt>io_tryread</tt> does not pause waiting for a descriptor that is not ready. +If you want to pause, use <tt>io_waitread</tt> or <tt>io_wait</tt>. +<hr> +<pre> + #include "io.h" + int64 <i>d</i>; + char <i>buf</i>[]; + int64 <i>len</i>; + int64 <i>result</i>; + <i>result</i> = io_waitread(<i>d</i>,<i>buf</i>,<i>len</i>); +</pre> +<tt>io_waitread</tt> tries to read <tt><i>len</i></tt> bytes of data +from descriptor <tt><i>d</i></tt> +into +<tt><i>buf</i>[0]</tt>, +<tt><i>buf</i>[1]</tt>, +..., +<tt><i>buf</i>[<i>len</i>-1]</tt>, +pausing if necessary so that the descriptor is ready. +(The effects are undefined if <tt><i>len</i></tt> is 0 or smaller.) +There are several possible results: +<ul> +<li><tt>io_waitread</tt> returns an integer between 1 and <tt><i>len</i></tt>: +This number of bytes was available for reading; +the bytes were read into the beginning of <tt><i>buf</i></tt>. +Note that this number can be, and often is, smaller than <tt><i>len</i></tt>; +you must not assume that <tt>io_waitread</tt> +always succeeds in reading exactly <tt><i>len</i></tt> bytes. +<li><tt>io_waitread</tt> returns 0: +No bytes were read, +because the descriptor is at end of file. +For example, +this descriptor has reached the end of a disk file, +or is reading an empty pipe that has been closed by all writers. +<li><tt>io_waitread</tt> returns -3, +setting <tt>errno</tt> to something other than <tt>EAGAIN</tt>: +No bytes were read, +because the read attempt encountered a persistent error, +such as a serious disk failure (<tt>EIO</tt>), +an unreachable network (<tt>ENETUNREACH</tt>), +or an invalid descriptor number (<tt>EBADF</tt>). +</ul> +<hr> +<h2><a name="write">Writing data</a></h2> +<pre> + #include "io.h" + int64 <i>d</i>; + const char <i>buf</i>[]; + int64 <i>len</i>; + int64 <i>result</i>; + <i>result</i> = io_trywrite(<i>d</i>,<i>buf</i>,<i>len</i>); +</pre> +<tt>io_trywrite</tt> tries to write <tt><i>len</i></tt> bytes of data +from +<tt><i>buf</i>[0]</tt>, +<tt><i>buf</i>[1]</tt>, +..., +<tt><i>buf</i>[<i>len</i>-1]</tt> +to descriptor <tt><i>d</i></tt>. +(The effects are undefined if <tt><i>len</i></tt> is 0 or smaller.) +There are several possible results: +<ul> +<li><tt>io_trywrite</tt> returns an integer between 1 and <tt><i>len</i></tt>: +This number of bytes was immediately written +from the beginning of <tt><i>buf</i></tt>. +Note that this number can be, and often is, smaller than <tt><i>len</i></tt>; +you must not assume that <tt>io_trywrite</tt> +always succeeds in writing exactly <tt><i>len</i></tt> bytes. +<li><tt>io_trywrite</tt> returns -1, +setting <tt>errno</tt> to <tt>EAGAIN</tt>: +No bytes were written, +because the descriptor is not ready. +For example, the descriptor is writing to a full pipe +that could still be read. +<li><tt>io_trywrite</tt> returns -3, +setting <tt>errno</tt> to something other than <tt>EAGAIN</tt>: +No bytes were written, +because the write attempt encountered a persistent error, +such as a serious disk failure (<tt>EIO</tt>), +a pipe that can no longer be read (<tt>EPIPE</tt>), +an unreachable network (<tt>ENETUNREACH</tt>), +or an invalid descriptor number (<tt>EBADF</tt>). +</ul> +<tt>io_trywrite</tt> does not pause waiting for a descriptor that is not ready. +If you want to pause, use <tt>io_waitwrite</tt> or <tt>io_wait</tt>. +<p> +Once upon a time, +many UNIX programs neglected to check the success of their writes. +They would often encounter <tt>EPIPE</tt>, +and would blithely continue writing, +rather than exiting with an appropriate exit code. +The UNIX kernel developers decided to send a <tt>SIGPIPE</tt> signal, +which terminates the process by default, +along with returning <tt>EPIPE</tt>. +This papers over the problem without fixing it: +the same programs ignore other errors such as <tt>EIO</tt>. +One hopes that the programs have been fixed by now; +kernels nevertheless continue to generate the <tt>SIGPIPE</tt> signal. +The first time <tt>io_trywrite</tt> or <tt>io_waitwrite</tt> is called, +it arranges for <tt>SIGPIPE</tt> to be ignored. +(Technically, for <tt>SIGPIPE</tt> to be caught by an empty signal handler, +so this doesn't affect child processes.) +Do not use <tt>SIGPIPE</tt> elsewhere in the program. +<hr> +<pre> + #include "io.h" + int64 <i>d</i>; + const char <i>buf</i>[]; + int64 <i>len</i>; + int64 <i>result</i>; + <i>result</i> = io_waitwrite(<i>d</i>,<i>buf</i>,<i>len</i>); +</pre> +<tt>io_waitwrite</tt> tries to write <tt><i>len</i></tt> bytes of data +from +<tt><i>buf</i>[0]</tt>, +<tt><i>buf</i>[1]</tt>, +..., +<tt><i>buf</i>[<i>len</i>-1]</tt> +to descriptor <tt><i>d</i></tt>, +pausing (perhaps repeatedly) until the descriptor is ready. +(The effects are undefined if <tt><i>len</i></tt> is 0 or smaller.) +There are several possible results: +<ul> +<li><tt>io_waitwrite</tt> returns <tt><i>len</i></tt>: +All the bytes were written. +<li><tt>io_waitwrite</tt> returns something between <tt>0</tt> +and <tt><i>len</i>-1</tt>, +setting <tt>errno</tt> to something other than <tt>EAGAIN</tt>: +After this number of bytes was written, +no further bytes were written, +because the write attempt encountered a persistent error, +such as a serious disk failure (<tt>EIO</tt>), +a pipe that can no longer be read (<tt>EPIPE</tt>), +an unreachable network (<tt>ENETUNREACH</tt>), +or an invalid descriptor number (<tt>EBADF</tt>). +</ul> +<hr> +<h2><a name="timeout">Setting time limits on descriptors</a></h2> +<pre> + #include "io.h" + int64 <i>d</i>; + tai6464 <i>t</i>; + io_timeout(<i>d</i>,<i>t</i>); +</pre> +The io library keeps track of an optional ``timeout'' for each descriptor. +The timeout is a specific moment in time, +stored in a <tt>tai6464</tt> variable. +<p> +<tt>io_timeout(<i>d</i>,<i>t</i>)</tt> +sets the timeout for descriptor <tt><i>d</i></tt> +to <tt><i>t</i></tt>. +<p> +<tt>io_timeout</tt> has no return value; it always succeeds. +(Space to store the timeout was already allocated as part of the descriptor.) +It has no effect +if <tt><i>d</i></tt> is not the number of a descriptor. +<hr> +<pre> + #include "io.h" + int64 <i>d</i>; + char <i>buf</i>[]; + int64 <i>len</i>; + int64 <i>result</i>; + <i>result</i> = io_tryreadtimeout(<i>d</i>,<i>buf</i>,<i>len</i>); +</pre> +<tt>io_tryreadtimeout</tt> is identical to <tt>io_tryread</tt>, +with the following exception: if +<ul> +<li><tt>io_tryread</tt> returns -1 (the descriptor is not ready for reading), +and +<li>the descriptor has a timeout, and +<li>the read attempt was after the descriptor's timeout, +</ul> +then <tt>io_tryreadtimeout</tt> instead returns -2, +with <tt>errno</tt> set to <tt>ETIMEDOUT</tt>. +<hr> +<pre> + #include "io.h" + int64 <i>d</i>; + const char <i>buf</i>[]; + int64 <i>len</i>; + int64 <i>result</i>; + <i>result</i> = io_trywritetimeout(<i>d</i>,<i>buf</i>,<i>len</i>); +</pre> +<tt>io_trywritetimeout</tt> is identical to <tt>io_trywrite</tt>, +with the following exception: if +<ul> +<li><tt>io_trywrite</tt> returns -1 (the descriptor is not ready for writing), +and +<li>the descriptor has a timeout, and +<li>the write attempt was after the descriptor's timeout, +</ul> +then <tt>io_trywritetimeout</tt> instead returns -2, +with <tt>errno</tt> set to <tt>ETIMEDOUT</tt>. +<hr> +<h2><a name="wait">Waiting for ready descriptors</a></h2> +<pre> + #include "io.h" + int64 <i>d</i>; + io_wantread(<i>d</i>); + io_wantwrite(<i>d</i>); + io_dontwantread(<i>d</i>); + io_dontwantwrite(<i>d</i>); +</pre> +For each descriptor, +the io library keeps track of the number of parts of the current program +interested in reading the descriptor. +The number is incremented by <tt>io_wantread</tt> +and decremented by <tt>io_dontwantread</tt>. +(The effects are undefined if the number is decremented below 0.) +The number is 0 when the descriptor is created. +Closing a descriptor implicitly sets the number to 0. +<p> +Similar comments apply to <tt>io_wantwrite</tt> and <tt>io_dontwantwrite</tt>. +<p> +These functions have no return value; they always succeed. +(Space to store the numbers was already allocated as part of the descriptor.) +They have no effect if <tt><i>d</i></tt> is not the number of a descriptor. +<p> +You do not have to indicate interest in a descriptor +before using the descriptor. +The importance of <tt>io_wantread</tt> and <tt>io_wantwrite</tt> +is their interaction with <tt>io_wait</tt>, +<tt>io_waituntil</tt>, and <tt>io_check</tt>. +<hr> +<pre> + #include "io.h" + tai6464 <i>t</i>; + io_wait(); + io_waituntil(<i>t</i>); + io_check(); +</pre> +<tt>io_wait()</tt> +checks the descriptors that the program is interested in +to see whether any of them are ready. +If none of them are ready, +<tt>io_wait()</tt> +tries to pause until one of them is ready, +so that it does not take time away +from other programs running on the same computer. +<p> +<tt>io_wait</tt> pays attention to timeouts: +if a descriptor reaches its timeout, +and the program is interested in reading or writing that descriptor, +<tt>io_wait</tt> will return promptly. +<p> +Under some circumstances, +<tt>io_wait</tt> will return even though no interesting descriptors are ready. +Do not assume that a descriptor is ready +merely because <tt>io_wait</tt> has returned. +<p> +<tt>io_wait</tt> is <i>not</i> interrupted by the delivery of a signal. +Programs that expect interruption are unreliable: +they will block if the same signal +is delivered a moment before <tt>io_wait</tt>. +The correct way to handle signals is with the +<a href="../docs/selfpipe.html">self-pipe trick</a>. +<p> +<tt>io_waituntil(<i>t</i>)</tt> +is like <tt>io_wait()</tt> +but does not wait (noticeably) past time <tt><i>t</i></tt>. +<tt>io_check()</tt> +is like <tt>io_wait()</tt> +but does not wait at all; +its importance is its interaction +with <tt>io_canread</tt> and <tt>io_canwrite</tt>. +<hr> +<pre> + #include "io.h" + int64 <i>d</i>; + <i>d</i> = io_canread(); + <i>d</i> = io_canwrite(); +</pre> +<tt>io_wait</tt> +saves a list of numbers of the descriptors +that are ready to be read (or that have timed out) +and that the program is interested in reading. +<tt>io_canread</tt> returns the next descriptor number on the list, +or -1 if there are no more descriptor numbers on the list. +The list is reset by the next call to <tt>io_wait</tt>. +<p> +<tt>io_waituntil</tt> and <tt>io_check</tt> +interact with <tt>io_canread</tt> in the same way that <tt>io_wait</tt> does. +<tt>io_wait</tt>, <tt>io_waituntil</tt>, and <tt>io_check</tt> +share one list of descriptors. +<p> +Do not assume that data can actually be read +merely because <tt>io_canread</tt> has pointed to a descriptor. +Data that was readable a moment ago +could already have been read by another program. +Even worse, the low-level UNIX routines +used by <tt>io_wait</tt> could have failed to allocate memory; +in this case, <tt>io_canread</tt> has no choice but to indicate +that all descriptors are ready. +You must check the results of <tt>io_tryread</tt>. +<p> +Similar comments apply to <tt>io_canwrite</tt>. +<p> +You do not need to use <tt>io_canread</tt> and <tt>io_canwrite</tt>. +You can call <tt>io_wait</tt>, +try <tt>io_tryread</tt> and <tt>io_trywrite</tt> for every descriptor, +and repeat. +However, +if you have thousands of descriptors of which only a few are ready, +most of the effort of trying descriptors will be wasted. +It is faster to focus on the descriptors indicated by <tt>io_canread</tt> +and <tt>io_canwrite</tt>. +<p> +(The <tt>io_wait</tt> implementation and underlying UNIX kernel routines +might have their own speed problems with thousands of descriptors, +but this problem can be solved without any change in programs that use +<tt>io_wait</tt>.) +<hr> +<h2><a name="absorb">Using descriptors created in other ways</a></h2> +<pre> + #include "io.h" + int64 <i>d</i>; + io_fd(<i>d</i>); +</pre> +There is a slight difference between the io library's view of descriptors +and the UNIX view of descriptors: +the io library has its own list of descriptors, +and will not work with UNIX descriptors that aren't on the list. +In particular: +<ul> +<li>When a program starts, +it typically ``inherits'' (is started with) UNIX descriptors +numbered 0 (stdin: standard input), +1 (stdout: standard output), and +2 (stderr: standard error). +More sophisticated UNIX programming +often involves more startup descriptors. +In contrast, the io library starts with an empty list. +The startup descriptors should be passed to <tt>io_fd</tt>. +<li>Various low-level mechanisms outside the io library, +such as the UNIX <tt>socket</tt> function, +create UNIX descriptors that aren't on the io list. +These descriptors should be passed to +<tt>io_closeonexec</tt>, <tt>io_nonblock</tt>, and <tt>io_fd</tt>. +</ul> +The <tt>io_fd</tt> function +adds the UNIX descriptor numbered <tt>d</tt> to the io list, +and returns 1. +If the descriptor is already on the list, +<tt>io_fd</tt> returns 1 without doing anything. +If something goes wrong (such as running out of memory), +<tt>io_fd</tt> returns 0, setting <tt>errno</tt> to indicate the error. +<hr> +<pre> + #include "io.h" + int64 <i>d</i>; + io_nonblock(<i>d</i>); +</pre> +<tt>io_nonblock</tt> puts UNIX descriptor <tt><i>d</i></tt> +into ``non-blocking mode.'' +Calling <tt>io_nonblock(<i>d</i>)</tt> +<i>before</i> <tt>io_fd(<i>d</i>)</tt> saves some time in +<tt>io_tryread</tt> and <tt>io_trywrite</tt>. +<p> +Actually, current UNIX kernels +do not support non-blocking <i>descriptors</i>; +they support non-blocking <i>open files</i>. +Furthermore, many programs will break if they encounter non-blocking mode. +This means that +you must not use <tt>io_nonblock</tt> for a descriptor +inherited from another program. +<p> +<tt>io_nonblock</tt> has no return value; it always succeeds. +If <tt><i>d</i></tt> is not the number of a UNIX descriptor, +<tt>io_nonblock</tt> has no effect. +<p> +If <tt>io_fd</tt> is given a descriptor in blocking mode, +<tt>io_tryread</tt> and <tt>io_trywrite</tt> go through +the following contortions to avoid blocking: +<ol> +<li>Stop if <tt>poll</tt> says that the descriptor is not ready. +Otherwise there's a good chance, but not a guarantee: +even if <tt>poll</tt> says the descriptor is ready, +the descriptor might not be ready a moment later. +(Furthermore, <tt>poll</tt> can fail on some systems.) +<li>Catch <tt>SIGALRM</tt>. +<tt>SIGALRM</tt> must not be blocked, +and must not be used elsewhere in the program. +<li>Set an interval timer +so that any blocking call will be interrupted by <tt>SIGALRM</tt> +within 10 milliseconds. +(Current UNIX kernels do not allow any shorter interval.) +Of course, this may still mean a 10-millisecond delay. +</ol> +If <tt>io_fd</tt> is given a descriptor in non-blocking mode +(or a descriptor for a regular disk file), +<tt>io_tryread</tt> and <tt>io_trywrite</tt> avoid these contortions. +<p> +Future versions of the io library may use +<a href="../unix/nonblock.html">kernel extensions</a> +to avoid these contortions. +<hr> +<pre> + #include "io.h" + int64 <i>d</i>; + io_closeonexec(<i>d</i>); +</pre> +<tt>io_closeonexec</tt> arranges for UNIX descriptor <tt><i>d</i></tt> +to <i>not</i> be inherited by children of the current process. +You should do this for any descriptor obtained from a UNIX function +such as <tt>socket</tt> and <tt>open</tt>; +it's an unfortunate historical accident that the UNIX functions don't do this. +(If you want a descriptor to be inherited by a child process, +arrange that when you create the child process.) +<p> +<tt>io_closeonexec</tt> has no return value; it always succeeds. +If <tt><i>d</i></tt> is not the number of a UNIX descriptor, +<tt>io_closeonexec</tt> has no effect. +</body> +</html> diff --git a/doc/npthread/README.md b/doc/npthread/README.md @@ -1,13 +1,13 @@ # The npthread library - notes -npthread.html was retrieved Sat 21 Jun 2003 00:03:18 UTC (Epoch +1056153798) +This copy of npthread.html was last modified Sat 21 Jun 2003 00:03:18 UTC (Epoch +1056153798) This npthread aims to be capable of exact conformance with the Bernstein documented npthreads by default. If you define NPTHREAD_VPTR, this compliance is lost, but the 'n' your f(n) is called with is expected to be a void pointer instead of an int64. I believe this use to be much more likely to be useful for most users. -If you include sc_npthread.h as well as npthread.h, you would gain access to additional thread call conditions to be determined. In thread-safe sc_npthread, those call conditions may involve pthread trylock successes, or data (from another true thread) in the rendezvous area. +If you include sc_npthread.h as well as npthread.h, you would gain access to additional thread call conditions to be determined. In thread-safe sc_npthread, those call conditions may involve pthread trylock successes, or data (from another true thread) in a mailbox area. Your threads should have a mechanism for saving their state, so if they choose to cut mid-procedure (e.g. starving of data from a fildes or the rendezvous area, or of a locked resource, or buffered I/O needs to drain before continuing), they can resume processing. In 2000, Simon Tatham designed a header capable of helping you do this. It is available under the MIT licence. <https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html> -User-defined lights (npthread_watchflag and npthread_waveflag) could be used to implement the message and trylock notes. +User-defined lights (npthread_watchflag and npthread_waveflag) could be used internally to implement the message and trylock notes. This package requires tai support, which can be had from many different places. diff --git a/head/io/io.h b/head/io/io.h @@ -0,0 +1,91 @@ +#ifndef _SC_IO_IO_H +#define _SC_IO_IO_H + +#define int64 int64_t + +#ifndef BERNSTEINLY_CORRECT +#define taitype tai6464 +#else +#define taitype taia +#endif + +extern int io_readfile(int64 *d, const char *s); +extern int io_createfile(int64 *d, const char *s); +extern int io_pipe(int64 *d); // must be of length 2 + +/* io_close always succeeds in deallocating the memory + * used by the io library related to this, but the underlying + * close(fd) system call may give an error return. in such a case + * io_close is to be considered successful, but if you aren't + * BERNSTEINLY_CORRECT you can harvest the output. + */ +#ifndef BERNSTEINLY_CORRECT +extern int io_close(int64 d); +#else +extern void io_close(int64 d); +#endif + +extern int64 io_tryread(int64, const char *, int64); +extern int64 io_waitread(int64, const char *, int64); + +extern int64 io_trywrite(int64, const char *, int64); +extern int64 io_waitwrite(int64, const char *, int64); + + +/* in thread-safe io, timeout can return -1 EAGAIN if a writer + * lock to the structure is not currently available. + * waittimeout will instead hang the current thread until the + * lock comes up. + * thread-safe CORRECT io will always hang. + * for reliably nonblock timeout sets, always use trytimeout, + * and for reliably block timeout sets, always use waittimeout. + * both of these functions are extensions in Suitcase io. + */ +#ifndef BERNSTEINLY_CORRECT +extern void io_timeout(int64, taitype); +#define io_waittimeout(i, t) io_timeout(i, t) +extern int io_trytimeout(int64, taitype); +#else +extern int io_timeout(int64, taitype); +extern void io_waittimeout(int64, taitype); +#define io_trytimeout(i, t) io_timeout(i, t) +#endif + +extern void io_wantread(int64); +extern void io_wantwrite(int64); +extern void io_dontwantread(int64); +extern void io_dontwantwrite(int64); + +/* io_trywant* family functions will return -1 EAGAIN if a writer + * lock to the structure is not currently available. + * this enables a thread to go to sleep with the desired value in + * its TLS, and an alarm connected to the lock available light, + * if it can't set the lock right now. + * bernstein standard versions of these functions will instead + * hang the current thread until the lock is available. + */ +#ifndef BERNSTEINLY_CORRECT +extern int io_trywantread(int64); +extern int io_trywantwrite(int64); +extern int io_trydontwantread(int64); +extern int io_trydontwantwrite(int64); +#endif + +/* int versions of io_wait family functions will return the number + * of FDs they've put into the queue, or on systems with native event + * queues, the number of FDs the OS reports + */ +#ifndef BERNSTEINLY_CORRECT +extern int64 io_waituntil(taitype); +extern int64 io_wait(); +extern int64 io_check(); +#else +extern void io_waituntil(taitype); +extern void io_wait(); +extern void io_check(); +#endif + +extern int64 io_canread(); +extern int64 io_canwrite(); + +#endif // _SC_IO_IO_H diff --git a/head/npthread/npthread.h b/head/npthread/npthread.h @@ -0,0 +1,42 @@ +#ifndef NPTHREAD_NPTHREAD_H +#define NPTHREAD_NPTHREAD_H + +#include <sys/types.h> + +#define int64 int64_t + +#ifndef BERNSTEINLY_CORRECT +#define thunktype void* +#define taitype tai6464 +#else +#define taitype taia +#define thunktype int64 +#endif + +#define threadnotype uint64_t + +extern int npthread_add(int (*f)(thunktype n), thunktype); +extern int npthread_addsignal(int (*f)(thunktype n), thunktype, int); + +extern int npthread_start(void); +extern threadnotype *_sc_curthread(); +/* In the thread-unsafe version, + * this will be implemented using a static. + * in the thread-safe version, we will use pthread keys. + * all of this will be transparent to the thread. + */ + +extern void npthread_jump(int (*f)(thunktype n), thunktype); +extern void npthread_important(void); +extern void npthread_unimportant(void); +extern void npthread_child(pid_t); +extern void npthread_childstatus(void); // uses thread local storage + +extern int64 npthread_newflag(void); +extern void npthread_watchflag(int64); +extern void npthread_waveflag(int64); + +extern void npthread_read(int64); // wants io_fd_t (int64) +extern void npthread_write(int64); + +#endif // NPTHREAD_NPTHREAD_H diff --git a/head/tai/caldate.h b/head/tai/caldate.h @@ -0,0 +1,19 @@ +#ifndef CALDATE_H +#define CALDATE_H + +struct caldate { + long year; + int month; + int day; +} ; + +extern unsigned int caldate_fmt(); +extern unsigned int caldate_scan(); + +extern void caldate_frommjd(); +extern long caldate_mjd(); +extern void caldate_normalize(); + +extern void caldate_easter(); + +#endif diff --git a/head/tai/caltime.h b/head/tai/caltime.h @@ -0,0 +1,20 @@ +#ifndef CALTIME_H +#define CALTIME_H + +#include "caldate.h" + +struct caltime { + struct caldate date; + int hour; + int minute; + int second; + long offset; +} ; + +extern void caltime_tai(); +extern void caltime_utc(); + +extern unsigned int caltime_fmt(); +extern unsigned int caltime_scan(); + +#endif diff --git a/head/tai/leapsecs.h b/head/tai/leapsecs.h @@ -0,0 +1,10 @@ +#ifndef LEAPSECS_H +#define LEAPSECS_H + +extern int leapsecs_init(); +extern int leapsecs_read(); + +extern void leapsecs_add(); +extern int leapsecs_sub(); + +#endif diff --git a/head/tai/tai.h b/head/tai/tai.h @@ -0,0 +1,22 @@ +#ifndef TAI_H +#define TAI_H + +#include "uint64.h" + +struct tai { + uint64 x; +} ; + +extern void tai_now(); + +#define tai_approx(t) ((double) ((t)->x)) + +extern void tai_add(); +extern void tai_sub(); +#define tai_less(t,u) ((t)->x < (u)->x) + +#define TAI_PACK 8 +extern void tai_pack(); +extern void tai_unpack(); + +#endif diff --git a/head/tai/taia.h b/head/tai/taia.h @@ -0,0 +1,31 @@ +#ifndef TAIA_H +#define TAIA_H + +#include "tai.h" + +struct taia { + struct tai sec; + unsigned long nano; /* 0...999999999 */ + unsigned long atto; /* 0...999999999 */ +} ; + +extern void taia_tai(); + +extern void taia_now(); + +extern double taia_approx(); +extern double taia_frac(); + +extern void taia_add(); +extern void taia_sub(); +extern void taia_half(); +extern int taia_less(); + +#define TAIA_PACK 16 +extern void taia_pack(); +extern void taia_unpack(); + +#define TAIA_FMTFRAC 19 +extern unsigned int taia_fmtfrac(); + +#endif diff --git a/head/tai/uint64.h b/head/tai/uint64.h @@ -0,0 +1,6 @@ +#ifndef UINT64_H +#define UINT64_H + +typedef unsigned long long uint64; + +#endif diff --git a/src/configlib.sh b/src/configlib.sh @@ -0,0 +1,21 @@ +setvar() { + $1="$2" +} + +# int getccvar setvar var ifundef +get1ccvar() { + if test ! -f "conf-compile/$2"; then + if test ! -f "conf-compile/defaults/$2"; then + if test ! -z "$3"; then + $1 "$3" + else + return 1 # could not give a valid argument to param setvar + fi + else + $1 "$(head -n1 "conf-compile/defaults/$2")" + fi + else + $1 "$(head -n1 "conf-compile/$2")" + fi + return 0 +} diff --git a/src/eloop/QUELLE b/src/eloop/QUELLE @@ -2,4 +2,4 @@ The headers and source files herewithin ultimately come from the event loop facility of MXF-Remote, which was retrieved from https://git.umbrellix.net/nightmaremail version @6f7024a6c31f36d306a02de9804cb9d93cd67a7c, concerning file descriptor and protegé process management. -This portion requires skalibs and the included uthash header. +This portion requires skalibs (or another source of tain and iopause_stamp) and the included uthash header. diff --git a/src/io/QUELLE b/src/io/QUELLE @@ -0,0 +1,3 @@ +/pkg/umbrellix.net/prog/suitcase/src/io Statement of Origin + +This is my (Ellenor et al Bjornsdottir's) original work, albeit drafting some inspiration from the fact that this thas already been done before by other authors. diff --git a/src/tai/QUELLE b/src/tai/QUELLE @@ -0,0 +1,5 @@ +/pkg/umbrellix.net/prog/suitcase/src/tai Statement of Origin + +This is basically a straight extraction of the libtai library, in version 0.60, as published by Daniel Bernstein. + +I've cleaned up function declarations so that they are in the more modern style. diff --git a/src/tai/caldate_fmjd.c b/src/tai/caldate_fmjd.c @@ -0,0 +1,48 @@ +#include <tai/caldate.h> + +void caldate_frommjd(cd,day,pwday,pyday) +struct caldate *cd; +long day; +int *pwday; +int *pyday; +{ + long year; + long month; + int yday; + + year = day / 146097L; + day %= 146097L; + day += 678881L; + while (day >= 146097L) { day -= 146097L; ++year; } + + /* year * 146097 + day - 678881 is MJD; 0 <= day < 146097 */ + /* 2000-03-01, MJD 51604, is year 5, day 0 */ + + if (pwday) *pwday = (day + 3) % 7; + + year *= 4; + if (day == 146096L) { year += 3; day = 36524L; } + else { year += day / 36524L; day %= 36524L; } + year *= 25; + year += day / 1461; + day %= 1461; + year *= 4; + + yday = (day < 306); + if (day == 1460) { year += 3; day = 365; } + else { year += day / 365; day %= 365; } + yday += day; + + day *= 10; + month = (day + 5) / 306; + day = (day + 5) % 306; + day /= 10; + if (month >= 10) { yday -= 306; ++year; month -= 10; } + else { yday += 59; month += 2; } + + cd->year = year; + cd->month = month + 1; + cd->day = day + 1; + + if (pyday) *pyday = yday; +} diff --git a/src/tai/caldate_fmt.c b/src/tai/caldate_fmt.c @@ -0,0 +1,23 @@ +#include <tai/caldate.h> + +unsigned int caldate_fmt(char *s, struct caldate *cd) +{ + long x; + int i = 0; + + x = cd->year; if (x < 0) x = -x; do { ++i; x /= 10; } while(x); + + if (s) { + x = cd->year; + if (x < 0) { x = -x; *s++ = '-'; } + s += i; do { *--s = '0' + (x % 10); x /= 10; } while(x); s += i; + + x = cd->month; + s[0] = '-'; s[2] = '0' + (x % 10); x /= 10; s[1] = '0' + (x % 10); + + x = cd->day; + s[3] = '-'; s[5] = '0' + (x % 10); x /= 10; s[4] = '0' + (x % 10); + } + + return (cd->year < 0) + i + 6; +} diff --git a/src/tai/caldate_mjd.c b/src/tai/caldate_mjd.c @@ -0,0 +1,43 @@ +#include <tai/caldate.h> + +static unsigned long times365[4] = { 0, 365, 730, 1095 } ; +static unsigned long times36524[4] = { 0, 36524UL, 73048UL, 109572UL } ; +static unsigned long montab[12] = +{ 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337 } ; +/* month length after february is (306 * m + 5) / 10 */ + +long caldate_mjd(struct caldate *cd) +{ + long y; + long m; + long d; + + d = cd->day - 678882L; + m = cd->month - 1; + y = cd->year; + + d += 146097L * (y / 400); + y %= 400; + + if (m >= 2) m -= 2; else { m += 10; --y; } + + y += (m / 12); + m %= 12; + if (m < 0) { m += 12; --y; } + + d += montab[m]; + + d += 146097L * (y / 400); + y %= 400; + if (y < 0) { y += 400; d -= 146097L; } + + d += times365[y & 3]; + y >>= 2; + + d += 1461L * (y % 25); + y /= 25; + + d += times36524[y & 3]; + + return d; +} diff --git a/src/tai/caldate_norm.c b/src/tai/caldate_norm.c @@ -0,0 +1,6 @@ +#include <tai/caldate.h> + +void caldate_normalize(struct caldate *cd) +{ + caldate_frommjd(cd,caldate_mjd(cd),(int *) 0,(int *) 0); +} diff --git a/src/tai/caldate_scan.c b/src/tai/caldate_scan.c @@ -0,0 +1,23 @@ +#include <tai/caldate.h> + +unsigned int caldate_scan(char *s, struct caldate *cd) +{ + int sign = 1; + char *t = s; + unsigned long z; + unsigned long c; + + if (*t == '-') { ++t; sign = -1; } + z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; } + cd->year = z * sign; + + if (*t++ != '-') return 0; + z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; } + cd->month = z; + + if (*t++ != '-') return 0; + z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; } + cd->day = z; + + return t - s; +} diff --git a/src/tai/caldate_ster.c b/src/tai/caldate_ster.c @@ -0,0 +1,23 @@ +#include <tai/caldate.h> + +void caldate_easter(struct caldate *cd) +{ + long c; + long t; + long j; + long n; + long y; + + y = cd->year; + + c = (y / 100) + 1; + t = 210 - (((c * 3) / 4) % 210); + j = y % 19; + n = 57 - ((14 + j * 11 + (c * 8 + 5) / 25 + t) % 30); + if ((n == 56) && (j > 10)) --n; + if (n == 57) --n; + n -= ((((y % 28) * 5) / 4 + t + n + 2) % 7); + + if (n < 32) { cd->month = 3; cd->day = n; } + else { cd->month = 4; cd->day = n - 31; } +} diff --git a/src/tai/caltime_fmt.c b/src/tai/caltime_fmt.c @@ -0,0 +1,43 @@ +#include <tai/caldate.h> +#include <tai/caltime.h> + +unsigned int caltime_fmt(char *s, struct caltime *ct) +{ + unsigned int result; + long x; + + result = caldate_fmt(s,&ct->date); + + if (s) { + s += result; + + x = ct->hour; + s[0] = ' '; + s[2] = '0' + (x % 10); x /= 10; + s[1] = '0' + (x % 10); + s += 3; + + x = ct->minute; + s[0] = ':'; + s[2] = '0' + (x % 10); x /= 10; + s[1] = '0' + (x % 10); + s += 3; + + x = ct->second; + s[0] = ':'; + s[2] = '0' + (x % 10); x /= 10; + s[1] = '0' + (x % 10); + s += 3; + + s[0] = ' '; + x = ct->offset; + if (x < 0) { s[1] = '-'; x = -x; } else s[1] = '+'; + + s[5] = '0' + (x % 10); x /= 10; + s[4] = '0' + (x % 6); x /= 6; + s[3] = '0' + (x % 10); x /= 10; + s[2] = '0' + (x % 10); + } + + return result + 15; +} diff --git a/src/tai/caltime_scan.c b/src/tai/caltime_scan.c @@ -0,0 +1,38 @@ +#include <tai/caltime.h> + +unsigned int caltime_scan(char *s, struct caltime *ct) +{ + char *t = s; + unsigned long z; + unsigned long c; + int sign; + + t += caldate_scan(t,&ct->date); + + while ((*t == ' ') || (*t == '\t') || (*t == 'T')) ++t; + z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; } + ct->hour = z; + + if (*t++ != ':') return 0; + z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; } + ct->minute = z; + + if (*t != ':') + ct->second = 0; + else { + ++t; + z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; } + ct->second = z; + } + + while ((*t == ' ') || (*t == '\t')) ++t; + if (*t == '+') sign = 1; else if (*t == '-') sign = -1; else return 0; + ++t; + c = (unsigned char) (*t++ - '0'); if (c > 9) return 0; z = c; + c = (unsigned char) (*t++ - '0'); if (c > 9) return 0; z = z * 10 + c; + c = (unsigned char) (*t++ - '0'); if (c > 9) return 0; z = z * 6 + c; + c = (unsigned char) (*t++ - '0'); if (c > 9) return 0; z = z * 10 + c; + ct->offset = z * sign; + + return t - s; +} diff --git a/src/tai/caltime_tai.c b/src/tai/caltime_tai.c @@ -0,0 +1,23 @@ +#include <tai/tai.h> +#include <tai/leapsecs.h> +#include <tai/caldate.h> +#include <tai/caltime.h> + +/* XXX: breaks tai encapsulation */ + +void caltime_tai(struct caltime *ct, struct tai *t) +{ + long day; + long s; + + /* XXX: check for overflow? */ + + day = caldate_mjd(&ct->date); + + s = ct->hour * 60 + ct->minute; + s = (s - ct->offset) * 60 + ct->second; + + t->x = day * 86400ULL + 4611686014920671114ULL + (long long) s; + + leapsecs_add(t,ct->second == 60); +} diff --git a/src/tai/caltime_utc.c b/src/tai/caltime_utc.c @@ -0,0 +1,31 @@ +#include <tai/tai.h> +#include <tai/leapsecs.h> +#include <tai/caldate.h> +#include <tai/caltime.h> + +/* XXX: breaks tai encapsulation */ + +void caltime_utc(struct caltime *ct, struct tai *t, int *pwday, int *pyday) +{ + struct tai t2 = *t; + uint64 u; + int leap; + long s; + + /* XXX: check for overfow? */ + + leap = leapsecs_sub(&t2); + u = t2.x; + + u += 58486; + s = u % 86400ULL; + + ct->second = (s % 60) + leap; s /= 60; + ct->minute = s % 60; s /= 60; + ct->hour = s; + + u /= 86400ULL; + caldate_frommjd(&ct->date,/*XXX*/(long) (u - 53375995543064ULL),pwday,pyday); + + ct->offset = 0; +} diff --git a/src/tai/check.c b/src/tai/check.c @@ -0,0 +1,50 @@ +#include <stdio.h> +#include <time.h> +#include <tai/tai.h> +#include <tai/leapsecs.h> +#include <tai/caltime.h> + +char line[100]; + +char *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } ; + +char out[101]; +char x[TAI_PACK]; + +int main(int argc, char **argv) +{ + struct tai t; + struct tai t2; + struct caltime ct; + struct caltime ct2; + int weekday; + int yearday; + int i; + double packerr; + + if (leapsecs_init() == -1) + printf("unable to init leapsecs\n"); + + while (fgets(line,sizeof line,stdin)) + if (!caltime_scan(line,&ct)) + printf("unable to parse\n"); + else { + caltime_tai(&ct,&t); + caltime_utc(&ct2,&t,&weekday,&yearday); + tai_pack(x,&t); + tai_unpack(x,&t2); + tai_sub(&t2,&t2,&t); + packerr = tai_approx(&t2); + for (i = 0;i < TAI_PACK;++i) + printf("%2.2x",(unsigned long) (unsigned char) x[i]); + if (packerr) + printf(" packerr=%f",packerr); + printf(" %03d %s",yearday,dayname[weekday]); + if (caltime_fmt((char *) 0,&ct2) + 1 < sizeof out) { + out[caltime_fmt(out,&ct2)] = 0; + printf(" %s",out); + } + printf("\n"); + } + exit(0); +} diff --git a/src/tai/easter.c b/src/tai/easter.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <tai/caldate.h> + +char *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } ; + +char out[101]; + +int main(int argc, char **argv) +{ + struct caldate cd; + long day; + int weekday; + int yearday; + int i; + + while (*++argv) { + cd.year = atoi(*argv); + if (cd.year > 0) { + caldate_easter(&cd); + day = caldate_mjd(&cd); + caldate_frommjd(&cd,day,&weekday,&yearday); + if (caldate_fmt((char *) 0,&cd) + 1 >= sizeof out) exit(1); + out[caldate_fmt(out,&cd)] = 0; + printf("%s %s yearday %d mjd %d\n",dayname[weekday],out,yearday,day); + } + } + exit(0); +} diff --git a/src/tai/leapsecs.c b/src/tai/leapsecs.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <tai/tai.h> +#include <tai/leapsecs.h> +#include <tai/caldate.h> + +/* XXX: breaks tai encapsulation */ + +/* XXX: output here has to be binary; DOS redirection uses ASCII */ + +char line[100]; + +int main(int argc, char **argv) +{ + struct caldate cd; + struct tai t; + char x[TAI_PACK]; + long leaps = 0; + + while (fgets(line,sizeof line,stdin)) + if (line[0] == '+') + if (caldate_scan(line + 1,&cd)) { + t.x = (caldate_mjd(&cd) + 1) * 86400ULL + 4611686014920671114ULL + leaps++; + tai_pack(x,&t); + fwrite(x,TAI_PACK,1,stdout); + } + + exit(0); +} diff --git a/src/tai/leapsecs_add.c b/src/tai/leapsecs_add.c @@ -0,0 +1,24 @@ +#include <tai/leapsecs.h> +#include <tai/tai.h> + +/* XXX: breaks tai encapsulation */ + +extern struct tai *leapsecs; +extern int leapsecs_num; + +void leapsecs_add(struct tai *t, int hit) +{ + int i; + uint64 u; + + if (leapsecs_init() == -1) return; + + u = t->x; + + for (i = 0;i < leapsecs_num;++i) { + if (u < leapsecs[i].x) break; + if (!hit || (u > leapsecs[i].x)) ++u; + } + + t->x = u; +} diff --git a/src/tai/leapsecs_init.c b/src/tai/leapsecs_init.c @@ -0,0 +1,11 @@ +#include <tai/leapsecs.h> + +static int flaginit = 0; + +int leapsecs_init() +{ + if (flaginit) return 0; + if (leapsecs_read() == -1) return -1; + flaginit = 1; + return 0; +} diff --git a/src/tai/leapsecs_read.c b/src/tai/leapsecs_read.c @@ -0,0 +1,50 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +// extern int errno; // XXX Thread safety +#include <tai/tai.h> +#include <tai/leapsecs.h> + +struct tai *leapsecs = 0; +int leapsecs_num = 0; + +int leapsecs_read() +{ + int fd; + struct stat st; + struct tai *t; + int n; + int i; + struct tai u; + + fd = open("/etc/leapsecs.dat",O_RDONLY | O_NDELAY); + if (fd == -1) { + if (errno != ENOENT) return -1; + if (leapsecs) free(leapsecs); + leapsecs = 0; + leapsecs_num = 0; + return 0; + } + + if (fstat(fd,&st) == -1) { close(fd); return -1; } + + t = (struct tai *) malloc(st.st_size); + if (!t) { close(fd); return -1; } + + n = read(fd,(char *) t,st.st_size); + close(fd); + if (n != st.st_size) { free(t); return -1; } + + n /= sizeof(struct tai); + + for (i = 0;i < n;++i) { + tai_unpack((char *) &t[i],&u); + t[i] = u; + } + + if (leapsecs) free(leapsecs); + + leapsecs = t; + leapsecs_num = n; +} diff --git a/src/tai/leapsecs_sub.c b/src/tai/leapsecs_sub.c @@ -0,0 +1,28 @@ +#include <tai/leapsecs.h> +#include <tai/tai.h> + +/* XXX: breaks tai encapsulation */ + +extern struct tai *leapsecs; +extern int leapsecs_num; + +int leapsecs_sub(struct tai *t) +{ + int i; + uint64 u; + int s; + + if (leapsecs_init() == -1) return 0; + + u = t->x; + s = 0; + + for (i = 0;i < leapsecs_num;++i) { + if (u < leapsecs[i].x) break; + ++s; + if (u == leapsecs[i].x) { t->x = u - s; return 1; } + } + + t->x = u - s; + return 0; +} diff --git a/src/tai/nowutc.c b/src/tai/nowutc.c @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <tai/leapsecs.h> +#include <tai/tai.h> +#include <tai/taia.h> +#include <tai/caltime.h> + +struct taia now; +struct tai sec; +struct caltime ct; + +char x[TAIA_FMTFRAC]; + +int main(int argc, char **argv) +{ + if (leapsecs_init() == -1) { + fprintf(stderr,"utcnow: fatal: unable to init leapsecs\n"); + exit(111); + } + + taia_now(&now); + x[taia_fmtfrac(x,&now)] = 0; + + taia_tai(&now,&sec); + caltime_utc(&ct,&sec,(int *) 0,(int *) 0); + + printf("%d-%02d-%02d %02d:%02d:%02d.%s\n" + ,ct.date.year + ,ct.date.month + ,ct.date.day + ,ct.hour + ,ct.minute + ,ct.second + ,x + ); + + exit(0); +} diff --git a/src/tai/tai_add.c b/src/tai/tai_add.c @@ -0,0 +1,6 @@ +#include <tai/tai.h> + +void tai_add(struct tai *t, struct tai *u, struct tai *v) +{ + t->x = u->x + v->x; +} diff --git a/src/tai/tai_now.c b/src/tai/tai_now.c @@ -0,0 +1,7 @@ +#include <time.h> +#include <tai/tai.h> + +void tai_now(struct tai *t) +{ + t->x = 4611686018427387914ULL + (uint64) time((long *) 0); +} diff --git a/src/tai/tai_pack.c b/src/tai/tai_pack.c @@ -0,0 +1,16 @@ +#include <tai/tai.h> + +void tai_pack(char *s, struct tai *t) +{ + uint64 x; + + x = t->x; + s[7] = x & 255; x >>= 8; + s[6] = x & 255; x >>= 8; + s[5] = x & 255; x >>= 8; + s[4] = x & 255; x >>= 8; + s[3] = x & 255; x >>= 8; + s[2] = x & 255; x >>= 8; + s[1] = x & 255; x >>= 8; + s[0] = x; +} diff --git a/src/tai/tai_sub.c b/src/tai/tai_sub.c @@ -0,0 +1,6 @@ +#include <tai/tai.h> + +void tai_sub(struct tai *t, struct tai *u, struct tai *v) +{ + t->x = u->x - v->x; +} diff --git a/src/tai/tai_unpack.c b/src/tai/tai_unpack.c @@ -0,0 +1,16 @@ +#include <tai/tai.h> + +void tai_unpack(char *s, struct tai *t) +{ + uint64 x; + + x = (unsigned char) s[0]; + x <<= 8; x += (unsigned char) s[1]; + x <<= 8; x += (unsigned char) s[2]; + x <<= 8; x += (unsigned char) s[3]; + x <<= 8; x += (unsigned char) s[4]; + x <<= 8; x += (unsigned char) s[5]; + x <<= 8; x += (unsigned char) s[6]; + x <<= 8; x += (unsigned char) s[7]; + t->x = x; +} diff --git a/src/tai/taia_add.c b/src/tai/taia_add.c @@ -0,0 +1,18 @@ +#include <tai/taia.h> + +/* XXX: breaks tai encapsulation */ + +void taia_add(struct taia *t, struct taia *u, struct taia *v) +{ + t->sec.x = u->sec.x + v->sec.x; + t->nano = u->nano + v->nano; + t->atto = u->atto + v->atto; + if (t->atto > 999999999UL) { + t->atto -= 1000000000UL; + ++t->nano; + } + if (t->nano > 999999999UL) { + t->nano -= 1000000000UL; + ++t->sec.x; + } +} diff --git a/src/tai/taia_approx.c b/src/tai/taia_approx.c @@ -0,0 +1,6 @@ +#include <tai/taia.h> + +double taia_approx(struct taia *t) +{ + return tai_approx(&t->sec) + taia_frac(t); +} diff --git a/src/tai/taia_fmtfrac.c b/src/tai/taia_fmtfrac.c @@ -0,0 +1,31 @@ +#include <tai/taia.h> + +unsigned int taia_fmtfrac(char *s, struct taia *t) +{ + unsigned long x; + + if (s) { + x = t->atto; + s[17] = '0' + (x % 10); x /= 10; + s[16] = '0' + (x % 10); x /= 10; + s[15] = '0' + (x % 10); x /= 10; + s[14] = '0' + (x % 10); x /= 10; + s[13] = '0' + (x % 10); x /= 10; + s[12] = '0' + (x % 10); x /= 10; + s[11] = '0' + (x % 10); x /= 10; + s[10] = '0' + (x % 10); x /= 10; + s[9] = '0' + (x % 10); + x = t->nano; + s[8] = '0' + (x % 10); x /= 10; + s[7] = '0' + (x % 10); x /= 10; + s[6] = '0' + (x % 10); x /= 10; + s[5] = '0' + (x % 10); x /= 10; + s[4] = '0' + (x % 10); x /= 10; + s[3] = '0' + (x % 10); x /= 10; + s[2] = '0' + (x % 10); x /= 10; + s[1] = '0' + (x % 10); x /= 10; + s[0] = '0' + (x % 10); + } + + return 18; +} diff --git a/src/tai/taia_frac.c b/src/tai/taia_frac.c @@ -0,0 +1,6 @@ +#include <tai/taia.h> + +double taia_frac(struct taia *t) +{ + return (t->atto * 0.000000001 + t->nano) * 0.000000001; +} diff --git a/src/tai/taia_half.c b/src/tai/taia_half.c @@ -0,0 +1,12 @@ +#include <tai/taia.h> + +/* XXX: breaks tai encapsulation */ + +void taia_half(struct taia *t, struct taia *u) +{ + t->atto = u->atto >> 1; + if (u->nano & 1) t->atto += 500000000UL; + t->nano = u->nano >> 1; + if (u->sec.x & 1) t->nano += 500000000UL; + t->sec.x = u->sec.x >> 1; +} diff --git a/src/tai/taia_less.c b/src/tai/taia_less.c @@ -0,0 +1,12 @@ +#include <tai/taia.h> + +/* XXX: breaks tai encapsulation */ + +int taia_less(struct taia *t, struct taia *u) +{ + if (t->sec.x < u->sec.x) return 1; + if (t->sec.x > u->sec.x) return 0; + if (t->nano < u->nano) return 1; + if (t->nano > u->nano) return 0; + return t->atto < u->atto; +} diff --git a/src/tai/taia_now.c b/src/tai/taia_now.c @@ -0,0 +1,14 @@ +#include <sys/types.h> +#include <sys/time.h> +#include <tai/taia.h> + +/* XXX: breaks tai encapsulation */ + +void taia_now(struct taia *t) +{ + struct timeval now; + gettimeofday(&now,(struct timezone *) 0); + t->sec.x = 4611686018427387914ULL + (uint64) now.tv_sec; + t->nano = 1000 * now.tv_usec + 500; + t->atto = 0; +} diff --git a/src/tai/taia_pack.c b/src/tai/taia_pack.c @@ -0,0 +1,20 @@ +#include <tai/taia.h> + +void taia_pack(char *s, struct taia *t) +{ + unsigned long x; + + tai_pack(s,&t->sec); + s += 8; + + x = t->atto; + s[7] = x & 255; x >>= 8; + s[6] = x & 255; x >>= 8; + s[5] = x & 255; x >>= 8; + s[4] = x; + x = t->nano; + s[3] = x & 255; x >>= 8; + s[2] = x & 255; x >>= 8; + s[1] = x & 255; x >>= 8; + s[0] = x; +} diff --git a/src/tai/taia_sub.c b/src/tai/taia_sub.c @@ -0,0 +1,21 @@ +#include <tai/taia.h> + +/* XXX: breaks tai encapsulation */ + +void taia_sub(struct taia *t, struct taia *u, struct taia *v) +{ + unsigned long unano = u->nano; + unsigned long uatto = u->atto; + + t->sec.x = u->sec.x - v->sec.x; + t->nano = unano - v->nano; + t->atto = uatto - v->atto; + if (t->atto > uatto) { + t->atto += 1000000000UL; + --t->nano; + } + if (t->nano > unano) { + t->nano += 1000000000UL; + --t->sec.x; + } +} diff --git a/src/tai/taia_tai.c b/src/tai/taia_tai.c @@ -0,0 +1,6 @@ +#include <tai/taia.h> + +void taia_tai(struct taia *ta, struct tai *t) +{ + *t = ta->sec; +} diff --git a/src/tai/taia_unpack.c b/src/tai/taia_unpack.c @@ -0,0 +1,20 @@ +#include <tai/taia.h> + +void taia_unpack(char *s, struct taia *t) +{ + unsigned long x; + + tai_unpack(s,&t->sec); + s += 8; + + x = (unsigned char) s[4]; + x <<= 8; x += (unsigned char) s[5]; + x <<= 8; x += (unsigned char) s[6]; + x <<= 8; x += (unsigned char) s[7]; + t->atto = x; + x = (unsigned char) s[0]; + x <<= 8; x += (unsigned char) s[1]; + x <<= 8; x += (unsigned char) s[2]; + x <<= 8; x += (unsigned char) s[3]; + t->nano = x; +} diff --git a/src/tai/trycpp.c b/src/tai/trycpp.c @@ -0,0 +1,7 @@ +void main() +{ +#ifdef NeXT + printf("nextstep\n"); exit(0); +#endif + printf("unknown\n"); exit(0); +} diff --git a/src/tai/yearcal.c b/src/tai/yearcal.c @@ -0,0 +1,65 @@ +#include <stdio.h> +#include <tai/caldate.h> + +char *montab[] = { + "January" +, "February" +, "March" +, "April" +, "May" +, "June" +, "July" +, "August" +, "September" +, "October" +, "November" +, "December" +} ; + +int main(int argc, char **argv) +{ + int year; + long daystart; + long dayend; + long day; + int weekday; + struct caldate cd; + + while (*++argv) { + year = atoi(*argv); + + cd.year = year; + cd.month = 1; + cd.day = 1; + daystart = caldate_mjd(&cd); + cd.year = year + 1; + dayend = caldate_mjd(&cd); + + while ((daystart + 3) % 7) --daystart; + while ((dayend + 3) % 7) ++dayend; + + for (day = daystart;day < dayend;++day) { + caldate_frommjd(&cd,day,&weekday,(int *) 0); + if (cd.year != year) + printf(" "); + else { + if (cd.month & 1) + if (cd.day < 10) + printf(" %d%c%d ",cd.day % 10,8,cd.day % 10); + else + printf("%d%c%d%d%c%d ",cd.day / 10,8,cd.day / 10,cd.day % 10,8,cd.day % 10); + else + printf("%2d ",cd.day); + if (weekday == 6) { + if ((cd.day >= 15) && (cd.day < 22)) + printf(" %s %d\n",montab[cd.month - 1],year); + else + printf("\n"); + } + } + } + printf("\n"); + } + + exit(0); +}