1
0
forked from cory/tildefriends

Compare commits

...

69 Commits

Author SHA1 Message Date
0fbc84d364 Let's release 0.0.13.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4651 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-29 23:40:04 +00:00
0dd0b835ec wiki new message fix and sorting.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4650 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-27 17:26:02 +00:00
d96e0a7497 wiki cruft.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4649 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-27 17:23:48 +00:00
625504b8eb Fix an httpd error log.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4648 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-27 17:23:31 +00:00
a185ded47e Exclude the sequence number from the request in the response to createHistoryStream and ebt.replicate. I believe I had done this to match a broken client when I implemented it.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4647 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-26 18:01:43 +00:00
5a0c77d06a Trim down dist sizes by filtering zip contents more effectively.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4646 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-26 17:36:35 +00:00
e54bd316d5 iOS OpenSSL => 3.2.0.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4645 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-25 17:40:08 +00:00
f908b45cc7 mingw64 OpenSSL => 3.2.0.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4644 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-25 17:32:12 +00:00
d02751ee08 Android OpenSSL => 3.2.0.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4643 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-25 17:30:55 +00:00
13ab9786f7 TIL HttpOnly https://owasp.org/www-community/HttpOnly.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4642 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-25 13:25:41 +00:00
ba13a08e78 sqlite-amalgamation-3440200.zip
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4641 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-25 13:21:49 +00:00
8c92a5ff7b CodeMirror 5.65.16.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4640 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-22 18:11:52 +00:00
37f728835b sqlite-amalgamation-3440100.zip
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4639 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-22 18:08:22 +00:00
a6f1eaa09e Put a cap on how many new messages we store browser-side. Unbounded growth is leading to crashed tabs and unresponsiveness.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4638 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-18 15:58:16 +00:00
dff8eca16e lit => 3.1.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4637 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-18 14:01:10 +00:00
a3cca9aae6 Slight wiki formatting tweaks.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4636 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-16 01:35:36 +00:00
edabd7735c Forgot this file.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4635 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-16 01:33:15 +00:00
461e7b7d5a Progress toward generating static wiki pages.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4634 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-16 01:33:00 +00:00
06ea8d4781 Have jshint discourage 'var'.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4633 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-15 03:29:39 +00:00
62ef0bcb42 Rename Makefile so it won't seem like it can be run with BSD make or other.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4632 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-15 02:41:05 +00:00
a0043ec49f Fix up links to other wiki-doc pages, and reduce the following depth to improve load times.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4631 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-14 17:38:48 +00:00
305f5232e7 Add a missing order by to fix missing wiki changes.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4630 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-13 17:32:15 +00:00
d467c4dd8a Support removing editors, I think, and include wikis from the app owner and from the authenticated user.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4629 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-12 20:17:23 +00:00
5b2ace80d4 Made it possible to add wiki editors.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4628 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-11 13:44:20 +00:00
1484a87cad Fix wiki following, and shows wiki-docs from editors of the wiki.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4627 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-11 02:22:53 +00:00
b23bc0b16b Trying to work toward multiple users. List wikis of people you are following. Also hook in to the lit updated event.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4626 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-09 17:39:05 +00:00
a6c8dd846c Put verbose messages on a command-line argument, finally, and format the messages a bit better.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4625 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-09 00:28:34 +00:00
5fff3b8161 Following asan fixes.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4624 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-09 00:08:04 +00:00
b4236d0ec0 Show names in the id picker.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4623 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-08 23:51:54 +00:00
5e8cd12760 Latest libsodium-1.0.19-stable.tar.gz
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4622 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-08 23:17:32 +00:00
699438602c Make import and export commands complete reliably.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4621 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-08 23:03:21 +00:00
52aa6eed0d Builds for OpenBSD!
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4620 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-08 03:36:08 +00:00
6cdf207dcd Encrypt draft wiki blobs.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4619 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-08 01:58:02 +00:00
607e9ef71b Show more information about encrypted messages.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4618 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-08 01:43:58 +00:00
367c489fc3 Hide wiki things that don't apply when you're not logged in.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4617 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-07 23:34:55 +00:00
b3c9ad2fcb Two wiki fixes that I've redone multiple times. :/
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4616 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-07 23:31:12 +00:00
ee9cb63327 libuv 1.47.0.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4615 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-07 17:30:39 +00:00
889773c38d Re-hook up all the wiki-related modification events.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4614 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-06 00:59:30 +00:00
b83704a218 Fix a runaway thing in journal, too, same as wiki.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4613 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-05 23:26:54 +00:00
dfe5d51d04 Fix a death spiral.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4612 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-05 23:25:55 +00:00
280dee0438 Might as well benefit from a little parallelism.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4611 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-05 23:05:26 +00:00
aa10ab69f6 Hitting some limit with following too many people. Working around it.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4610 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-05 13:07:07 +00:00
6ef14d985d Maybe avoid increating load with the wiki app as requested accrue.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4609 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-05 01:07:08 +00:00
61a3226e14 Fix some wiki issues I found while making journal.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4608 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-04 23:03:14 +00:00
f9c370212b Add the journal app.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4607 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-04 18:15:58 +00:00
021f3ad5bc Fix wiki doc confusingly and incorrectly being pre-selected.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4606 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-04 16:52:49 +00:00
8bdc27bf5c lit => 3.0.2.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4605 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-04 16:37:12 +00:00
00eb5222f8 Fumbling with wiki some more.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4604 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-04 16:32:21 +00:00
d06f490cc2 Work in progress wiki simplification, I hope.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4603 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-04 02:00:35 +00:00
b087a09d37 Fix blocking the same way, too.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4602 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-03 00:49:17 +00:00
4cedc54d2d Reworked some following math.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4601 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-03 00:45:30 +00:00
8fe7adc50e wiki: Make it possible for links to work. Minor cleanup.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4600 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-02 01:43:32 +00:00
bf5236e68b collections -> wiki
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4599 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-02 01:20:15 +00:00
da1d686705 Some fixes around drafts, and set the app icon.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4598 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-02 01:19:14 +00:00
2ce5bc73d5 Drafts. Boom.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4597 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-02 00:45:20 +00:00
c6ae9313cc More wiki layout/navigation fixes, and use markdown for the wiki.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4596 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-02 00:29:07 +00:00
8f3883563f Close to the general experience I want for editing wiki pages. Bugs galore.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4595 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-01 23:39:34 +00:00
950273da41 If you can get all identities, you might as well be able to see the identities of the owner of a package.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4594 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-01 23:10:29 +00:00
391da742fd Collections progress.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4593 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-01 22:21:42 +00:00
4414676076 sqlite-amalgamation-3440000.zip
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4592 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-11-01 22:00:08 +00:00
0da45b7b40 lit => 3.0.1.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4591 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-10-30 16:42:30 +00:00
7e02cb90f6 Use ssb.following() in the ssb app.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4590 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-10-30 16:18:07 +00:00
01ba90fdba Add a work-in-progress collections app.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4589 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-10-30 00:22:30 +00:00
b394140f9e Expose ssb.following to JS.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4588 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-10-29 19:05:32 +00:00
4a1d136721 Report 'haiku' as a platform, and don't bind to :: on it, because that doesn't seem to be working.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4587 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-10-26 16:41:57 +00:00
ab3009f771 This seems to be a safer way to generate version.h.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4586 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-10-26 03:03:25 +00:00
bf340f3de4 Working on 0.0.13.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4585 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-10-26 02:59:37 +00:00
68f5827dee Builds for Haiku.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4584 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-10-26 02:56:33 +00:00
b695a4ba3b Sort issues open first, and show checkboxes for open/closed.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4583 ed5197a5-7fde-0310-b194-c3ffbd925b24
2023-10-25 23:13:46 +00:00
1524 changed files with 110666 additions and 19276 deletions
GNUmakefile
apps
core
deps
codemirror
libsodium
libuv
.github
AUTHORSCMakeLists.txtChangeLogconfigure.ac
docs
include
src
test
benchmark-async-pummel.cbenchmark-async.cbenchmark-getaddrinfo.cbenchmark-loop-count.cbenchmark-million-async.cbenchmark-million-timers.cbenchmark-multi-accept.cbenchmark-ping-pongs.cbenchmark-ping-udp.cbenchmark-pound.cbenchmark-pump.cbenchmark-queue-work.cbenchmark-spawn.cbenchmark-tcp-write-batch.cbenchmark-thread.cbenchmark-udp-pummel.cblackhole-server.cecho-server.crun-tests.crunner-win.ctask.htest-active.ctest-async-null-cb.ctest-async.ctest-barrier.ctest-callback-stack.ctest-close-fd.ctest-close-order.ctest-condvar.ctest-connect-unspecified.ctest-connection-fail.ctest-cwd-and-chdir.ctest-default-loop-close.ctest-delayed-accept.ctest-dlerror.ctest-eintr-handling.ctest-embed.ctest-emfile.ctest-env-vars.ctest-error.ctest-fork.ctest-fs-copyfile.ctest-fs-event.ctest-fs-fd-hash.ctest-fs-open-flags.ctest-fs-poll.ctest-fs-readdir.ctest-fs.ctest-get-currentexe.ctest-get-loadavg.ctest-get-memory.ctest-get-passwd.ctest-getaddrinfo.ctest-gethostname.ctest-getnameinfo.ctest-getsockname.ctest-getters-setters.ctest-gettimeofday.ctest-handle-fileno.ctest-homedir.ctest-hrtime.ctest-idle.ctest-idna.ctest-ip-name.ctest-ip4-addr.ctest-ip6-addr.ctest-ipc-heavy-traffic-deadlock-bug.ctest-ipc-send-recv.ctest-ipc.ctest-list.htest-loop-alive.ctest-loop-close.ctest-loop-configure.ctest-loop-handles.ctest-loop-stop.ctest-loop-time.ctest-metrics.ctest-multiple-listen.ctest-mutexes.ctest-not-readable-nor-writable-on-read-error.ctest-not-writable-after-shutdown.ctest-osx-select.ctest-ping-pong.ctest-pipe-bind-error.ctest-pipe-close-stdout-read-stdin.ctest-pipe-connect-error.ctest-pipe-connect-multiple.ctest-pipe-connect-prepare.ctest-pipe-getsockname.ctest-pipe-pending-instances.ctest-pipe-sendmsg.ctest-pipe-server-close.ctest-pipe-set-fchmod.ctest-pipe-set-non-blocking.ctest-platform-output.ctest-poll-close-doesnt-corrupt-stack.ctest-poll-close.ctest-poll-closesocket.ctest-poll-multiple-handles.ctest-poll-oob.ctest-poll.ctest-process-priority.ctest-process-title-threadsafe.ctest-process-title.ctest-queue-foreach-delete.ctest-random.ctest-readable-on-eof.ctest-ref.ctest-run-nowait.ctest-run-once.ctest-semaphore.ctest-shutdown-close.ctest-shutdown-eof.ctest-shutdown-simultaneous.ctest-shutdown-twice.ctest-signal-multiple-loops.ctest-signal-pending-on-close.ctest-signal.ctest-socket-buffer-size.ctest-spawn.ctest-stdio-over-pipes.ctest-strscpy.ctest-strtok.ctest-tcp-alloc-cb-fail.ctest-tcp-bind-error.ctest-tcp-bind6-error.ctest-tcp-close-accept.ctest-tcp-close-after-read-timeout.ctest-tcp-close-reset.ctest-tcp-close-while-connecting.ctest-tcp-close.ctest-tcp-connect-error-after-write.ctest-tcp-connect-error.ctest-tcp-connect-timeout.ctest-tcp-connect6-error.ctest-tcp-create-socket-early.ctest-tcp-flags.ctest-tcp-oob.ctest-tcp-open.ctest-tcp-read-stop-start.ctest-tcp-read-stop.ctest-tcp-rst.ctest-tcp-shutdown-after-write.ctest-tcp-try-write-error.ctest-tcp-try-write.ctest-tcp-unexpected-read.ctest-tcp-write-after-connect.ctest-tcp-write-fail.ctest-tcp-write-in-a-row.ctest-tcp-write-queue-order.ctest-tcp-write-to-half-open-connection.ctest-tcp-writealot.ctest-thread-affinity.ctest-thread-equal.ctest-thread.ctest-threadpool-cancel.ctest-threadpool.ctest-timer-again.ctest-timer-from-check.ctest-timer.ctest-tmpdir.ctest-tty-duplicate-key.ctest-tty-escape-sequence-processing.ctest-tty.ctest-udp-alloc-cb-fail.ctest-udp-bind.ctest-udp-connect.ctest-udp-connect6.ctest-udp-create-socket-early.ctest-udp-dgram-too-big.ctest-udp-ipv6.ctest-udp-mmsg.ctest-udp-multicast-interface.ctest-udp-multicast-interface6.ctest-udp-multicast-join.ctest-udp-multicast-join6.ctest-udp-multicast-ttl.ctest-udp-open.ctest-udp-options.ctest-udp-recv-in-a-row.ctest-udp-send-and-recv.ctest-udp-send-hang-loop.ctest-udp-send-immediate.ctest-udp-send-unreachable.ctest-udp-sendmmsg-error.ctest-udp-try-send.ctest-uname.ctest-walk-handles.ctest-watcher-cross-stop.c
lit
openssl
android
arm64-v8a
usr
local
include
crypto
internal
openssl
lib
armeabi-v7a
usr
local
include
crypto
internal
openssl
x86
usr
local
include
crypto
internal
openssl
x86_64
usr
local
include
crypto
internal
openssl
lib
ios
ios64-xcrun
usr
local
include
crypto
internal
openssl
lib
iossimulator-xcrun
usr
local
include
crypto
internal
openssl
mingw64
usr
local
include
crypto
internal
openssl
quickjs
sqlite
src
tools

@ -3,9 +3,9 @@
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules
VERSION_CODE := 12
VERSION_NUMBER := 0.0.12
VERSION_NAME := Where everybody knows your name.
VERSION_CODE := 13
VERSION_NUMBER := 0.0.13
VERSION_NAME := Served on grilled naan or gluten free sweet potato flatbread.
PROJECT = tildefriends
BUILD_DIR ?= out
@ -21,6 +21,22 @@ BUILD_TYPES := debug release
HAVE_ANDROID = $(if $(shell which $(ANDROID_SDK)/platform-tools/adb),1,0)
HAVE_LINUX_IOS = $(if $(shell which deps/ios_toolchain/target/bin deps/ios_toolchain/target/bin/arm-apple-darwin11-clang),1,0)
HAVE_WIN = $(if $(shell which x86_64-w64-mingw32-gcc-win32),1,0)
else ifeq ($(UNAME_S),Haiku)
BUILD_TYPES := debug release
CFLAGS += -Dstatic_assert=_Static_assert
LDFLAGS += \
-lbsd \
-lnetwork
else ifeq ($(UNAME_S),OpenBSD)
BUILD_TYPES := debug release
CFLAGS += \
-Wno-unknown-warning-option
LDFLAGS += \
-lexecinfo \
-lc++abi
HAVE_ANDROID := 0
HAVE_LINUX_IOS := 0
HAVE_WIN := 0
else
$(error Unexpected host platform $(UNAME_S).)
endif
@ -190,9 +206,11 @@ $(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/inc
$(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib
ifeq ($(UNAME_M),x86_64)
ifneq ($(UNAME_S),Haiku)
debug: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
debug: LDFLAGS += -fsanitize=address -fsanitize=undefined
endif
endif
get_objs = \
$(foreach build_type,$(BUILD_TYPES),$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)))))) \
@ -257,23 +275,42 @@ UV_SOURCES_unix := \
deps/libuv/src/unix/fs.c \
deps/libuv/src/unix/getaddrinfo.c \
deps/libuv/src/unix/getnameinfo.c \
deps/libuv/src/unix/linux.c \
deps/libuv/src/unix/loop-watcher.c \
deps/libuv/src/unix/loop.c \
deps/libuv/src/unix/pipe.c \
deps/libuv/src/unix/poll.c \
deps/libuv/src/unix/process.c \
deps/libuv/src/unix/procfs-exepath.c \
deps/libuv/src/unix/proctitle.c \
deps/libuv/src/unix/random-devurandom.c \
deps/libuv/src/unix/random-getrandom.c \
deps/libuv/src/unix/random-sysctl-linux.c \
deps/libuv/src/unix/signal.c \
deps/libuv/src/unix/stream.c \
deps/libuv/src/unix/tcp.c \
deps/libuv/src/unix/thread.c \
deps/libuv/src/unix/tty.c \
deps/libuv/src/unix/udp.c
ifeq ($(UNAME_S),Linux)
UV_SOURCES_unix += \
deps/libuv/src/unix/linux.c \
deps/libuv/src/unix/procfs-exepath.c \
deps/libuv/src/unix/proctitle.c \
deps/libuv/src/unix/random-sysctl-linux.c
else ifeq ($(UNAME_S),Haiku)
UV_SOURCES_unix += \
deps/libuv/src/unix/bsd-ifaddrs.c \
deps/libuv/src/unix/haiku.c \
deps/libuv/src/unix/no-fsevents.c \
deps/libuv/src/unix/no-proctitle.c \
deps/libuv/src/unix/posix-hrtime.c \
deps/libuv/src/unix/posix-poll.c
else ifeq ($(UNAME_S),OpenBSD)
UV_SOURCES_unix += \
deps/libuv/src/unix/bsd-ifaddrs.c \
deps/libuv/src/unix/kqueue.c \
deps/libuv/src/unix/no-proctitle.c \
deps/libuv/src/unix/openbsd.c \
deps/libuv/src/unix/posix-hrtime.c \
deps/libuv/src/unix/random-getentropy.c
endif
UV_SOURCES_android := \
deps/libuv/src/unix/random-getentropy.c
UV_SOURCES_win := \
@ -336,10 +373,18 @@ $(UV_OBJS): CFLAGS += \
-Wno-incompatible-pointer-types \
-Wno-maybe-uninitialized \
-Wno-sign-compare \
-Wno-unused-but-set-parameter \
-Wno-unused-but-set-variable \
-Wno-unused-result \
-Wno-unused-variable \
-Wno-unused-variable
ifeq ($(UNAME_S),Linux)
$(UV_OBJS): CFLAGS += \
-D_GNU_SOURCE
else ifeq ($(UNAME_S),Haiku)
$(UV_OBJS): CFLAGS += \
-D_BSD_SOURCE \
-Wno-format-truncation
endif
SODIUM_SOURCES := \
deps/libsodium/src/libsodium/crypto_aead/aegis128l/aead_aegis128l.c \
@ -403,7 +448,7 @@ $(SODIUM_OBJS): CFLAGS += \
-Wno-attributes \
-Ideps/libsodium/builds/msvc \
-Ideps/libsodium/src/libsodium/include/sodium
#(SODIUM_OBJS_unix): CFLAGS += \
$(SODIUM_OBJS_unix): CFLAGS += \
-DHAVE_ALLOCA_H
SQLITE_SOURCES := deps/sqlite/sqlite3.c
@ -528,9 +573,14 @@ LDFLAGS += \
-pthread \
-lm
debug release $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
-ldl \
-lssl \
-lcrypto
ifneq ($(UNAME_S),Haiku)
ifneq ($(UNAME_S),OpenBSD)
debug release $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
-ldl
endif
endif
$(WINDOWS_TARGETS): LDFLAGS += \
-lssl \
-lcrypto \
@ -605,7 +655,8 @@ $(foreach build_type,$(BUILD_TYPES),$(eval $(call build_rules,$(build_type))))
src/version.h : $(firstword $(MAKEFILE_LIST))
@echo [version] $@
@echo "#define VERSION_NUMBER \"$(VERSION_NUMBER)\"\n#define VERSION_NAME \"$(VERSION_NAME)\"\n" > $@
@echo "#define VERSION_NUMBER \"$(VERSION_NUMBER)\"" > $@
@echo "#define VERSION_NAME \"$(VERSION_NAME)\"" >> $@
src/android/AndroidManifest.xml : $(firstword $(MAKEFILE_LIST))
@echo [android_version] $@
@ -649,7 +700,7 @@ PACKAGE_DIRS := \
deps/codemirror/ \
deps/lit/
RAW_FILES := $(filter-out apps/gg% apps/welcome%, $(shell find $(PACKAGE_DIRS) -type f))
RAW_FILES := $(filter-out apps/gg% apps/welcome% %.map, $(shell find $(PACKAGE_DIRS) -type f))
out/apk/TildeFriends-arm-debug.unsigned.apk: BUILD_TYPE := debug
out/apk/TildeFriends-arm-release.unsigned.apk: BUILD_TYPE := release
@ -706,7 +757,7 @@ out/%.app/tildefriends.png: src/ios/tildefriends.png
@cp -v $< $@
out/%/data.zip: $(RAW_FILES)
@zip -u $@ -q -9 -x '*.map' -r $(PACKAGE_DIRS) $(RAW_FILES)
@zip -u $@ -q -9 $(RAW_FILES)
out/tildefriends-%.app/tildefriends: out/%/tildefriends out/tildefriends-%.app/Info.plist out/tildefriends-%.app/tildefriends.png out/tildefriends-%.app/data.zip
@mkdir -p $(dir $@)

