xref: /netbsd-src/external/mit/libuv/dist/docs/src/guide/utilities.rst (revision 5f2f42719cd62ff11fd913b40b7ce19f07c4fd25)
10e552da7SchristosUtilities
20e552da7Schristos=========
30e552da7Schristos
40e552da7SchristosThis chapter catalogues tools and techniques which are useful for common tasks.
50e552da7SchristosThe `libev man page`_ already covers some patterns which can be adopted to
60e552da7Schristoslibuv through simple API changes. It also covers parts of the libuv API that
70e552da7Schristosdon't require entire chapters dedicated to them.
80e552da7Schristos
90e552da7SchristosTimers
100e552da7Schristos------
110e552da7Schristos
120e552da7SchristosTimers invoke the callback after a certain time has elapsed since the timer was
130e552da7Schristosstarted. libuv timers can also be set to invoke at regular intervals instead of
140e552da7Schristosjust once.
150e552da7Schristos
160e552da7SchristosSimple use is to init a watcher and start it with a ``timeout``, and optional ``repeat``.
170e552da7SchristosTimers can be stopped at any time.
180e552da7Schristos
190e552da7Schristos.. code-block:: c
200e552da7Schristos
210e552da7Schristos    uv_timer_t timer_req;
220e552da7Schristos
230e552da7Schristos    uv_timer_init(loop, &timer_req);
240e552da7Schristos    uv_timer_start(&timer_req, callback, 5000, 2000);
250e552da7Schristos
260e552da7Schristoswill start a repeating timer, which first starts 5 seconds (the ``timeout``) after the execution
270e552da7Schristosof ``uv_timer_start``, then repeats every 2 seconds (the ``repeat``). Use:
280e552da7Schristos
290e552da7Schristos.. code-block:: c
300e552da7Schristos
310e552da7Schristos    uv_timer_stop(&timer_req);
320e552da7Schristos
330e552da7Schristosto stop the timer. This can be used safely from within the callback as well.
340e552da7Schristos
350e552da7SchristosThe repeat interval can be modified at any time with::
360e552da7Schristos
370e552da7Schristos    uv_timer_set_repeat(uv_timer_t *timer, int64_t repeat);
380e552da7Schristos
390e552da7Schristoswhich will take effect **when possible**. If this function is called from
400e552da7Schristosa timer callback, it means:
410e552da7Schristos
420e552da7Schristos* If the timer was non-repeating, the timer has already been stopped. Use
430e552da7Schristos  ``uv_timer_start`` again.
440e552da7Schristos* If the timer is repeating, the next timeout has already been scheduled, so
450e552da7Schristos  the old repeat interval will be used once more before the timer switches to
460e552da7Schristos  the new interval.
470e552da7Schristos
480e552da7SchristosThe utility function::
490e552da7Schristos
500e552da7Schristos    int uv_timer_again(uv_timer_t *)
510e552da7Schristos
520e552da7Schristosapplies **only to repeating timers** and is equivalent to stopping the timer
530e552da7Schristosand then starting it with both initial ``timeout`` and ``repeat`` set to the
540e552da7Schristosold ``repeat`` value. If the timer hasn't been started it fails (error code
550e552da7Schristos``UV_EINVAL``) and returns -1.
560e552da7Schristos
570e552da7SchristosAn actual timer example is in the :ref:`reference count section
580e552da7Schristos<reference-count>`.
590e552da7Schristos
600e552da7Schristos.. _reference-count:
610e552da7Schristos
620e552da7SchristosEvent loop reference count
630e552da7Schristos--------------------------
640e552da7Schristos
650e552da7SchristosThe event loop only runs as long as there are active handles. This system
660e552da7Schristosworks by having every handle increase the reference count of the event loop
670e552da7Schristoswhen it is started and decreasing the reference count when stopped. It is also
680e552da7Schristospossible to manually change the reference count of handles using::
690e552da7Schristos
700e552da7Schristos    void uv_ref(uv_handle_t*);
710e552da7Schristos    void uv_unref(uv_handle_t*);
720e552da7Schristos
730e552da7SchristosThese functions can be used to allow a loop to exit even when a watcher is
740e552da7Schristosactive or to use custom objects to keep the loop alive.
750e552da7Schristos
760e552da7SchristosThe latter can be used with interval timers. You might have a garbage collector
770e552da7Schristoswhich runs every X seconds, or your network service might send a heartbeat to
780e552da7Schristosothers periodically, but you don't want to have to stop them along all clean
790e552da7Schristosexit paths or error scenarios. Or you want the program to exit when all your
800e552da7Schristosother watchers are done. In that case just unref the timer immediately after
810e552da7Schristoscreation so that if it is the only watcher running then ``uv_run`` will still
820e552da7Schristosexit.
830e552da7Schristos
840e552da7SchristosThis is also used in node.js where some libuv methods are being bubbled up to
850e552da7Schristosthe JS API. A ``uv_handle_t`` (the superclass of all watchers) is created per
860e552da7SchristosJS object and can be ref/unrefed.
870e552da7Schristos
880e552da7Schristos.. rubric:: ref-timer/main.c
890e552da7Schristos.. literalinclude:: ../../code/ref-timer/main.c
90*5f2f4271Schristos    :language: c
910e552da7Schristos    :linenos:
920e552da7Schristos    :lines: 5-8, 17-
930e552da7Schristos    :emphasize-lines: 9
940e552da7Schristos
950e552da7SchristosWe initialize the garbage collector timer, then immediately ``unref`` it.
960e552da7SchristosObserve how after 9 seconds, when the fake job is done, the program
970e552da7Schristosautomatically exits, even though the garbage collector is still running.
980e552da7Schristos
990e552da7SchristosIdler pattern
1000e552da7Schristos-------------
1010e552da7Schristos
1020e552da7SchristosThe callbacks of idle handles are invoked once per event loop. The idle
1030e552da7Schristoscallback can be used to perform some very low priority activity. For example,
1040e552da7Schristosyou could dispatch a summary of the daily application performance to the
1050e552da7Schristosdevelopers for analysis during periods of idleness, or use the application's
1060e552da7SchristosCPU time to perform SETI calculations :) An idle watcher is also useful in
1070e552da7Schristosa GUI application. Say you are using an event loop for a file download. If the
1080e552da7SchristosTCP socket is still being established and no other events are present your
1090e552da7Schristosevent loop will pause (**block**), which means your progress bar will freeze
1100e552da7Schristosand the user will face an unresponsive application. In such a case queue up and
1110e552da7Schristosidle watcher to keep the UI operational.
1120e552da7Schristos
1130e552da7Schristos.. rubric:: idle-compute/main.c
1140e552da7Schristos.. literalinclude:: ../../code/idle-compute/main.c
115*5f2f4271Schristos    :language: c
1160e552da7Schristos    :linenos:
1170e552da7Schristos    :lines: 5-9, 34-
1180e552da7Schristos    :emphasize-lines: 13
1190e552da7Schristos
1200e552da7SchristosHere we initialize the idle watcher and queue it up along with the actual
1210e552da7Schristosevents we are interested in. ``crunch_away`` will now be called repeatedly
1220e552da7Schristosuntil the user types something and presses Return. Then it will be interrupted
1230e552da7Schristosfor a brief amount as the loop deals with the input data, after which it will
1240e552da7Schristoskeep calling the idle callback again.
1250e552da7Schristos
1260e552da7Schristos.. rubric:: idle-compute/main.c
1270e552da7Schristos.. literalinclude:: ../../code/idle-compute/main.c
128*5f2f4271Schristos    :language: c
1290e552da7Schristos    :linenos:
1300e552da7Schristos    :lines: 10-19
1310e552da7Schristos
1320e552da7Schristos.. _baton:
1330e552da7Schristos
1340e552da7SchristosPassing data to worker thread
1350e552da7Schristos-----------------------------
1360e552da7Schristos
1370e552da7SchristosWhen using ``uv_queue_work`` you'll usually need to pass complex data through
1380e552da7Schristosto the worker thread. The solution is to use a ``struct`` and set
1390e552da7Schristos``uv_work_t.data`` to point to it. A slight variation is to have the
1400e552da7Schristos``uv_work_t`` itself as the first member of this struct (called a baton [#]_).
1410e552da7SchristosThis allows cleaning up the work request and all the data in one free call.
1420e552da7Schristos
1430e552da7Schristos.. code-block:: c
1440e552da7Schristos    :linenos:
1450e552da7Schristos    :emphasize-lines: 2
1460e552da7Schristos
1470e552da7Schristos    struct ftp_baton {
1480e552da7Schristos        uv_work_t req;
1490e552da7Schristos        char *host;
1500e552da7Schristos        int port;
1510e552da7Schristos        char *username;
1520e552da7Schristos        char *password;
1530e552da7Schristos    }
1540e552da7Schristos
1550e552da7Schristos.. code-block:: c
1560e552da7Schristos    :linenos:
1570e552da7Schristos    :emphasize-lines: 2
1580e552da7Schristos
1590e552da7Schristos    ftp_baton *baton = (ftp_baton*) malloc(sizeof(ftp_baton));
1600e552da7Schristos    baton->req.data = (void*) baton;
1610e552da7Schristos    baton->host = strdup("my.webhost.com");
1620e552da7Schristos    baton->port = 21;
1630e552da7Schristos    // ...
1640e552da7Schristos
1650e552da7Schristos    uv_queue_work(loop, &baton->req, ftp_session, ftp_cleanup);
1660e552da7Schristos
1670e552da7SchristosHere we create the baton and queue the task.
1680e552da7Schristos
1690e552da7SchristosNow the task function can extract the data it needs:
1700e552da7Schristos
1710e552da7Schristos.. code-block:: c
1720e552da7Schristos    :linenos:
1730e552da7Schristos    :emphasize-lines: 2, 12
1740e552da7Schristos
1750e552da7Schristos    void ftp_session(uv_work_t *req) {
1760e552da7Schristos        ftp_baton *baton = (ftp_baton*) req->data;
1770e552da7Schristos
1780e552da7Schristos        fprintf(stderr, "Connecting to %s\n", baton->host);
1790e552da7Schristos    }
1800e552da7Schristos
1810e552da7Schristos    void ftp_cleanup(uv_work_t *req) {
1820e552da7Schristos        ftp_baton *baton = (ftp_baton*) req->data;
1830e552da7Schristos
1840e552da7Schristos        free(baton->host);
1850e552da7Schristos        // ...
1860e552da7Schristos        free(baton);
1870e552da7Schristos    }
1880e552da7Schristos
1890e552da7SchristosWe then free the baton which also frees the watcher.
1900e552da7Schristos
1910e552da7SchristosExternal I/O with polling
1920e552da7Schristos-------------------------
1930e552da7Schristos
1940e552da7SchristosUsually third-party libraries will handle their own I/O, and keep track of
1950e552da7Schristostheir sockets and other files internally. In this case it isn't possible to use
1960e552da7Schristosthe standard stream I/O operations, but the library can still be integrated
1970e552da7Schristosinto the libuv event loop. All that is required is that the library allow you
1980e552da7Schristosto access the underlying file descriptors and provide functions that process
1990e552da7Schristostasks in small increments as decided by your application. Some libraries though
2000e552da7Schristoswill not allow such access, providing only a standard blocking function which
2010e552da7Schristoswill perform the entire I/O transaction and only then return. It is unwise to
2020e552da7Schristosuse these in the event loop thread, use the :ref:`threadpool` instead. Of
2030e552da7Schristoscourse, this will also mean losing granular control on the library.
2040e552da7Schristos
2050e552da7SchristosThe ``uv_poll`` section of libuv simply watches file descriptors using the
2060e552da7Schristosoperating system notification mechanism. In some sense, all the I/O operations
2070e552da7Schristosthat libuv implements itself are also backed by ``uv_poll`` like code. Whenever
2080e552da7Schristosthe OS notices a change of state in file descriptors being polled, libuv will
2090e552da7Schristosinvoke the associated callback.
2100e552da7Schristos
2110e552da7SchristosHere we will walk through a simple download manager that will use libcurl_ to
2120e552da7Schristosdownload files. Rather than give all control to libcurl, we'll instead be
2130e552da7Schristosusing the libuv event loop, and use the non-blocking, async multi_ interface to
2140e552da7Schristosprogress with the download whenever libuv notifies of I/O readiness.
2150e552da7Schristos
2160e552da7Schristos.. _libcurl: https://curl.haxx.se/libcurl/
2170e552da7Schristos.. _multi: https://curl.haxx.se/libcurl/c/libcurl-multi.html
2180e552da7Schristos
2190e552da7Schristos.. rubric:: uvwget/main.c - The setup
2200e552da7Schristos.. literalinclude:: ../../code/uvwget/main.c
221*5f2f4271Schristos    :language: c
2220e552da7Schristos    :linenos:
223*5f2f4271Schristos    :lines: 1-9,142-
2240e552da7Schristos    :emphasize-lines: 7,21,24-25
2250e552da7Schristos
2260e552da7SchristosThe way each library is integrated with libuv will vary. In the case of
2270e552da7Schristoslibcurl, we can register two callbacks. The socket callback ``handle_socket``
2280e552da7Schristosis invoked whenever the state of a socket changes and we have to start polling
2290e552da7Schristosit. ``start_timeout`` is called by libcurl to notify us of the next timeout
2300e552da7Schristosinterval, after which we should drive libcurl forward regardless of I/O status.
2310e552da7SchristosThis is so that libcurl can handle errors or do whatever else is required to
2320e552da7Schristosget the download moving.
2330e552da7Schristos
2340e552da7SchristosOur downloader is to be invoked as::
2350e552da7Schristos
2360e552da7Schristos    $ ./uvwget [url1] [url2] ...
2370e552da7Schristos
2380e552da7SchristosSo we add each argument as an URL
2390e552da7Schristos
2400e552da7Schristos.. rubric:: uvwget/main.c - Adding urls
2410e552da7Schristos.. literalinclude:: ../../code/uvwget/main.c
242*5f2f4271Schristos    :language: c
2430e552da7Schristos    :linenos:
2440e552da7Schristos    :lines: 39-56
2450e552da7Schristos    :emphasize-lines: 13-14
2460e552da7Schristos
2470e552da7SchristosWe let libcurl directly write the data to a file, but much more is possible if
2480e552da7Schristosyou so desire.
2490e552da7Schristos
2500e552da7Schristos``start_timeout`` will be called immediately the first time by libcurl, so
251*5f2f4271Schristosthings are set in motion. This simply starts a libuv `timer <#timers>`_ which
2520e552da7Schristosdrives ``curl_multi_socket_action`` with ``CURL_SOCKET_TIMEOUT`` whenever it
2530e552da7Schristostimes out. ``curl_multi_socket_action`` is what drives libcurl, and what we
2540e552da7Schristoscall whenever sockets change state. But before we go into that, we need to poll
2550e552da7Schristoson sockets whenever ``handle_socket`` is called.
2560e552da7Schristos
2570e552da7Schristos.. rubric:: uvwget/main.c - Setting up polling
2580e552da7Schristos.. literalinclude:: ../../code/uvwget/main.c
259*5f2f4271Schristos    :language: c
2600e552da7Schristos    :linenos:
2610e552da7Schristos    :lines: 102-140
2620e552da7Schristos    :emphasize-lines: 9,11,15,21,24
2630e552da7Schristos
2640e552da7SchristosWe are interested in the socket fd ``s``, and the ``action``. For every socket
2650e552da7Schristoswe create a ``uv_poll_t`` handle if it doesn't exist, and associate it with the
2660e552da7Schristossocket using ``curl_multi_assign``. This way ``socketp`` points to it whenever
2670e552da7Schristosthe callback is invoked.
2680e552da7Schristos
2690e552da7SchristosIn the case that the download is done or fails, libcurl requests removal of the
2700e552da7Schristospoll. So we stop and free the poll handle.
2710e552da7Schristos
2720e552da7SchristosDepending on what events libcurl wishes to watch for, we start polling with
2730e552da7Schristos``UV_READABLE`` or ``UV_WRITABLE``. Now libuv will invoke the poll callback
2740e552da7Schristoswhenever the socket is ready for reading or writing. Calling ``uv_poll_start``
2750e552da7Schristosmultiple times on the same handle is acceptable, it will just update the events
2760e552da7Schristosmask with the new value. ``curl_perform`` is the crux of this program.
2770e552da7Schristos
2780e552da7Schristos.. rubric:: uvwget/main.c - Driving libcurl.
2790e552da7Schristos.. literalinclude:: ../../code/uvwget/main.c
280*5f2f4271Schristos    :language: c
2810e552da7Schristos    :linenos:
2820e552da7Schristos    :lines: 81-95
2830e552da7Schristos    :emphasize-lines: 2,6-7,12
2840e552da7Schristos
2850e552da7SchristosThe first thing we do is to stop the timer, since there has been some progress
2860e552da7Schristosin the interval. Then depending on what event triggered the callback, we set
2870e552da7Schristosthe correct flags. Then we call ``curl_multi_socket_action`` with the socket
2880e552da7Schristosthat progressed and the flags informing about what events happened. At this
2890e552da7Schristospoint libcurl does all of its internal tasks in small increments, and will
2900e552da7Schristosattempt to return as fast as possible, which is exactly what an evented program
2910e552da7Schristoswants in its main thread. libcurl keeps queueing messages into its own queue
2920e552da7Schristosabout transfer progress. In our case we are only interested in transfers that
2930e552da7Schristosare completed. So we extract these messages, and clean up handles whose
2940e552da7Schristostransfers are done.
2950e552da7Schristos
2960e552da7Schristos.. rubric:: uvwget/main.c - Reading transfer status.
2970e552da7Schristos.. literalinclude:: ../../code/uvwget/main.c
298*5f2f4271Schristos    :language: c
2990e552da7Schristos    :linenos:
3000e552da7Schristos    :lines: 58-79
3010e552da7Schristos    :emphasize-lines: 6,9-10,13-14
3020e552da7Schristos
3030e552da7SchristosCheck & Prepare watchers
3040e552da7Schristos------------------------
3050e552da7Schristos
3060e552da7SchristosTODO
3070e552da7Schristos
3080e552da7SchristosLoading libraries
3090e552da7Schristos-----------------
3100e552da7Schristos
3110e552da7Schristoslibuv provides a cross platform API to dynamically load `shared libraries`_.
3120e552da7SchristosThis can be used to implement your own plugin/extension/module system and is
3130e552da7Schristosused by node.js to implement ``require()`` support for bindings. The usage is
3140e552da7Schristosquite simple as long as your library exports the right symbols. Be careful with
3150e552da7Schristossanity and security checks when loading third party code, otherwise your
3160e552da7Schristosprogram will behave unpredictably. This example implements a very simple
3170e552da7Schristosplugin system which does nothing except print the name of the plugin.
3180e552da7Schristos
3190e552da7SchristosLet us first look at the interface provided to plugin authors.
3200e552da7Schristos
3210e552da7Schristos.. rubric:: plugin/plugin.h
3220e552da7Schristos.. literalinclude:: ../../code/plugin/plugin.h
323*5f2f4271Schristos    :language: c
3240e552da7Schristos    :linenos:
3250e552da7Schristos
3260e552da7SchristosYou can similarly add more functions that plugin authors can use to do useful
3270e552da7Schristosthings in your application [#]_. A sample plugin using this API is:
3280e552da7Schristos
3290e552da7Schristos.. rubric:: plugin/hello.c
3300e552da7Schristos.. literalinclude:: ../../code/plugin/hello.c
331*5f2f4271Schristos    :language: c
3320e552da7Schristos    :linenos:
3330e552da7Schristos
3340e552da7SchristosOur interface defines that all plugins should have an ``initialize`` function
3350e552da7Schristoswhich will be called by the application. This plugin is compiled as a shared
3360e552da7Schristoslibrary and can be loaded by running our application::
3370e552da7Schristos
3380e552da7Schristos    $ ./plugin libhello.dylib
3390e552da7Schristos    Loading libhello.dylib
3400e552da7Schristos    Registered plugin "Hello World!"
3410e552da7Schristos
3420e552da7Schristos.. NOTE::
3430e552da7Schristos
3440e552da7Schristos    The shared library filename will be different depending on platforms. On
3450e552da7Schristos    Linux it is ``libhello.so``.
3460e552da7Schristos
3470e552da7SchristosThis is done by using ``uv_dlopen`` to first load the shared library
3480e552da7Schristos``libhello.dylib``. Then we get access to the ``initialize`` function using
3490e552da7Schristos``uv_dlsym`` and invoke it.
3500e552da7Schristos
3510e552da7Schristos.. rubric:: plugin/main.c
3520e552da7Schristos.. literalinclude:: ../../code/plugin/main.c
353*5f2f4271Schristos    :language: c
3540e552da7Schristos    :linenos:
3550e552da7Schristos    :lines: 7-
3560e552da7Schristos    :emphasize-lines: 15, 18, 24
3570e552da7Schristos
3580e552da7Schristos``uv_dlopen`` expects a path to the shared library and sets the opaque
3590e552da7Schristos``uv_lib_t`` pointer. It returns 0 on success, -1 on error. Use ``uv_dlerror``
3600e552da7Schristosto get the error message.
3610e552da7Schristos
3620e552da7Schristos``uv_dlsym`` stores a pointer to the symbol in the second argument in the third
3630e552da7Schristosargument. ``init_plugin_function`` is a function pointer to the sort of
3640e552da7Schristosfunction we are looking for in the application's plugins.
3650e552da7Schristos
3660e552da7Schristos.. _shared libraries: https://en.wikipedia.org/wiki/Shared_library#Shared_libraries
3670e552da7Schristos
3680e552da7SchristosTTY
3690e552da7Schristos---
3700e552da7Schristos
3710e552da7SchristosText terminals have supported basic formatting for a long time, with a `pretty
3720e552da7Schristosstandardised`_ command set. This formatting is often used by programs to
3730e552da7Schristosimprove the readability of terminal output. For example ``grep --colour``.
3740e552da7Schristoslibuv provides the ``uv_tty_t`` abstraction (a stream) and related functions to
3750e552da7Schristosimplement the ANSI escape codes across all platforms. By this I mean that libuv
3760e552da7Schristosconverts ANSI codes to the Windows equivalent, and provides functions to get
3770e552da7Schristosterminal information.
3780e552da7Schristos
3790e552da7Schristos.. _pretty standardised: https://en.wikipedia.org/wiki/ANSI_escape_sequences
3800e552da7Schristos
3810e552da7SchristosThe first thing to do is to initialize a ``uv_tty_t`` with the file descriptor
3820e552da7Schristosit reads/writes from. This is achieved with::
3830e552da7Schristos
3840e552da7Schristos    int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int unused)
3850e552da7Schristos
3860e552da7SchristosThe ``unused`` parameter is now auto-detected and ignored. It previously needed
3870e552da7Schristosto be set to use ``uv_read_start()`` on the stream.
3880e552da7Schristos
3890e552da7SchristosIt is then best to use ``uv_tty_set_mode`` to set the mode to *normal*
3900e552da7Schristoswhich enables most TTY formatting, flow-control and other settings. Other_ modes
3910e552da7Schristosare also available.
3920e552da7Schristos
3930e552da7Schristos.. _Other: http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_mode_t
3940e552da7Schristos
3950e552da7SchristosRemember to call ``uv_tty_reset_mode`` when your program exits to restore the
3960e552da7Schristosstate of the terminal. Just good manners. Another set of good manners is to be
3970e552da7Schristosaware of redirection. If the user redirects the output of your command to
3980e552da7Schristosa file, control sequences should not be written as they impede readability and
3990e552da7Schristos``grep``. To check if the file descriptor is indeed a TTY, call
4000e552da7Schristos``uv_guess_handle`` with the file descriptor and compare the return value with
4010e552da7Schristos``UV_TTY``.
4020e552da7Schristos
4030e552da7SchristosHere is a simple example which prints white text on a red background:
4040e552da7Schristos
4050e552da7Schristos.. rubric:: tty/main.c
4060e552da7Schristos.. literalinclude:: ../../code/tty/main.c
407*5f2f4271Schristos    :language: c
4080e552da7Schristos    :linenos:
4090e552da7Schristos    :emphasize-lines: 11-12,14,17,27
4100e552da7Schristos
4110e552da7SchristosThe final TTY helper is ``uv_tty_get_winsize()`` which is used to get the
4120e552da7Schristoswidth and height of the terminal and returns ``0`` on success. Here is a small
4130e552da7Schristosprogram which does some animation using the function and character position
4140e552da7Schristosescape codes.
4150e552da7Schristos
4160e552da7Schristos.. rubric:: tty-gravity/main.c
4170e552da7Schristos.. literalinclude:: ../../code/tty-gravity/main.c
418*5f2f4271Schristos    :language: c
4190e552da7Schristos    :linenos:
4200e552da7Schristos    :emphasize-lines: 19,25,38
4210e552da7Schristos
4220e552da7SchristosThe escape codes are:
4230e552da7Schristos
4240e552da7Schristos======  =======================
4250e552da7SchristosCode    Meaning
4260e552da7Schristos======  =======================
4270e552da7Schristos*2* J    Clear part of the screen, 2 is entire screen
4280e552da7SchristosH        Moves cursor to certain position, default top-left
4290e552da7Schristos*n* B    Moves cursor down by n lines
4300e552da7Schristos*n* C    Moves cursor right by n columns
4310e552da7Schristosm        Obeys string of display settings, in this case green background (40+2), white text (30+7)
4320e552da7Schristos======  =======================
4330e552da7Schristos
4340e552da7SchristosAs you can see this is very useful to produce nicely formatted output, or even
4350e552da7Schristosconsole based arcade games if that tickles your fancy. For fancier control you
4360e552da7Schristoscan try `ncurses`_.
4370e552da7Schristos
4380e552da7Schristos.. _ncurses: https://www.gnu.org/software/ncurses/ncurses.html
4390e552da7Schristos
4400e552da7Schristos.. versionchanged:: 1.23.1: the `readable` parameter is now unused and ignored.
4410e552da7Schristos                    The appropriate value will now be auto-detected from the kernel.
4420e552da7Schristos
4430e552da7Schristos----
4440e552da7Schristos
4450e552da7Schristos.. [#] I was first introduced to the term baton in this context, in Konstantin
4460e552da7Schristos       Käfer's excellent slides on writing node.js bindings --
4470e552da7Schristos       https://kkaefer.com/node-cpp-modules/#baton
4480e552da7Schristos.. [#] mfp is My Fancy Plugin
4490e552da7Schristos
4500e552da7Schristos.. _libev man page: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#COMMON_OR_USEFUL_IDIOMS_OR_BOTH
451