@ -1,4 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "📜"
"emoji": "📜",
"previous": "&miGORZ8BwjHg2YO0t4bms6SI28XWPYqnqOZ8u9zsbZc=.sha256"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,4 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "🦟"
"emoji": "🦟",
"previous": "&TegdzvFE+im94shygaHkgDYSaSrwY2h0OKUXSRPBQDM=.sha256"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -136,7 +136,7 @@ class TfIssuesAppElement extends LitElement {
break;
}
}
this.issues = Object.values(issues).sort((x, y) => y.created - x.created);
this.issues = Object.values(issues).sort((x, y) => (y.open - x.open) || (y.created - x.created));
if (this.selected) {
for (let issue of this.issues) {
if (issue.id == this.selected.id) {
@ -149,7 +149,7 @@ class TfIssuesAppElement extends LitElement {
render_issue_table_row(issue) {
return html`
<tr>
<td>${issue.open ? 'open' : 'closed'}</td>
<td>${issue.open ? 'open' : 'closed'}</td>
<td style="max-width: 8em; overflow: hidden; white-space: nowrap; text-overflow: ellipsis">${issue.author}</td>
<td style="max-width: 40em; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; cursor: pointer" @click=${() => this.selected = issue}>
${issue.text.split('\n')?.[0]}

5
apps/journal.json Normal file

@ -0,0 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "📝",
"previous": "&2hdIDbBrAg63T2X1MzdGSF7yiqHvlnfF0PnInQLp0DA=.sha256"
}

173
apps/journal/app.js Normal file

@ -0,0 +1,173 @@
import * as tfrpc from '/tfrpc.js';
let g_hash;
let g_collection_notifies = {};
tfrpc.register(async function getOwnerIdentities() {
return ssb.getOwnerIdentities();
});
tfrpc.register(async function getIdentities() {
return ssb.getIdentities();
});
tfrpc.register(async function query(sql, args) {
let result = [];
await ssb.sqlAsync(sql, args, function callback(row) {
result.push(row);
});
return result;
});
tfrpc.register(async function localStorageGet(key) {
return app.localStorageGet(key);
});
tfrpc.register(async function localStorageSet(key, value) {
return app.localStorageSet(key, value);
});
tfrpc.register(async function following(ids, depth) {
return ssb.following(ids, depth);
});
tfrpc.register(async function appendMessage(id, message) {
return ssb.appendMessageWithIdentity(id, message);
});
tfrpc.register(async function store_blob(blob) {
if (Array.isArray(blob)) {
blob = Uint8Array.from(blob);
}
return await ssb.blobStore(blob);
});
tfrpc.register(async function get_blob(id) {
return utf8Decode(await ssb.blobGet(id));
});
let g_new_message_resolve;
let g_new_message_promise = new Promise(function(resolve, reject) {
g_new_message_resolve = resolve;
});
function new_message() {
return g_new_message_promise;
}
ssb.addEventListener('message', function(id) {
let resolve = g_new_message_resolve;
g_new_message_promise = new Promise(function(resolve, reject) {
g_new_message_resolve = resolve;
});
if (resolve) {
resolve();
}
});
core.register('message', async function message_handler(message) {
if (message.event == 'hashChange') {
print('hash change', message.hash);
g_hash = message.hash;
await tfrpc.rpc.hash_changed(message.hash);
}
});
tfrpc.register(function set_hash(hash) {
if (g_hash != hash) {
return app.setHash(hash);
}
});
tfrpc.register(function get_hash(id, message) {
return g_hash;
});
tfrpc.register(async function try_decrypt(id, content) {
return await ssb.privateMessageDecrypt(id, content);
});
tfrpc.register(async function encrypt(id, recipients, content) {
return await ssb.privateMessageEncrypt(id, recipients, content);
});
async function process_message(whoami, collection, message, kind, parent) {
let content = JSON.parse(message.content);
if (typeof content == 'string') {
let x;
for (let id of whoami) {
x = await ssb.privateMessageDecrypt(id, content);
if (x) {
content = JSON.parse(x);
break;
}
}
if (!x) {
return;
}
if (content.type !== kind ||
(parent && content.parent !== parent)) {
return;
}
}
if (content?.key) {
if (content?.tombstone) {
delete collection[content.key];
} else {
collection[content.key] = Object.assign(collection[content.key] || {}, content);
}
} else {
collection[message.id] = Object.assign(content, {id: message.id});
}
return true;
}
tfrpc.register(async function collection(ids, kind, parent, max_rowid, data) {
let whoami = await ssb.getIdentities();
data = data ?? {};
let rowid = 0;
await ssb.sqlAsync('SELECT MAX(rowid) AS rowid FROM messages', [], function(row) {
rowid = row.rowid;
});
while (true) {
if (rowid == max_rowid) {
await new_message();
await ssb.sqlAsync('SELECT MAX(rowid) AS rowid FROM messages', [], function(row) {
rowid = row.rowid;
});
}
let modified = false;
let rows = [];
await ssb.sqlAsync(`
SELECT messages.id, author, content, timestamp
FROM messages
JOIN json_each(?1) AS id ON messages.author = id.value
WHERE
messages.rowid > ?2 AND
messages.rowid <= ?3 AND
((json_extract(messages.content, '$.type') = ?4 AND
(?5 IS NULL OR json_extract(messages.content, '$.parent') = ?5)) OR
content LIKE '"%')
`,
[JSON.stringify(ids), max_rowid ?? -1, rowid, kind, parent],
function(row) {
rows.push(row);
});
max_rowid = rowid;
for (let row of rows) {
if (await process_message(whoami, data, row, kind, parent)) {
modified = true;
}
}
if (modified) {
break;
}
}
return [rowid, data];
});
async function main() {
await app.setDocument(utf8Decode(await getFile('index.html')));
}
main();

1
apps/journal/commonmark.min.js vendored Normal file

File diff suppressed because one or more lines are too long

14
apps/journal/index.html Normal file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body style="color: #fff">
<tf-journal-app></tf-journal-app>
<script src="commonmark.min.js"></script>
<script>window.litDisableBundleWarning = true;</script>
<script src="tf-journal-app.js" type="module"></script>
<script src="tf-journal-entry.js" type="module"></script>
<script src="tf-id-picker.js" type="module"></script>
</body>
</html>

120
apps/journal/lit-all.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,36 @@
import {LitElement, html} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
/*
** Provide a list of IDs, and this lets the user pick one.
*/
class TfIdentityPickerElement extends LitElement {
static get properties() {
return {
ids: {type: Array},
selected: {type: String},
};
}
constructor() {
super();
this.ids = [];
}
changed(event) {
this.selected = event.srcElement.value;
this.dispatchEvent(new Event('change', {
srcElement: this,
}));
}
render() {
return html`
<select @change=${this.changed} style="max-width: 100%">
${(this.ids ?? []).map(id => html`<option ?selected=${id == this.selected} value=${id}>${id}</option>`)}
</select>
`;
}
}
customElements.define('tf-id-picker', TfIdentityPickerElement);

@ -0,0 +1,75 @@
import {LitElement, html, keyed, live} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
class TfJournalAppElement extends LitElement {
static get properties() {
return {
ids: {type: Array},
owner_ids: {type: Array},
whoami: {type: String},
journals: {type: Object},
};
}
constructor() {
super();
this.ids = [];
this.owner_ids = [];
this.journals = {};
this.load();
}
async load() {
this.ids = await tfrpc.rpc.getIdentities();
this.whoami = await tfrpc.rpc.localStorageGet('journal_whoami');
await this.read_journals();
}
async read_journals() {
let max_rowid;
let journals;
while (true)
{
[max_rowid, journals] = await tfrpc.rpc.collection([this.whoami], 'journal-entry', undefined, max_rowid, journals);
this.journals = Object.assign({}, journals);
console.log('JOURNALS', this.journals);
}
}
async on_whoami_changed(event) {
let new_id = event.srcElement.selected;
await tfrpc.rpc.localStorageSet('journal_whoami', new_id);
this.whoami = new_id;
}
async on_journal_publish(event) {
let key = event.detail.key;
let text = event.detail.text;
let message = {
type: 'journal-entry',
key: key,
text: text,
};
message.recps = [this.whoami];
print(message);
message = await tfrpc.rpc.encrypt(this.whoami, message.recps, JSON.stringify(message));
print(message);
await tfrpc.rpc.appendMessage(this.whoami, message);
}
render() {
console.log('RENDER APP', this.journals);
let self = this;
return html`
<div>
<tf-id-picker .ids=${this.ids} selected=${this.whoami} @change=${this.on_whoami_changed}></tf-id-picker>
</div>
<tf-journal-entry
whoami=${this.whoami}
.journals=${this.journals}
@publish=${this.on_journal_publish}></tf-journal-entry>
`;
}
}
customElements.define('tf-journal-app', TfJournalAppElement);

@ -0,0 +1,84 @@
import {LitElement, html, unsafeHTML, range} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
class TfJournalEntryElement extends LitElement {
static get properties() {
return {
whoami: {type: String},
key: {type: String},
journals: {type: Object},
text: {type: String},
};
}
constructor() {
super();
this.journals = {};
this.key = new Date().toISOString().split('T')[0];
}
markdown(md) {
var reader = new commonmark.Parser({safe: true});
var writer = new commonmark.HtmlRenderer();
var parsed = reader.parse(md || '');
return writer.render(parsed);
}
on_discard(event) {
this.text = undefined;
}
async on_publish() {
console.log('publish', this.text);
this.dispatchEvent(new CustomEvent('publish', {
bubbles: true,
detail: {
key: this.shadowRoot.getElementById('date_picker').value,
text: this.text,
},
}));
}
back_dates(count) {
let now = new Date();
let result = [];
for (let i = 0; i < count; i++) {
let next = new Date(now);
next.setDate(now.getDate() - i);
result.push(next.toISOString().split('T')[0]);
}
return result;
}
on_edit(event) {
this.text = event.srcElement.value;
}
on_date_change(event) {
this.key = event.srcElement.value;
this.text = this.journals[this.key]?.text;
}
render() {
console.log('RENDER ENTRY', this.key, this.journals?.[this.key]);
return html`
<select id="date_picker" @change=${this.on_date_change}>
${this.back_dates(10).map(x => html`
<option value=${x}>${x}</option>
`)}
</select>
<div style="display: inline-flex; flex-direction: row">
<button ?disabled=${this.text == this.journals?.[this.key]?.text} @click=${this.on_publish}>Publish</button>
<button @click=${this.on_discard}>Discard</button>
</div>
<div style="display: flex; flex-direction: row">
<textarea
style="flex: 1 1; min-height: 10em"
@input=${this.on_edit} .value=${this.text ?? this.journals?.[this.key]?.text ?? ''}></textarea>
<div style="flex: 1 1">${unsafeHTML(this.markdown(this.text ?? this.journals?.[this.key]?.text))}</div>
</div>
`;
}
}
customElements.define('tf-journal-entry', TfJournalEntryElement);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "🐌",
"previous": "&HrGonbL2IZBtoP3zh1glMUO16+PZ4/t0KFTpkNMYoPI=.sha256"
"previous": "&vIYnoUkbz97WRvyunV+ETe+Y6tJk7tTEVvgYuwkoDiM=.sha256"
}

@ -30,6 +30,9 @@ tfrpc.register(async function getIdentities() {
tfrpc.register(async function getAllIdentities() {
return ssb.getAllIdentities();
});
tfrpc.register(async function following(ids, depth) {
return ssb.following(ids, depth);
});
tfrpc.register(async function getBroadcasts() {
return ssb.getBroadcasts();
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -75,78 +75,6 @@ class TfElement extends LitElement {
}
}
async contacts_internal(id, last_row_id, following, max_row_id) {
let result = Object.assign({}, following[id] || {});
result.following = result.following || {};
result.blocking = result.blocking || {};
let contacts = await tfrpc.rpc.query(
`
SELECT content FROM messages
WHERE author = ? AND
rowid > ? AND
rowid <= ? AND
json_extract(content, '$.type') = 'contact'
ORDER BY sequence
`,
[id, last_row_id, max_row_id]);
for (let row of contacts) {
let contact = JSON.parse(row.content);
if (contact.following === true) {
result.following[contact.contact] = true;
} else if (contact.following === false) {
delete result.following[contact.contact];
} else if (contact.blocking === true) {
result.blocking[contact.contact] = true;
} else if (contact.blocking === false) {
delete result.blocking[contact.contact];
}
}
following[id] = result;
return result;
}
async contact(id, last_row_id, following, max_row_id) {
return await this.contacts_internal(id, last_row_id, following, max_row_id);
}
async following_deep_internal(ids, depth, blocking, last_row_id, following, max_row_id) {
let contacts = await Promise.all([...new Set(ids)].map(x => this.contact(x, last_row_id, following, max_row_id)));
let result = {};
for (let i = 0; i < ids.length; i++) {
let id = ids[i];
let contact = contacts[i];
let all_blocking = Object.assign({}, contact.blocking, blocking);
let found = Object.keys(contact.following).filter(y => !all_blocking[y]);
let deeper = depth > 1 ? await this.following_deep_internal(found, depth - 1, all_blocking, last_row_id, following, max_row_id) : [];
result[id] = [id, ...found, ...deeper];
}
return [...new Set(Object.values(result).flat())];
}
async following_deep(ids, depth, blocking) {
const k_cache_version = 5;
let cache = await tfrpc.rpc.databaseGet('following');
cache = cache ? JSON.parse(cache) : {};
if (cache.version !== k_cache_version) {
cache = {
version: k_cache_version,
following: {},
last_row_id: 0,
};
}
let max_row_id = (await tfrpc.rpc.query(`
SELECT MAX(rowid) AS max_row_id FROM messages
`, []))[0].max_row_id;
let result = await this.following_deep_internal(ids, depth, blocking, cache.last_row_id, cache.following, max_row_id);
cache.last_row_id = max_row_id;
let store = JSON.stringify(cache);
/* 2023-02-20: Exceeding message size. */
//if (store.length < 512 * 1024) {
await tfrpc.rpc.databaseSet('following', store);
//}
return [result, cache.following];
}
async fetch_about(ids, users) {
const k_cache_version = 1;
let cache = await tfrpc.rpc.databaseGet('about');
@ -228,6 +156,7 @@ class TfElement extends LitElement {
]);
if (messages && messages.length) {
this.unread = [...this.unread, ...messages];
this.unread = this.unread.slice(this.unread.length - 1024);
}
}
@ -255,7 +184,7 @@ class TfElement extends LitElement {
render_id_picker() {
return html`
<tf-id-picker id="picker" selected=${this.whoami} .ids=${this.ids} @change=${this._handle_whoami_changed}></tf-id-picker>
<tf-id-picker id="picker" selected=${this.whoami} .ids=${this.ids} .users=${this.users} @change=${this._handle_whoami_changed}></tf-id-picker>
<button @click=${this.create_identity} id="create_identity">Create Identity</button>
`;
}
@ -283,9 +212,21 @@ class TfElement extends LitElement {
async load() {
let whoami = this.whoami;
let tags = this.load_recent_tags();
let [following, users] = await this.following_deep([whoami], 2, {});
users = await this.fetch_about(following.sort(), users);
this.following = following;
let following = await tfrpc.rpc.following([whoami], 2);
let users = {};
let by_count = [];
for (let [id, v] of Object.entries(following)) {
users[id] = {
following: v.of,
blocking: v.ob,
followed: v.if,
blocked: v.ib,
};
by_count.push({count: v.of, id: id});
}
console.log(by_count.sort((x, y) => y.count - x.count).slice(0, 20));
users = await this.fetch_about(Object.keys(following).sort(), users);
this.following = Object.keys(following);
this.users = users;
await tags;
console.log(`load finished ${whoami} => ${this.whoami}`);

@ -9,12 +9,14 @@ class TfIdentityPickerElement extends LitElement {
return {
ids: {type: Array},
selected: {type: String},
users: {type: Object},
};
}
constructor() {
super();
this.ids = [];
this.users = {};
}
changed(event) {
@ -27,7 +29,7 @@ class TfIdentityPickerElement extends LitElement {
render() {
return html`
<select @change=${this.changed} style="max-width: 100%">
${(this.ids ?? []).map(id => html`<option ?selected=${id == this.selected} value=${id}>${id}</option>`)}
${(this.ids ?? []).map(id => html`<option ?selected=${id == this.selected} value=${id}>${this.users[id]?.name ? (this.users[id]?.name + ' - ') : undefined}<small>${id}</small></option>`)}
</select>
`;
}

@ -258,9 +258,16 @@ class TfMessageElement extends LitElement {
case 'md':
raw_button = html`<input type="button" value="Message" @click=${() => self.format = 'message'}></input>`;
break;
default:
case 'decrypted':
raw_button = html`<input type="button" value="Raw" @click=${() => self.format = 'raw'}></input>`;
break;
default:
if (this.message.decrypted) {
raw_button = html`<input type="button" value="Decrypted" @click=${() => self.format = 'decrypted'}></input>`;
} else {
raw_button = html`<input type="button" value="Raw" @click=${() => self.format = 'raw'}></input>`;
}
break;
}
function small_frame(inner) {
let body;
@ -526,7 +533,11 @@ class TfMessageElement extends LitElement {
`);
} else if (typeof(this.message.content) == 'string') {
if (this.message?.decrypted) {
return small_frame(html`<span>🔓</span><pre>${JSON.stringify(this.decrypted, null, 2)}</pre>`);
if (this.format == 'decrypted') {
return small_frame(html`<span>🔓</span><pre>${JSON.stringify(this.message.decrypted, null, 2)}</pre>`);
} else {
return small_frame(html`<span>🔓</span><div>${this.message.decrypted.type}</div>`);
}
} else {
return small_frame(html`<span>🔒</span>`);
}

@ -12,6 +12,8 @@ class TfProfileElement extends LitElement {
users: {type: Object},
size: {type: Number},
server_follows_me: {type: Boolean},
following: {type: Boolean},
blocking: {type: Boolean},
};
}
@ -28,11 +30,39 @@ class TfProfileElement extends LitElement {
this.server_follows_me = undefined;
}
async load() {
if (this.whoami !== this._follow_whoami) {
this._follow_whoami = this.whoami;
this.following = undefined;
this.blocking = undefined;
let result = await tfrpc.rpc.query(`
SELECT json_extract(content, '$.following') AS following
FROM messages WHERE author = ? AND
json_extract(content, '$.type') = 'contact' AND
json_extract(content, '$.contact') = ? AND
following IS NOT NULL
ORDER BY sequence DESC LIMIT 1
`, [this.whoami, this.id]);
this.following = result?.[0]?.following ?? false;
result = await tfrpc.rpc.query(`
SELECT json_extract(content, '$.blocking') AS blocking
FROM messages WHERE author = ? AND
json_extract(content, '$.type') = 'contact' AND
json_extract(content, '$.contact') = ? AND
blocking IS NOT NULL
ORDER BY sequence DESC LIMIT 1
`, [this.whoami, this.id]);
this.blocking = result?.[0]?.blocking ?? false;
}
}
async initial_load() {
this.server_follows_me = undefined;
let server_id = await tfrpc.rpc.getServerIdentity();
let followed = await tfrpc.rpc.query(`
SELECT json_extract(content, '$.following') AS following FROM messages
SELECT json_extract(content, '$.following') AS following
FROM messages
WHERE author = ? AND
json_extract(content, '$.type') = 'contact' AND
json_extract(content, '$.contact') = ? ORDER BY sequence DESC LIMIT 1
@ -138,6 +168,7 @@ class TfProfileElement extends LitElement {
if (this.id == this.whoami && this.editing && this.server_follows_me === undefined) {
this.initial_load();
}
this.load();
let self = this;
let profile = this.users[this.id] || {};
tfrpc.rpc.query(
@ -166,16 +197,16 @@ class TfProfileElement extends LitElement {
}
}
if (this.id !== this.whoami &&
this.users[this.whoami]?.following) {
this.following !== undefined) {
follow =
this.users[this.whoami].following[this.id] ?
this.following ?
html`<input type="button" value="Unfollow" @click=${this.unfollow}></input>` :
html`<input type="button" value="Follow" @click=${this.follow}></input>`;
}
if (this.id !== this.whoami &&
this.users[this.whoami]?.blocking) {
this.blocking !== undefined) {
block =
this.users[this.whoami].blocking[this.id] ?
this.blocking ?
html`<input type="button" value="Unblock" @click=${this.unblock}></input>` :
html`<input type="button" value="Block" @click=${this.block}></input>`;
}
@ -208,10 +239,10 @@ class TfProfileElement extends LitElement {
</div>
</div>
<div>
Following ${Object.keys(profile.following || {}).length} identities.
Followed by ${Object.values(self.users).filter(x => (x.following || {})[self.id]).length} identities.
Blocking ${Object.keys(profile.blocking || {}).length} identities.
Blocked by ${Object.values(self.users).filter(x => (x.blocking || {})[self.id]).length} identities.
Following ${profile.following} identities.
Followed by ${profile.followed} identities.
Blocking ${profile.blocking} identities.
Blocked by ${profile.blocked} identities.
</div>
<div>
${edit}

@ -65,34 +65,39 @@ class TfTabNewsFeedElement extends LitElement {
this.hash.substring(1),
]);
} else {
return await tfrpc.rpc.query(
`
WITH news AS (SELECT messages.*
FROM messages
JOIN json_each(?) AS following ON messages.author = following.value
WHERE messages.timestamp > ? AND messages.timestamp < ?
ORDER BY messages.timestamp DESC)
SELECT messages.*
FROM news
JOIN messages_refs ON news.id = messages_refs.ref
JOIN messages ON messages_refs.message = messages.id
UNION
SELECT messages.*
FROM news
JOIN messages_refs ON news.id = messages_refs.message
JOIN messages ON messages_refs.ref = messages.id
UNION
SELECT news.* FROM news
`,
[
JSON.stringify(this.following),
this.start_time,
/*
** Don't show messages more than a day into the future to prevent
** messages with far-future timestamps from staying at the top forever.
*/
new Date().valueOf() + 24 * 60 * 60 * 1000,
]);
let promises = [];
const k_following_limit = 256;
for (let i = 0; i < this.following.length; i += k_following_limit) {
promises.push(tfrpc.rpc.query(
`
WITH news AS (SELECT messages.*
FROM messages
JOIN json_each(?) AS following ON messages.author = following.value
WHERE messages.timestamp > ? AND messages.timestamp < ?
ORDER BY messages.timestamp DESC)
SELECT messages.*
FROM news
JOIN messages_refs ON news.id = messages_refs.ref
JOIN messages ON messages_refs.message = messages.id
UNION
SELECT messages.*
FROM news
JOIN messages_refs ON news.id = messages_refs.message
JOIN messages ON messages_refs.ref = messages.id
UNION
SELECT news.* FROM news
`,
[
JSON.stringify(this.following.slice(i, i + k_following_limit)),
this.start_time,
/*
** Don't show messages more than a day into the future to prevent
** messages with far-future timestamps from staying at the top forever.
*/
new Date().valueOf() + 24 * 60 * 60 * 1000,
]));
}
return [].concat(...(await Promise.all(promises)));
}
}
@ -128,6 +133,7 @@ class TfTabNewsFeedElement extends LitElement {
}
async decrypt(messages) {
console.log('decrypt');
let result = [];
for (let message of messages) {
let content;
@ -162,7 +168,7 @@ class TfTabNewsFeedElement extends LitElement {
if (!this.messages ||
this._messages_hash !== this.hash ||
this._messages_following !== this.following) {
console.log(`loading messages for ${this.whoami}`);
console.log(`loading messages for ${this.whoami} (following ${this.following.length})`);
let self = this;
this.messages = [];
this._messages_hash = this.hash;

5
apps/wiki.json Normal file

@ -0,0 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "📝",
"previous": "&r+JXDhWclHwMbeZHYjueOnSPaYCAXUlnl1Gyjgw6TxM=.sha256"
}

81
apps/wiki/app.js Normal file

@ -0,0 +1,81 @@
import * as tfrpc from '/tfrpc.js';
import * as utils from './utils.js';
let g_hash;
let g_collection_notifies = {};
tfrpc.register(async function getOwnerIdentities() {
return ssb.getOwnerIdentities();
});
tfrpc.register(async function getIdentities() {
return ssb.getIdentities();
});
tfrpc.register(async function query(sql, args) {
let result = [];
await ssb.sqlAsync(sql, args, function callback(row) {
result.push(row);
});
return result;
});
tfrpc.register(async function localStorageGet(key) {
return app.localStorageGet(key);
});
tfrpc.register(async function localStorageSet(key, value) {
return app.localStorageSet(key, value);
});
tfrpc.register(async function following(ids, depth) {
return ssb.following(ids, depth);
});
tfrpc.register(async function appendMessage(id, message) {
print('APPENDING', message);
return ssb.appendMessageWithIdentity(id, message);
});
tfrpc.register(async function store_blob(blob) {
if (Array.isArray(blob)) {
blob = Uint8Array.from(blob);
}
return await ssb.blobStore(blob);
});
tfrpc.register(async function get_blob(id) {
return utf8Decode(await ssb.blobGet(id));
});
core.register('message', async function message_handler(message) {
if (message.event == 'hashChange') {
g_hash = message.hash;
await tfrpc.rpc.hash_changed(message.hash);
}
});
tfrpc.register(function set_hash(hash) {
if (g_hash != hash) {
return app.setHash(hash);
}
});
tfrpc.register(function get_hash(id, message) {
return g_hash;
});
tfrpc.register(async function try_decrypt(id, content) {
return await ssb.privateMessageDecrypt(id, content);
});
tfrpc.register(async function encrypt(id, recipients, content) {
return await ssb.privateMessageEncrypt(id, recipients, content);
});
tfrpc.register(utils.collection);
async function main() {
await app.setDocument(utf8Decode(await getFile('index.html')));
}
main();

1
apps/wiki/commonmark.min.js vendored Normal file

File diff suppressed because one or more lines are too long

71
apps/wiki/handler.js Normal file

@ -0,0 +1,71 @@
import * as utils from './utils.js';
import * as commonmark from './commonmark.min.js';
function markdown(md) {
let reader = new commonmark.Parser({safe: true});
let writer = new commonmark.HtmlRenderer();
let parsed = reader.parse(md || '');
let walker = parsed.walker();
let event;
while ((event = walker.next())) {
let node = event.node;
if (event.entering) {
if (node.type === 'link') {
if (node.destination.indexOf(':') == -1 &&
node.destination.indexOf('/') == -1) {
node.destination = `#${this.wiki?.name}/${node.destination}`;
}
}
}
}
return writer.render(parsed);
}
async function main() {
let slash = request.path.indexOf('/');
if (slash != -1) {
let wiki_name = request.path.substring(0, slash);
let wiki_doc_name = request.path.substring(slash + 1);
let ids = Object.keys(await ssb.following(await ssb.getOwnerIdentities(), 1));
let [max_row_id, wikis] = await utils.collection(ids, 'wiki', null, -1, {});
let wiki;
for (let w of Object.values(wikis)) {
if (w.name === wiki_name && !w.tombstone) {
wiki = w;
break;
}
}
let wiki_doc;
if (wiki) {
let [max_row_id, wiki_docs] = await utils.collection(ids, 'wiki-doc', wiki.id, -1, {});
for (let w of Object.values(wiki_docs)) {
if (w.name === wiki_doc_name && !w.tombstone) {
wiki_doc = w;
break;
}
}
}
let md;
if (wiki_doc?.blob) {
md = utf8Decode(await ssb.blobGet(wiki_doc.blob));
}
await respond({
data: `
<h1>${wiki_name}: ${wiki_doc_name}</h1>
<div>${markdown(md)}</div>
`,
content_type: 'text/html',
status_code: 200,
});
} else {
await respond({
data: '<h1>File not found</h1>',
content_type: 'text/html',
status_code: 404,
});
}
}
main();

14
apps/wiki/index.html Normal file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body style="color: #fff">
<tf-collections-app></tf-collections-app>
<script>window.litDisableBundleWarning = true;</script>
<script src="tf-collection.js" type="module"></script>
<script src="tf-id-picker.js" type="module"></script>
<script src="tf-wiki-doc.js" type="module"></script>
<script src="tf-wiki-app.js" type="module"></script>
</body>
</html>

120
apps/wiki/lit-all.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,95 @@
import {LitElement, html} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
class TfCollectionElement extends LitElement {
static get properties() {
return {
whoami: {type: String},
collection: {type: Object},
selected_id: {type: String},
is_creating: {type: Boolean},
is_renaming: {type: Boolean},
};
}
on_create(event) {
let name = this.shadowRoot.getElementById('create_name').value;
this.dispatchEvent(new CustomEvent('create', {
bubbles: true,
detail: {
name: name,
},
}));
this.is_creating = false;
}
on_rename(event) {
let id = this.shadowRoot.getElementById('select').value;
let name = this.shadowRoot.getElementById('rename_name').value;
this.dispatchEvent(new CustomEvent('rename', {
bubbles: true,
detail: {
id: id,
value: this.collection[id],
name: name,
},
}));
this.is_renaming = false;
}
on_tombstone(event) {
let id = this.shadowRoot.getElementById('select').value;
if (confirm(`Are you sure you want to delete '${this.collection[id].name}'?`)) {
this.dispatchEvent(new CustomEvent('tombstone', {
bubbles: true,
detail: {
id: id,
value: this.collection[id],
},
}));
}
}
on_selected(event) {
let id = event.srcElement.value;
this.selected_id = id != '' ? id : undefined;
this.dispatchEvent(new CustomEvent('change', {
bubbles: true,
detail: {
id: id,
value: this.collection[id],
},
}));
}
render() {
let self = this;
return html`
<span style="display: inline-flex; flex-direction: row">
<select @change=${this.on_selected} id="select" value=${this.selected_id}>
<option value="" ?selected=${this.selected_id === ''} disabled hidden>(select)</option>
${Object.values(this.collection ?? {}).sort((x, y) => x.name.localeCompare(y.name)).map(x => html`<option value=${x.id} ?selected=${this.selected_id === x.id}>${x.name}</option>`)}
</select>
<span ?hidden=${!this.is_renaming || !this.whoami}>
<span style="display: inline-flex; flex-direction: row; margin-left: 8px; margin-right: 8px">
<label for="rename_name">🏷Rename to:</label>
<input type="text" id="rename_name"></input>
<button @click=${this.on_rename}>Rename ${this.type}</button>
<button @click=${() => self.is_renaming = false}>x</button>
</span>
</span>
<button @click=${() => self.is_renaming = true} ?disabled=${this.is_renaming || !this.selected_id} ?hidden=${!this.whoami}>🏷</button>
<button @click=${self.on_tombstone} ?disabled=${!this.selected_id} ?hidden=${!this.whoami}>🪦</button>
<span ?hidden=${!this.is_creating || !this.whoami}>
<label for="create_name">New ${this.type} name:</label>
<input type="text" id="create_name"></input>
<button @click=${this.on_create}>Create ${this.type}</button>
<button @click=${() => self.is_creating = false}>x</button>
</span>
<button @click=${() => self.is_creating = true} ?hidden=${this.is_creating || !this.whoami}>+</button>
</span>
`;
}
}
customElements.define('tf-collection', TfCollectionElement);

36
apps/wiki/tf-id-picker.js Normal file

@ -0,0 +1,36 @@
import {LitElement, html} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
/*
** Provide a list of IDs, and this lets the user pick one.
*/
class TfIdentityPickerElement extends LitElement {
static get properties() {
return {
ids: {type: Array},
selected: {type: String},
};
}
constructor() {
super();
this.ids = [];
}
changed(event) {
this.selected = event.srcElement.value;
this.dispatchEvent(new Event('change', {
srcElement: this,
}));
}
render() {
return html`
<select @change=${this.changed} style="max-width: 100%">
${(this.ids ?? []).map(id => html`<option ?selected=${id == this.selected} value=${id}>${id}</option>`)}
</select>
`;
}
}
customElements.define('tf-id-picker', TfIdentityPickerElement);

291
apps/wiki/tf-wiki-app.js Normal file

@ -0,0 +1,291 @@
import {LitElement, html, keyed} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
class TfCollectionsAppElement extends LitElement {
static get properties() {
return {
ids: {type: Array},
owner_ids: {type: Array},
whoami: {type: String},
following: {type: Array},
wikis: {type: Object},
wiki_docs: {type: Object},
wiki: {type: Object},
wiki_doc: {type: Object},
hash: {type: String},
adding_editor: {type: Boolean},
expand_editors: {type: Boolean},
};
}
constructor() {
super();
this.ids = [];
this.owner_ids = [];
this.following = [];
this.load();
let self = this;
tfrpc.register(function hash_changed(hash) {
self.notify_hash_changed(hash);
});
tfrpc.rpc.get_hash().then(hash => self.notify_hash_changed(hash));
}
async load() {
this.ids = await tfrpc.rpc.getIdentities();
this.owner_ids = await tfrpc.rpc.getOwnerIdentities();
this.whoami = await tfrpc.rpc.localStorageGet('collections_whoami');
let ids = [...new Set([...this.owner_ids, this.whoami])].sort();
this.following = Object.keys(await tfrpc.rpc.following(ids, 1)).sort();
await this.read_wikis();
await this.read_Wiki_docs();
}
async read_wikis() {
let max_rowid;
let wikis;
let start_whoami = this.whoami;
while (true)
{
console.log('read_wikis', this.whoami);
[max_rowid, wikis] = await tfrpc.rpc.collection(this.following, 'wiki', undefined, max_rowid, wikis, false);
console.log('read ->', wikis);
if (this.whoami !== start_whoami) {
break;
}
console.log('wikis =>', wikis);
this.wikis = wikis;
this.update_wiki();
}
}
async read_wiki_docs() {
if (!this.wiki?.id) {
return;
}
let start_id = this.wiki.id;
let max_rowid;
let wiki_docs;
while (true)
{
[max_rowid, wiki_docs] = await tfrpc.rpc.collection(this.wiki?.editors, 'wiki-doc', this.wiki?.id, max_rowid, wiki_docs);
if (this.wiki?.id !== start_id) {
break;
}
this.wiki_docs = wiki_docs;
this.update_wiki_doc();
}
}
hash_wiki() {
let hash = this.hash ?? '';
hash = hash.charAt(0) == '#' ? hash.substring(1) : hash;
let parts = hash.split('/');
return parts[0];
}
hash_wiki_doc() {
let hash = this.hash ?? '';
hash = hash.charAt(0) == '#' ? hash.substring(1) : hash;
let slash = hash.indexOf('/');
return slash != -1 ? hash.substring(slash + 1) : undefined;
}
update_wiki() {
let want_wiki = this.hash_wiki();
for (let wiki of Object.values(this.wikis ?? {})) {
if (wiki.name === want_wiki) {
this.wiki = wiki;
this.read_wiki_docs();
break;
}
}
}
update_wiki_doc() {
let want_wiki_doc = this.hash_wiki_doc();
for (let wiki_doc of Object.values(this.wiki_docs ?? {})) {
if (wiki_doc.name === want_wiki_doc) {
this.wiki_doc = wiki_doc;
}
}
}
notify_hash_changed(hash) {
this.hash = hash;
this.update_wiki();
this.update_wiki_doc();
}
async on_whoami_changed(event) {
let new_id = event.srcElement.selected;
await tfrpc.rpc.localStorageSet('collections_whoami', new_id);
this.whoami = new_id;
}
update_hash() {
tfrpc.rpc.set_hash(this.wiki_doc ? `${this.wiki.name}/${this.wiki_doc.name}` : `${this.wiki.name}`);
}
async on_wiki_changed(event) {
this.wiki = event.detail.value;
this.wiki_doc = undefined;
this.wiki_docs = undefined;
this.adding_editor = false;
this.update_hash();
this.read_wiki_docs();
}
async on_wiki_create(event) {
await tfrpc.rpc.appendMessage(this.whoami, {
type: 'wiki',
name: event.detail.name,
});
}
async on_wiki_rename(event) {
await tfrpc.rpc.appendMessage(this.whoami, {
type: 'wiki',
key: event.detail.id,
name: event.detail.name,
});
}
async on_add_editor(event) {
let id = this.shadowRoot.getElementById('add_editor').value;
let editors = [...this.wiki.editors];
if (editors.indexOf(id) == -1) {
editors.push(id);
editors.sort();
}
await tfrpc.rpc.appendMessage(this.whoami, {
type: 'wiki',
key: this.wiki.id,
editors: editors,
});
this.adding_editor = false;
}
async on_remove_editor(id) {
if (confirm(`Are you sure you want to remove ${id} as an editor?`)) {
let editors = [...this.wiki.editors];
if (editors.indexOf(id) != -1) {
editors = editors.filter(x => x !== id);
}
await tfrpc.rpc.appendMessage(this.whoami, {
type: 'wiki',
key: this.wiki.id,
editors: editors,
});
}
}
async on_wiki_tombstone(event) {
await tfrpc.rpc.appendMessage(this.whoami, {
type: 'wiki',
key: event.detail.id,
tombstone: {
date: new Date().valueOf(),
reason: 'tombstoned by user',
},
});
}
async on_wiki_doc_create(event) {
await tfrpc.rpc.appendMessage(this.whoami, {
type: 'wiki-doc',
parent: this.wiki.id,
name: event.detail.name,
});
}
async on_wiki_doc_rename(event) {
await tfrpc.rpc.appendMessage(this.whoami, {
type: 'wiki-doc',
parent: this.wiki.id,
key: event.detail.id,
name: event.detail.name,
});
}
async on_wiki_doc_tombstone(event) {
await tfrpc.rpc.appendMessage(this.whoami, {
type: 'wiki-doc',
parent: this.wiki.id,
key: event.detail.id,
tombstone: {
date: new Date().valueOf(),
reason: 'tombstoned by user',
},
});
}
async on_wiki_doc_changed(event) {
this.wiki_doc = event.detail.value;
this.update_hash();
}
updated(changed_properties) {
if (changed_properties.has('whoami')) {
this.wikis = {};
this.wiki_docs = {};
this.read_wikis();
}
}
render() {
let self = this;
return html`
<div>
<tf-id-picker .ids=${this.ids} selected=${this.whoami} @change=${this.on_whoami_changed} ?hidden=${!this.ids?.length}></tf-id-picker>
</div>
<div>
${keyed(this.whoami, html`<tf-collection
.collection=${this.wikis}
whoami=${this.whoami}
selected_id=${this.wiki?.id}
@create=${this.on_wiki_create}
@rename=${this.on_wiki_rename}
@tombstone=${this.on_wiki_tombstone}
@change=${this.on_wiki_changed}></tf-collection>`)}
${keyed(this.wiki_doc?.id, html`<tf-collection
.collection=${this.wiki_docs}
whoami=${this.whoami}
selected_id=${(this.wiki_doc && this.wiki_doc?.parent == this.wiki?.id) ? this.wiki_doc?.id : ''}
@create=${this.on_wiki_doc_create}
@rename=${this.on_wiki_doc_rename}
@tombstone=${this.on_wiki_doc_tombstone}
@change=${this.on_wiki_doc_changed}></tf-collection>`)}
<button @click=${() => self.expand_editors = !self.expand_editors}>${this.wiki?.editors?.length} editor${this.wiki?.editors?.length > 1 ? 's' : ''}</button>
<div ?hidden=${!this.wiki?.editors || !this.expand_editors}>
<div>
<ul>
${this.wiki?.editors.map(id => html`<li><button ?hidden=${id == this.whoami} @click=${() => self.on_remove_editor(id)}>x</button> ${id}</li>`)}
<li>
<button @click=${() => self.adding_editor = true} ?hidden=${this.wiki?.editors?.indexOf(this.whoami) == -1 || this.adding_editor}>+</button>
<div ?hidden=${!this.adding_editor}>
<label for="add_editor">Add Editor:</label>
<input type="text" id="add_editor"></input>
<button @click=${this.on_add_editor}>Add Editor</button>
<button @click=${() => self.adding_editor = false}>x</button>
</div>
</li>
</ul>
</div>
</div>
</div>
${this.wiki_doc && this.wiki_doc.parent === this.wiki?.id ? html`
<tf-wiki-doc
whoami=${this.whoami}
.wiki=${this.wiki}
.value=${this.wiki_doc}></tf-wiki-doc>
` : undefined}
`;
}
}
customElements.define('tf-collections-app', TfCollectionsAppElement);

120
apps/wiki/tf-wiki-doc.js Normal file

@ -0,0 +1,120 @@
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
import * as commonmark from './commonmark.min.js';
class TfWikiDocElement extends LitElement {
static get properties() {
return {
whoami: {type: String},
wiki: {type: String},
value: {type: Object},
blob: {type: String},
blob_original: {type: String},
blob_for_value: {type: String},
is_editing: {type: Boolean},
};
}
constructor() {
super();
}
markdown(md) {
var reader = new commonmark.Parser({safe: true});
var writer = new commonmark.HtmlRenderer();
var parsed = reader.parse(md || '');
let walker = parsed.walker();
let event;
while ((event = walker.next())) {
let node = event.node;
if (event.entering) {
if (node.type === 'link') {
if (node.destination.indexOf(':') == -1 &&
node.destination.indexOf('/') == -1) {
node.destination = `#${this.wiki?.name}/${node.destination}`;
}
}
}
}
return writer.render(parsed);
}
async load_blob() {
let blob = await tfrpc.rpc.get_blob(this.value?.blob);
if (blob.endsWith('.box')) {
let d = await tfrpc.rpc.try_decrypt(this.whoami, blob);
if (d) {
blob = d;
}
}
this.blob = blob;
this.blob_original = blob;
}
on_edit(event) {
this.blob = event.srcElement.value;
}
on_discard(event) {
this.blob = this.blob_original;
this.is_editing = false;
}
async append_message(draft) {
let blob = this.blob;
if (draft) {
blob = await tfrpc.rpc.encrypt(this.whoami, this.value.editors, blob);
}
let id = await tfrpc.rpc.store_blob(blob);
let message = {
type: 'wiki-doc',
key: this.value.id,
parent: this.value.parent,
blob: id,
};
if (draft) {
message.recps = this.value.editors;
print(message);
message = await tfrpc.rpc.encrypt(this.whoami, this.value.editors, JSON.stringify(message));
}
print(message);
await tfrpc.rpc.appendMessage(this.whoami, message);
this.is_editing = false;
}
async on_save_draft() {
return this.append_message(true);
}
async on_publish() {
return this.append_message(false);
}
render() {
let value = JSON.stringify(this.value);
if (this.blob_for_value != value) {
this.blob_for_value = value;
this.blob = undefined;
this.blob_original = undefined;
this.load_blob();
}
let self = this;
return html`
<div style="display: inline-flex; flex-direction: row">
<button ?disabled=${!this.whoami || this.is_editing} @click=${() => self.is_editing = true}>Edit</button>
<button ?disabled=${this.blob == this.blob_original} @click=${this.on_save_draft}>Save Draft</button>
<button ?disabled=${this.blob == this.blob_original && !this.value?.draft} @click=${this.on_publish}>Publish</button>
<button ?disabled=${!this.is_editing} @click=${this.on_discard}>Discard</button>
</div>
<div style="display: flex; flex-direction: row">
<textarea
?hidden=${!this.is_editing}
style="flex: 1 1; min-height: 10em"
@input=${this.on_edit} .value=${this.blob ?? ''}></textarea>
<div style="flex: 1 1">${unsafeHTML(this.markdown(this.blob))}</div>
</div>
`;
}
}
customElements.define('tf-wiki-doc', TfWikiDocElement);

105
apps/wiki/utils.js Normal file

@ -0,0 +1,105 @@
async function process_message(whoami, collection, message, kind, parent) {
let content = JSON.parse(message.content);
if (typeof content == 'string') {
let x;
for (let id of (whoami || [])) {
x = await ssb.privateMessageDecrypt(id, content);
if (x) {
try {
content = JSON.parse(x);
content.draft = true;
break;
} catch {
return;
}
}
}
if (!x) {
return;
}
if (content.type !== kind ||
(parent && content.parent !== parent)) {
return;
}
} else {
content.draft = false;
}
if (content?.key) {
if (content?.tombstone) {
delete collection[content.key];
} else {
collection[content.key] = Object.assign(collection[content.key] || {}, content);
}
} else {
collection[message.id] = Object.assign(content, {id: message.id});
if (!collection[message.id].editors) {
collection[message.id].editors = [message.author];
}
}
return true;
}
let g_new_message_resolve;
let g_new_message_promise = new Promise(function(resolve, reject) {
g_new_message_resolve = resolve;
});
function new_message() {
return g_new_message_promise;
}
ssb.addEventListener('message', function(id) {
let resolve = g_new_message_resolve;
g_new_message_promise = new Promise(function(resolve, reject) {
g_new_message_resolve = resolve;
});
if (resolve) {
resolve();
}
});
export async function collection(ids, kind, parent, max_rowid, data, include_private) {
let whoami = await ssb.getIdentities();
data = data ?? {};
let rowid = 0;
let first = true;
await ssb.sqlAsync('SELECT MAX(rowid) AS rowid FROM messages', [], function(row) {
rowid = row.rowid;
});
while (true) {
if (rowid == max_rowid) {
await new_message();
await ssb.sqlAsync('SELECT MAX(rowid) AS rowid FROM messages', [], function(row) {
rowid = row.rowid;
});
first = false;
}
let modified = false;
let rows = [];
await ssb.sqlAsync(`
SELECT messages.id, author, content, timestamp
FROM messages
JOIN json_each(?1) AS id ON messages.author = id.value
WHERE
messages.rowid > ?2 AND
messages.rowid <= ?3 AND
((json_extract(messages.content, '$.type') = ?4 AND
(?5 IS NULL OR json_extract(messages.content, '$.parent') = ?5)) OR
(?6 AND content LIKE '"%'))
ORDER BY timestamp
`, [JSON.stringify(ids), max_rowid ?? -1, rowid, kind, parent, include_private ? true : false], function(row) {
rows.push(row);
});
max_rowid = rowid;
for (let row of rows) {
if (await process_message(whoami, data, row, kind, parent)) {
modified = true;
}
}
if (first || modified) {
break;
}
}
return [rowid, data];
}

@ -196,7 +196,7 @@ function handler(request, response) {
}
}
let cookie = `session=${session}; path=/; Max-Age=${kRefreshInterval}; ${request.client.tls ? 'Secure; ' : ''}SameSite=Strict`;
let cookie = `session=${session}; path=/; Max-Age=${kRefreshInterval}; ${request.client.tls ? 'Secure; ' : ''}SameSite=Strict; HttpOnly`;
let entry = readSession(session);
if (entry && formData.return) {
response.writeHead(303, {"Location": formData.return, "Set-Cookie": cookie});
@ -220,7 +220,7 @@ function handler(request, response) {
});
}
} else if (request.uri == "/login/logout") {
response.writeHead(303, {"Set-Cookie": `session=; path=/; ${request.client.tls ? 'Secure; ' : ''}SameSite=Strict; expires=Thu, 01 Jan 1970 00:00:00 GMT`, "Location": "/login" + (request.query ? "?" + request.query : "")});
response.writeHead(303, {"Set-Cookie": `session=; path=/; ${request.client.tls ? 'Secure; ' : ''}SameSite=Strict; expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly`, "Location": "/login" + (request.query ? "?" + request.query : "")});
response.end();
} else {
response.writeHead(200, {"Content-Type": "text/plain; charset=utf-8", "Connection": "close"});

@ -508,7 +508,8 @@ function load(path) {
'mode': {'js': 'javascript'}[(path || url()).split('.').pop()],
'lint': {
'options': {
'esversion': 2021,
esversion: 2021,
varstmt: true,
},
},
});

@ -391,6 +391,11 @@ async function getProcessBlob(blobId, key, options) {
return ssb.createIdentity(process.credentials.session.name);
}
};
imports.ssb.getOwnerIdentities = function() {
if (options.packageOwner) {
return ssb.getIdentities(options.packageOwner);
}
};
imports.ssb.getIdentities = function() {
if (process.credentials &&
process.credentials.session &&

@ -519,7 +519,7 @@ function handleConnection(client) {
}
let kBacklog = 8;
let kHost = '::';
let kHost = platform() == 'haiku' ? 'localhost' : '::';
let socket = new Socket();
socket.bind(kHost, tildefriends.http_port).then(function(port) {
@ -582,7 +582,7 @@ if (tildefriends.https_port) {
handleConnection(client);
return result;
} catch (error) {
logError("[" + new Date() + "] [" + client.peerName + "] " + error);
logError("[" + new Date() + "] " + error);
}
});
}).catch(function(error) {

File diff suppressed because one or more lines are too long

@ -1,20 +1,20 @@
LINKS="
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/addon/dialog/dialog.min.css
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/addon/dialog/dialog.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/addon/edit/trailingspace.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/addon/lint/javascript-lint.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/addon/scroll/annotatescrollbar.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/addon/search/matchesonscrollbar.min.css
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/addon/search/matchesonscrollbar.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/addon/search/search.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/addon/search/searchcursor.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/codemirror.min.css
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/codemirror.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/mode/css/css.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/mode/htmlmixed/htmlmixed.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/mode/javascript/javascript.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/mode/xml/xml.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/theme/base16-dark.min.css
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/dialog/dialog.min.css
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/dialog/dialog.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/edit/trailingspace.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/lint/javascript-lint.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/scroll/annotatescrollbar.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/search/matchesonscrollbar.min.css
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/search/matchesonscrollbar.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/search/search.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/search/searchcursor.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/css/css.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/htmlmixed/htmlmixed.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/javascript/javascript.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/xml/xml.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/theme/base16-dark.min.css
"
for link in $LINKS; do

@ -1,3 +1,11 @@
* Version 1.0.19-stable
- Building with `zig build` now works both with Zig 0.11 and Zig 0.12.
- When using the traditional build system, -O3 is used instead of -Ofast.
- Improved detection of the compiler flags required on aarch64.
- Improved compatibility with custom build systems on aarch64.
- apple-xcframework: VisionOS packages are not built if Xcode doesn't
include that SDK.
* Version 1.0.19
This release includes all the changes from 1.0.18-stable, as well as two
additions:
@ -19,7 +27,7 @@ the SHA-256 and SHA-512 hash functions.
- Visual Studio: AVX512 implementations are enabled on supported CPUs.
- Visual Studio: an MSVC 2022 solution was added.
- Apple XCFramework: support for VisionOS was added.
- Apple XCFranework: support for Catalyst was added.
- Apple XCFramework: support for Catalyst was added.
- Apple XCFramework: building the simulators is now optional.
- iOS: bitcode is not generated any more, as it was deprecated by Apple.
- watchOS: support for arm64 was added.

@ -4,7 +4,7 @@
# shellcheck disable=SC2006,SC2268 # see below for rationale
timestamp='2023-07-31'
timestamp='2023-09-19'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@ -1181,7 +1181,7 @@ case $cpu-$vendor in
case $cpu in
1750a | 580 \
| a29k \
| aarch64 | aarch64c | aarch64_be \
| aarch64 | aarch64_be | aarch64c | arm64ec \
| abacus \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
@ -1200,6 +1200,7 @@ case $cpu-$vendor in
| d10v | d30v | dlx | dsp16xx \
| e2k | elxsi | epiphany \
| f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
| javascript \
| h8300 | h8500 \
| hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
@ -1284,11 +1285,12 @@ esac
# Decode manufacturer-specific aliases for certain operating systems.
if test x$basic_os != x
if test x"$basic_os" != x
then
# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
# set os.
obj=
case $basic_os in
gnu/linux*)
kernel=linux
@ -1488,10 +1490,16 @@ case $os in
os=eabi
;;
*)
os=elf
os=
obj=elf
;;
esac
;;
aout* | coff* | elf* | pe*)
# These are machine code file formats, not OSes
obj=$os
os=
;;
*)
# No normalization, but not necessarily accepted, that comes below.
;;
@ -1510,12 +1518,15 @@ else
# system, and we'll never get to this point.
kernel=
obj=
case $cpu-$vendor in
score-*)
os=elf
os=
obj=elf
;;
spu-*)
os=elf
os=
obj=elf
;;
*-acorn)
os=riscix1.2
@ -1525,28 +1536,35 @@ case $cpu-$vendor in
os=gnu
;;
arm*-semi)
os=aout
os=
obj=aout
;;
c4x-* | tic4x-*)
os=coff
os=
obj=coff
;;
c8051-*)
os=elf
os=
obj=elf
;;
clipper-intergraph)
os=clix
;;
hexagon-*)
os=elf
os=
obj=elf
;;
tic54x-*)
os=coff
os=
obj=coff
;;
tic55x-*)
os=coff
os=
obj=coff
;;
tic6x-*)
os=coff
os=
obj=coff
;;
# This must come before the *-dec entry.
pdp10-*)
@ -1568,19 +1586,24 @@ case $cpu-$vendor in
os=sunos3
;;
m68*-cisco)
os=aout
os=
obj=aout
;;
mep-*)
os=elf
os=
obj=elf
;;
mips*-cisco)
os=elf
os=
obj=elf
;;
mips*-*)
os=elf
os=
obj=elf
;;
or32-*)
os=coff
os=
obj=coff
;;
*-tti) # must be before sparc entry or we get the wrong os.
os=sysv3
@ -1589,7 +1612,8 @@ case $cpu-$vendor in
os=sunos4.1.1
;;
pru-*)
os=elf
os=
obj=elf
;;
*-be)
os=beos
@ -1670,10 +1694,12 @@ case $cpu-$vendor in
os=uxpv
;;
*-rom68k)
os=coff
os=
obj=coff
;;
*-*bug)
os=coff
os=
obj=coff
;;
*-apple)
os=macos
@ -1691,7 +1717,8 @@ esac
fi
# Now, validate our (potentially fixed-up) OS.
# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
case $os in
# Sometimes we do "kernel-libc", so those need to count as OSes.
musl* | newlib* | relibc* | uclibc*)
@ -1702,6 +1729,9 @@ case $os in
# VxWorks passes extra cpu info in the 4th filed.
simlinux | simwindows | spe)
;;
# See `case $cpu-$os` validation below
ghcjs)
;;
# Now accept the basic system types.
# The portable systems comes first.
# Each alternative MUST end in a * to match a version number.
@ -1719,11 +1749,11 @@ case $os in
| mirbsd* | netbsd* | dicos* | openedition* | ose* \
| bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
| ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
| bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
| ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
| bosx* | nextstep* | cxux* | oabi* \
| ptx* | ecoff* | winnt* | domain* | vsta* \
| udi* | lites* | ieee* | go32* | aux* | hcos* \
| chorusrdb* | cegcc* | glidix* | serenity* \
| cygwin* | msys* | pe* | moss* | proelf* | rtems* \
| cygwin* | msys* | moss* | proelf* | rtems* \
| midipix* | mingw32* | mingw64* | mint* \
| uxpv* | beos* | mpeix* | udk* | moxiebox* \
| interix* | uwin* | mks* | rhapsody* | darwin* \
@ -1747,60 +1777,95 @@ case $os in
kernel* | msvc* )
# Restricted further below
;;
'')
if test x"$obj" = x
then
echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2
fi
;;
*)
echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
exit 1
;;
esac
case $obj in
aout* | coff* | elf* | pe*)
;;
'')
# empty is fine
;;
*)
echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
exit 1
;;
esac
# Here we handle the constraint that a (synthetic) cpu and os are
# valid only in combination with each other and nowhere else.
case $cpu-$os in
# The "javascript-unknown-ghcjs" triple is used by GHC; we
# accept it here in order to tolerate that, but reject any
# variations.
javascript-ghcjs)
;;
javascript-* | *-ghcjs)
echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
exit 1
;;
esac
# As a final step for OS-related things, validate the OS-kernel combination
# (given a valid OS), if there is a kernel.
case $kernel-$os in
linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
| linux-musl* | linux-relibc* | linux-uclibc* | linux-mlibc* )
case $kernel-$os-$obj in
linux-gnu*- | linux-dietlibc*- | linux-android*- | linux-newlib*- \
| linux-musl*- | linux-relibc*- | linux-uclibc*- | linux-mlibc*- )
;;
uclinux-uclibc* )
uclinux-uclibc*- )
;;
managarm-mlibc* | managarm-kernel* )
managarm-mlibc*- | managarm-kernel*- )
;;
windows*-gnu* | windows*-msvc*)
windows*-msvc*-)
;;
-dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* | -mlibc* )
-dietlibc*- | -newlib*- | -musl*- | -relibc*- | -uclibc*- | -mlibc*- )
# These are just libc implementations, not actual OSes, and thus
# require a kernel.
echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
exit 1
;;
-kernel* )
-kernel*- )
echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
exit 1
;;
*-kernel* )
*-kernel*- )
echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
exit 1
;;
*-msvc* )
*-msvc*- )
echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
exit 1
;;
kfreebsd*-gnu* | kopensolaris*-gnu*)
kfreebsd*-gnu*- | kopensolaris*-gnu*-)
;;
vxworks-simlinux | vxworks-simwindows | vxworks-spe)
vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
;;
nto-qnx*)
nto-qnx*-)
;;
os2-emx)
os2-emx-)
;;
*-eabi* | *-gnueabi*)
*-eabi*- | *-gnueabi*-)
;;
none-coff* | none-elf*)
none--*)
# None (no kernel, i.e. freestanding / bare metal),
# can be paired with an output format "OS"
# can be paired with an machine code file format
;;
-*)
-*-)
# Blank kernel with real OS is always fine.
;;
*-*)
--*)
# Blank kernel and OS with real machine code file format is always fine.
;;
*-*-*)
echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
exit 1
;;
@ -1884,7 +1949,7 @@ case $vendor in
;;
esac
echo "$cpu-$vendor-${kernel:+$kernel-}$os"
echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
exit
# Local variables:

@ -103,9 +103,17 @@ pub fn build(b: *std.build.Builder) !void {
lib.defineCMacro("HAVE_TI_MODE", "1");
if (target.cpu_arch) |arch| {
switch (arch.endian()) {
.Big => lib.defineCMacro("NATIVE_BIG_ENDIAN", "1"),
.Little => lib.defineCMacro("NATIVE_LITTLE_ENDIAN", "1"),
const endian = arch.endian();
if (@hasField(@TypeOf(endian), "big")) {
switch (endian) {
.big => lib.defineCMacro("NATIVE_BIG_ENDIAN", "1"),
.little => lib.defineCMacro("NATIVE_LITTLE_ENDIAN", "1"),
}
} else {
switch (endian) {
.Big => lib.defineCMacro("NATIVE_BIG_ENDIAN", "1"),
.Little => lib.defineCMacro("NATIVE_LITTLE_ENDIAN", "1"),
}
}
}
@ -247,13 +255,18 @@ pub fn build(b: *std.build.Builder) !void {
const name = entry.basename;
if (mem.endsWith(u8, name, ".c")) {
const full_path = try fmt.allocPrint(allocator, "{s}/{s}", .{ src_path, entry.path });
lib.addCSourceFiles(&.{full_path}, &.{
const flags = &.{
"-fvisibility=hidden",
"-fno-strict-aliasing",
"-fno-strict-overflow",
"-fwrapv",
"-flax-vector-conversions",
});
};
if (@hasDecl(std.Build.Step.Compile, "AddCSourceFilesOptions")) {
lib.addCSourceFiles(.{ .files = &.{full_path}, .flags = flags });
} else {
lib.addCSourceFiles(&.{full_path}, flags);
}
} else if (mem.endsWith(u8, name, ".S")) {
const full_path = try fmt.allocPrint(allocator, "{s}/{s}", .{ src_path, entry.path });
lib.addAssemblyFile(.{ .path = full_path });
@ -291,8 +304,11 @@ pub fn build(b: *std.build.Builder) !void {
exe.addIncludePath(.{ .path = "src/libsodium/include" });
exe.addIncludePath(.{ .path = "test/quirks" });
const full_path = try fmt.allocPrint(allocator, "{s}/{s}", .{ test_path, entry.path });
exe.addCSourceFiles(&.{full_path}, &.{});
if (@hasDecl(std.Build.Step.Compile, "AddCSourceFilesOptions")) {
exe.addCSourceFiles(.{ .files = &.{full_path} });
} else {
exe.addCSourceFiles(&.{full_path}, &.{});
}
if (enable_benchmarks) {
exe.defineCMacro("BENCHMARKS", "1");
var buf: [16]u8 = undefined;

@ -5294,43 +5294,6 @@ fi
if test "$sodium_CFLAGS" != "set" ; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Ofast" >&5
printf %s "checking whether C compiler accepts -Ofast... " >&6; }
if test ${ax_cv_check_cflags___Ofast+y}
then :
printf %s "(cached) " >&6
else $as_nop
ax_check_save_flags=$CFLAGS
CFLAGS="$CFLAGS -Ofast"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <time.h>
int
main (void)
{
time_t x; int fodder = 0; if (fodder > -1000 && time(&x)) return (int) x
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"
then :
ax_cv_check_cflags___Ofast=yes
else $as_nop
ax_cv_check_cflags___Ofast=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CFLAGS=$ax_check_save_flags
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___Ofast" >&5
printf "%s\n" "$ax_cv_check_cflags___Ofast" >&6; }
if test "x$ax_cv_check_cflags___Ofast" = xyes
then :
CFLAGS="$CFLAGS -Ofast"
else $as_nop
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -O3" >&5
printf %s "checking whether C compiler accepts -O3... " >&6; }
if test ${ax_cv_check_cflags___O3+y}
@ -5490,8 +5453,6 @@ fi
fi
fi
# Check whether --enable-ssp was given.
if test ${enable_ssp+y}
@ -18562,11 +18523,6 @@ printf %s "checking for ARM crypto instructions set... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifdef __clang__
# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), apply_to = function)
#elif defined(__GNUC__)
# pragma GCC target("+simd+crypto")
#endif
#ifndef __ARM_FEATURE_CRYPTO
# define __ARM_FEATURE_CRYPTO 1
#endif
@ -18576,6 +18532,12 @@ printf %s "checking for ARM crypto instructions set... " >&6; }
#include <arm_neon.h>
#ifdef __clang__
# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), apply_to = function)
#elif defined(__GNUC__)
# pragma GCC target("+simd+crypto")
#endif
int
main (void)
{

@ -52,11 +52,10 @@ AC_USE_SYSTEM_EXTENSIONS
dnl Default optimization flags
if test "$sodium_CFLAGS" != "set" ; then
AX_CHECK_COMPILE_FLAG([-Ofast], [CFLAGS="$CFLAGS -Ofast"],
[AX_CHECK_COMPILE_FLAG([-O3], [CFLAGS="$CFLAGS -O3"],
[AX_CHECK_COMPILE_FLAG([-O2], [CFLAGS="$CFLAGS -O2"],
[AX_CHECK_COMPILE_FLAG([-O1], [CFLAGS="$CFLAGS -O1"],
[AX_CHECK_COMPILE_FLAG([-O], [CFLAGS="$CFLAGS -O"])])])])])
AX_CHECK_COMPILE_FLAG([-O3], [CFLAGS="$CFLAGS -O3"],
[AX_CHECK_COMPILE_FLAG([-O2], [CFLAGS="$CFLAGS -O2"],
[AX_CHECK_COMPILE_FLAG([-O1], [CFLAGS="$CFLAGS -O1"],
[AX_CHECK_COMPILE_FLAG([-O], [CFLAGS="$CFLAGS -O"])])])])
fi
dnl Switches
@ -398,11 +397,6 @@ AS_IF([test "x$EMSCRIPTEN" = "x"], [
have_armcrypto=no
AC_MSG_CHECKING(for ARM crypto instructions set)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#ifdef __clang__
# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), apply_to = function)
#elif defined(__GNUC__)
# pragma GCC target("+simd+crypto")
#endif
#ifndef __ARM_FEATURE_CRYPTO
# define __ARM_FEATURE_CRYPTO 1
#endif
@ -411,6 +405,12 @@ AS_IF([test "x$EMSCRIPTEN" = "x"], [
#endif
#include <arm_neon.h>
#ifdef __clang__
# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), apply_to = function)
#elif defined(__GNUC__)
# pragma GCC target("+simd+crypto")
#endif
]], [[
int64x2_t x = { 0, 0 };
vaeseq_u8(vmovq_n_u8(0), vmovq_n_u8(0));

@ -51,9 +51,8 @@ else
export LIBSODIUM_ENABLE_MINIMAL_FLAG=""
fi
APPLE_SILICON_SUPPORTED=false
echo 'int main(void){return 0;}' >comptest.c && cc --target=arm64-macos comptest.c 2>/dev/null && APPLE_SILICON_SUPPORTED=true
rm -f comptest.c
VISIONOS_SUPPORTED=false
[ -d "${XCODEDIR}/Platforms/XROS.platform" ] && VISIONOS_SUPPORTED=true
NPROCESSORS=$(getconf NPROCESSORS_ONLN 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null)
PROCESSORS=${NPROCESSORS:-3}
@ -70,18 +69,16 @@ build_macos() {
export PATH="${BASEDIR}/usr/bin:$BASEDIR/usr/sbin:$PATH"
## macOS arm64
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
export CFLAGS="-Ofast -arch arm64 -mmacosx-version-min=${MACOS_VERSION_MIN}"
export LDFLAGS="-arch arm64 -mmacosx-version-min=${MACOS_VERSION_MIN}"
export CFLAGS="-O3 -arch arm64 -mmacosx-version-min=${MACOS_VERSION_MIN}"
export LDFLAGS="-arch arm64 -mmacosx-version-min=${MACOS_VERSION_MIN}"
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-darwin23 --prefix="$MACOS_ARM64_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
fi
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-darwin23 --prefix="$MACOS_ARM64_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
## macOS x86_64
export CFLAGS="-Ofast -arch x86_64 -mmacosx-version-min=${MACOS_VERSION_MIN}"
export CFLAGS="-O3 -arch x86_64 -mmacosx-version-min=${MACOS_VERSION_MIN}"
export LDFLAGS="-arch x86_64 -mmacosx-version-min=${MACOS_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -96,7 +93,7 @@ build_ios() {
export SDK="${BASEDIR}/SDKs/iPhoneOS.sdk"
## 32-bit iOS
export CFLAGS="-Ofast -mthumb -arch armv7 -isysroot ${SDK} -mios-version-min=${IOS_VERSION_MIN}"
export CFLAGS="-O3 -mthumb -arch armv7 -isysroot ${SDK} -mios-version-min=${IOS_VERSION_MIN}"
export LDFLAGS="-mthumb -arch armv7 -isysroot ${SDK} -mios-version-min=${IOS_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -105,7 +102,7 @@ build_ios() {
make -j${PROCESSORS} install || exit 1
## 32-bit armv7s iOS
export CFLAGS="-Ofast -mthumb -arch armv7s -isysroot ${SDK} -mios-version-min=${IOS_VERSION_MIN}"
export CFLAGS="-O3 -mthumb -arch armv7s -isysroot ${SDK} -mios-version-min=${IOS_VERSION_MIN}"
export LDFLAGS="-mthumb -arch armv7s -isysroot ${SDK} -mios-version-min=${IOS_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -114,7 +111,7 @@ build_ios() {
make -j${PROCESSORS} install || exit 1
## 64-bit iOS
export CFLAGS="-Ofast -arch arm64 -isysroot ${SDK} -mios-version-min=${IOS_VERSION_MIN}"
export CFLAGS="-O3 -arch arm64 -isysroot ${SDK} -mios-version-min=${IOS_VERSION_MIN}"
export LDFLAGS="-arch arm64 -isysroot ${SDK} -mios-version-min=${IOS_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -129,18 +126,16 @@ build_ios_simulator() {
export SDK="${BASEDIR}/SDKs/iPhoneSimulator.sdk"
## arm64 simulator
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
export CFLAGS="-Ofast -arch arm64 -isysroot ${SDK} -mios-simulator-version-min=${IOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch arm64 -isysroot ${SDK} -mios-simulator-version-min=${IOS_SIMULATOR_VERSION_MIN}"
export CFLAGS="-O3 -arch arm64 -isysroot ${SDK} -mios-simulator-version-min=${IOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch arm64 -isysroot ${SDK} -mios-simulator-version-min=${IOS_SIMULATOR_VERSION_MIN}"
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-darwin23 --prefix="$IOS_SIMULATOR_ARM64_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
fi
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-darwin23 --prefix="$IOS_SIMULATOR_ARM64_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
## i386 simulator
export CFLAGS="-Ofast -arch i386 -isysroot ${SDK} -mios-simulator-version-min=${IOS_SIMULATOR_VERSION_MIN}"
export CFLAGS="-O3 -arch i386 -isysroot ${SDK} -mios-simulator-version-min=${IOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch i386 -isysroot ${SDK} -mios-simulator-version-min=${IOS_SIMULATOR_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -149,7 +144,7 @@ build_ios_simulator() {
make -j${PROCESSORS} install || exit 1
## x86_64 simulator
export CFLAGS="-Ofast -arch x86_64 -isysroot ${SDK} -mios-simulator-version-min=${IOS_SIMULATOR_VERSION_MIN}"
export CFLAGS="-O3 -arch x86_64 -isysroot ${SDK} -mios-simulator-version-min=${IOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch x86_64 -isysroot ${SDK} -mios-simulator-version-min=${IOS_SIMULATOR_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -164,7 +159,7 @@ build_watchos() {
export SDK="${BASEDIR}/SDKs/WatchOS.sdk"
# 32-bit watchOS
export CFLAGS="-Ofast -mthumb -arch armv7k -isysroot ${SDK} -mwatchos-version-min=${WATCHOS_VERSION_MIN}"
export CFLAGS="-O3 -mthumb -arch armv7k -isysroot ${SDK} -mwatchos-version-min=${WATCHOS_VERSION_MIN}"
export LDFLAGS="-mthumb -arch armv7k -isysroot ${SDK} -mwatchos-version-min=${WATCHOS_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -173,7 +168,7 @@ build_watchos() {
make -j${PROCESSORS} install || exit 1
## 64-bit arm64_32 watchOS
export CFLAGS="-Ofast -mthumb -arch arm64_32 -isysroot ${SDK} -mwatchos-version-min=${WATCHOS_VERSION_MIN}"
export CFLAGS="-O3 -mthumb -arch arm64_32 -isysroot ${SDK} -mwatchos-version-min=${WATCHOS_VERSION_MIN}"
export LDFLAGS="-mthumb -arch arm64_32 -isysroot ${SDK} -mwatchos-version-min=${WATCHOS_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -182,7 +177,7 @@ build_watchos() {
make -j${PROCESSORS} install || exit 1
## 64-bit arm64 watchOS
export CFLAGS="-Ofast -mthumb -arch arm64 -isysroot ${SDK} -mwatchos-version-min=${WATCHOS_VERSION_MIN}"
export CFLAGS="-O3 -mthumb -arch arm64 -isysroot ${SDK} -mwatchos-version-min=${WATCHOS_VERSION_MIN}"
export LDFLAGS="-mthumb -arch arm64 -isysroot ${SDK} -mwatchos-version-min=${WATCHOS_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -197,18 +192,16 @@ build_watchos_simulator() {
export SDK="${BASEDIR}/SDKs/WatchSimulator.sdk"
## arm64 simulator
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
export CFLAGS="-Ofast -arch arm64 -isysroot ${SDK} -mwatchos-simulator-version-min=${WATCHOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch arm64 -isysroot ${SDK} -mwatchos-simulator-version-min=${WATCHOS_SIMULATOR_VERSION_MIN}"
export CFLAGS="-O3 -arch arm64 -isysroot ${SDK} -mwatchos-simulator-version-min=${WATCHOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch arm64 -isysroot ${SDK} -mwatchos-simulator-version-min=${WATCHOS_SIMULATOR_VERSION_MIN}"
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-darwin23 --prefix="$WATCHOS_SIMULATOR_ARM64_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
fi
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-darwin23 --prefix="$WATCHOS_SIMULATOR_ARM64_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
## i386 simulator
export CFLAGS="-Ofast -arch i386 -isysroot ${SDK} -mwatchos-simulator-version-min=${WATCHOS_SIMULATOR_VERSION_MIN}"
export CFLAGS="-O3 -arch i386 -isysroot ${SDK} -mwatchos-simulator-version-min=${WATCHOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch i386 -isysroot ${SDK} -mwatchos-simulator-version-min=${WATCHOS_SIMULATOR_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -217,7 +210,7 @@ build_watchos_simulator() {
make -j${PROCESSORS} install || exit 1
## x86_64 simulator
export CFLAGS="-Ofast -arch x86_64 -isysroot ${SDK} -mwatchos-simulator-version-min=${WATCHOS_SIMULATOR_VERSION_MIN}"
export CFLAGS="-O3 -arch x86_64 -isysroot ${SDK} -mwatchos-simulator-version-min=${WATCHOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch x86_64 -isysroot ${SDK} -mwatchos-simulator-version-min=${WATCHOS_SIMULATOR_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -232,7 +225,7 @@ build_tvos() {
export SDK="${BASEDIR}/SDKs/AppleTVOS.sdk"
## 64-bit tvOS
export CFLAGS="-Ofast -arch arm64 -isysroot ${SDK} -mtvos-version-min=${TVOS_VERSION_MIN}"
export CFLAGS="-O3 -arch arm64 -isysroot ${SDK} -mtvos-version-min=${TVOS_VERSION_MIN}"
export LDFLAGS="-arch arm64 -isysroot ${SDK} -mtvos-version-min=${TVOS_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -247,18 +240,16 @@ build_tvos_simulator() {
export SDK="${BASEDIR}/SDKs/AppleTVSimulator.sdk"
## arm64 simulator
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
export CFLAGS="-Ofast -arch arm64 -isysroot ${SDK} -mtvos-simulator-version-min=${TVOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch arm64 -isysroot ${SDK} -mtvos-simulator-version-min=${TVOS_SIMULATOR_VERSION_MIN}"
export CFLAGS="-O3 -arch arm64 -isysroot ${SDK} -mtvos-simulator-version-min=${TVOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch arm64 -isysroot ${SDK} -mtvos-simulator-version-min=${TVOS_SIMULATOR_VERSION_MIN}"
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-darwin23 --prefix="$TVOS_SIMULATOR_ARM64_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
fi
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-darwin23 --prefix="$TVOS_SIMULATOR_ARM64_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
## x86_64 simulator
export CFLAGS="-Ofast -arch x86_64 -isysroot ${SDK} -mtvos-simulator-version-min=${TVOS_SIMULATOR_VERSION_MIN}"
export CFLAGS="-O3 -arch x86_64 -isysroot ${SDK} -mtvos-simulator-version-min=${TVOS_SIMULATOR_VERSION_MIN}"
export LDFLAGS="-arch x86_64 -isysroot ${SDK} -mtvos-simulator-version-min=${TVOS_SIMULATOR_VERSION_MIN}"
make distclean >/dev/null 2>&1
@ -272,7 +263,7 @@ build_visionos() {
export PATH="${BASEDIR}/usr/bin:$BASEDIR/usr/sbin:$PATH"
export SDK="${BASEDIR}/SDKs/XROS.sdk"
export CFLAGS="-Ofast -arch arm64 -isysroot ${SDK}"
export CFLAGS="-O3 -arch arm64 -isysroot ${SDK}"
export LDFLAGS="-arch arm64 -isysroot ${SDK}"
make distclean >/dev/null 2>&1
@ -286,15 +277,13 @@ build_visionos_simulator() {
export PATH="${BASEDIR}/usr/bin:$BASEDIR/usr/sbin:$PATH"
export SDK="${BASEDIR}/SDKs/XRSimulator.sdk"
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
export CFLAGS="-Ofast -arch arm64 -isysroot ${SDK}"
export LDFLAGS="-arch arm64 -isysroot ${SDK}"
export CFLAGS="-O3 -arch arm64 -isysroot ${SDK}"
export LDFLAGS="-arch arm64 -isysroot ${SDK}"
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-darwin23 --prefix="$VISIONOS_SIMULATOR_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
fi
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-darwin23 --prefix="$VISIONOS_SIMULATOR_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
}
build_catalyst() {
@ -303,18 +292,16 @@ build_catalyst() {
export SDK="${BASEDIR}/SDKs/MacOSX.sdk"
## arm64 catalyst
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
export CFLAGS="-Ofast -arch arm64 -target arm64-apple-ios13.1-macabi -isysroot ${SDK}"
export LDFLAGS="-arch arm64 -target arm64-apple-ios13.1-macabi -isysroot ${SDK}"
export CFLAGS="-O3 -arch arm64 -target arm64-apple-ios13.1-macabi -isysroot ${SDK}"
export LDFLAGS="-arch arm64 -target arm64-apple-ios13.1-macabi -isysroot ${SDK}"
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-ios --prefix="$CATALYST_ARM64_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
fi
make distclean >/dev/null 2>&1
./configure --host=aarch64-apple-ios --prefix="$CATALYST_ARM64_PREFIX" \
${LIBSODIUM_ENABLE_MINIMAL_FLAG} || exit 1
make -j${PROCESSORS} install || exit 1
## x86_64 catalyst
export CFLAGS="-Ofast -arch x86_64 -target x86_64-apple-ios13.1-macabi -isysroot ${SDK}"
export CFLAGS="-O3 -arch x86_64 -target x86_64-apple-ios13.1-macabi -isysroot ${SDK}"
export LDFLAGS="-arch x86_64 -target x86_64-apple-ios13.1-macabi -isysroot ${SDK}"
make distclean >/dev/null 2>&1
@ -333,10 +320,12 @@ echo "Building for watchOS..."
build_watchos >"$LOG_FILE" 2>&1 || exit 1
echo "Building for tvOS..."
build_tvos >"$LOG_FILE" 2>&1 || exit 1
echo "Building for visionOS..."
build_visionos >"$LOG_FILE" 2>&1 || exit 1
echo "Building for Catalyst..."
build_catalyst >"$LOG_FILE" 2>&1 || exit 1
if [ "$VISIONOS_SUPPORTED" = true ]; then
echo "Building for visionOS..."
build_visionos >"$LOG_FILE" 2>&1 || exit 1
fi
if [ -z "$LIBSODIUM_SKIP_SIMULATORS" ]; then
echo "Building for the iOS simulator..."
@ -345,8 +334,10 @@ if [ -z "$LIBSODIUM_SKIP_SIMULATORS" ]; then
build_watchos_simulator >"$LOG_FILE" 2>&1 || exit 1
echo "Building for the tvOS simulator..."
build_tvos_simulator >"$LOG_FILE" 2>&1 || exit 1
echo "Building for the visionOS simulator..."
build_visionos_simulator >"$LOG_FILE" 2>&1 || exit 1
if [ "$VISIONOS_SUPPORTED" = true ]; then
echo "Building for the visionOS simulator..."
build_visionos_simulator >"$LOG_FILE" 2>&1 || exit 1
fi
else
echo "[Skipping the simulators]"
fi
@ -362,16 +353,10 @@ echo "Bundling macOS targets..."
mkdir -p "${PREFIX}/macos/lib"
cp -a "${MACOS_X86_64_PREFIX}/include" "${PREFIX}/macos/"
for ext in a dylib; do
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
lipo -create \
"${MACOS_ARM64_PREFIX}/lib/libsodium.${ext}" \
"${MACOS_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/macos/lib/libsodium.${ext}"
else
lipo -create \
"${MACOS_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/macos/lib/libsodium.${ext}"
fi
lipo -create \
"${MACOS_ARM64_PREFIX}/lib/libsodium.${ext}" \
"${MACOS_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/macos/lib/libsodium.${ext}"
done
echo "Bundling iOS targets..."
@ -408,15 +393,17 @@ for ext in a dylib; do
-output "$PREFIX/tvos/lib/libsodium.${ext}"
done
echo "Bundling visionOS targets..."
if [ "$VISIONOS_SUPPORTED" = true ]; then
echo "Bundling visionOS targets..."
mkdir -p "${PREFIX}/visionos/lib"
cp -a "${VISIONOS_PREFIX}/include" "${PREFIX}/visionos/"
for ext in a dylib; do
lipo -create \
"$VISIONOS_PREFIX/lib/libsodium.${ext}" \
-output "$PREFIX/visionos/lib/libsodium.${ext}"
done
mkdir -p "${PREFIX}/visionos/lib"
cp -a "${VISIONOS_PREFIX}/include" "${PREFIX}/visionos/"
for ext in a dylib; do
lipo -create \
"$VISIONOS_PREFIX/lib/libsodium.${ext}" \
-output "$PREFIX/visionos/lib/libsodium.${ext}"
done
fi
echo "Bundling Catalyst targets..."
@ -426,16 +413,10 @@ for ext in a dylib; do
if [ ! -f "${CATALYST_X86_64_PREFIX}/lib/libsodium.${ext}" ]; then
continue
fi
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
lipo -create \
"${CATALYST_ARM64_PREFIX}/lib/libsodium.${ext}" \
"${CATALYST_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/catalyst/lib/libsodium.${ext}"
else
lipo -create \
"${CATALYST_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/catalyst/lib/libsodium.${ext}"
fi
lipo -create \
"${CATALYST_ARM64_PREFIX}/lib/libsodium.${ext}" \
"${CATALYST_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/catalyst/lib/libsodium.${ext}"
done
if [ -z "$LIBSODIUM_SKIP_SIMULATORS" ]; then
@ -444,18 +425,11 @@ if [ -z "$LIBSODIUM_SKIP_SIMULATORS" ]; then
mkdir -p "${PREFIX}/ios-simulators/lib"
cp -a "${IOS_SIMULATOR_X86_64_PREFIX}/include" "${PREFIX}/ios-simulators/"
for ext in a dylib; do
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
lipo -create \
"${IOS_SIMULATOR_ARM64_PREFIX}/lib/libsodium.${ext}" \
"${IOS_SIMULATOR_I386_PREFIX}/lib/libsodium.${ext}" \
"${IOS_SIMULATOR_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/ios-simulators/lib/libsodium.${ext}" || exit 1
else
lipo -create \
"${IOS_SIMULATOR_I386_PREFIX}/lib/libsodium.${ext}" \
"${IOS_SIMULATOR_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/ios-simulators/lib/libsodium.${ext}" || exit 1
fi
lipo -create \
"${IOS_SIMULATOR_ARM64_PREFIX}/lib/libsodium.${ext}" \
"${IOS_SIMULATOR_I386_PREFIX}/lib/libsodium.${ext}" \
"${IOS_SIMULATOR_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/ios-simulators/lib/libsodium.${ext}" || exit 1
done
echo "Bundling watchOS simulators..."
@ -463,18 +437,11 @@ if [ -z "$LIBSODIUM_SKIP_SIMULATORS" ]; then
mkdir -p "${PREFIX}/watchos-simulators/lib"
cp -a "${WATCHOS_SIMULATOR_X86_64_PREFIX}/include" "${PREFIX}/watchos-simulators/"
for ext in a dylib; do
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
lipo -create \
"${WATCHOS_SIMULATOR_ARM64_PREFIX}/lib/libsodium.${ext}" \
"${WATCHOS_SIMULATOR_I386_PREFIX}/lib/libsodium.${ext}" \
"${WATCHOS_SIMULATOR_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/watchos-simulators/lib/libsodium.${ext}"
else
lipo -create \
"${WATCHOS_SIMULATOR_I386_PREFIX}/lib/libsodium.${ext}" \
"${WATCHOS_SIMULATOR_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/watchos-simulators/lib/libsodium.${ext}"
fi
lipo -create \
"${WATCHOS_SIMULATOR_ARM64_PREFIX}/lib/libsodium.${ext}" \
"${WATCHOS_SIMULATOR_I386_PREFIX}/lib/libsodium.${ext}" \
"${WATCHOS_SIMULATOR_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/watchos-simulators/lib/libsodium.${ext}"
done
echo "Bundling tvOS simulators..."
@ -482,29 +449,23 @@ if [ -z "$LIBSODIUM_SKIP_SIMULATORS" ]; then
mkdir -p "${PREFIX}/tvos-simulators/lib"
cp -a "${TVOS_SIMULATOR_X86_64_PREFIX}/include" "${PREFIX}/tvos-simulators/"
for ext in a dylib; do
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
lipo -create \
"${TVOS_SIMULATOR_ARM64_PREFIX}/lib/libsodium.${ext}" \
"${TVOS_SIMULATOR_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/tvos-simulators/lib/libsodium.${ext}" || exit 1
else
lipo -create \
"${TVOS_SIMULATOR_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/tvos-simulators/lib/libsodium.${ext}" || exit 1
fi
lipo -create \
"${TVOS_SIMULATOR_ARM64_PREFIX}/lib/libsodium.${ext}" \
"${TVOS_SIMULATOR_X86_64_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/tvos-simulators/lib/libsodium.${ext}" || exit 1
done
echo "Bundling visionOS simulators..."
if [ "$VISIONOS_SUPPORTED" = true ]; then
echo "Bundling visionOS simulators..."
mkdir -p "${PREFIX}/visionos-simulators/lib"
cp -a "${VISIONOS_SIMULATOR_PREFIX}/include" "${PREFIX}/visionos-simulators/"
for ext in a dylib; do
if [ "$APPLE_SILICON_SUPPORTED" = "true" ]; then
mkdir -p "${PREFIX}/visionos-simulators/lib"
cp -a "${VISIONOS_SIMULATOR_PREFIX}/include" "${PREFIX}/visionos-simulators/"
for ext in a dylib; do
lipo -create \
"${VISIONOS_SIMULATOR_PREFIX}/lib/libsodium.${ext}" \
-output "${PREFIX}/visionos-simulators/lib/libsodium.${ext}" || exit 1
fi
done
done
fi
fi
echo "Creating Clibsodium.xcframework..."
@ -513,11 +474,17 @@ rm -rf "${PREFIX}/Clibsodium.xcframework"
XCFRAMEWORK_ARGS=""
for f in macos ios watchos tvos visionos catalyst; do
if [ "$VISIONOS_SUPPORTED" = false ] && [ "$f" = "visionos" ]; then
continue
fi
XCFRAMEWORK_ARGS="${XCFRAMEWORK_ARGS} -library ${PREFIX}/${f}/lib/libsodium.a"
XCFRAMEWORK_ARGS="${XCFRAMEWORK_ARGS} -headers ${PREFIX}/${f}/include"
done
if [ -z "$LIBSODIUM_SKIP_SIMULATORS" ]; then
for f in ios-simulators watchos-simulators tvos-simulators visionos-simulators; do
if [ "$VISIONOS_SUPPORTED" = false ] && [ "$f" = "visionos-simulators" ]; then
continue
fi
XCFRAMEWORK_ARGS="${XCFRAMEWORK_ARGS} -library ${PREFIX}/${f}/lib/libsodium.a"
XCFRAMEWORK_ARGS="${XCFRAMEWORK_ARGS} -headers ${PREFIX}/${f}/include"
done

@ -14,7 +14,7 @@ PROCESSORS=${NPROCESSORS:-3}
mkdir -p $PREFIX || exit 1
export CFLAGS="-mmacosx-version-min=${MACOS_VERSION_MIN} -Ofast"
export CFLAGS="-mmacosx-version-min=${MACOS_VERSION_MIN} -O3"
export LDFLAGS="-mmacosx-version-min=${MACOS_VERSION_MIN}"
make distclean >/dev/null

@ -1,6 +1,6 @@
#! /bin/sh
export CFLAGS="-Ofast -fomit-frame-pointer -m32 -march=pentium3 -mtune=westmere"
export CFLAGS="-O3 -fomit-frame-pointer -m32 -march=pentium3 -mtune=westmere"
export PREFIX="$(pwd)/libsodium-win32"
if (i686-w64-mingw32-gcc --version >/dev/null 2>&1); then

@ -1,6 +1,6 @@
#! /bin/sh
export CFLAGS="-Ofast -fomit-frame-pointer -m64 -mtune=westmere"
export CFLAGS="-O3 -fomit-frame-pointer -m64 -mtune=westmere"
export PREFIX="$(pwd)/libsodium-win64"
if (x86_64-w64-mingw32-gcc --version >/dev/null 2>&1); then

@ -17,12 +17,6 @@
#include "aegis128l_armcrypto.h"
#ifdef __clang__
#pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), apply_to = function)
#elif defined(__GNUC__)
#pragma GCC target("+simd+crypto")
#endif
#ifndef __ARM_FEATURE_CRYPTO
#define __ARM_FEATURE_CRYPTO 1
#endif
@ -32,6 +26,12 @@
#include <arm_neon.h>
#ifdef __clang__
#pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), apply_to = function)
#elif defined(__GNUC__)
#pragma GCC target("+simd+crypto")
#endif
#define AES_BLOCK_LENGTH 16
typedef uint8x16_t aes_block_t;

@ -17,12 +17,6 @@
#include "aegis256_armcrypto.h"
#ifdef __clang__
#pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), apply_to = function)
#elif defined(__GNUC__)
#pragma GCC target("+simd+crypto")
#endif
#ifndef __ARM_FEATURE_CRYPTO
#define __ARM_FEATURE_CRYPTO 1
#endif
@ -32,6 +26,12 @@
#include <arm_neon.h>
#ifdef __clang__
#pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), apply_to = function)
#elif defined(__GNUC__)
#pragma GCC target("+simd+crypto")
#endif
#define AES_BLOCK_LENGTH 16
typedef uint8x16_t aes_block_t;

@ -19,12 +19,6 @@
#define __vectorcall
#endif
#ifdef __clang__
#pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), apply_to = function)
#elif defined(__GNUC__)
#pragma GCC target("+simd+crypto")
#endif
#ifndef __ARM_FEATURE_CRYPTO
#define __ARM_FEATURE_CRYPTO 1
#endif
@ -34,6 +28,12 @@
#include <arm_neon.h>
#ifdef __clang__
#pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), apply_to = function)
#elif defined(__GNUC__)
#pragma GCC target("+simd+crypto")
#endif
#define ABYTES crypto_aead_aes256gcm_ABYTES
#define NPUBBYTES crypto_aead_aes256gcm_NPUBBYTES
#define KEYBYTES crypto_aead_aes256gcm_KEYBYTES

@ -228,7 +228,7 @@ xor_buf(unsigned char *out, const unsigned char *in, size_t n)
#ifdef _MSC_VER
# if defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86)
# if defined(_M_X64) || defined(_M_IX86)
# include <intrin.h>
# define HAVE_INTRIN_H 1

@ -9,7 +9,7 @@
#if defined(HAVE_EMMINTRIN_H) && \
!(defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || \
defined(_M_X64) || defined(_M_AMD64))
defined(_M_X64))
# include <emmintrin.h>
# include <stdint.h>

@ -150,8 +150,7 @@ _sodium_runtime_arm_cpu_features(CPUFeatures * const cpu_features)
static void
_cpuid(unsigned int cpu_info[4U], const unsigned int cpu_info_type)
{
#if defined(_MSC_VER) && \
(defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86))
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
__cpuid((int *) cpu_info, cpu_info_type);
#elif defined(HAVE_CPUID)
cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;

@ -125,7 +125,7 @@ jobs:
# this ensure install latest qemu on ubuntu, apt get version is old
env:
QEMU_SRC: "http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu"
QEMU_VER: "qemu-user-static_7\\.0+dfsg-.*_amd64.deb$"
QEMU_VER: "qemu-user-static_7\\.2+dfsg-.*_amd64.deb$"
run: |
DEB=`curl -s $QEMU_SRC/ | grep -o -E 'href="([^"#]+)"' | cut -d'"' -f2 | grep $QEMU_VER | tail -1`
wget $QEMU_SRC/$DEB

@ -26,6 +26,8 @@ jobs:
- {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022}
- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022}
- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN}
- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: UBSAN}
- {toolchain: Visual Studio 17 2022, arch: arm64, server: 2022}
steps:
- uses: actions/checkout@v2
- name: Envinfo
@ -35,30 +37,33 @@ jobs:
run:
cmake -S . -B build -DBUILD_TESTING=ON
-G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }}
${{ matrix.config.config == 'ASAN' && '-DASAN=on -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded' || '' }}
${{ matrix.config.config == 'ASAN' && '-DASAN=on -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded' ||
matrix.config.config == 'UBSAN' && '-DUBSAN=on' || '' }}
cmake --build build --config RelWithDebInfo
ls -l build
- name: platform_output
if: ${{ matrix.config.arch != 'arm64' }}
shell: cmd
run:
build\\RelWithDebInfo\\uv_run_tests.exe platform_output
- name: platform_output_a
if: ${{ matrix.config.arch != 'arm64' }}
shell: cmd
run:
build\\RelWithDebInfo\\uv_run_tests_a.exe platform_output
- name: Test
# only valid with libuv-master with the fix for
# https://github.com/libuv/leps/blob/master/005-windows-handles-not-fd.md
if: ${{ matrix.config.config != 'ASAN' }}
if: ${{ matrix.config.config != 'ASAN' && matrix.config.arch != 'arm64' }}
shell: cmd
run:
cd build
ctest -C RelWithDebInfo -V
- name: Test only static
if: ${{ matrix.config.config == 'ASAN' }}
if: ${{ matrix.config.config == 'ASAN' && matrix.config.arch != 'arm64' }}
shell: cmd
run:
build\\RelWithDebInfo\\uv_run_tests_a.exe

@ -13,7 +13,7 @@ on:
- master
jobs:
sanitizers:
sanitizers-linux:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
@ -60,3 +60,64 @@ jobs:
- name: UBSAN Test
run: |
./build-ubsan/uv_run_tests_a
sanitizers-macos:
runs-on: macos-11
steps:
- uses: actions/checkout@v2
- name: Envinfo
run: npx envinfo
- name: ASAN Build
run: |
mkdir build-asan
(cd build-asan && cmake .. -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug)
cmake --build build-asan
- name: ASAN Test
run: |
./build-asan/uv_run_tests_a
- name: TSAN Build
run: |
mkdir build-tsan
(cd build-tsan && cmake .. -DBUILD_TESTING=ON -DTSAN=ON -DCMAKE_BUILD_TYPE=Release)
cmake --build build-tsan
- name: TSAN Test
run: |
./build-tsan/uv_run_tests_a
- name: UBSAN Build
run: |
mkdir build-ubsan
(cd build-ubsan && cmake .. -DBUILD_TESTING=ON -DUBSAN=ON -DCMAKE_BUILD_TYPE=Debug)
cmake --build build-ubsan
- name: UBSAN Test
run: |
./build-ubsan/uv_run_tests_a
sanitizers-windows:
runs-on: windows-2022
steps:
- uses: actions/checkout@v2
- name: Setup
run: |
choco install ninja
# Note: clang shipped with VS2022 has an issue where the UBSAN runtime doesn't link.
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v1
with:
version: "17"
- name: Envinfo
run: npx envinfo
- name: UBSAN Build
run: |
mkdir build-ubsan
cmake -B build-ubsan -G Ninja -DBUILD_TESTING=ON -DUBSAN=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang
cmake --build build-ubsan
- name: UBSAN Test
run: |
./build-ubsan/uv_run_tests_a

12
deps/libuv/AUTHORS vendored

@ -548,3 +548,15 @@ liuxiang88 <94350585+liuxiang88@users.noreply.github.com>
Jeffrey H. Johnson <trnsz@pobox.com>
Abdirahim Musse <33973272+abmusse@users.noreply.github.com>
小明 <7737673+caobug@users.noreply.github.com>
Shuduo Sang <sangshuduo@gmail.com>
Keith Winstein <keithw@cs.stanford.edu>
michalbiesek <michalbiesek@gmail.com>
Alois Klink <alois@aloisklink.com>
SmorkalovG <smorkalov.g@gmail.com>
Pleuvens <pleuvens.fervil@gmail.com>
jolai <58589285+laijonathan@users.noreply.github.com>
Julien Roncaglia <fox@vbfox.net>
prubel <paul@rubels.net>
Per Allansson <65364157+per-allansson@users.noreply.github.com>
Matheus Izvekov <mizvekov@gmail.com>
Christian Heimlich <chris@pcserenity.com>

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.4)
cmake_minimum_required(VERSION 3.9)
if(POLICY CMP0091)
cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting
@ -186,7 +186,8 @@ if(WIN32)
ws2_32
dbghelp
ole32
uuid)
uuid
shell32)
list(APPEND uv_sources
src/win/async.c
src/win/core.c
@ -477,7 +478,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS390")
endif()
target_link_libraries(uv_a ${uv_libraries})
set_target_properties(uv_a PROPERTIES OUTPUT_NAME "uv")
if(MSVC)
if(WIN32)
set_target_properties(uv_a PROPERTIES PREFIX "lib")
endif()

111
deps/libuv/ChangeLog vendored

@ -1,4 +1,113 @@
2023.06.30, Version 1.46.0 (Stable)
2023.11.06, Version 1.47.0 (Stable)
Changes since version 1.46.0:
* test: fix license blurb (Ben Noordhuis)
* linux: fix harmless warn_unused_result warning (Shuduo Sang)
* darwin: fix build warnings (小明)
* linux: don't use io_uring on pre-5.10.186 kernels (Ben Noordhuis)
* fs: fix WTF-8 decoding issue (Jameson Nash)
* test: enable disabled tcp_connect6_error_fault (Ben Noordhuis)
* test: enable disabled fs_link (Ben Noordhuis)
* test: enable disabled spawn_same_stdout_stderr (Ben Noordhuis)
* linux: handle UNAME26 personality (Ben Noordhuis)
* build: move cmake_minimum_required version to 3.9 (Keith Winstein)
* unix: set ipv6 scope id for link-local addresses (Ben Noordhuis)
* unix: match kqueue and epoll code (Trevor Norris)
* win,spawn: allow `%PATH%` to be unset (Kyle Edwards)
* doc: switch to Furo, a more modern Sphinx theme (Saúl Ibarra Corretgé)
* darwin: make TCP_KEEPINTVL and TCP_KEEPCNT available (小明)
* win,fs: avoid winapi macro redefinition (Brad King)
* linux: add missing riscv syscall numbers (michalbiesek)
* doc: fix broken "Shared library" Wikipedia link (Alois Klink)
* unix: get mainline kernel version in Ubuntu (Santiago Gimeno)
* unix: get mainline kernel version in Debian (Ben Noordhuis)
* build: fix qemu install in CI-unix workflow (Santiago Gimeno)
* unix: disable io_uring close on selected kernels (Santiago Gimeno)
* test: skip tests when ipv6 is not available (Santiago Gimeno)
* ibmi: implement ifaddrs, getifaddrs, freeifaddrs (Abdirahim Musse)
* unix: reset signal counters after fork (SmorkalovG)
* win,process: avoid assert after spawning Store app (Jameson Nash)
* unix: remove pread/preadv conditionals (Ben Noordhuis)
* unix: remove pwrite/pwritev conditionals (Ben Noordhuis)
* darwin: remove workaround for data corruption bug (Ben Noordhuis)
* src: default to stream=stderr in handle printer (Ben Noordhuis)
* test: switch to new-style ASSERT_EQ macros (Pleuvens)
* zos: correctly get cpu model in uv_cpu_info() (jolai)
* test: fix get_passwd2 on IBM i (Abdirahim Musse)
* unix: don't malloc on sync uv_fs_read (Ben Noordhuis)
* freebsd: get fs event path with fcntl(F_KINFO) (David Carlier)
* test: switch from ASSERT_* to ASSERT_PTR_* (Pleuvens)
* darwin: workaround apple pthread_cond_wait bug (Julien Roncaglia)
* doc: uv_close should be called after exit callback (Pleuvens)
* test: 192.0.2.0/24 is the actual -TEST-NET-1 (prubel)
* unix: add back preadv/pwritev fallback (Ben Noordhuis)
* unix: rename variable for consistency (Ben Noordhuis)
* unix: merge read/write code into single functions (Ben Noordhuis)
* doc: filename arg to uv_fs_event_cb can be NULL (Ben Noordhuis)
* build,win: we need to link against shell32.lib (Per Allansson)
* unix: no preadv/pwritev workaround if not needed (Jeffrey H. Johnson)
* build: add CI for Windows ARM64 (build only) (Per Allansson)
* linux: disable io_uring on 32 bits arm systems (Ben Noordhuis)
* build: run sanitizers on macos ci (Ben Noordhuis)
* misc: export WTF8 conversion utilities (Jameson Nash)
* build: fix libuv.a file name for cmake (Jameson Nash)
* build: add windows ubsan and clang ci (Matheus Izvekov)
* win: improve accuracy of ProductName between arch (Christian Heimlich)
2023.06.30, Version 1.46.0 (Stable), f0bb7e40f0508bedf6fad33769b3f87bb8aedfa6
Changes since version 1.45.0:

@ -13,7 +13,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57)
AC_INIT([libuv], [1.46.0], [https://github.com/libuv/libuv/issues])
AC_INIT([libuv], [1.47.0], [https://github.com/libuv/libuv/issues])
AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4])
m4_include([m4/as_case.m4])
@ -74,7 +74,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false])
AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])])
AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])])
AS_CASE([$host_os],[mingw*], [
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32 -ldbghelp -lole32 -luuid"
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32 -ldbghelp -lole32 -luuid -lshell32"
])
AS_CASE([$host_os], [solaris2.10], [
CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS"

@ -1,27 +1,36 @@
# primary
sphinx==6.1.3
furo==2023.5.20
Sphinx==6.1.3
# dependencies
alabaster==0.7.13
Babel==2.11.0
beautifulsoup4==4.12.2
certifi==2022.12.7
charset-normalizer==3.0.1
colorama==0.4.6
docutils==0.19
idna==3.4
imagesize==1.4.1
importlib-metadata==6.0.0
Jinja2==3.1.2
livereload==2.6.3
MarkupSafe==2.1.2
packaging==23.0
Pygments==2.14.0
pytz==2022.7.1
requests==2.28.2
six==1.16.0
snowballstemmer==2.2.0
sphinxcontrib-applehelp==1.0.3
soupsieve==2.4.1
sphinx-autobuild==2021.3.14
sphinx-basic-ng==1.0.0b2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
sphinxcontrib.applehelp==1.0.3
tornado==6.3.2
urllib3==1.26.14
zipp==3.11.0

@ -118,7 +118,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'nature'
html_theme = 'furo'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the

@ -39,8 +39,12 @@ Data types
.. c:type:: void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, int events, int status)
Callback passed to :c:func:`uv_fs_event_start` which will be called repeatedly
after the handle is started. If the handle was started with a directory the
`filename` parameter will be a relative path to a file contained in the directory.
after the handle is started.
If the handle was started with a directory the `filename` parameter will
be a relative path to a file contained in the directory, or `NULL` if the
file name cannot be determined.
The `events` parameter is an ORed mask of :c:type:`uv_fs_event` elements.
.. c:type:: uv_fs_event

@ -53,6 +53,8 @@ ID of the child process.
The exit callback will be invoked with the *exit status* and the type of *signal*
which caused the exit.
Note that it is important **not** to call ``uv_close`` before the exit callback.
.. rubric:: spawn/main.c
.. literalinclude:: ../../code/spawn/main.c
:language: c
@ -126,7 +128,8 @@ of ``uv_kill`` is::
For processes started using libuv, you may use ``uv_process_kill`` instead,
which accepts the ``uv_process_t`` watcher as the first argument, rather than
the pid. In this case, **remember to call** ``uv_close`` on the watcher.
the pid. In this case, **remember to call** ``uv_close`` on the watcher _after_
the exit callback has been called.
Signals
-------

@ -363,7 +363,7 @@ to get the error message.
argument. ``init_plugin_function`` is a function pointer to the sort of
function we are looking for in the application's plugins.
.. _shared libraries: https://en.wikipedia.org/wiki/Shared_library#Shared_libraries
.. _shared libraries: https://en.wikipedia.org/wiki/Shared_library
TTY
---

@ -839,3 +839,50 @@ API
Causes the calling thread to sleep for `msec` milliseconds.
.. versionadded:: 1.34.0
String manipulation functions
-----------------------------
These string utilities are needed internally for dealing with Windows, and are
exported to allow clients to work uniformly with this data when the libuv API
is not complete.
.. c:function:: size_t uv_utf16_length_as_wtf8(const uint16_t* utf16, ssize_t utf16_len)
Get the length of a UTF-16 (or UCS-2) `utf16` value after converting it to
WTF-8. If `utf16` is NUL terminated, `utf16_len` can be set to -1,
otherwise it must be specified.
.. versionadded:: 1.47.0
.. c:function:: int uv_utf16_to_wtf8(const uint16_t* utf16, ssize_t utf16_len, char** wtf8_ptr, size_t* wtf8_len_ptr)
Convert UTF-16 (or UCS-2) data in `utf16` to WTF-8 data in `*wtf8_ptr`. The
`utf16_len` count (in characters) gives the length of `utf16`. If `utf16`
is NUL terminated, `utf16_len` can be set to -1, otherwise it must be
specified. If `wtf8_ptr` is `NULL`, no result will be computed, but the
length (equal to `uv_utf16_length_as_wtf8`) will be stored in `wtf8_ptr`.
If `*wtf8_ptr` is `NULL`, space for the conversion will be allocated and
returned in `wtf8_ptr` and the length will be returned in `wtf8_len_ptr`.
Otherwise, the length of `*wtf8_ptr` must be passed in `wtf8_len_ptr`. The
`wtf8_ptr` must contain an extra space for an extra NUL after the result.
If the result is truncated, `UV_ENOBUFS` will be returned and
`wtf8_len_ptr` will be the length of the required `wtf8_ptr` to contain the
whole result.
.. versionadded:: 1.47.0
.. c:function:: ssize_t uv_wtf8_length_as_utf16(const char* wtf8)
Get the length in characters of a NUL-terminated WTF-8 `wtf8` value
after converting it to UTF-16 (or UCS-2), including NUL terminator.
.. versionadded:: 1.47.0
.. c:function:: void uv_wtf8_to_utf16(const char* utf8, uint16_t* utf16, size_t utf16_len)
Convert NUL-terminated WTF-8 data in `wtf8` to UTF-16 (or UCS-2) data
in `utf16`. The `utf16_len` count (in characters) must include space
for the NUL terminator.
.. versionadded:: 1.47.0

@ -1885,6 +1885,18 @@ struct uv_loop_s {
UV_EXTERN void* uv_loop_get_data(const uv_loop_t*);
UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
/* String utilities needed internally for dealing with Windows. */
size_t uv_utf16_length_as_wtf8(const uint16_t* utf16,
ssize_t utf16_len);
int uv_utf16_to_wtf8(const uint16_t* utf16,
ssize_t utf16_len,
char** wtf8_ptr,
size_t* wtf8_len_ptr);
ssize_t uv_wtf8_length_as_utf16(const char* wtf8);
void uv_wtf8_to_utf16(const char* wtf8,
uint16_t* utf16,
size_t utf16_len);
/* Don't export the private CPP symbols. */
#undef UV_HANDLE_TYPE_PRIVATE
#undef UV_REQ_TYPE_PRIVATE

@ -31,7 +31,7 @@
*/
#define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 46
#define UV_VERSION_MINOR 47
#define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX ""

244
deps/libuv/src/idna.c vendored

@ -1,4 +1,4 @@
/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
/* Copyright libuv contributors. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -18,11 +18,56 @@
*/
#include "uv.h"
#include "uv-common.h"
#include "idna.h"
#include <assert.h>
#include <string.h>
#include <limits.h> /* UINT_MAX */
static int32_t uv__wtf8_decode1(const char** input) {
uint32_t code_point;
uint8_t b1;
uint8_t b2;
uint8_t b3;
uint8_t b4;
b1 = **input;
if (b1 <= 0x7F)
return b1; /* ASCII code point */
if (b1 < 0xC2)
return -1; /* invalid: continuation byte */
code_point = b1;
b2 = *++*input;
if ((b2 & 0xC0) != 0x80)
return -1; /* invalid: not a continuation byte */
code_point = (code_point << 6) | (b2 & 0x3F);
if (b1 <= 0xDF)
return 0x7FF & code_point; /* two-byte character */
b3 = *++*input;
if ((b3 & 0xC0) != 0x80)
return -1; /* invalid: not a continuation byte */
code_point = (code_point << 6) | (b3 & 0x3F);
if (b1 <= 0xEF)
return 0xFFFF & code_point; /* three-byte character */
b4 = *++*input;
if ((b4 & 0xC0) != 0x80)
return -1; /* invalid: not a continuation byte */
code_point = (code_point << 6) | (b4 & 0x3F);
if (b1 <= 0xF4) {
code_point &= 0x1FFFFF;
if (code_point <= 0x10FFFF)
return code_point; /* four-byte character */
}
/* code point too large */
return -1;
}
static unsigned uv__utf8_decode1_slow(const char** p,
const char* pe,
unsigned a) {
@ -89,6 +134,7 @@ static unsigned uv__utf8_decode1_slow(const char** p,
return a;
}
unsigned uv__utf8_decode1(const char** p, const char* pe) {
unsigned a;
@ -102,6 +148,7 @@ unsigned uv__utf8_decode1(const char** p, const char* pe) {
return uv__utf8_decode1_slow(p, pe, a);
}
static int uv__idna_toascii_label(const char* s, const char* se,
char** d, char* de) {
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
@ -267,7 +314,8 @@ static int uv__idna_toascii_label(const char* s, const char* se,
return 0;
}
long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
const char* si;
const char* st;
unsigned c;
@ -313,3 +361,195 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
return d - ds; /* Number of bytes written. */
}
ssize_t uv_wtf8_length_as_utf16(const char* source_ptr) {
size_t w_target_len = 0;
int32_t code_point;
do {
code_point = uv__wtf8_decode1(&source_ptr);
if (code_point < 0)
return -1;
if (code_point > 0xFFFF)
w_target_len++;
w_target_len++;
} while (*source_ptr++);
return w_target_len;
}
void uv_wtf8_to_utf16(const char* source_ptr,
uint16_t* w_target,
size_t w_target_len) {
int32_t code_point;
do {
code_point = uv__wtf8_decode1(&source_ptr);
/* uv_wtf8_length_as_utf16 should have been called and checked first. */
assert(code_point >= 0);
if (code_point > 0x10000) {
assert(code_point < 0x10FFFF);
*w_target++ = (((code_point - 0x10000) >> 10) + 0xD800);
*w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00;
w_target_len -= 2;
} else {
*w_target++ = code_point;
w_target_len -= 1;
}
} while (*source_ptr++);
assert(w_target_len == 0);
}
static int32_t uv__get_surrogate_value(const uint16_t* w_source_ptr,
ssize_t w_source_len) {
uint16_t u;
uint16_t next;
u = w_source_ptr[0];
if (u >= 0xD800 && u <= 0xDBFF && w_source_len != 1) {
next = w_source_ptr[1];
if (next >= 0xDC00 && next <= 0xDFFF)
return 0x10000 + ((u - 0xD800) << 10) + (next - 0xDC00);
}
return u;
}
size_t uv_utf16_length_as_wtf8(const uint16_t* w_source_ptr,
ssize_t w_source_len) {
size_t target_len;
int32_t code_point;
target_len = 0;
while (w_source_len) {
code_point = uv__get_surrogate_value(w_source_ptr, w_source_len);
/* Can be invalid UTF-8 but must be valid WTF-8. */
assert(code_point >= 0);
if (w_source_len < 0 && code_point == 0)
break;
if (code_point < 0x80)
target_len += 1;
else if (code_point < 0x800)
target_len += 2;
else if (code_point < 0x10000)
target_len += 3;
else {
target_len += 4;
w_source_ptr++;
if (w_source_len > 0)
w_source_len--;
}
w_source_ptr++;
if (w_source_len > 0)
w_source_len--;
}
return target_len;
}
int uv_utf16_to_wtf8(const uint16_t* w_source_ptr,
ssize_t w_source_len,
char** target_ptr,
size_t* target_len_ptr) {
size_t target_len;
char* target;
char* target_end;
int32_t code_point;
/* If *target_ptr is provided, then *target_len_ptr must be its length
* (excluding space for NUL), otherwise we will compute the target_len_ptr
* length and may return a new allocation in *target_ptr if target_ptr is
* provided. */
if (target_ptr == NULL || *target_ptr == NULL) {
target_len = uv_utf16_length_as_wtf8(w_source_ptr, w_source_len);
if (target_len_ptr != NULL)
*target_len_ptr = target_len;
} else {
target_len = *target_len_ptr;
}
if (target_ptr == NULL)
return 0;
if (*target_ptr == NULL) {
target = uv__malloc(target_len + 1);
if (target == NULL) {
return UV_ENOMEM;
}
*target_ptr = target;
} else {
target = *target_ptr;
}
target_end = target + target_len;
while (target != target_end && w_source_len) {
code_point = uv__get_surrogate_value(w_source_ptr, w_source_len);
/* Can be invalid UTF-8 but must be valid WTF-8. */
assert(code_point >= 0);
if (w_source_len < 0 && code_point == 0) {
w_source_len = 0;
break;
}
if (code_point < 0x80) {
*target++ = code_point;
} else if (code_point < 0x800) {
*target++ = 0xC0 | (code_point >> 6);
if (target == target_end)
break;
*target++ = 0x80 | (code_point & 0x3F);
} else if (code_point < 0x10000) {
*target++ = 0xE0 | (code_point >> 12);
if (target == target_end)
break;
*target++ = 0x80 | ((code_point >> 6) & 0x3F);
if (target == target_end)
break;
*target++ = 0x80 | (code_point & 0x3F);
} else {
*target++ = 0xF0 | (code_point >> 18);
if (target == target_end)
break;
*target++ = 0x80 | ((code_point >> 12) & 0x3F);
if (target == target_end)
break;
*target++ = 0x80 | ((code_point >> 6) & 0x3F);
if (target == target_end)
break;
*target++ = 0x80 | (code_point & 0x3F);
/* uv__get_surrogate_value consumed 2 input characters */
w_source_ptr++;
if (w_source_len > 0)
w_source_len--;
}
target_len = target - *target_ptr;
w_source_ptr++;
if (w_source_len > 0)
w_source_len--;
}
if (target != target_end && target_len_ptr != NULL)
/* Did not fill all of the provided buffer, so update the target_len_ptr
* output with the space used. */
*target_len_ptr = target - *target_ptr;
/* Check if input fit into target exactly. */
if (w_source_len < 0 && target == target_end && w_source_ptr[0] == 0)
w_source_len = 0;
*target++ = '\0';
/* Characters remained after filling the buffer, compute the remaining length now. */
if (w_source_len) {
if (target_len_ptr != NULL)
*target_len_ptr = target_len + uv_utf16_length_as_wtf8(w_source_ptr, w_source_len);
return UV_ENOBUFS;
}
return 0;
}

@ -1,4 +1,4 @@
/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
/* Copyright libuv contributors. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -26,6 +26,6 @@ unsigned uv__utf8_decode1(const char** p, const char* pe);
* is the number of bytes written to |d|, including the trailing nul byte.
* A return value < 0 is a libuv error code. |s| and |d| can not overlap.
*/
long uv__idna_toascii(const char* s, const char* se, char* d, char* de);
ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de);
#endif /* UV_SRC_IDNA_H_ */

@ -209,7 +209,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
if (cpuspeed == 0)
/* If sysctl hw.cputype == CPU_TYPE_ARM64, the correct value is unavailable
* from Apple, but we can hard-code it here to a plausible value. */
cpuspeed = 2400000000;
cpuspeed = 2400000000U;
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
(processor_info_array_t*)&info,
@ -235,7 +235,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
cpu_info->cpu_times.irq = 0;
cpu_info->model = uv__strdup(model);
cpu_info->speed = cpuspeed/1000000;
cpu_info->speed = (int)(cpuspeed / 1000000);
}
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);

@ -41,25 +41,10 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
# define HAVE_PREADV 1
#else
# define HAVE_PREADV 0
#endif
/* preadv() and pwritev() were added in Android N (level 24) */
#if defined(__linux__) && !(defined(__ANDROID__) && __ANDROID_API__ < 24)
# define TRY_PREADV 1
#endif
#if defined(__linux__)
# include <sys/sendfile.h>
#endif
@ -97,6 +82,15 @@
# include <sys/statfs.h>
#endif
#if defined(__CYGWIN__) || \
(defined(__HAIKU__) && B_HAIKU_VERSION < B_HAIKU_VERSION_1_PRE_BETA_5) || \
(defined(__sun) && !defined(__illumos__))
#define preadv(fd, bufs, nbufs, off) \
pread(fd, (bufs)->iov_base, (bufs)->iov_len, off)
#define pwritev(fd, bufs, nbufs, off) \
pwrite(fd, (bufs)->iov_base, (bufs)->iov_len, off)
#endif
#if defined(_AIX) && _XOPEN_SOURCE <= 600
extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
#endif
@ -410,123 +404,57 @@ static ssize_t uv__fs_open(uv_fs_t* req) {
}
#if !HAVE_PREADV
static ssize_t uv__fs_preadv(uv_file fd,
uv_buf_t* bufs,
unsigned int nbufs,
off_t off) {
uv_buf_t* buf;
uv_buf_t* end;
ssize_t result;
ssize_t rc;
size_t pos;
assert(nbufs > 0);
result = 0;
pos = 0;
buf = bufs + 0;
end = bufs + nbufs;
for (;;) {
do
rc = pread(fd, buf->base + pos, buf->len - pos, off + result);
while (rc == -1 && errno == EINTR);
if (rc == 0)
break;
if (rc == -1 && result == 0)
return UV__ERR(errno);
if (rc == -1)
break; /* We read some data so return that, ignore the error. */
pos += rc;
result += rc;
if (pos < buf->len)
continue;
pos = 0;
buf += 1;
if (buf == end)
break;
}
return result;
}
#endif
static ssize_t uv__fs_read(uv_fs_t* req) {
#if TRY_PREADV
static _Atomic int no_preadv;
#endif
const struct iovec* bufs;
unsigned int iovmax;
ssize_t result;
size_t nbufs;
ssize_t r;
off_t off;
int fd;
fd = req->file;
off = req->off;
bufs = (const struct iovec*) req->bufs;
nbufs = req->nbufs;
iovmax = uv__getiovmax();
if (req->nbufs > iovmax)
req->nbufs = iovmax;
if (nbufs > iovmax)
nbufs = iovmax;
if (req->off < 0) {
if (req->nbufs == 1)
result = read(req->file, req->bufs[0].base, req->bufs[0].len);
else
result = readv(req->file, (struct iovec*) req->bufs, req->nbufs);
r = 0;
if (off < 0) {
if (nbufs == 1)
r = read(fd, bufs->iov_base, bufs->iov_len);
else if (nbufs > 1)
r = readv(fd, bufs, nbufs);
} else {
if (req->nbufs == 1) {
result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
goto done;
}
#if HAVE_PREADV
result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
#else
# if TRY_PREADV
if (atomic_load_explicit(&no_preadv, memory_order_relaxed)) retry:
# endif
{
result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
}
# if TRY_PREADV
else {
result = preadv(req->file,
(struct iovec*) req->bufs,
req->nbufs,
req->off);
if (result == -1 && errno == ENOSYS) {
atomic_store_explicit(&no_preadv, 1, memory_order_relaxed);
goto retry;
}
}
# endif
#endif
if (nbufs == 1)
r = pread(fd, bufs->iov_base, bufs->iov_len, off);
else if (nbufs > 1)
r = preadv(fd, bufs, nbufs, off);
}
done:
/* Early cleanup of bufs allocation, since we're done with it. */
if (req->bufs != req->bufsml)
uv__free(req->bufs);
req->bufs = NULL;
req->nbufs = 0;
#ifdef __PASE__
/* PASE returns EOPNOTSUPP when reading a directory, convert to EISDIR */
if (result == -1 && errno == EOPNOTSUPP) {
if (r == -1 && errno == EOPNOTSUPP) {
struct stat buf;
ssize_t rc;
rc = uv__fstat(req->file, &buf);
rc = uv__fstat(fd, &buf);
if (rc == 0 && S_ISDIR(buf.st_mode)) {
errno = EISDIR;
}
}
#endif
return result;
/* We don't own the buffer list in the synchronous case. */
if (req->cb != NULL)
if (req->bufs != req->bufsml)
uv__free(req->bufs);
req->bufs = NULL;
req->nbufs = 0;
return r;
}
@ -1161,65 +1089,34 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
static ssize_t uv__fs_write(uv_fs_t* req) {
#if TRY_PREADV
static _Atomic int no_pwritev;
#endif
const struct iovec* bufs;
size_t nbufs;
ssize_t r;
off_t off;
int fd;
/* Serialize writes on OS X, concurrent write() and pwrite() calls result in
* data loss. We can't use a per-file descriptor lock, the descriptor may be
* a dup().
*/
#if defined(__APPLE__)
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
fd = req->file;
off = req->off;
bufs = (const struct iovec*) req->bufs;
nbufs = req->nbufs;
if (pthread_mutex_lock(&lock))
abort();
#endif
if (req->off < 0) {
if (req->nbufs == 1)
r = write(req->file, req->bufs[0].base, req->bufs[0].len);
else
r = writev(req->file, (struct iovec*) req->bufs, req->nbufs);
r = 0;
if (off < 0) {
if (nbufs == 1)
r = write(fd, bufs->iov_base, bufs->iov_len);
else if (nbufs > 1)
r = writev(fd, bufs, nbufs);
} else {
if (req->nbufs == 1) {
r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
goto done;
}
#if HAVE_PREADV
r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
#else
# if TRY_PREADV
if (atomic_load_explicit(&no_pwritev, memory_order_relaxed)) retry:
# endif
{
r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
}
# if TRY_PREADV
else {
r = pwritev(req->file,
(struct iovec*) req->bufs,
req->nbufs,
req->off);
if (r == -1 && errno == ENOSYS) {
atomic_store_explicit(&no_pwritev, 1, memory_order_relaxed);
goto retry;
}
}
# endif
#endif
if (nbufs == 1)
r = pwrite(fd, bufs->iov_base, bufs->iov_len, off);
else if (nbufs > 1)
r = pwritev(fd, bufs, nbufs, off);
}
done:
#if defined(__APPLE__)
if (pthread_mutex_unlock(&lock))
abort();
#endif
return r;
}
static ssize_t uv__fs_copyfile(uv_fs_t* req) {
uv_fs_t fs_req;
uv_file srcfd;
@ -1979,9 +1876,14 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
if (bufs == NULL || nbufs == 0)
return UV_EINVAL;
req->off = off;
req->file = file;
req->bufs = (uv_buf_t*) bufs; /* Safe, doesn't mutate |bufs| */
req->nbufs = nbufs;
if (cb == NULL)
goto post;
req->bufs = req->bufsml;
if (nbufs > ARRAY_SIZE(req->bufsml))
req->bufs = uv__malloc(nbufs * sizeof(*bufs));
@ -1991,12 +1893,10 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
req->off = off;
if (cb != NULL)
if (uv__iou_fs_read_or_write(loop, req, /* is_read */ 1))
return 0;
if (uv__iou_fs_read_or_write(loop, req, /* is_read */ 1))
return 0;
post:
POST;
}

@ -30,6 +30,9 @@
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#if defined(__FreeBSD__)
#include <sys/user.h>
#endif
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
@ -262,6 +265,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (nfds == -1)
assert(errno == EINTR);
else if (nfds == 0)
/* Unlimited timeout should only return with events or signal. */
assert(timeout != -1);
if (pset != NULL)
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
@ -286,8 +292,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
timeout = user_timeout;
reset_timeout = 0;
} else if (nfds == 0) {
/* Reached the user timeout value. */
assert(timeout != -1);
return;
}
@ -479,6 +483,16 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
*/
if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
path = uv__basename_r(pathbuf);
#elif defined(F_KINFO)
/* We try to get the file info reference from the file descriptor.
* the struct's kf_structsize must be initialised beforehand
* whether with the KINFO_FILE_SIZE constant or this way.
*/
struct kinfo_file kf;
kf.kf_structsize = sizeof(kf);
if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0)
path = uv__basename_r(kf.kf_path);
#endif
handle->cb(handle, path, events, 0);

@ -79,6 +79,8 @@
# define __NR_copy_file_range 379
# elif defined(__arc__)
# define __NR_copy_file_range 285
# elif defined(__riscv)
# define __NR_copy_file_range 285
# endif
#endif /* __NR_copy_file_range */
@ -95,6 +97,8 @@
# define __NR_statx 383
# elif defined(__s390__)
# define __NR_statx 379
# elif defined(__riscv)
# define __NR_statx 291
# endif
#endif /* __NR_statx */
@ -111,6 +115,8 @@
# define __NR_getrandom 359
# elif defined(__s390__)
# define __NR_getrandom 349
# elif defined(__riscv)
# define __NR_getrandom 278
# endif
#endif /* __NR_getrandom */
@ -317,17 +323,64 @@ unsigned uv__kernel_version(void) {
unsigned major;
unsigned minor;
unsigned patch;
char v_sig[256];
char* needle;
version = atomic_load_explicit(&cached_version, memory_order_relaxed);
if (version != 0)
return version;
/* Check /proc/version_signature first as it's the way to get the mainline
* kernel version in Ubuntu. The format is:
* Ubuntu ubuntu_kernel_version mainline_kernel_version
* For example:
* Ubuntu 5.15.0-79.86-generic 5.15.111
*/
if (0 == uv__slurp("/proc/version_signature", v_sig, sizeof(v_sig)))
if (3 == sscanf(v_sig, "Ubuntu %*s %u.%u.%u", &major, &minor, &patch))
goto calculate_version;
if (-1 == uname(&u))
return 0;
/* In Debian we need to check `version` instead of `release` to extract the
* mainline kernel version. This is an example of how it looks like:
* #1 SMP Debian 5.10.46-4 (2021-08-03)
*/
needle = strstr(u.version, "Debian ");
if (needle != NULL)
if (3 == sscanf(needle, "Debian %u.%u.%u", &major, &minor, &patch))
goto calculate_version;
if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch))
return 0;
/* Handle it when the process runs under the UNAME26 personality:
*
* - kernels >= 3.x identify as 2.6.40+x
* - kernels >= 4.x identify as 2.6.60+x
*
* UNAME26 is a poorly conceived hack that doesn't let us distinguish
* between 4.x kernels and 5.x/6.x kernels so we conservatively assume
* that 2.6.60+x means 4.x.
*
* Fun fact of the day: it's technically possible to observe the actual
* kernel version for a brief moment because uname() first copies out the
* real release string before overwriting it with the backcompat string.
*/
if (major == 2 && minor == 6) {
if (patch >= 60) {
major = 4;
minor = patch - 60;
patch = 0;
} else if (patch >= 40) {
major = 3;
minor = patch - 40;
patch = 0;
}
}
calculate_version:
version = major * 65536 + minor * 256 + patch;
atomic_store_explicit(&cached_version, version, memory_order_relaxed);
@ -422,6 +475,9 @@ int uv__io_uring_register(int fd, unsigned opcode, void* arg, unsigned nargs) {
static int uv__use_io_uring(void) {
#if defined(__ANDROID_API__)
return 0; /* Possibly available but blocked by seccomp. */
#elif defined(__arm__) && __SIZEOF_POINTER__ == 4
/* See https://github.com/libuv/libuv/issues/4158. */
return 0; /* All 32 bits kernels appear buggy. */
#else
/* Ternary: unknown=0, yes=1, no=-1 */
static _Atomic int use_io_uring;
@ -431,8 +487,14 @@ static int uv__use_io_uring(void) {
use = atomic_load_explicit(&use_io_uring, memory_order_relaxed);
if (use == 0) {
/* Older kernels have a bug where the sqpoll thread uses 100% CPU. */
use = uv__kernel_version() >= /* 5.10.186 */ 0x050ABA ? 1 : -1;
/* But users can still enable it if they so desire. */
val = getenv("UV_USE_IO_URING");
use = val == NULL || atoi(val) ? 1 : -1;
if (val != NULL)
use = atoi(val) ? 1 : -1;
atomic_store_explicit(&use_io_uring, use, memory_order_relaxed);
}
@ -756,7 +818,9 @@ static void uv__iou_submit(struct uv__iou* iou) {
int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req) {
struct uv__io_uring_sqe* sqe;
struct uv__iou* iou;
int kv;
kv = uv__kernel_version();
/* Work around a poorly understood bug in older kernels where closing a file
* descriptor pointing to /foo/bar results in ETXTBSY errors when trying to
* execve("/foo/bar") later on. The bug seems to have been fixed somewhere
@ -764,10 +828,17 @@ int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req) {
* but good candidates are the several data race fixes. Interestingly, it
* seems to manifest only when running under Docker so the possibility of
* a Docker bug can't be completely ruled out either. Yay, computers.
* Also, disable on non-longterm versions between 5.16.0 (non-longterm) and
* 6.1.0 (longterm). Starting with longterm 6.1.x, the issue seems to be
* solved.
*/
if (uv__kernel_version() < /* 5.15.90 */ 0x050F5A)
if (kv < /* 5.15.90 */ 0x050F5A)
return 0;
if (kv >= /* 5.16.0 */ 0x050A00 && kv < /* 6.1.0 */ 0x060100)
return 0;
iou = &uv__get_internal_fields(loop)->iou;
sqe = uv__iou_get_sqe(iou, loop, req);
@ -1364,41 +1435,20 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
*/
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
if (nfds == -1)
assert(errno == EINTR);
else if (nfds == 0)
/* Unlimited timeout should only return with events or signal. */
assert(timeout != -1);
if (nfds == 0 || nfds == -1) {
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
} else if (nfds == 0) {
return;
}
if (timeout == -1)
continue;
if (timeout == 0)
break;
/* We may have been inside the system call for longer than |timeout|
* milliseconds so we need to update the timestamp to avoid drift.
*/
goto update_timeout;
}
if (nfds == -1) {
if (errno != EINTR)
abort();
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
if (timeout == -1)
continue;
if (timeout == 0)
break;
/* Interrupted by a signal. Update timeout and poll again. */
goto update_timeout;
}
@ -1509,13 +1559,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
break;
}
update_timeout:
if (timeout == 0)
break;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
real_timeout -= (loop->time - base);
@ -1718,7 +1768,8 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) {
return UV__ERR(errno);
}
fgets(buf, sizeof(buf), fp); /* Skip first line. */
if (NULL == fgets(buf, sizeof(buf), fp))
abort();
for (;;) {
memset(&t, 0, sizeof(t));
@ -1729,7 +1780,8 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) {
if (n != 7)
break;
fgets(buf, sizeof(buf), fp); /* Skip rest of line. */
if (NULL == fgets(buf, sizeof(buf), fp))
abort();
if (cpu >= ARRAY_SIZE(*cpus))
continue;
@ -1809,7 +1861,8 @@ nocpuinfo:
if (fp == NULL)
continue;
fscanf(fp, "%llu", &(*cpus)[cpu].freq);
if (1 != fscanf(fp, "%llu", &(*cpus)[cpu].freq))
abort();
fclose(fp);
fp = NULL;
}

@ -19,6 +19,7 @@
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <sys/ioctl.h>
#include <net/if.h>
@ -30,6 +31,7 @@
#include <sys/msg.h>
#include <sys/resource.h>
#include "zos-base.h"
#include "zos-sys-info.h"
#if defined(__clang__)
#include "csrsic.h"
#else
@ -66,9 +68,6 @@
/* Total number of frames currently on all available frame queues. */
#define RCEAFC_OFFSET 0x088
/* CPC model length from the CSRSI Service. */
#define CPCMODEL_LENGTH 16
/* Pointer to the home (current) ASCB. */
#define PSAAOLD 0x224
@ -258,9 +257,12 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
idx = 0;
while (idx < *count) {
cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability);
cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1);
memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1);
memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH);
cpu_info->model = uv__malloc(ZOSCPU_MODEL_LENGTH + 1);
if (cpu_info->model == NULL) {
uv_free_cpu_info(*cpu_infos, idx);
return UV_ENOMEM;
}
__get_cpu_model(cpu_info->model, ZOSCPU_MODEL_LENGTH + 1);
cpu_info->cpu_times.user = cpu_usage_avg;
/* TODO: implement the following */
cpu_info->cpu_times.sys = 0;

@ -279,6 +279,8 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) {
int uv__signal_loop_fork(uv_loop_t* loop) {
struct uv__queue* q;
if (loop->signal_pipefd[0] == -1)
return 0;
uv__io_stop(loop, &loop->signal_io_watcher, POLLIN);
@ -286,6 +288,19 @@ int uv__signal_loop_fork(uv_loop_t* loop) {
uv__close(loop->signal_pipefd[1]);
loop->signal_pipefd[0] = -1;
loop->signal_pipefd[1] = -1;
uv__queue_foreach(q, &loop->handle_queue) {
uv_handle_t* handle = uv__queue_data(q, uv_handle_t, handle_queue);
uv_signal_t* sh;
if (handle->type != UV_SIGNAL)
continue;
sh = (uv_signal_t*) handle;
sh->caught_signals = 0;
sh->dispatched_signals = 0;
}
return uv__signal_loop_once_init(loop);
}

@ -27,6 +27,17 @@
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#if defined(__PASE__)
#include <as400_protos.h>
#define ifaddrs ifaddrs_pase
#define getifaddrs Qp2getifaddrs
#define freeifaddrs Qp2freeifaddrs
#else
#include <ifaddrs.h>
#endif
static int maybe_bind_socket(int fd) {
union uv__sockaddr s;
@ -198,11 +209,50 @@ int uv__tcp_bind(uv_tcp_t* tcp,
}
static int uv__is_ipv6_link_local(const struct sockaddr* addr) {
const struct sockaddr_in6* a6;
uint8_t b[2];
if (addr->sa_family != AF_INET6)
return 0;
a6 = (const struct sockaddr_in6*) addr;
memcpy(b, &a6->sin6_addr, sizeof(b));
return b[0] == 0xFE && b[1] == 0x80;
}
static int uv__ipv6_link_local_scope_id(void) {
struct sockaddr_in6* a6;
struct ifaddrs* ifa;
struct ifaddrs* p;
int rv;
if (getifaddrs(&ifa))
return 0;
for (p = ifa; p != NULL; p = p->ifa_next)
if (uv__is_ipv6_link_local(p->ifa_addr))
break;
rv = 0;
if (p != NULL) {
a6 = (struct sockaddr_in6*) p->ifa_addr;
rv = a6->sin6_scope_id;
}
freeifaddrs(ifa);
return rv;
}
int uv__tcp_connect(uv_connect_t* req,
uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen,
uv_connect_cb cb) {
struct sockaddr_in6 tmp6;
int err;
int r;
@ -220,6 +270,14 @@ int uv__tcp_connect(uv_connect_t* req,
if (err)
return err;
if (uv__is_ipv6_link_local(addr)) {
memcpy(&tmp6, addr, sizeof(tmp6));
if (tmp6.sin6_scope_id == 0) {
tmp6.sin6_scope_id = uv__ipv6_link_local_scope_id();
addr = (void*) &tmp6;
}
}
do {
errno = 0;
r = connect(uv__stream_fd(handle), addr, addrlen);
@ -374,28 +432,39 @@ int uv__tcp_nodelay(int fd, int on) {
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
int intvl;
int cnt;
(void) &intvl;
(void) &cnt;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
return UV__ERR(errno);
if (!on)
return 0;
#ifdef TCP_KEEPIDLE
if (on) {
int intvl = 1; /* 1 second; same as default on Win32 */
int cnt = 10; /* 10 retries; same as hardcoded on Win32 */
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
return UV__ERR(errno);
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
return UV__ERR(errno);
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
return UV__ERR(errno);
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
return UV__ERR(errno);
/* Solaris/SmartOS, if you don't support keep-alive,
* then don't advertise it in your system headers...
*/
/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
#elif defined(TCP_KEEPALIVE) && !defined(__sun)
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
return UV__ERR(errno);
#endif
/* Solaris/SmartOS, if you don't support keep-alive,
* then don't advertise it in your system headers...
*/
/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
#if defined(TCP_KEEPALIVE) && !defined(__sun)
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
#ifdef TCP_KEEPINTVL
intvl = 1; /* 1 second; same as default on Win32 */
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
return UV__ERR(errno);
#endif
#ifdef TCP_KEEPCNT
cnt = 10; /* 10 retries; same as hardcoded on Win32 */
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
return UV__ERR(errno);
#endif

@ -789,11 +789,33 @@ void uv_cond_broadcast(uv_cond_t* cond) {
abort();
}
#if defined(__APPLE__) && defined(__MACH__)
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
int r;
errno = 0;
r = pthread_cond_wait(cond, mutex);
/* Workaround for a bug in OS X at least up to 13.6
* See https://github.com/libuv/libuv/issues/4165
*/
if (r == EINVAL)
if (errno == EBUSY)
return;
if (r)
abort();
}
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
if (pthread_cond_wait(cond, mutex))
abort();
}
#endif
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
int r;

@ -559,6 +559,9 @@ static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
if (loop == NULL)
loop = uv_default_loop();
if (stream == NULL)
stream = stderr;
uv__queue_foreach(q, &loop->handle_queue) {
h = uv__queue_data(q, uv_handle_t, handle_queue);

@ -27,18 +27,17 @@ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno);
int uv_dlopen(const char* filename, uv_lib_t* lib) {
WCHAR filename_w[32768];
ssize_t r;
lib->handle = NULL;
lib->errmsg = NULL;
if (!MultiByteToWideChar(CP_UTF8,
0,
filename,
-1,
filename_w,
ARRAY_SIZE(filename_w))) {
return uv__dlerror(lib, filename, GetLastError());
}
r = uv_wtf8_length_as_utf16(filename);
if (r < 0)
return uv__dlerror(lib, filename, ERROR_NO_UNICODE_TRANSLATION);
if ((size_t) r > ARRAY_SIZE(filename_w))
return uv__dlerror(lib, filename, ERROR_INSUFFICIENT_BUFFER);
uv_wtf8_to_utf16(filename, filename_w, r);
lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (lib->handle == NULL) {

@ -157,7 +157,8 @@ int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
const char* path,
unsigned int flags) {
int name_size, is_path_dir, size;
int is_path_dir;
size_t size;
DWORD attr, last_error;
WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
DWORD short_path_buffer_len;
@ -176,23 +177,9 @@ int uv_fs_event_start(uv_fs_event_t* handle,
uv__handle_start(handle);
/* Convert name to UTF16. */
name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) *
sizeof(WCHAR);
pathw = (WCHAR*)uv__malloc(name_size);
if (!pathw) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!MultiByteToWideChar(CP_UTF8,
0,
path,
-1,
pathw,
name_size / sizeof(WCHAR))) {
return uv_translate_sys_error(GetLastError());
}
last_error = uv__convert_utf8_to_utf16(path, &pathw);
if (last_error)
goto error_uv;
/* Determine whether path is a file or a directory. */
attr = GetFileAttributesW(pathw);
@ -333,6 +320,9 @@ short_path_done:
return 0;
error:
last_error = uv_translate_sys_error(last_error);
error_uv:
if (handle->path) {
uv__free(handle->path);
handle->path = NULL;
@ -365,7 +355,7 @@ error:
uv__free(short_path);
return uv_translate_sys_error(last_error);
return last_error;
}

@ -31,13 +31,16 @@
#include <stdio.h>
#include "uv.h"
/* <winioctl.h> requires <windows.h>, included via "uv.h" above, but needs to
be included before our "winapi.h", included via "internal.h" below. */
#include <winioctl.h>
#include "internal.h"
#include "req-inl.h"
#include "handle-inl.h"
#include "fs-fd-hash-inl.h"
#include <winioctl.h>
#define UV_FS_FREE_PATHS 0x0002
#define UV_FS_FREE_PTR 0x0008
@ -144,279 +147,6 @@ void uv__fs_init(void) {
}
static int32_t fs__decode_wtf8_char(const char** input) {
uint32_t code_point;
uint8_t b1;
uint8_t b2;
uint8_t b3;
uint8_t b4;
b1 = **input;
if (b1 <= 0x7F)
return b1; /* ASCII code point */
if (b1 < 0xC2)
return -1; /* invalid: continuation byte */
code_point = b1;
b2 = *++*input;
if ((b2 & 0xC0) != 0x80)
return -1; /* invalid: not a continuation byte */
code_point = (code_point << 6) | (b2 & 0x3F);
if (b1 <= 0xDF)
return 0x7FF & code_point; /* two-byte character */
b3 = *++*input;
if ((b3 & 0xC0) != 0x80)
return -1; /* invalid: not a continuation byte */
code_point = (code_point << 6) | (b3 & 0x3F);
if (b1 <= 0xEF)
return 0xFFFF & code_point; /* three-byte character */
b4 = *++*input;
if ((b4 & 0xC0) != 0x80)
return -1; /* invalid: not a continuation byte */
code_point = (code_point << 6) | (b4 & 0x3F);
if (b1 <= 0xF4)
if (code_point <= 0x10FFFF)
return code_point; /* four-byte character */
/* code point too large */
return -1;
}
static ssize_t fs__get_length_wtf8(const char* source_ptr) {
size_t w_target_len = 0;
int32_t code_point;
do {
code_point = fs__decode_wtf8_char(&source_ptr);
if (code_point < 0)
return -1;
if (code_point > 0xFFFF)
w_target_len++;
w_target_len++;
} while (*source_ptr++);
return w_target_len;
}
static void fs__wtf8_to_wide(const char* source_ptr, WCHAR* w_target) {
int32_t code_point;
do {
code_point = fs__decode_wtf8_char(&source_ptr);
/* fs__get_length_wtf8 should have been called and checked first. */
assert(code_point >= 0);
if (code_point > 0x10000) {
assert(code_point < 0x10FFFF);
*w_target++ = (((code_point - 0x10000) >> 10) + 0xD800);
*w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00;
} else {
*w_target++ = code_point;
}
} while (*source_ptr++);
}
INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
const char* new_path, const int copy_path) {
WCHAR* buf;
WCHAR* pos;
size_t buf_sz = 0;
size_t path_len = 0;
ssize_t pathw_len = 0;
ssize_t new_pathw_len = 0;
/* new_path can only be set if path is also set. */
assert(new_path == NULL || path != NULL);
if (path != NULL) {
pathw_len = fs__get_length_wtf8(path);
if (pathw_len < 0)
return ERROR_INVALID_NAME;
buf_sz += pathw_len * sizeof(WCHAR);
}
if (path != NULL && copy_path) {
path_len = 1 + strlen(path);
buf_sz += path_len;
}
if (new_path != NULL) {
new_pathw_len = fs__get_length_wtf8(new_path);
if (new_pathw_len < 0)
return ERROR_INVALID_NAME;
buf_sz += new_pathw_len * sizeof(WCHAR);
}
if (buf_sz == 0) {
req->file.pathw = NULL;
req->fs.info.new_pathw = NULL;
req->path = NULL;
return 0;
}
buf = uv__malloc(buf_sz);
if (buf == NULL) {
return ERROR_OUTOFMEMORY;
}
pos = buf;
if (path != NULL) {
fs__wtf8_to_wide(path, pos);
req->file.pathw = pos;
pos += pathw_len;
} else {
req->file.pathw = NULL;
}
if (new_path != NULL) {
fs__wtf8_to_wide(new_path, pos);
req->fs.info.new_pathw = pos;
pos += new_pathw_len;
} else {
req->fs.info.new_pathw = NULL;
}
req->path = path;
if (path != NULL && copy_path) {
memcpy(pos, path, path_len);
assert(path_len == buf_sz - (pos - buf) * sizeof(WCHAR));
req->path = (char*) pos;
}
req->flags |= UV_FS_FREE_PATHS;
return 0;
}
INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req,
uv_fs_type fs_type, const uv_fs_cb cb) {
uv__once_init();
UV_REQ_INIT(req, UV_FS);
req->loop = loop;
req->flags = 0;
req->fs_type = fs_type;
req->sys_errno_ = 0;
req->result = 0;
req->ptr = NULL;
req->path = NULL;
req->cb = cb;
memset(&req->fs, 0, sizeof(req->fs));
}
static int32_t fs__get_surrogate_value(const WCHAR* w_source_ptr,
size_t w_source_len) {
WCHAR u;
WCHAR next;
u = w_source_ptr[0];
if (u >= 0xD800 && u <= 0xDBFF && w_source_len > 1) {
next = w_source_ptr[1];
if (next >= 0xDC00 && next <= 0xDFFF)
return 0x10000 + ((u - 0xD800) << 10) + (next - 0xDC00);
}
return u;
}
static size_t fs__get_length_wide(const WCHAR* w_source_ptr,
size_t w_source_len) {
size_t target_len;
int32_t code_point;
target_len = 0;
for (; w_source_len; w_source_len--, w_source_ptr++) {
code_point = fs__get_surrogate_value(w_source_ptr, w_source_len);
/* Can be invalid UTF-8 but must be valid WTF-8. */
assert(code_point >= 0);
if (code_point < 0x80)
target_len += 1;
else if (code_point < 0x800)
target_len += 2;
else if (code_point < 0x10000)
target_len += 3;
else {
target_len += 4;
w_source_ptr++;
w_source_len--;
}
}
return target_len;
}
static int fs__wide_to_wtf8(WCHAR* w_source_ptr,
size_t w_source_len,
char** target_ptr,
size_t* target_len_ptr) {
size_t target_len;
char* target;
int32_t code_point;
/* If *target_ptr is provided, then *target_len_ptr must be its length
* (excluding space for null), otherwise we will compute the target_len_ptr
* length and may return a new allocation in *target_ptr if target_ptr is
* provided. */
if (target_ptr == NULL || *target_ptr == NULL) {
target_len = fs__get_length_wide(w_source_ptr, w_source_len);
if (target_len_ptr != NULL)
*target_len_ptr = target_len;
} else {
target_len = *target_len_ptr;
}
if (target_ptr == NULL)
return 0;
if (*target_ptr == NULL) {
target = uv__malloc(target_len + 1);
if (target == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return -1;
}
*target_ptr = target;
} else {
target = *target_ptr;
}
for (; w_source_len; w_source_len--, w_source_ptr++) {
code_point = fs__get_surrogate_value(w_source_ptr, w_source_len);
/* Can be invalid UTF-8 but must be valid WTF-8. */
assert(code_point >= 0);
if (code_point < 0x80) {
*target++ = code_point;
} else if (code_point < 0x800) {
*target++ = 0xC0 | (code_point >> 6);
*target++ = 0x80 | (code_point & 0x3F);
} else if (code_point < 0x10000) {
*target++ = 0xE0 | (code_point >> 12);
*target++ = 0x80 | ((code_point >> 6) & 0x3F);
*target++ = 0x80 | (code_point & 0x3F);
} else {
*target++ = 0xF0 | (code_point >> 18);
*target++ = 0x80 | ((code_point >> 12) & 0x3F);
*target++ = 0x80 | ((code_point >> 6) & 0x3F);
*target++ = 0x80 | (code_point & 0x3F);
w_source_ptr++;
w_source_len--;
}
}
assert((size_t) (target - *target_ptr) == target_len);
*target++ = '\0';
return 0;
}
INLINE static int fs__readlink_handle(HANDLE handle,
char** target_ptr,
size_t* target_len_ptr) {
@ -550,7 +280,98 @@ INLINE static int fs__readlink_handle(HANDLE handle,
}
assert(target_ptr == NULL || *target_ptr == NULL);
return fs__wide_to_wtf8(w_target, w_target_len, target_ptr, target_len_ptr);
return uv_utf16_to_wtf8(w_target, w_target_len, target_ptr, target_len_ptr);
}
INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
const char* new_path, const int copy_path) {
WCHAR* buf;
WCHAR* pos;
size_t buf_sz = 0;
size_t path_len = 0;
ssize_t pathw_len = 0;
ssize_t new_pathw_len = 0;
/* new_path can only be set if path is also set. */
assert(new_path == NULL || path != NULL);
if (path != NULL) {
pathw_len = uv_wtf8_length_as_utf16(path);
if (pathw_len < 0)
return ERROR_INVALID_NAME;
buf_sz += pathw_len * sizeof(WCHAR);
}
if (path != NULL && copy_path) {
path_len = 1 + strlen(path);
buf_sz += path_len;
}
if (new_path != NULL) {
new_pathw_len = uv_wtf8_length_as_utf16(new_path);
if (new_pathw_len < 0)
return ERROR_INVALID_NAME;
buf_sz += new_pathw_len * sizeof(WCHAR);
}
if (buf_sz == 0) {
req->file.pathw = NULL;
req->fs.info.new_pathw = NULL;
req->path = NULL;
return 0;
}
buf = uv__malloc(buf_sz);
if (buf == NULL) {
return ERROR_OUTOFMEMORY;
}
pos = buf;
if (path != NULL) {
uv_wtf8_to_utf16(path, pos, pathw_len);
req->file.pathw = pos;
pos += pathw_len;
} else {
req->file.pathw = NULL;
}
if (new_path != NULL) {
uv_wtf8_to_utf16(new_path, pos, new_pathw_len);
req->fs.info.new_pathw = pos;
pos += new_pathw_len;
} else {
req->fs.info.new_pathw = NULL;
}
req->path = path;
if (path != NULL && copy_path) {
memcpy(pos, path, path_len);
assert(path_len == buf_sz - (pos - buf) * sizeof(WCHAR));
req->path = (char*) pos;
}
req->flags |= UV_FS_FREE_PATHS;
return 0;
}
INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req,
uv_fs_type fs_type, const uv_fs_cb cb) {
uv__once_init();
UV_REQ_INIT(req, UV_FS);
req->loop = loop;
req->flags = 0;
req->fs_type = fs_type;
req->sys_errno_ = 0;
req->result = 0;
req->ptr = NULL;
req->path = NULL;
req->cb = cb;
memset(&req->fs, 0, sizeof(req->fs));
}
@ -1569,7 +1390,7 @@ void fs__scandir(uv_fs_t* req) {
continue;
/* Compute the space required to store the filename as WTF-8. */
wtf8_len = fs__get_length_wide(&info->FileName[0], wchar_len);
wtf8_len = uv_utf16_length_as_wtf8(&info->FileName[0], wchar_len);
/* Resize the dirent array if needed. */
if (dirents_used >= dirents_size) {
@ -1597,8 +1418,8 @@ void fs__scandir(uv_fs_t* req) {
/* Convert file name to UTF-8. */
wtf8 = &dirent->d_name[0];
if (fs__wide_to_wtf8(&info->FileName[0], wchar_len, &wtf8, &wtf8_len) == -1)
goto win32_error;
if (uv_utf16_to_wtf8(&info->FileName[0], wchar_len, &wtf8, &wtf8_len) != 0)
goto out_of_memory_error;
/* Fill out the type field. */
if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE)
@ -2824,7 +2645,7 @@ static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
}
assert(*realpath_ptr == NULL);
r = fs__wide_to_wtf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL);
r = uv_utf16_to_wtf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL);
uv__free(w_realpath_buf);
return r;
}

@ -104,13 +104,14 @@ static void uv__getaddrinfo_work(struct uv__work* w) {
*/
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
uv_getaddrinfo_t* req;
int addrinfo_len = 0;
int name_len = 0;
size_t addrinfo_len = 0;
ssize_t name_len = 0;
size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
struct addrinfoW* addrinfow_ptr;
struct addrinfo* addrinfo_ptr;
char* alloc_ptr = NULL;
char* cur_ptr = NULL;
int r;
req = container_of(w, uv_getaddrinfo_t, work_req);
@ -131,19 +132,12 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
addrinfo_len += addrinfo_struct_len +
ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
NULL,
0,
NULL,
NULL);
if (name_len == 0) {
req->retcode = uv_translate_sys_error(GetLastError());
name_len = uv_utf16_length_as_wtf8(addrinfow_ptr->ai_canonname, -1);
if (name_len < 0) {
req->retcode = name_len;
goto complete;
}
addrinfo_len += ALIGNED_SIZE(name_len);
addrinfo_len += ALIGNED_SIZE(name_len + 1);
}
addrinfow_ptr = addrinfow_ptr->ai_next;
}
@ -182,27 +176,14 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
/* convert canonical name to UTF-8 */
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
NULL,
0,
NULL,
NULL);
assert(name_len > 0);
assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
cur_ptr,
name_len,
NULL,
NULL);
assert(name_len > 0);
name_len = alloc_ptr + addrinfo_len - cur_ptr;
r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname,
-1,
cur_ptr,
(size_t*)&name_len);
assert(r == 0);
addrinfo_ptr->ai_canonname = cur_ptr;
cur_ptr += ALIGNED_SIZE(name_len);
cur_ptr += ALIGNED_SIZE(name_len + 1);
}
assert(cur_ptr <= alloc_ptr + addrinfo_len);
@ -261,12 +242,11 @@ int uv_getaddrinfo(uv_loop_t* loop,
const char* service,
const struct addrinfo* hints) {
char hostname_ascii[256];
int nodesize = 0;
int servicesize = 0;
int hintssize = 0;
size_t nodesize = 0;
size_t servicesize = 0;
size_t hintssize = 0;
char* alloc_ptr = NULL;
int err;
long rc;
ssize_t rc;
if (req == NULL || (node == NULL && service == NULL)) {
return UV_EINVAL;
@ -286,56 +266,36 @@ int uv_getaddrinfo(uv_loop_t* loop,
hostname_ascii + sizeof(hostname_ascii));
if (rc < 0)
return rc;
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
-1, NULL, 0) * sizeof(WCHAR));
if (nodesize == 0) {
err = GetLastError();
goto error;
}
nodesize = strlen(hostname_ascii) + 1;
node = hostname_ascii;
}
if (service != NULL) {
servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
0,
service,
-1,
NULL,
0) *
sizeof(WCHAR));
if (servicesize == 0) {
err = GetLastError();
goto error;
}
rc = uv_wtf8_length_as_utf16(service);
if (rc < 0)
return rc;
servicesize = rc;
}
if (hints != NULL) {
hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
}
/* allocate memory for inputs, and partition it as needed */
alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
if (!alloc_ptr) {
err = WSAENOBUFS;
goto error;
}
alloc_ptr = uv__malloc(ALIGNED_SIZE(nodesize * sizeof(WCHAR)) +
ALIGNED_SIZE(servicesize * sizeof(WCHAR)) +
hintssize);
if (!alloc_ptr)
return UV_ENOMEM;
/* save alloc_ptr now so we can free if error */
req->alloc = (void*)alloc_ptr;
req->alloc = (void*) alloc_ptr;
/* Convert node string to UTF16 into allocated memory and save pointer in the
* request. */
* request. The node here has been converted to ascii. */
if (node != NULL) {
req->node = (WCHAR*)alloc_ptr;
if (MultiByteToWideChar(CP_UTF8,
0,
node,
-1,
(WCHAR*) alloc_ptr,
nodesize / sizeof(WCHAR)) == 0) {
err = GetLastError();
goto error;
}
alloc_ptr += nodesize;
req->node = (WCHAR*) alloc_ptr;
uv_wtf8_to_utf16(node, (WCHAR*) alloc_ptr, nodesize);
alloc_ptr += ALIGNED_SIZE(nodesize * sizeof(WCHAR));
} else {
req->node = NULL;
}
@ -343,24 +303,16 @@ int uv_getaddrinfo(uv_loop_t* loop,
/* Convert service string to UTF16 into allocated memory and save pointer in
* the req. */
if (service != NULL) {
req->service = (WCHAR*)alloc_ptr;
if (MultiByteToWideChar(CP_UTF8,
0,
service,
-1,
(WCHAR*) alloc_ptr,
servicesize / sizeof(WCHAR)) == 0) {
err = GetLastError();
goto error;
}
alloc_ptr += servicesize;
req->service = (WCHAR*) alloc_ptr;
uv_wtf8_to_utf16(service, (WCHAR*) alloc_ptr, servicesize);
alloc_ptr += ALIGNED_SIZE(servicesize * sizeof(WCHAR));
} else {
req->service = NULL;
}
/* copy hints to allocated memory and save pointer in req */
if (hints != NULL) {
req->addrinfow = (struct addrinfoW*)alloc_ptr;
req->addrinfow = (struct addrinfoW*) alloc_ptr;
req->addrinfow->ai_family = hints->ai_family;
req->addrinfow->ai_socktype = hints->ai_socktype;
req->addrinfow->ai_protocol = hints->ai_protocol;
@ -387,19 +339,11 @@ int uv_getaddrinfo(uv_loop_t* loop,
uv__getaddrinfo_done(&req->work_req, 0);
return req->retcode;
}
error:
if (req != NULL) {
uv__free(req->alloc);
req->alloc = NULL;
}
return uv_translate_sys_error(err);
}
int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
NET_LUID luid;
wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
DWORD bufsize;
int r;
if (buffer == NULL || size == NULL || *size == 0)
@ -415,31 +359,7 @@ int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
if (r != 0)
return uv_translate_sys_error(r);
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
*size = bufsize;
return UV_ENOBUFS;
}
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
wname,
-1,
buffer,
*size,
NULL,
NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
*size = bufsize - 1;
return 0;
return uv__copy_utf16_to_utf8(wname, -1, buffer, size);
}
int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {

@ -42,6 +42,7 @@ static void uv__getnameinfo_work(struct uv__work* w) {
uv_getnameinfo_t* req;
WCHAR host[NI_MAXHOST];
WCHAR service[NI_MAXSERV];
size_t size;
int ret;
req = container_of(w, uv_getnameinfo_t, work_req);
@ -57,29 +58,17 @@ static void uv__getnameinfo_work(struct uv__work* w) {
return;
}
ret = WideCharToMultiByte(CP_UTF8,
0,
host,
-1,
req->host,
sizeof(req->host),
NULL,
NULL);
if (ret == 0) {
req->retcode = uv_translate_sys_error(GetLastError());
size = sizeof(req->host);
ret = uv__copy_utf16_to_utf8(host, -1, req->host, &size);
if (ret < 0) {
req->retcode = ret;
return;
}
ret = WideCharToMultiByte(CP_UTF8,
0,
service,
-1,
req->service,
sizeof(req->service),
NULL,
NULL);
if (ret == 0) {
req->retcode = uv_translate_sys_error(GetLastError());
size = sizeof(req->service);
ret = uv__copy_utf16_to_utf8(service, -1, req->service, &size);
if (ret < 0) {
req->retcode = ret;
}
}

@ -257,8 +257,9 @@ void uv__util_init(void);
uint64_t uv__hrtime(unsigned int scale);
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16);
int uv__convert_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char** utf8);
int uv__copy_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char* utf8, size_t *size);
int uv__convert_utf8_to_utf16(const char* utf8, WCHAR** utf16);
typedef int (WINAPI *uv__peersockfunc)(SOCKET, struct sockaddr*, int*);

@ -49,7 +49,7 @@ static const int default_pending_pipe_instances = 4;
/* Pipe prefix */
static char pipe_prefix[] = "\\\\?\\pipe";
static const int pipe_prefix_len = sizeof(pipe_prefix) - 1;
static const size_t pipe_prefix_len = sizeof(pipe_prefix) - 1;
/* IPC incoming xfer queue item. */
typedef struct {
@ -703,7 +703,7 @@ int uv_pipe_bind2(uv_pipe_t* handle,
size_t namelen,
unsigned int flags) {
uv_loop_t* loop = handle->loop;
int i, err, nameSize;
int i, err;
uv_pipe_accept_t* req;
if (flags & ~UV_PIPE_NO_TRUNCATE) {
@ -742,9 +742,8 @@ int uv_pipe_bind2(uv_pipe_t* handle,
handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*)
uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances);
if (!handle->pipe.serv.accept_reqs) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!handle->pipe.serv.accept_reqs)
return UV_ENOMEM;
for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
req = &handle->pipe.serv.accept_reqs[i];
@ -754,22 +753,9 @@ int uv_pipe_bind2(uv_pipe_t* handle,
req->next_pending = NULL;
}
/* Convert name to UTF16. */
nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
handle->name = uv__malloc(nameSize);
if (!handle->name) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!MultiByteToWideChar(CP_UTF8,
0,
name,
-1,
handle->name,
nameSize / sizeof(WCHAR))) {
err = GetLastError();
goto error;
}
err = uv__convert_utf8_to_utf16(name, &handle->name);
if (err)
return err;
/*
* Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
@ -795,10 +781,8 @@ int uv_pipe_bind2(uv_pipe_t* handle,
return 0;
error:
if (handle->name) {
uv__free(handle->name);
handle->name = NULL;
}
uv__free(handle->name);
handle->name = NULL;
return uv_translate_sys_error(err);
}
@ -861,7 +845,8 @@ int uv_pipe_connect2(uv_connect_t* req,
unsigned int flags,
uv_connect_cb cb) {
uv_loop_t* loop = handle->loop;
int err, nameSize;
int err;
size_t nameSize;
HANDLE pipeHandle = INVALID_HANDLE_VALUE;
DWORD duplex_flags;
@ -904,26 +889,16 @@ int uv_pipe_connect2(uv_connect_t* req,
}
uv__pipe_connection_init(handle);
/* Convert name to UTF16. */
nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
handle->name = uv__malloc(nameSize);
if (!handle->name) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!MultiByteToWideChar(CP_UTF8,
0,
name,
-1,
handle->name,
nameSize / sizeof(WCHAR))) {
err = GetLastError();
err = uv__convert_utf8_to_utf16(name, &handle->name);
if (err) {
err = ERROR_NO_UNICODE_TRANSLATION;
goto error;
}
pipeHandle = open_named_pipe(handle->name, &duplex_flags);
if (pipeHandle == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_PIPE_BUSY) {
nameSize = (wcslen(handle->name) + 1) * sizeof(WCHAR);
req->u.connect.name = uv__malloc(nameSize);
if (!req->u.connect.name) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
@ -2439,7 +2414,6 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
FILE_NAME_INFORMATION tmp_name_info;
FILE_NAME_INFORMATION* name_info;
WCHAR* name_buf;
unsigned int addrlen;
unsigned int name_size;
unsigned int name_len;
int err;
@ -2450,46 +2424,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
if (handle->name != NULL) {
/* The user might try to query the name before we are connected,
* and this is just easier to return the cached value if we have it. */
name_buf = handle->name;
name_len = wcslen(name_buf);
/* check how much space we need */
addrlen = WideCharToMultiByte(CP_UTF8,
0,
name_buf,
name_len,
NULL,
0,
NULL,
NULL);
if (!addrlen) {
*size = 0;
err = uv_translate_sys_error(GetLastError());
return err;
} else if (addrlen >= *size) {
*size = addrlen + 1;
err = UV_ENOBUFS;
goto error;
}
addrlen = WideCharToMultiByte(CP_UTF8,
0,
name_buf,
name_len,
buffer,
addrlen,
NULL,
NULL);
if (!addrlen) {
*size = 0;
err = uv_translate_sys_error(GetLastError());
return err;
}
*size = addrlen;
buffer[addrlen] = '\0';
return 0;
return uv__copy_utf16_to_utf8(handle->name, -1, buffer, size);
}
if (handle->handle == INVALID_HANDLE_VALUE) {
@ -2517,8 +2452,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
name_info = uv__malloc(name_size);
if (!name_info) {
*size = 0;
err = UV_ENOMEM;
goto cleanup;
return UV_ENOMEM;
}
nt_status = pNtQueryInformationFile(handle->handle,
@ -2551,51 +2485,19 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
name_len /= sizeof(WCHAR);
/* check how much space we need */
addrlen = WideCharToMultiByte(CP_UTF8,
0,
name_buf,
name_len,
NULL,
0,
NULL,
NULL);
if (!addrlen) {
/* "\\\\.\\pipe" + name */
if (*size < pipe_prefix_len) {
*size = 0;
err = uv_translate_sys_error(GetLastError());
goto error;
} else if (pipe_prefix_len + addrlen >= *size) {
/* "\\\\.\\pipe" + name */
*size = pipe_prefix_len + addrlen + 1;
err = UV_ENOBUFS;
goto error;
}
memcpy(buffer, pipe_prefix, pipe_prefix_len);
addrlen = WideCharToMultiByte(CP_UTF8,
0,
name_buf,
name_len,
buffer+pipe_prefix_len,
*size-pipe_prefix_len,
NULL,
NULL);
if (!addrlen) {
*size = 0;
err = uv_translate_sys_error(GetLastError());
goto error;
else {
memcpy(buffer, pipe_prefix, pipe_prefix_len);
*size -= pipe_prefix_len;
}
addrlen += pipe_prefix_len;
*size = addrlen;
buffer[addrlen] = '\0';
err = 0;
err = uv__copy_utf16_to_utf8(name_buf, name_len, buffer+pipe_prefix_len, size);
*size += pipe_prefix_len;
error:
uv__free(name_info);
cleanup:
return err;
}

@ -105,38 +105,26 @@ static void uv__init_global_job_handle(void) {
&info,
sizeof info))
uv_fatal_error(GetLastError(), "SetInformationJobObject");
if (!AssignProcessToJobObject(uv_global_job_handle_, GetCurrentProcess())) {
/* Make sure this handle is functional. The Windows kernel has a bug that
* if the first use of AssignProcessToJobObject is for a Windows Store
* program, subsequent attempts to use the handle with fail with
* INVALID_PARAMETER (87). This is possibly because all uses of the handle
* must be for the same Terminal Services session. We can ensure it is tied
* to our current session now by adding ourself to it. We could remove
* ourself afterwards, but there doesn't seem to be a reason to.
*/
DWORD err = GetLastError();
if (err != ERROR_ACCESS_DENIED)
uv_fatal_error(err, "AssignProcessToJobObject");
}
}
static int uv__utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
int ws_len, r;
WCHAR* ws;
ws_len = MultiByteToWideChar(CP_UTF8,
0,
s,
-1,
NULL,
0);
if (ws_len <= 0) {
return GetLastError();
}
ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR));
if (ws == NULL) {
return ERROR_OUTOFMEMORY;
}
r = MultiByteToWideChar(CP_UTF8,
0,
s,
-1,
ws,
ws_len);
assert(r == ws_len);
*ws_ptr = ws;
return 0;
return uv__convert_utf8_to_utf16(s, ws_ptr);
}
@ -396,7 +384,7 @@ static WCHAR* search_path(const WCHAR *file,
name_has_ext);
while (result == NULL) {
if (*dir_end == L'\0') {
if (dir_end == NULL || *dir_end == L'\0') {
break;
}
@ -539,21 +527,15 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
/* Count the required size. */
for (arg = args; *arg; arg++) {
DWORD arg_len;
ssize_t arg_len;
arg_len = MultiByteToWideChar(CP_UTF8,
0,
*arg,
-1,
NULL,
0);
if (arg_len == 0) {
return GetLastError();
}
arg_len = uv_wtf8_length_as_utf16(*arg);
if (arg_len < 0)
return arg_len;
dst_len += arg_len;
if (arg_len > temp_buffer_len)
if ((size_t) arg_len > temp_buffer_len)
temp_buffer_len = arg_len;
arg_count++;
@ -564,34 +546,28 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
dst_len = dst_len * 2 + arg_count * 2;
/* Allocate buffer for the final command line. */
dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR));
dst = uv__malloc(dst_len * sizeof(WCHAR));
if (dst == NULL) {
err = ERROR_OUTOFMEMORY;
err = UV_ENOMEM;
goto error;
}
/* Allocate temporary working buffer. */
temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR));
temp_buffer = uv__malloc(temp_buffer_len * sizeof(WCHAR));
if (temp_buffer == NULL) {
err = ERROR_OUTOFMEMORY;
err = UV_ENOMEM;
goto error;
}
pos = dst;
for (arg = args; *arg; arg++) {
DWORD arg_len;
ssize_t arg_len;
/* Convert argument to wide char. */
arg_len = MultiByteToWideChar(CP_UTF8,
0,
*arg,
-1,
temp_buffer,
(int) (dst + dst_len - pos));
if (arg_len == 0) {
err = GetLastError();
goto error;
}
arg_len = uv_wtf8_length_as_utf16(*arg);
assert(arg_len > 0);
assert(temp_buffer_len >= (size_t) arg_len);
uv_wtf8_to_utf16(*arg, temp_buffer, arg_len);
if (verbatim_arguments) {
/* Copy verbatim. */
@ -603,6 +579,7 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
}
*pos++ = *(arg + 1) ? L' ' : L'\0';
assert(pos <= dst + dst_len);
}
uv__free(temp_buffer);
@ -688,55 +665,43 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
WCHAR* ptr;
char** env;
size_t env_len = 0;
int len;
size_t len;
size_t i;
DWORD var_size;
size_t var_size;
size_t env_block_count = 1; /* 1 for null-terminator */
WCHAR* dst_copy;
WCHAR** ptr_copy;
WCHAR** env_copy;
DWORD required_vars_value_len[ARRAY_SIZE(required_vars)];
size_t required_vars_value_len[ARRAY_SIZE(required_vars)];
/* first pass: determine size in UTF-16 */
for (env = env_block; *env; env++) {
int len;
ssize_t len;
if (strchr(*env, '=')) {
len = MultiByteToWideChar(CP_UTF8,
0,
*env,
-1,
NULL,
0);
if (len <= 0) {
return GetLastError();
}
len = uv_wtf8_length_as_utf16(*env);
if (len < 0)
return len;
env_len += len;
env_block_count++;
}
}
/* second pass: copy to UTF-16 environment block */
dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR));
dst_copy = uv__malloc(env_len * sizeof(WCHAR));
if (dst_copy == NULL && env_len > 0) {
return ERROR_OUTOFMEMORY;
return UV_ENOMEM;
}
env_copy = alloca(env_block_count * sizeof(WCHAR*));
ptr = dst_copy;
ptr_copy = env_copy;
for (env = env_block; *env; env++) {
ssize_t len;
if (strchr(*env, '=')) {
len = MultiByteToWideChar(CP_UTF8,
0,
*env,
-1,
ptr,
(int) (env_len - (ptr - dst_copy)));
if (len <= 0) {
DWORD err = GetLastError();
uv__free(dst_copy);
return err;
}
len = uv_wtf8_length_as_utf16(*env);
assert(len > 0);
assert((size_t) len <= env_len - (ptr - dst_copy));
uv_wtf8_to_utf16(*env, ptr, len);
*ptr_copy++ = ptr;
ptr += len;
}
@ -754,7 +719,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
cmp = -1;
} else {
cmp = env_strncmp(required_vars[i].wide_eq,
required_vars[i].len,
required_vars[i].len,
*ptr_copy);
}
if (cmp < 0) {
@ -777,7 +742,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
dst = uv__malloc((1+env_len) * sizeof(WCHAR));
if (!dst) {
uv__free(dst_copy);
return ERROR_OUTOFMEMORY;
return UV_ENOMEM;
}
for (ptr = dst, ptr_copy = env_copy, i = 0;
@ -975,26 +940,26 @@ int uv_spawn(uv_loop_t* loop,
err = uv__utf8_to_utf16_alloc(options->file, &application);
if (err)
goto done;
goto done_uv;
err = make_program_args(
options->args,
options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
&arguments);
if (err)
goto done;
goto done_uv;
if (options->env) {
err = make_program_env(options->env, &env);
if (err)
goto done;
goto done_uv;
}
if (options->cwd) {
/* Explicit cwd */
err = uv__utf8_to_utf16_alloc(options->cwd, &cwd);
if (err)
goto done;
goto done_uv;
} else {
/* Inherit cwd */
@ -1025,22 +990,19 @@ int uv_spawn(uv_loop_t* loop,
DWORD path_len, r;
path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
if (path_len == 0) {
err = GetLastError();
goto done;
}
if (path_len != 0) {
alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
if (alloc_path == NULL) {
err = ERROR_OUTOFMEMORY;
goto done;
}
path = alloc_path;
alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
if (alloc_path == NULL) {
err = ERROR_OUTOFMEMORY;
goto done;
}
path = alloc_path;
r = GetEnvironmentVariableW(L"PATH", path, path_len);
if (r == 0 || r >= path_len) {
err = GetLastError();
goto done;
r = GetEnvironmentVariableW(L"PATH", path, path_len);
if (r == 0 || r >= path_len) {
err = GetLastError();
goto done;
}
}
}
@ -1102,6 +1064,7 @@ int uv_spawn(uv_loop_t* loop,
* breakaway.
*/
process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
process_flags |= CREATE_SUSPENDED;
}
if (!CreateProcessW(application_path,
@ -1119,11 +1082,6 @@ int uv_spawn(uv_loop_t* loop,
goto done;
}
/* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
process->process_handle = info.hProcess;
process->pid = info.dwProcessId;
/* If the process isn't spawned as detached, assign to the global job object
* so windows will kill it when the parent process dies. */
if (!(options->flags & UV_PROCESS_DETACHED)) {
@ -1146,6 +1104,19 @@ int uv_spawn(uv_loop_t* loop,
}
}
if (process_flags & CREATE_SUSPENDED) {
if (ResumeThread(info.hThread) == ((DWORD)-1)) {
err = GetLastError();
TerminateProcess(info.hProcess, 1);
goto done;
}
}
/* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
process->process_handle = info.hProcess;
process->pid = info.dwProcessId;
/* Set IPC pid to all IPC pipes. */
for (i = 0; i < options->stdio_count; i++) {
const uv_stdio_container_t* fdopt = &options->stdio[i];
@ -1173,8 +1144,13 @@ int uv_spawn(uv_loop_t* loop,
* made or the handle is closed, whichever happens first. */
uv__handle_start(process);
goto done_uv;
/* Cleanup, whether we succeeded or failed. */
done:
err = uv_translate_sys_error(err);
done_uv:
uv__free(application);
uv__free(application_path);
uv__free(arguments);
@ -1188,7 +1164,7 @@ int uv_spawn(uv_loop_t* loop,
child_stdio_buffer = NULL;
}
return uv_translate_sys_error(err);
return err;
}

@ -482,9 +482,11 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
uv_loop_t* loop;
uv_tty_t* handle;
uv_req_t* req;
DWORD bytes, read_bytes;
DWORD bytes;
size_t read_bytes;
WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
DWORD chars, read_chars;
DWORD chars;
DWORD read_chars;
LONG status;
COORD pos;
BOOL read_console_success;
@ -525,16 +527,13 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
NULL);
if (read_console_success) {
read_bytes = WideCharToMultiByte(CP_UTF8,
0,
utf16,
read_chars,
handle->tty.rd.read_line_buffer.base,
bytes,
NULL,
NULL);
read_bytes = bytes;
uv_utf16_to_wtf8(utf16,
read_chars,
&handle->tty.rd.read_line_buffer.base,
&read_bytes);
SET_REQ_SUCCESS(req);
req->u.io.overlapped.InternalHigh = read_bytes;
req->u.io.overlapped.InternalHigh = (DWORD) read_bytes;
} else {
SET_REQ_ERROR(req, GetLastError());
}
@ -798,7 +797,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
}
if (KEV.uChar.UnicodeChar != 0) {
int prefix_len, char_len;
int prefix_len;
size_t char_len;
char* last_key_buf;
/* Character key pressed */
if (KEV.uChar.UnicodeChar >= 0xD800 &&
@ -819,38 +820,31 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
prefix_len = 0;
}
if (KEV.uChar.UnicodeChar >= 0xDC00 &&
KEV.uChar.UnicodeChar < 0xE000) {
char_len = sizeof handle->tty.rd.last_key;
last_key_buf = &handle->tty.rd.last_key[prefix_len];
if (handle->tty.rd.last_utf16_high_surrogate) {
/* UTF-16 surrogate pair */
WCHAR utf16_buffer[2];
utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate;
utf16_buffer[1] = KEV.uChar.UnicodeChar;
char_len = WideCharToMultiByte(CP_UTF8,
0,
utf16_buffer,
2,
&handle->tty.rd.last_key[prefix_len],
sizeof handle->tty.rd.last_key,
NULL,
NULL);
if (uv_utf16_to_wtf8(utf16_buffer,
2,
&last_key_buf,
&char_len))
char_len = 0;
handle->tty.rd.last_utf16_high_surrogate = 0;
} else {
/* Single UTF-16 character */
char_len = WideCharToMultiByte(CP_UTF8,
0,
&KEV.uChar.UnicodeChar,
1,
&handle->tty.rd.last_key[prefix_len],
sizeof handle->tty.rd.last_key,
NULL,
NULL);
if (uv_utf16_to_wtf8(&KEV.uChar.UnicodeChar,
1,
&last_key_buf,
&char_len))
char_len = 0;
}
/* Whatever happened, the last character wasn't a high surrogate. */
handle->tty.rd.last_utf16_high_surrogate = 0;
/* If the utf16 character(s) couldn't be converted something must be
* wrong. */
if (!char_len) {
if (char_len == 0) {
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
handle->read_cb((uv_stream_t*) handle,

@ -95,7 +95,7 @@ void uv__util_init(void) {
int uv_exepath(char* buffer, size_t* size_ptr) {
int utf8_len, utf16_buffer_len, utf16_len;
size_t utf8_len, utf16_buffer_len, utf16_len;
WCHAR* utf16_buffer;
int err;
@ -123,25 +123,17 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
}
/* Convert to UTF-8 */
utf8_len = WideCharToMultiByte(CP_UTF8,
0,
utf16_buffer,
-1,
buffer,
(int) *size_ptr,
NULL,
NULL);
if (utf8_len == 0) {
err = GetLastError();
goto error;
utf8_len = *size_ptr - 1; /* Reserve space for NUL */
err = uv_utf16_to_wtf8(utf16_buffer, utf16_len, &buffer, &utf8_len);
if (err == UV_ENOBUFS) {
utf8_len = *size_ptr - 1;
err = 0;
}
*size_ptr = utf8_len;
uv__free(utf16_buffer);
/* utf8_len *does* include the terminating null at this point, but the
* returned size shouldn't. */
*size_ptr = utf8_len - 1;
return 0;
return err;
error:
uv__free(utf16_buffer);
@ -204,45 +196,14 @@ int uv_cwd(char* buffer, size_t* size) {
}
r = uv__cwd(&utf16_buffer, &utf16_len);
if (r < 0) {
if (r < 0)
return r;
}
/* Check how much space we need */
r = WideCharToMultiByte(CP_UTF8,
0,
utf16_buffer,
-1,
NULL,
0,
NULL,
NULL);
if (r == 0) {
uv__free(utf16_buffer);
return uv_translate_sys_error(GetLastError());
} else if (r > (int) *size) {
uv__free(utf16_buffer);
*size = r;
return UV_ENOBUFS;
}
r = uv__copy_utf16_to_utf8(utf16_buffer, utf16_len, buffer, size);
/* Convert to UTF-8 */
r = WideCharToMultiByte(CP_UTF8,
0,
utf16_buffer,
-1,
buffer,
*size > INT_MAX ? INT_MAX : (int) *size,
NULL,
NULL);
uv__free(utf16_buffer);
if (r == 0) {
return uv_translate_sys_error(GetLastError());
}
*size = r - 1;
return 0;
return r;
}
@ -252,33 +213,10 @@ int uv_chdir(const char* dir) {
WCHAR drive_letter, env_var[4];
int r;
if (dir == NULL) {
return UV_EINVAL;
}
utf16_len = MultiByteToWideChar(CP_UTF8,
0,
dir,
-1,
NULL,
0);
if (utf16_len == 0) {
return uv_translate_sys_error(GetLastError());
}
utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
if (utf16_buffer == NULL) {
return UV_ENOMEM;
}
if (MultiByteToWideChar(CP_UTF8,
0,
dir,
-1,
utf16_buffer,
utf16_len) == 0) {
uv__free(utf16_buffer);
return uv_translate_sys_error(GetLastError());
}
/* Convert to UTF-16 */
r = uv__convert_utf8_to_utf16(dir, &utf16_buffer);
if (r)
return r;
if (!SetCurrentDirectoryW(utf16_buffer)) {
uv__free(utf16_buffer);
@ -416,29 +354,14 @@ int uv_set_process_title(const char* title) {
uv__once_init();
/* Find out how big the buffer for the wide-char title must be */
length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
if (!length) {
err = GetLastError();
goto done;
}
/* Convert to wide-char string */
title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length);
if (!title_w) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length);
if (!length) {
err = GetLastError();
goto done;
}
err = uv__convert_utf8_to_utf16(title, &title_w);
if (err)
return err;
/* If the title must be truncated insert a \0 terminator there */
if (length > MAX_TITLE_LENGTH) {
length = wcslen(title_w);
if (length >= MAX_TITLE_LENGTH)
title_w[MAX_TITLE_LENGTH - 1] = L'\0';
}
if (!SetConsoleTitleW(title_w)) {
err = GetLastError();
@ -460,20 +383,19 @@ done:
static int uv__get_process_title(void) {
WCHAR title_w[MAX_TITLE_LENGTH];
DWORD wlen;
if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
return -1;
}
wlen = GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR));
if (wlen == 0)
return uv_translate_sys_error(GetLastError());
if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0)
return -1;
return 0;
return uv__convert_utf16_to_utf8(title_w, wlen, &process_title);
}
int uv_get_process_title(char* buffer, size_t size) {
size_t len;
int r;
if (buffer == NULL || size == 0)
return UV_EINVAL;
@ -485,9 +407,12 @@ int uv_get_process_title(char* buffer, size_t size) {
* If the process_title was never read before nor explicitly set,
* we must query it with getConsoleTitleW
*/
if (!process_title && uv__get_process_title() == -1) {
LeaveCriticalSection(&process_title_lock);
return uv_translate_sys_error(GetLastError());
if (process_title == NULL) {
r = uv__get_process_title();
if (r) {
LeaveCriticalSection(&process_title_lock);
return r;
}
}
assert(process_title);
@ -833,19 +758,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
continue;
/* Compute the size of the interface name. */
name_size = WideCharToMultiByte(CP_UTF8,
0,
adapter->FriendlyName,
-1,
NULL,
0,
NULL,
FALSE);
if (name_size <= 0) {
uv__free(win_address_buf);
return uv_translate_sys_error(GetLastError());
}
uv_address_buf_size += name_size;
name_size = uv_utf16_length_as_wtf8(adapter->FriendlyName, -1);
uv_address_buf_size += name_size + 1;
/* Count the number of addresses associated with this interface, and
* compute the size. */
@ -875,30 +789,25 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
adapter != NULL;
adapter = adapter->Next) {
IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
int name_size;
size_t max_name_size;
size_t name_size;
int r;
if (adapter->OperStatus != IfOperStatusUp ||
adapter->FirstUnicastAddress == NULL)
continue;
/* Convert the interface name to UTF8. */
max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
if (max_name_size > (size_t) INT_MAX)
max_name_size = INT_MAX;
name_size = WideCharToMultiByte(CP_UTF8,
0,
adapter->FriendlyName,
-1,
name_buf,
(int) max_name_size,
NULL,
FALSE);
if (name_size <= 0) {
name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
r = uv__copy_utf16_to_utf8(adapter->FriendlyName,
-1,
name_buf,
&name_size);
if (r) {
uv__free(win_address_buf);
uv__free(uv_address_buf);
return uv_translate_sys_error(GetLastError());
return r;
}
name_size += 1; /* Add NUL byte. */
/* Add an uv_interface_address_t element for every unicast address. */
for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
@ -1061,7 +970,6 @@ int uv_os_homedir(char* buffer, size_t* size) {
int uv_os_tmpdir(char* buffer, size_t* size) {
wchar_t *path;
DWORD bufsize;
size_t len;
if (buffer == NULL || size == NULL || *size == 0)
@ -1078,7 +986,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
if (path == NULL) {
return UV_ENOMEM;
}
len = GetTempPathW(len, path);
len = GetTempPathW(len, path);
if (len == 0) {
uv__free(path);
@ -1093,34 +1001,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
path[len] = L'\0';
}
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
uv__free(path);
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
uv__free(path);
*size = bufsize;
return UV_ENOBUFS;
}
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
path,
-1,
buffer,
*size,
NULL,
NULL);
uv__free(path);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
*size = bufsize - 1;
return 0;
return uv__copy_utf16_to_utf8(path, len, buffer, size);
}
@ -1131,95 +1012,71 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
* If utf16 is null terminated, utf16len can be set to -1, otherwise it must
* be specified.
*/
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) {
DWORD bufsize;
int uv__convert_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char** utf8) {
size_t utf8_len = 0;
if (utf16 == NULL)
return UV_EINVAL;
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
utf16,
utf16len,
NULL,
0,
NULL,
NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
/* Allocate the destination buffer adding an extra byte for the terminating
* NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so
* we do it ourselves always, just in case. */
*utf8 = uv__malloc(bufsize + 1);
if (*utf8 == NULL)
return UV_ENOMEM;
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
utf16,
utf16len,
*utf8,
bufsize,
NULL,
NULL);
if (bufsize == 0) {
uv__free(*utf8);
*utf8 = NULL;
return uv_translate_sys_error(GetLastError());
}
(*utf8)[bufsize] = '\0';
return 0;
*utf8 = NULL;
return uv_utf16_to_wtf8(utf16, utf16len, utf8, &utf8_len);
}
/*
* Converts a UTF-8 string into a UTF-16 one. The resulting string is
* null-terminated.
*
* If utf8 is null terminated, utf8len can be set to -1, otherwise it must
* be specified.
*/
int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
int uv__convert_utf8_to_utf16(const char* utf8, WCHAR** utf16) {
int bufsize;
if (utf8 == NULL)
return UV_EINVAL;
/* Check how much space we need */
bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0);
/* Check how much space we need (including NUL). */
bufsize = uv_wtf8_length_as_utf16(utf8);
if (bufsize < 0)
return UV__EINVAL;
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
/* Allocate the destination buffer adding an extra byte for the terminating
* NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so
* we do it ourselves always, just in case. */
*utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1));
/* Allocate the destination buffer. */
*utf16 = uv__malloc(sizeof(WCHAR) * bufsize);
if (*utf16 == NULL)
return UV_ENOMEM;
/* Convert to UTF-16 */
bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
uv_wtf8_to_utf16(utf8, *utf16, bufsize);
if (bufsize == 0) {
uv__free(*utf16);
*utf16 = NULL;
return uv_translate_sys_error(GetLastError());
}
(*utf16)[bufsize] = L'\0';
return 0;
}
/*
* Converts a UTF-16 string into a UTF-8 one in an existing buffer. The
* resulting string is null-terminated.
*
* If utf16 is null terminated, utf16len can be set to -1, otherwise it must
* be specified.
*/
int uv__copy_utf16_to_utf8(const WCHAR* utf16buffer, size_t utf16len, char* utf8, size_t *size) {
int r;
if (utf8 == NULL || size == NULL)
return UV_EINVAL;
if (*size == 0) {
*size = uv_utf16_length_as_wtf8(utf16buffer, utf16len);
r = UV_ENOBUFS;
} else {
*size -= 1; /* Reserve space for NUL. */
r = uv_utf16_to_wtf8(utf16buffer, utf16len, &utf8, size);
}
if (r == UV_ENOBUFS)
*size += 1; /* Add space for NUL. */
return r;
}
static int uv__getpwuid_r(uv_passwd_t* pwd) {
HANDLE token;
wchar_t username[UNLEN + 1];
@ -1384,14 +1241,13 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
wchar_t* var;
DWORD varlen;
wchar_t* name_w;
DWORD bufsize;
size_t len;
int r;
if (name == NULL || buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
r = uv__convert_utf8_to_utf16(name, -1, &name_w);
r = uv__convert_utf8_to_utf16(name, &name_w);
if (r != 0)
return r;
@ -1432,35 +1288,7 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
}
}
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
r = uv_translate_sys_error(GetLastError());
goto fail;
} else if (bufsize > *size) {
*size = bufsize;
r = UV_ENOBUFS;
goto fail;
}
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
var,
-1,
buffer,
*size,
NULL,
NULL);
if (bufsize == 0) {
r = uv_translate_sys_error(GetLastError());
goto fail;
}
*size = bufsize - 1;
r = 0;
r = uv__copy_utf16_to_utf8(var, len, buffer, size);
fail:
@ -1482,12 +1310,12 @@ int uv_os_setenv(const char* name, const char* value) {
if (name == NULL || value == NULL)
return UV_EINVAL;
r = uv__convert_utf8_to_utf16(name, -1, &name_w);
r = uv__convert_utf8_to_utf16(name, &name_w);
if (r != 0)
return r;
r = uv__convert_utf8_to_utf16(value, -1, &value_w);
r = uv__convert_utf8_to_utf16(value, &value_w);
if (r != 0) {
uv__free(name_w);
@ -1512,7 +1340,7 @@ int uv_os_unsetenv(const char* name) {
if (name == NULL)
return UV_EINVAL;
r = uv__convert_utf8_to_utf16(name, -1, &name_w);
r = uv__convert_utf8_to_utf16(name, &name_w);
if (r != 0)
return r;
@ -1529,9 +1357,6 @@ int uv_os_unsetenv(const char* name) {
int uv_os_gethostname(char* buffer, size_t* size) {
WCHAR buf[UV_MAXHOSTNAMESIZE];
size_t len;
char* utf8_str;
int convert_result;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
@ -1544,22 +1369,7 @@ int uv_os_gethostname(char* buffer, size_t* size) {
if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
return uv_translate_sys_error(WSAGetLastError());
convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str);
if (convert_result != 0)
return convert_result;
len = strlen(utf8_str);
if (len >= *size) {
*size = len + 1;
uv__free(utf8_str);
return UV_ENOBUFS;
}
memcpy(buffer, utf8_str, len + 1);
uv__free(utf8_str);
*size = len;
return 0;
return uv__copy_utf16_to_utf8(buf, -1, buffer, size);
}
@ -1665,7 +1475,7 @@ int uv_os_uname(uv_utsname_t* buffer) {
HKEY registry_key;
WCHAR product_name_w[256];
DWORD product_name_w_size;
int version_size;
size_t version_size;
int processor_level;
int r;
@ -1696,7 +1506,7 @@ int uv_os_uname(uv_utsname_t* buffer) {
r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
0,
KEY_QUERY_VALUE,
KEY_QUERY_VALUE | KEY_WOW64_64KEY,
&registry_key);
if (r == ERROR_SUCCESS) {
@ -1727,37 +1537,29 @@ int uv_os_uname(uv_utsname_t* buffer) {
}
}
version_size = WideCharToMultiByte(CP_UTF8,
0,
product_name_w,
-1,
buffer->version,
sizeof(buffer->version),
NULL,
NULL);
if (version_size == 0) {
r = uv_translate_sys_error(GetLastError());
version_size = sizeof(buffer->version);
r = uv__copy_utf16_to_utf8(product_name_w,
-1,
buffer->version,
&version_size);
if (r)
goto error;
}
}
}
/* Append service pack information to the version if present. */
if (os_info.szCSDVersion[0] != L'\0') {
if (version_size > 0)
buffer->version[version_size - 1] = ' ';
buffer->version[version_size++] = ' ';
if (WideCharToMultiByte(CP_UTF8,
0,
os_info.szCSDVersion,
-1,
buffer->version + version_size,
sizeof(buffer->version) - version_size,
NULL,
NULL) == 0) {
r = uv_translate_sys_error(GetLastError());
version_size = sizeof(buffer->version) - version_size;
r = uv__copy_utf16_to_utf8(os_info.szCSDVersion,
-1,
buffer->version +
sizeof(buffer->version) - version_size,
&version_size);
if (r)
goto error;
}
}
/* Populate the sysname field. */

@ -71,21 +71,21 @@ static int test_async_pummel(int nthreads) {
tids = calloc(nthreads, sizeof(tids[0]));
ASSERT_NOT_NULL(tids);
ASSERT(0 == uv_async_init(uv_default_loop(), &handle, async_cb));
ASSERT_OK(uv_async_init(uv_default_loop(), &handle, async_cb));
ACCESS_ONCE(const char*, handle.data) = running;
for (i = 0; i < nthreads; i++)
ASSERT(0 == uv_thread_create(tids + i, pummel, &handle));
ASSERT_OK(uv_thread_create(tids + i, pummel, &handle));
time = uv_hrtime();
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
time = uv_hrtime() - time;
done = 1;
for (i = 0; i < nthreads; i++)
ASSERT(0 == uv_thread_join(tids + i));
ASSERT_OK(uv_thread_join(tids + i));
printf("async_pummel_%d: %s callbacks in %.2f seconds (%s/sec)\n",
nthreads,

@ -43,7 +43,7 @@ struct ctx {
static void worker_async_cb(uv_async_t* handle) {
struct ctx* ctx = container_of(handle, struct ctx, worker_async);
ASSERT(0 == uv_async_send(&ctx->main_async));
ASSERT_OK(uv_async_send(&ctx->main_async));
ctx->worker_sent++;
ctx->worker_seen++;
@ -55,7 +55,7 @@ static void worker_async_cb(uv_async_t* handle) {
static void main_async_cb(uv_async_t* handle) {
struct ctx* ctx = container_of(handle, struct ctx, main_async);
ASSERT(0 == uv_async_send(&ctx->worker_async));
ASSERT_OK(uv_async_send(&ctx->worker_async));
ctx->main_sent++;
ctx->main_seen++;
@ -66,8 +66,8 @@ static void main_async_cb(uv_async_t* handle) {
static void worker(void* arg) {
struct ctx* ctx = arg;
ASSERT(0 == uv_async_send(&ctx->main_async));
ASSERT(0 == uv_run(&ctx->loop, UV_RUN_DEFAULT));
ASSERT_OK(uv_async_send(&ctx->main_async));
ASSERT_OK(uv_run(&ctx->loop, UV_RUN_DEFAULT));
uv_loop_close(&ctx->loop);
}
@ -85,29 +85,29 @@ static int test_async(int nthreads) {
for (i = 0; i < nthreads; i++) {
ctx = threads + i;
ctx->nthreads = nthreads;
ASSERT(0 == uv_loop_init(&ctx->loop));
ASSERT(0 == uv_async_init(&ctx->loop, &ctx->worker_async, worker_async_cb));
ASSERT(0 == uv_async_init(uv_default_loop(),
&ctx->main_async,
main_async_cb));
ASSERT(0 == uv_thread_create(&ctx->thread, worker, ctx));
ASSERT_OK(uv_loop_init(&ctx->loop));
ASSERT_OK(uv_async_init(&ctx->loop, &ctx->worker_async, worker_async_cb));
ASSERT_OK(uv_async_init(uv_default_loop(),
&ctx->main_async,
main_async_cb));
ASSERT_OK(uv_thread_create(&ctx->thread, worker, ctx));
}
time = uv_hrtime();
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
for (i = 0; i < nthreads; i++)
ASSERT(0 == uv_thread_join(&threads[i].thread));
ASSERT_OK(uv_thread_join(&threads[i].thread));
time = uv_hrtime() - time;
for (i = 0; i < nthreads; i++) {
ctx = threads + i;
ASSERT(ctx->worker_sent == NUM_PINGS);
ASSERT(ctx->worker_seen == NUM_PINGS);
ASSERT(ctx->main_sent == (unsigned int) NUM_PINGS);
ASSERT(ctx->main_seen == (unsigned int) NUM_PINGS);
ASSERT_EQ(ctx->worker_sent, NUM_PINGS);
ASSERT_EQ(ctx->worker_seen, NUM_PINGS);
ASSERT_EQ(ctx->main_sent, (unsigned int) NUM_PINGS);
ASSERT_EQ(ctx->main_seen, (unsigned int) NUM_PINGS);
}
printf("async%d: %.2f sec (%s/sec)\n",

Some files were not shown because too many files have changed in this diff Show More