GNU bug report logs - #70007
[PATCH] native JSON encoder

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: emacs; Reported by: Mattias Engdegård <mattias.engdegard@HIDDEN>; Keywords: patch; dated Tue, 26 Mar 2024 15:35:01 UTC; Maintainer for emacs is bug-gnu-emacs@HIDDEN.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 2 Apr 2024 17:19:20 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Apr 02 13:19:20 2024
Received: from localhost ([127.0.0.1]:56132 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rrhn5-0004Ob-7e
	for submit <at> debbugs.gnu.org; Tue, 02 Apr 2024 13:19:20 -0400
Received: from mail-lf1-x134.google.com ([2a00:1450:4864:20::134]:60882)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mattias.engdegard@HIDDEN>) id 1rrhn2-0004Nv-L2
 for 70007 <at> debbugs.gnu.org; Tue, 02 Apr 2024 13:19:17 -0400
Received: by mail-lf1-x134.google.com with SMTP id
 2adb3069b0e04-516a0b7f864so2360455e87.1
 for <70007 <at> debbugs.gnu.org>; Tue, 02 Apr 2024 10:19:12 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1712078347; x=1712683147; darn=debbugs.gnu.org;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:from:to:cc:subject
 :date:message-id:reply-to;
 bh=eip8XF+fdQbsw8sTVeeFplConaC/dOIoJk19myoPvd0=;
 b=AeeSHmD3nUs7VvbQN+CaDw6MjH9D3I/SavJEwJbdwKh6HwnoSynA8gaycZRcTmeKrv
 EeeJyG5zROMFP1H1UFHQTyTDLe+MTA8dccZu/nYNCEspSZkn2yE38F1iwwGdWU39kgZL
 9zBCCPYeG1GEvlSsxidWTsu8crLiH3EtNtwTckRN4TO8QLVW3aMyqJIWMUjJXFaId+Lr
 hfTDxs9hLDF+ffDAp22G52QIse/viQ3JANj5OgOK8WX8KfqjXG/kUyogPzqLLvDXDqSK
 4Hbcmi0FPyyVJJfOhA5WxPzhMOu3bhw/jPVKkw30DRdQGFlisWS8Y2kDNuxIn+5fOUoF
 caFg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1712078347; x=1712683147;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:x-gm-message-state
 :from:to:cc:subject:date:message-id:reply-to;
 bh=eip8XF+fdQbsw8sTVeeFplConaC/dOIoJk19myoPvd0=;
 b=D0q8NYLfjjsrM8yzlt9s/dOZOkVEsIaf5DrTUSGFr+5AOMDKiq2oaXA6iglt9JkevH
 w28gPECTxgdpBXPBENJVwOf2dhN63F89XPKEL3nUwD888CjjupCF+2Tfk4iR7bkN7pAx
 qaApx/5K5ImheIdri9hgD7qfN6LA32fhYlUmcUs9OioDhEmyW59WuVZYr+L9Dtt9oTOl
 xEnC6WS0uWy5pKAOyVMogbAOd4tO4DqUjjpossr1vm4t9etFSVRjbYBsQ4IAqTto66wN
 sTqOI1H5B525r/RuUfQTYU7Xeiy+ySTvbh42QYQhBbo/DIYoq/FuZJka/2ih3cx2Q7Vw
 y1bg==
X-Forwarded-Encrypted: i=1;
 AJvYcCU+/7+8Oo9AkPUsGOdBwofMOfKRPhD/FjnSvqMz9eWz25UhY9lZ5ssFYDO0t05R4Fltqm7NG62x9pWuajEqv56wwjL47y4=
X-Gm-Message-State: AOJu0YzRAf++mflbMyIjBLqj1ogG33cREYmH3s0r3b7XY0Ew6UMKSEYI
 jDYS+fUvw+Z5YZOc1pVjbpysRUTwckRIIhq3xdyAcPd2QbPv29qE
X-Google-Smtp-Source: AGHT+IH+rj5u2GoseylIExHx7COsgCQDywopljOGXwbQhhryS9AWM9qpymY5+1up9j9TLhrNg+KqqA==
X-Received: by 2002:a05:6512:23a1:b0:512:d877:df6f with SMTP id
 c33-20020a05651223a100b00512d877df6fmr11488394lfv.2.1712078344413; 
 Tue, 02 Apr 2024 10:19:04 -0700 (PDT)
Received: from smtpclient.apple (c80-217-1-132.bredband.tele2.se.
 [80.217.1.132]) by smtp.gmail.com with ESMTPSA id
 t7-20020a19ad07000000b00516a25e592fsm913815lfc.306.2024.04.02.10.19.03
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Tue, 02 Apr 2024 10:19:03 -0700 (PDT)
Content-Type: text/plain;
	charset=us-ascii
Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.15\))
Subject: Re: bug#70007: [PATCH] native JSON encoder
From: =?utf-8?Q?Mattias_Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <86cyr7agjo.fsf@HIDDEN>
Date: Tue, 2 Apr 2024 19:19:03 +0200
Content-Transfer-Encoding: quoted-printable
Message-Id: <850DEC32-F318-4F3E-BA87-55FC6DC74CD3@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> <86le5zdfbi.fsf@HIDDEN>
 <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
 <4C93E902-282D-4408-B449-C8E771B2B3E4@HIDDEN> <86cyr7agjo.fsf@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
X-Mailer: Apple Mail (2.3654.120.0.1.15)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

2 apr. 2024 kl. 18.13 skrev Eli Zaretskii <eliz@HIDDEN>:

>> This made me look at the Fjson_insert logic a bit. I'm probably =
betraying my lack of knowledge about buffer subtleties here, but since =
the serialiser always produces (correct) UTF-8, shouldn't it be enough =
to copy the bytes, don't bother with any decoding, and perform the =
buffer insertion ceremonies?
>=20
> Yes, I think that's true.

Thank you, now pushed with added tests.

> One nit, though: if the result could be an empty string, then we
> should not do anything at all, not even invalidate_buffer_caches.

I don't think json-insert can ever end up inserting the empty string =
(unless it signals, and then we won't get to the insertion stage). But I =
added an assertion for this.





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 2 Apr 2024 16:14:32 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Apr 02 12:14:32 2024
Received: from localhost ([127.0.0.1]:55814 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rrgmM-0007j4-F5
	for submit <at> debbugs.gnu.org; Tue, 02 Apr 2024 12:14:32 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:36984)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1rrgmI-0007id-Rg
 for 70007 <at> debbugs.gnu.org; Tue, 02 Apr 2024 12:14:29 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1rrgm9-0000Vs-Lc; Tue, 02 Apr 2024 12:14:17 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=I4ts5uEPz70vdQzF2ivdvkPm5EBF//BagkhPLti65RI=; b=hzsktpUJSsTf/BBIvBmA
 BFMlMLqtjA7kTL6U4fki+C7oI0u9J7oR2PbkollOYMjw2EL63JKuzc5zlzWITEfghAhOue430NWg+
 WmlFoWUgiPFCOgjg1pPe5xUY7wIOJ720Y6HxV0CfIdFc/8VIyH24wP27EHC74BbdSzR+QwSIvDekw
 rrpgYGa1YHlvKS+xtOxjq+RLOo9fzVPWKjWjBDxql80DeVOtlptc4u9jjZuE5zi6HClPyVf1HuYnT
 hgHCQuQKbg/JM88IhM27v0BPIV2nNbkJ4TDbhLYpDwWuGyOWnwOzvxkx40775nYMen75oT1BPW+bp
 L77ZekltdQI/pg==;
Date: Tue, 02 Apr 2024 19:13:47 +0300
Message-Id: <86cyr7agjo.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Mattias =?utf-8?Q?Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <4C93E902-282D-4408-B449-C8E771B2B3E4@HIDDEN> (message from
 Mattias =?utf-8?Q?Engdeg=C3=A5rd?= on Tue, 2 Apr 2024 16:13:58 +0200)
Subject: Re: bug#70007: [PATCH] native JSON encoder
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> <86le5zdfbi.fsf@HIDDEN>
 <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
 <4C93E902-282D-4408-B449-C8E771B2B3E4@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: Mattias Engdegård <mattias.engdegard@HIDDEN>
> Date: Tue, 2 Apr 2024 16:13:58 +0200
> Cc: casouri@HIDDEN,
>  70007 <at> debbugs.gnu.org
> 
> Looks like the new serialiser inherited a bug from the old code: `json-insert` in a unibyte buffer does not move point correctly. Example:
> 
> (with-temp-buffer
>   (set-buffer-multibyte nil)
>   (json-insert "é")
>   (list (buffer-string) (point)))
> => ("\"\303\251\"" 4)
> 
> The string is correct but the position should be 5, not 4.

In a build with --enable-checking, this hits an assertion.  So I think
we should add this to the test suite.

> This made me look at the Fjson_insert logic a bit. I'm probably betraying my lack of knowledge about buffer subtleties here, but since the serialiser always produces (correct) UTF-8, shouldn't it be enough to copy the bytes, don't bother with any decoding, and perform the buffer insertion ceremonies?

Yes, I think that's true.

One nit, though: if the result could be an empty string, then we
should not do anything at all, not even invalidate_buffer_caches.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 2 Apr 2024 14:14:14 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Apr 02 10:14:14 2024
Received: from localhost ([127.0.0.1]:54855 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rretx-0007Iu-JL
	for submit <at> debbugs.gnu.org; Tue, 02 Apr 2024 10:14:14 -0400
Received: from mail-lf1-x130.google.com ([2a00:1450:4864:20::130]:59702)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mattias.engdegard@HIDDEN>) id 1rretv-0007I1-C9
 for 70007 <at> debbugs.gnu.org; Tue, 02 Apr 2024 10:14:12 -0400
Received: by mail-lf1-x130.google.com with SMTP id
 2adb3069b0e04-516b80252c5so854827e87.3
 for <70007 <at> debbugs.gnu.org>; Tue, 02 Apr 2024 07:14:07 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1712067241; x=1712672041; darn=debbugs.gnu.org;
 h=references:to:cc:in-reply-to:date:subject:mime-version:message-id
 :from:sender:from:to:cc:subject:date:message-id:reply-to;
 bh=8gyVk4MN1Zd5mZnqH3NH0cDrb7AxYffHP1IZSp9XBFo=;
 b=hl+o7cxWdIIDxaUD83IwxBPvJmQR+uVjSpPG4RdEIjSMZoP2lS6Nw7KmPM7ZCYAGIX
 wH7Ri/xXPEfcA67L64eHSKweoBydeo44/Pq46hN+p66nwzpok1IXRuS5TWQ6RW6E0F6y
 70mkx3udL1yQWwJQ2POOOF1wf8lNlq12gSfjO7H4EEORQQdKkuDsniYRC+UC0shEv55u
 F5T2odUYY21qlwv9cpVbzwcUpky6UOkpkio6wlpDcF2ZBlwkL1e+s8ePv9mKQmg1zfct
 dKi6QoWeOoSQRiE0LNoSdPeTpHnCegHhICoONmx37yib+qnhd2AfUFAAW2xX0g/ab7X7
 wPBg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1712067241; x=1712672041;
 h=references:to:cc:in-reply-to:date:subject:mime-version:message-id
 :from:sender:x-gm-message-state:from:to:cc:subject:date:message-id
 :reply-to;
 bh=8gyVk4MN1Zd5mZnqH3NH0cDrb7AxYffHP1IZSp9XBFo=;
 b=ZSbE0BcGy63wuEXmsy3T7/XVBjmYwNsf+iFmxNLKxMKADvVHNXBtudA/1FxF8QwC00
 x0Dg3Ni1mheIAECSHEJhqHSvS2Yww17XqhNYagwCXAFPHy63i2KcSWTqBrQg4JOBiA0/
 wGgBcyyMe1lGx3Jp4HijES8NQU5gOC3onOqe2eYD82oQS1UGPd8HYICjzoiGerqDDnNd
 e6uQ8fCY3eGqkPxPOjuDG7mtQhWIvHiM0W0wzNu1U6iC4STNXsMghIVPSe+CbSsKivQR
 Yz/ZsFOxCG1Z+fehV+/GikICT+EqmeSMJYF0ePC7ZS8dc80nsygY1kZvkb/DDdpT3zSQ
 PVvQ==
X-Forwarded-Encrypted: i=1;
 AJvYcCX7zjtXuOMLpni+N6BJM8BUfOHMLX1EYNApSZyxXytcSAY1gh2dVr4ZjUPOZMEwGKtMEWMBw4vj+I5w0vi/yszWLW8JF7M=
X-Gm-Message-State: AOJu0YwP2Cu4EtyJBE9K+m7VSpMA5GZTRKIKC0uIEc0qYfvANhoe93NB
 ocr+1tXoLRPDKBVU3yv4Nl3tQo+1TNUE2rxonKdvHeILiIK6/HaT
X-Google-Smtp-Source: AGHT+IGrlhQZ+mPtyJyqcMWuHId2NUpkYnTCwKoS2OAX3xO5R0Eroh22cUe99XwxSfJUVZO1Ue3f9w==
X-Received: by 2002:ac2:424b:0:b0:515:9ee7:ce45 with SMTP id
 m11-20020ac2424b000000b005159ee7ce45mr9207827lfl.49.1712067241078; 
 Tue, 02 Apr 2024 07:14:01 -0700 (PDT)
Received: from smtpclient.apple (c80-217-1-132.bredband.tele2.se.
 [80.217.1.132]) by smtp.gmail.com with ESMTPSA id
 c15-20020a19760f000000b00515ac3af704sm1739962lff.79.2024.04.02.07.13.59
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Tue, 02 Apr 2024 07:14:00 -0700 (PDT)
From: =?utf-8?Q?Mattias_Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
Message-Id: <4C93E902-282D-4408-B449-C8E771B2B3E4@HIDDEN>
Content-Type: multipart/mixed;
 boundary="Apple-Mail=_02BFADEC-F9DF-4C2E-8704-AF3AF789CAD1"
Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.15\))
Subject: Re: bug#70007: [PATCH] native JSON encoder
Date: Tue, 2 Apr 2024 16:13:58 +0200
In-Reply-To: <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> <86le5zdfbi.fsf@HIDDEN>
 <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
X-Mailer: Apple Mail (2.3654.120.0.1.15)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)


--Apple-Mail=_02BFADEC-F9DF-4C2E-8704-AF3AF789CAD1
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=utf-8

Looks like the new serialiser inherited a bug from the old code: =
`json-insert` in a unibyte buffer does not move point correctly. =
Example:

(with-temp-buffer
  (set-buffer-multibyte nil)
  (json-insert "=C3=A9")
  (list (buffer-string) (point)))
=3D> ("\"\303\251\"" 4)

The string is correct but the position should be 5, not 4.

This made me look at the Fjson_insert logic a bit. I'm probably =
betraying my lack of knowledge about buffer subtleties here, but since =
the serialiser always produces (correct) UTF-8, shouldn't it be enough =
to copy the bytes, don't bother with any decoding, and perform the =
buffer insertion ceremonies?

Proposed patch attached. (There will also be a test, of course.)


--Apple-Mail=_02BFADEC-F9DF-4C2E-8704-AF3AF789CAD1
Content-Disposition: attachment;
	filename=json-insert.diff
Content-Type: application/octet-stream;
	x-unix-mode=0644;
	name="json-insert.diff"
Content-Transfer-Encoding: 7bit

diff --git a/src/json.c b/src/json.c
index c3244ad04d2..7c62d63c6fd 100644
--- a/src/json.c
+++ b/src/json.c
@@ -656,39 +656,14 @@ DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, MANY,
   /* No need to keep allocation beyond this point.  */
   unbind_to (count, Qnil);
 
-  ptrdiff_t inserted = 0;
+  bool ub_buffer = NILP (BVAR (current_buffer, enable_multibyte_characters));
   ptrdiff_t inserted_bytes = jo.size;
+  ptrdiff_t inserted = ub_buffer ? jo.size : jo.size - jo.chars_delta;
 
-  /* If required, decode the stuff we've read into the gap.  */
-  struct coding_system coding;
-  /* JSON strings are UTF-8 encoded strings.  */
-  setup_coding_system (Qutf_8_unix, &coding);
-  coding.dst_multibyte = !NILP (BVAR (current_buffer,
-				      enable_multibyte_characters));
-  if (CODING_MAY_REQUIRE_DECODING (&coding))
-    {
-      /* Now we have all the new bytes at the beginning of the gap,
-	 but `decode_coding_gap` needs them at the end of the gap, so
-	 we need to move them.  */
-      memmove (GAP_END_ADDR - inserted_bytes, GPT_ADDR, inserted_bytes);
-      decode_coding_gap (&coding, inserted_bytes);
-      inserted = coding.produced_char;
-    }
-  else
-    {
-      /* Make the inserted text part of the buffer, as unibyte text.  */
-      eassert (NILP (BVAR (current_buffer, enable_multibyte_characters)));
-      insert_from_gap_1 (inserted_bytes, inserted_bytes, false);
-
-      /* The target buffer is unibyte, so we don't need to decode.  */
-      invalidate_buffer_caches (current_buffer,
-				PT, PT + inserted_bytes);
-      adjust_after_insert (PT, PT_BYTE,
-			   PT + inserted_bytes,
-			   PT_BYTE + inserted_bytes,
-			   inserted_bytes);
-      inserted = inserted_bytes;
-    }
+  insert_from_gap_1 (inserted, inserted_bytes, false);
+  invalidate_buffer_caches (current_buffer, PT, PT + inserted);
+  adjust_after_insert (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted_bytes,
+		       inserted);
 
   /* Call after-change hooks.  */
   signal_after_change (PT, 0, inserted);

--Apple-Mail=_02BFADEC-F9DF-4C2E-8704-AF3AF789CAD1--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 30 Mar 2024 23:30:29 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 30 19:30:29 2024
Received: from localhost ([127.0.0.1]:46335 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rqi9b-0005Xv-Vp
	for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 19:30:29 -0400
Received: from mail-qt1-x82f.google.com ([2607:f8b0:4864:20::82f]:50403)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <rcopley@HIDDEN>) id 1rqi9W-0005XR-Mc
 for 70007 <at> debbugs.gnu.org; Sat, 30 Mar 2024 19:30:26 -0400
Received: by mail-qt1-x82f.google.com with SMTP id
 d75a77b69052e-430a25ed4e7so20620251cf.0
 for <70007 <at> debbugs.gnu.org>; Sat, 30 Mar 2024 16:30:20 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1711841415; x=1712446215; darn=debbugs.gnu.org;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:from:to:cc:subject:date:message-id:reply-to;
 bh=mRajx0uQyjI3aBH1/zXgfsO1xKQAeUtPlNKWJt3kja4=;
 b=jIEq1TN+FAnnRtTlL9rgU9lmApvzivu63+qD5d1/R/KCK0dO2cEh4HsCmqUN/8Rz+n
 wZeoeSKymxGJoLpvo8fGOriOOxyxzF03k4iXc5SRhkaP6K5w5mmhFxMVMrus81hF2JVw
 kZ1sg96bTq5Wlgw4ZVUbH5qzweMH9DpejQ/DCo3tNdhRXWMg7SA0TG1EWk8f17YzT1ZY
 bD5ltzscogD4X2A0a1Bze4zqnoimcGC1Q9NBlZyqMrNbCP4Th67/hNiCTakSHe1v4w1c
 LM1r+2RPxrvOz8xTx748I59N74t5DqkWIMGLqxi1mdkH/9vhXti7lb6FEEGBnX/e2+8G
 7e4w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711841415; x=1712446215;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id
 :reply-to;
 bh=mRajx0uQyjI3aBH1/zXgfsO1xKQAeUtPlNKWJt3kja4=;
 b=NvYDuJwGax3GSOkRLJJ1DQgvPvU+XpWRYJNlBki7xzcy4L7WMu5mHz8S7So+QrSgQQ
 +9HZCLI7l/YXLDXFYMMPexx1Xog/btDdPfWkG/kKoFJhU7f0xKBB+3J8rMKjzdStvCUG
 Aw6uLqvuZESB5OQUsfMc2Vndrh45sq/SLSZkRJScmw/pUh4XkWNlgh+25L+sS8Je+k13
 0srqI4DGfyI6gps/A1Fr9Y6vTn8j48Z3MCpo30ONCvx55QzNbtZRcWM6uA1xLeVHhIax
 Fi+zAZLPpV1GuQ8gGcVjF1bGaz9+aSe0uejJ3mdtJqsroaXC0aqZei7NN/8ufBqXjP1Y
 iG7g==
X-Forwarded-Encrypted: i=1;
 AJvYcCWY4M+FvCFgVP96CkAHVfRLwwKHxDhsCRKqcco+0B7khEKWckpKgfj10801oEEH96CmWxfoPBl8ECsNmLan6lYQ4HUb+VM=
X-Gm-Message-State: AOJu0YxkCVz39bYPLBU8tC80EXZI7OWyy+rAd32sbU1WD3PF2McAQ8ep
 VLT689TEeu0pvs58SSCNVptGh1LEJ7P8mM8gggGtOytf+FQZ/MPSd1YUqVRkqgV559sS4n9DYBw
 nfkMzjFput0rNOkLMmNl6BgDKhw4=
X-Google-Smtp-Source: AGHT+IGsWMP0ORgpnuW1U6MSjPw399ZieCFqrApVwkQa6udijVTeoJ3Y5yx5Dnsqb67kABg8tnhl6AAHCwR1edoL25Y=
X-Received: by 2002:ac8:59c8:0:b0:431:f7fc:dd0f with SMTP id
 f8-20020ac859c8000000b00431f7fcdd0fmr6763613qtf.54.1711841415003; Sat, 30 Mar
 2024 16:30:15 -0700 (PDT)
MIME-Version: 1.0
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> <86le5zdfbi.fsf@HIDDEN>
 <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
 <f55f685b-03c2-5132-c32d-3e0127816fd0@HIDDEN>
 <868r1zd65p.fsf@HIDDEN>
In-Reply-To: <868r1zd65p.fsf@HIDDEN>
From: Richard Copley <rcopley@HIDDEN>
Date: Sat, 30 Mar 2024 23:29:48 +0000
Message-ID: <CAPM58oiUY43iO6yVYsHvGdFmdH-Z26oT760OdoKEdo1CpwXbYA@HIDDEN>
Subject: Re: bug#70007: [PATCH] native JSON encoder
To: Eli Zaretskii <eliz@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: mattias.engdegard@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

On Sat, 30 Mar 2024 at 16:40, Eli Zaretskii <eliz@HIDDEN> wrote:
> Please try again, I hope I fixed this.
Thanks, looks good.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 30 Mar 2024 20:37:22 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 30 16:37:22 2024
Received: from localhost ([127.0.0.1]:46241 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rqfS6-0005Fp-8n
	for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 16:37:22 -0400
Received: from mail-oa1-f43.google.com ([209.85.160.43]:47164)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mplscorwin@HIDDEN>) id 1rqfS4-0005FY-1D
 for 70007 <at> debbugs.gnu.org; Sat, 30 Mar 2024 16:37:21 -0400
Received: by mail-oa1-f43.google.com with SMTP id
 586e51a60fabf-221816e3ab9so1523915fac.2
 for <70007 <at> debbugs.gnu.org>; Sat, 30 Mar 2024 13:37:17 -0700 (PDT)
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711831032; x=1712435832;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id
 :reply-to;
 bh=k4xqMacIBpa6m84WFFRzqy5B35zCrTMfMMwpJB+iiTw=;
 b=kPTbbmm2wqKcOkXRAV6APfXVHgyd2GNnWPlGYCHcLJw8v/l4krAVfXXfiQUrgVj2sF
 T/zHues+gWZk5eoUCbCc7tEi4gpQileZFG15hTFgfv0+gNDItwp0aerP4NUgbGZp2MEc
 HlbTXwmaRXx0WLK6sNZstbUCJZPUusqYPQeKYcJLsuytYuVyL8YUxDSP8+ljhVoKu+Yn
 qHgPV9cNlawr0RBIh58ILUNHO5Palyn1ihoMh2qpkl68kLMnC9n3aUNt9u2CWRVodQKr
 y9LjCLT7oDx8wrkx4OQ1pd3QavPyXANKqEfScOd7k/UWrQfuu+qJlK0txTEXFwlo+5Sm
 ZPFQ==
X-Gm-Message-State: AOJu0YwpH+cVh3Ke0tRjEuK8NWF+MwKo6k4faFfD37kL7IOKc0YekmwI
 TMwzF6l2OMDvHPllnqeguOoyAw2KrPfiCEHJqUreQVOVJJYy92HFUhKWbjxbyjzcLTHi7gP0LO8
 XqkVCF2cKm5l3OiwX6Kjww7fHNg0=
X-Google-Smtp-Source: AGHT+IGxNFCgdmpWjxBH+jtrALzZpB3g9krz5DDUlmySXD5M8oYrHKkgG6bvg8kqJ004sXdhl8galdFhNH56K9svKH8=
X-Received: by 2002:a05:6871:7a8:b0:229:fc1d:1ae with SMTP id
 o40-20020a05687107a800b00229fc1d01aemr6036840oap.31.1711831031958; Sat, 30
 Mar 2024 13:37:11 -0700 (PDT)
MIME-Version: 1.0
References: <86wmpphrg7.fsf@HIDDEN>
 <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> <86le5zdfbi.fsf@HIDDEN>
 <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
 <f55f685b-03c2-5132-c32d-3e0127816fd0@HIDDEN>
 <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN> <86r0fr3by5.fsf@HIDDEN>
In-Reply-To: <86r0fr3by5.fsf@HIDDEN>
From: Corwin Brust <corwin@HIDDEN>
Date: Sat, 30 Mar 2024 15:36:59 -0500
Message-ID: <CAJf-WoT9zSNTe4FWHPAbwKXA7Qaiour94KfH6WLk39fTN9-Tdg@HIDDEN>
Subject: Re: bug#70007: [PATCH] native JSON encoder
To: Andy Moreton <andrewjmoreton@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
X-Spam-Score: 0.2 (/)
X-Debbugs-Envelope-To: 70007
Cc: 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.8 (/)

> >> I made the changes above and installed it on master, as well as a sweeping removal of all things Jansson.

This builds okay for me with MSYS2/Mingw64; here are some Windows
binaries if anyone would like to test:

https://corwin.bru.st/emacs-30/emacs-30-000f91

Thanks!




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 30 Mar 2024 20:21:52 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 30 16:21:51 2024
Received: from localhost ([127.0.0.1]:46212 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rqfD5-0004N3-Jl
	for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 16:21:51 -0400
Received: from mail-lj1-x22e.google.com ([2a00:1450:4864:20::22e]:44442)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mattias.engdegard@HIDDEN>) id 1rqfD2-0004MV-Qw
 for 70007 <at> debbugs.gnu.org; Sat, 30 Mar 2024 16:21:49 -0400
Received: by mail-lj1-x22e.google.com with SMTP id
 38308e7fff4ca-2d6dda3adb9so29380891fa.1
 for <70007 <at> debbugs.gnu.org>; Sat, 30 Mar 2024 13:21:46 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1711830101; x=1712434901; darn=debbugs.gnu.org;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:from:to:cc:subject
 :date:message-id:reply-to;
 bh=qWI4qdW35vQOcSR92ag/e0g97VjK6MWekRpYhN+YG9w=;
 b=USwJYHSI9YQYP1VuL48TG99xN8WVqapGMeJ5bdC1pafbWCEqsOfbJ0J9qleYtppESD
 xRnxbrWham6z7pIwckv4f2JNAQwPaoHFJNyAPLg2yNjVICqUv1TojnEgudEgUYzAPFXe
 FhUeoHJa590ny1VQBTm9Br10chpp5eIagsrXd/11j6LvIHIoBkq1HGyqRzv8+07bb4JS
 VscTY9Fy9NuuqdG+rVh8mjtqcaY6hcZRWiXyBWKh3RJbihfgBqsxWN38tDNNnwPmUaDj
 JPZKNhUPQskXwCM/qtHOrBFUznB00V3My93XZ84Mxfdd060lyxnUrgzQdffToUI2QIrY
 /cxQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711830101; x=1712434901;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:x-gm-message-state
 :from:to:cc:subject:date:message-id:reply-to;
 bh=qWI4qdW35vQOcSR92ag/e0g97VjK6MWekRpYhN+YG9w=;
 b=P/YXVwO6L610wv+qjIYpvpPtEXpEf71gyugxSjpFHsjOxz+V6favx2NtNmpqeh3ELK
 eHePkdGDNO0QwxWgRleabmmaJgg1Agm7KzN5DSaZZ0J6lNwQC2on3R1+QhrIGbn5TghI
 8xWV1cPVTZr2p3Vur5kcnBrppR39bd/e+tY4ABn9Hl72ko+Fh2TlZ2kJ3f+rzsm7D2SJ
 UJm1u3rJfh5ETQYf3m3h/WjI9P0zWDhZFGeiqqBspyRTjwQ68vg7ktHYYWKJLotITKSR
 2k8Tw6CagwWReuvyOZLXnbdX0Y6McR5hJVMlZBAk2m6E9DYnNLhVwqnuHZ7M4uHm5yG4
 SnVg==
X-Forwarded-Encrypted: i=1;
 AJvYcCWLAKQFwB66ywvDYcAj77U0aaXYpVCUMkgnw/hDbsX+J1FVTPjZhsmraXSffr2aMmo/3Hw46YID+z46N03vplJcdCi9DuM=
X-Gm-Message-State: AOJu0YxKn4X/Os27kcy0gRQbZNOKRxkfxaUfXpCXo5Uz2YoUPeZBFcpX
 0A3ivSIq2f+EsAQI66b2q9eIYyHnp16dRGviUQ50GKOa6tKa2neM+90h0SC7
X-Google-Smtp-Source: AGHT+IGdfIUmPRsq1IrYKx1E9IUWdp1P0ITGkmh3HCw/pIYIEI4Z2Jg3hMtleQ2BNYn4KotD4KACGw==
X-Received: by 2002:a05:6512:3052:b0:515:a8f0:221 with SMTP id
 b18-20020a056512305200b00515a8f00221mr4834994lfb.37.1711830100500; 
 Sat, 30 Mar 2024 13:21:40 -0700 (PDT)
Received: from smtpclient.apple (c80-217-1-132.bredband.tele2.se.
 [80.217.1.132]) by smtp.gmail.com with ESMTPSA id
 g13-20020a19e04d000000b00516a2fe4290sm112023lfj.253.2024.03.30.13.21.39
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Sat, 30 Mar 2024 13:21:39 -0700 (PDT)
Content-Type: text/plain;
	charset=us-ascii
Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.15\))
Subject: Re: bug#70007: [PATCH] native JSON encoder
From: =?utf-8?Q?Mattias_Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <86edbrd6bv.fsf@HIDDEN>
Date: Sat, 30 Mar 2024 21:21:39 +0100
Content-Transfer-Encoding: quoted-printable
Message-Id: <FD8BB0FC-A423-477F-A4C1-3C11455B1751@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> <86le5zdfbi.fsf@HIDDEN>
 <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN> <86edbrd6bv.fsf@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
X-Mailer: Apple Mail (2.3654.120.0.1.15)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

30 mars 2024 kl. 17.37 skrev Eli Zaretskii <eliz@HIDDEN>:

> Thanks. =20


> The new code failed to link due to an omission in
> src/Makefile.in, and also the "clever" initialization in
> json_serialize confused make-docfile (so globals.h were generated
> incorrectly: they missed the DEFSYMs in syms_of_json).  I think I
> fixed that, but please eyeball the changes to see if I missed
> something.

Blast, I thought I had bootstrapped and tested it but naturally used the =
wrong tree. Thanks for putting it right.

We should do something about make-docfile one of these days.





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 30 Mar 2024 16:46:19 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 30 12:46:19 2024
Received: from localhost ([127.0.0.1]:46104 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rqbqV-0001dO-Bl
	for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 12:46:19 -0400
Received: from lists.gnu.org ([2001:470:142::17]:38404)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <geb-bug-gnu-emacs@HIDDEN>)
 id 1rqbqT-0001cP-5Q
 for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 12:46:18 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <geb-bug-gnu-emacs@HIDDEN>)
 id 1rqbqL-0004iY-QS
 for bug-gnu-emacs@HIDDEN; Sat, 30 Mar 2024 12:46:09 -0400
Received: from ciao.gmane.io ([116.202.254.214])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <geb-bug-gnu-emacs@HIDDEN>)
 id 1rqbqK-00024z-Iz
 for bug-gnu-emacs@HIDDEN; Sat, 30 Mar 2024 12:46:09 -0400
Received: from list by ciao.gmane.io with local (Exim 4.92)
 (envelope-from <geb-bug-gnu-emacs@HIDDEN>)
 id 1rqbqF-0005Fo-TM
 for bug-gnu-emacs@HIDDEN; Sat, 30 Mar 2024 17:46:03 +0100
X-Injected-Via-Gmane: http://gmane.org/
To: bug-gnu-emacs@HIDDEN
From: Andy Moreton <andrewjmoreton@HIDDEN>
Subject: Re: bug#70007: [PATCH] native JSON encoder
Date: Sat, 30 Mar 2024 16:45:54 +0000
Message-ID: <86r0fr3by5.fsf@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN>
 <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN>
 <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN>
 <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN>
 <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN>
 <86le5zdfbi.fsf@HIDDEN>
 <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
 <f55f685b-03c2-5132-c32d-3e0127816fd0@HIDDEN>
Mime-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit
User-Agent: Gnus/5.13 (Gnus v5.13)
Cancel-Lock: sha1:Z2gUAVUf3EQ3GFdPO6Gp7AbrwZM=
Received-SPF: pass client-ip=116.202.254.214;
 envelope-from=geb-bug-gnu-emacs@HIDDEN; helo=ciao.gmane.io
X-Spam_score_int: 3
X-Spam_score: 0.3
X-Spam_bar: /
X-Spam_report: (0.3 / 5.0 requ) BAYES_00=-1.9, DKIM_ADSP_CUSTOM_MED=0.001,
 FORGED_GMAIL_RCVD=1, FREEMAIL_FORGED_FROMDOMAIN=0.001, FREEMAIL_FROM=0.001,
 HEADER_FROM_DIFFERENT_DOMAINS=0.249, NML_ADSP_CUSTOM_MED=0.9,
 SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no
X-Spam_action: no action
X-Spam-Score: 1.3 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  On Sat 30 Mar 2024, Richard Copley wrote: > On 30/03/2024
   14:22, Mattias Engdegård wrote: >> I made the changes above and installed
   it on master, as well as a sweeping removal of all things Jansson. > > Hi
   Mattias, > A clean build fails with [...] 
 
 Content analysis details:   (1.3 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  0.0 FREEMAIL_FROM          Sender email is commonly abused enduser mail
                             provider (andrewjmoreton[at]gmail.com)
  0.0 T_SPF_PERMERROR        SPF: test of record failed (permerror)
  1.0 FORGED_GMAIL_RCVD      'From' gmail.com does not match 'Received'
                             headers
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
  0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level
                             mail domains are different
  0.0 FREEMAIL_FORGED_FROMDOMAIN 2nd level domains in From and
                             EnvelopeFrom freemail headers are
                             different
X-Debbugs-Envelope-To: submit
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.3 (/)

On Sat 30 Mar 2024, Richard Copley wrote:

> On 30/03/2024 14:22, Mattias Engdegård wrote:
>> I made the changes above and installed it on master, as well as a sweeping removal of all things Jansson.
>
> Hi Mattias,
> A clean build fails with a linker error:
>
>   CCLD     temacs
> /usr/bin/ld: /tmp/cc4stUid.ltrans15.ltrans.o: in function `main':
> <artificial>:(.text.startup+0x39a9): undefined reference to `syms_of_json'
> collect2: error: ld returned 1 exit status
> make[2]: *** [Makefile:739: temacs] Error 1

Commit 1135ce461d18 ("Always enable native JSON support and remove
Jansson references") removed json.o from configure.ac, but did not add it
in Makefile.in to ensure it is always built.

Adding json.o to base_obj there appears to fix the build.

    AndyM





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 30 Mar 2024 16:41:02 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 30 12:41:02 2024
Received: from localhost ([127.0.0.1]:46095 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rqblO-0001LA-56
	for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 12:41:02 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:57942)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1rqblM-0001KT-AU
 for 70007 <at> debbugs.gnu.org; Sat, 30 Mar 2024 12:41:00 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1rqblF-0000at-0K; Sat, 30 Mar 2024 12:40:53 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=vKgOY8YUrwC/p8lSHU9GBDq4XpDcOXA0nmKoLIOV43s=; b=f9vIkaQqiVeOmJnr+IN1
 uprwb2PMgIda+ID5jj6aJFGNuk1O7c0hC2zY/pzxdnX1kHd7Ub5iue/zDtAzCPqFDAuN4d3KMoMoA
 byIqyZ8X53n4C3L/BhwV3DGqdP+XVZeFIqoYeD4mvBMsLIt4ZdcqOedZyNGOnnvflzIy/vvlrfXzh
 xeUHazi/GR64IIH45/LQQfUC9bDoCcgQuoNEc/hibNb+E4rMdUwjWtEMPSh2U+y00w0toskaozWz1
 fbPBOND543H1gJuUuZINX4ZZzf9JbYihsvV7Uc4P1JbI0quwVxkoHL9+Np4AK2BpyZjiT+mEpmDSw
 Bq3erVC1RhklHw==;
Date: Sat, 30 Mar 2024 19:40:50 +0300
Message-Id: <868r1zd65p.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Richard Copley <rcopley@HIDDEN>
In-Reply-To: <f55f685b-03c2-5132-c32d-3e0127816fd0@HIDDEN> (message from
 Richard Copley on Sat, 30 Mar 2024 16:14:45 +0000)
Subject: Re: bug#70007: [PATCH] native JSON encoder
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> <86le5zdfbi.fsf@HIDDEN>
 <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
 <f55f685b-03c2-5132-c32d-3e0127816fd0@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 70007
Cc: mattias.engdegard@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> Cc: 70007 <at> debbugs.gnu.org
> Date: Sat, 30 Mar 2024 16:14:45 +0000
> From: Richard Copley <rcopley@HIDDEN>
> 
> On 30/03/2024 14:22, Mattias Engdegård wrote:
> > I made the changes above and installed it on master, as well as a sweeping removal of all things Jansson.
> 
> Hi Mattias,
> A clean build fails with a linker error:
> 
>    CCLD     temacs
> /usr/bin/ld: /tmp/cc4stUid.ltrans15.ltrans.o: in function `main':
> <artificial>:(.text.startup+0x39a9): undefined reference to `syms_of_json'
> collect2: error: ld returned 1 exit status
> make[2]: *** [Makefile:739: temacs] Error 1

Please try again, I hope I fixed this.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 30 Mar 2024 16:37:23 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 30 12:37:23 2024
Received: from localhost ([127.0.0.1]:46080 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rqbhq-00017W-Tq
	for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 12:37:23 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:59962)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1rqbhp-00017K-II
 for 70007 <at> debbugs.gnu.org; Sat, 30 Mar 2024 12:37:22 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1rqbhg-0007w5-0t; Sat, 30 Mar 2024 12:37:13 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=NlBWV6b+a6Qet4RFvQX459nX8mvidWaSQkp+eKFa5GE=; b=iwfm9a7eOGIyWPYIP9dC
 j+khJUURgk7I4y9n0hyhIzjlrIWs8tnwfRCHf/EqvGq5GtOCgOzqVVboOnl/hqkDAPd+jaou/Os1K
 3rl4bYTOBGsohAlg/x7uRss6G/9NHsBnEbnwbxm3qawXzTu9PnQCd0jBgHOo0vd1eOsDBW47G/4AB
 6F4QkIqzvkKPfFYIlyYm5FPwkonAIRVEdYeEIGeWuI44I2IJHNmrALRz+xXcFhp2gjQHUkUsN9EoH
 xHOhp1A51AR8Czfm5zsrUoDZNirrbc2nOr5MfzLM6qOM8rr9nHECWGVhXSEF5Sc3GiuFABIbBuXww
 2nowblRARLf2rg==;
Date: Sat, 30 Mar 2024 19:37:08 +0300
Message-Id: <86edbrd6bv.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Mattias =?utf-8?Q?Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN> (message from
 Mattias =?utf-8?Q?Engdeg=C3=A5rd?= on Sat, 30 Mar 2024 15:22:34 +0100)
Subject: Re: bug#70007: [PATCH] native JSON encoder
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> <86le5zdfbi.fsf@HIDDEN>
 <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: Mattias Engdegård <mattias.engdegard@HIDDEN>
> Date: Sat, 30 Mar 2024 15:22:34 +0100
> Cc: casouri@HIDDEN,
>  70007 <at> debbugs.gnu.org
> 
> I made the changes above and installed it on master, as well as a sweeping removal of all things Jansson.

Thanks.  The new code failed to link due to an omission in
src/Makefile.in, and also the "clever" initialization in
json_serialize confused make-docfile (so globals.h were generated
incorrectly: they missed the DEFSYMs in syms_of_json).  I think I
fixed that, but please eyeball the changes to see if I missed
something.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 30 Mar 2024 16:15:00 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 30 12:14:59 2024
Received: from localhost ([127.0.0.1]:46070 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rqbMB-0008V7-KH
	for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 12:14:59 -0400
Received: from mail-wr1-x435.google.com ([2a00:1450:4864:20::435]:58875)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <rcopley@HIDDEN>) id 1rqbM8-0008Ui-C9
 for 70007 <at> debbugs.gnu.org; Sat, 30 Mar 2024 12:14:58 -0400
Received: by mail-wr1-x435.google.com with SMTP id
 ffacd0b85a97d-3417a3151c5so1864394f8f.1
 for <70007 <at> debbugs.gnu.org>; Sat, 30 Mar 2024 09:14:54 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1711815288; x=1712420088; darn=debbugs.gnu.org;
 h=content-transfer-encoding:in-reply-to:from:references:cc:to:subject
 :user-agent:mime-version:date:message-id:from:to:cc:subject:date
 :message-id:reply-to;
 bh=oAO4CkWlfPWVrjyMazn+b8+xuijnxvS09ivHs7Jpj7Q=;
 b=c6uiYKU8/NSdP5NWqHv3auK6VCJEqHRITcUe5CetGc46js/mue8t4jKgNYna7I01/s
 OnjfeAu5iGW0hefPWHh2wmISTUEv4EB9NBLRTDNPszMY88EB4iAmReuzJswIRvFD6o7Q
 aPySKWUA84GpWSYW22Pvsx7pwKRQwX32ayQ2AE1bwyODj2FY0OcX4EkubA3ZOsWQdSdh
 ceEUJcRi+55fim25OvUANN5H8smNwYmv53mVw0ji36U8a/jfu4fX21csgx49ZWHIHIhY
 tmMIwzwo4TtPjMp1TLRvdUmr4xN7IsSwspWeI7reEjM+787RS+lT36PFrwvOi0BB5Ueu
 efUQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711815288; x=1712420088;
 h=content-transfer-encoding:in-reply-to:from:references:cc:to:subject
 :user-agent:mime-version:date:message-id:x-gm-message-state:from:to
 :cc:subject:date:message-id:reply-to;
 bh=oAO4CkWlfPWVrjyMazn+b8+xuijnxvS09ivHs7Jpj7Q=;
 b=IwCtMbu2SVgOK8j1LS4mwRDK5gagDLK+SmaIHjGde3sjm5Tl45GcpnKKAwHBofCYlF
 Zd6koh9NePgW91B6OYK07J6WGGnaQXvbOX+dof1gI/dsEHYMY3Rf5pJbsyPoZYUWuJGm
 s8TvBf1bQ3VjlxzwKgZNsPv1JimVFGwurrYRcuck7qAgKxQkdsYZAw04w1C/MC7hv+Ej
 XX77ivTdgO1QK3O5ttfgLeOuFUARtTj4cWZe5UfVnaBCHu27fnlTpRDtzFx84Sps63Cw
 RZ/bgw3x+321pJTZrou0v3ZmH1rXH0mlr4i3KGWQMwm4r1/velPOoBEmNpnjkuOAbBLF
 Rekg==
X-Gm-Message-State: AOJu0YyRTrCN3GFf8d+8Y5IVYIfpFfZ9buOvwZ+ImnVj1beV/IifcqG8
 3KKNRIJm80dXykpYKkn/7SWvflvsXamngGbdAn3mDRul6V13B38G
X-Google-Smtp-Source: AGHT+IH0Al3mlijbL5wy74vCHgPpcP5D0HRM0DaOoYWV355DS2O2w6Qgz6mq0syYv1FjFBoeojj0Zg==
X-Received: by 2002:adf:fe46:0:b0:33e:69a5:68f9 with SMTP id
 m6-20020adffe46000000b0033e69a568f9mr3749782wrs.17.1711815288258; 
 Sat, 30 Mar 2024 09:14:48 -0700 (PDT)
Received: from [192.168.1.101]
 (dsl-multi-static-81-140-129-201.in-addr.broadbandscope.com.
 [81.140.129.201]) by smtp.gmail.com with ESMTPSA id
 a9-20020a056000050900b00341d7596ec0sm6734320wrf.15.2024.03.30.09.14.47
 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);
 Sat, 30 Mar 2024 09:14:47 -0700 (PDT)
Message-ID: <f55f685b-03c2-5132-c32d-3e0127816fd0@HIDDEN>
Date: Sat, 30 Mar 2024 16:14:45 +0000
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101
 Thunderbird/102.15.1
Subject: Re: bug#70007: [PATCH] native JSON encoder
To: =?UTF-8?Q?Mattias_Engdeg=c3=a5rd?= <mattias.engdegard@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> <86le5zdfbi.fsf@HIDDEN>
 <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
From: Richard Copley <rcopley@HIDDEN>
In-Reply-To: <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
X-Spam-Score: -3.0 (---)
X-Debbugs-Envelope-To: 70007
Cc: 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -4.0 (----)

On 30/03/2024 14:22, Mattias Engdegård wrote:
> I made the changes above and installed it on master, as well as a sweeping removal of all things Jansson.

Hi Mattias,
A clean build fails with a linker error:

   CCLD     temacs
/usr/bin/ld: /tmp/cc4stUid.ltrans15.ltrans.o: in function `main':
<artificial>:(.text.startup+0x39a9): undefined reference to `syms_of_json'
collect2: error: ld returned 1 exit status
make[2]: *** [Makefile:739: temacs] Error 1





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 30 Mar 2024 14:22:49 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 30 10:22:49 2024
Received: from localhost ([127.0.0.1]:45936 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rqZbc-00036p-7e
	for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 10:22:49 -0400
Received: from mail-lf1-x12b.google.com ([2a00:1450:4864:20::12b]:47416)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mattias.engdegard@HIDDEN>) id 1rqZbZ-00036D-4a
 for 70007 <at> debbugs.gnu.org; Sat, 30 Mar 2024 10:22:46 -0400
Received: by mail-lf1-x12b.google.com with SMTP id
 2adb3069b0e04-513da1c1f26so3240599e87.3
 for <70007 <at> debbugs.gnu.org>; Sat, 30 Mar 2024 07:22:43 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1711808556; x=1712413356; darn=debbugs.gnu.org;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:from:to:cc:subject
 :date:message-id:reply-to;
 bh=Sg55lROk4ZoqZgqWtEkgdYtr3pbcsZw2+SEUmuuK93k=;
 b=Utrv2NI0PO5iWMWnPJaMxyTu57sjbxYSBUacW1Wc/PEX7Lxw4BUg/oCmJN7YjMCvHp
 658kR401xM+UdA1DcO+/DcbSZnJZrWj2mqZWGXiFtv8Ooo0tGTFvdV+Uj0OKsQkpTs0r
 fFmvPT1Bey4i94dL+oDZV6450leMCRAdpRKmhYJMHNSVIGv7cFzn+y8dhTnGFN6IZcw+
 HBXnOykWM20QHibNx4BxAL1CeUPq3g6t6hkjnRAV5OFzQUJK6g73iqB5Q8aqAAkZ6Yyc
 R67hPhzASimKsqvui8KNXkU0pmu5R9K3f3dRLDzfbXo8ImtrKf15sJVeSJMv7lw5D8cW
 FDJw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711808556; x=1712413356;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:x-gm-message-state
 :from:to:cc:subject:date:message-id:reply-to;
 bh=Sg55lROk4ZoqZgqWtEkgdYtr3pbcsZw2+SEUmuuK93k=;
 b=GOTxYUC6Kepyke0my9EddZSq2d5BJUrkBh/vRcRm/uCAqIqOSFQumu5AC2XQyfJdQn
 46tctaZcOYPl18jrMlsKqibZpbA+Yvi4DbnguiZei+v9iEE4GKV1Am7gwIyFeptWXMTY
 QfYZ/vl6m7c/4Es1RzvQlpVUyNYAC4/FjHUo1lWrKOU1Nc2gKaATD8NWIpdlBDJPY594
 I0eJY2t1J7yMlc4fuJgzRFRsg4Tw4Jsz3M8ENLxMQbLp+hii2GfL+uPWm/FsLs7cxrVz
 NNjuLgGW15zb+CptUI0ZwsFNbTdnd3TfAxHBTW4T9zZRS7DX/AQ3GuwlNQZDrUWMd3PA
 CtXw==
X-Forwarded-Encrypted: i=1;
 AJvYcCWw0mtyZVLhYGn2Y+ujQdh/THAmkMjlAUdvupxSuEqLjSAC+qNc4UoGGur5G/ZKwLzACIkks8ObQw0B8FI0HzIi9OJJpzs=
X-Gm-Message-State: AOJu0YwIwoDKPI7qKX366kxO1FsTokmWO7lubUTtaXXconPOBvcR7c3v
 Dh1Kt4UjwXJje462W2wnKDZtUVaPb6XbhQj3V4tMIP+s3Eg9fWJ6
X-Google-Smtp-Source: AGHT+IGqaq61OrP6i6sc/u0798tFmfaLPiw6VLFI0QCXHTLacCGlB2Z1CpXVWqaEvC4PXM83C2Yy+Q==
X-Received: by 2002:a05:6512:31c7:b0:513:cc91:9ed7 with SMTP id
 j7-20020a05651231c700b00513cc919ed7mr140370lfe.11.1711808555934; 
 Sat, 30 Mar 2024 07:22:35 -0700 (PDT)
Received: from smtpclient.apple (c80-217-1-132.bredband.tele2.se.
 [80.217.1.132]) by smtp.gmail.com with ESMTPSA id
 16-20020ac25f50000000b0051596fe5619sm920293lfz.40.2024.03.30.07.22.34
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Sat, 30 Mar 2024 07:22:35 -0700 (PDT)
Content-Type: text/plain;
	charset=us-ascii
Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.15\))
Subject: Re: bug#70007: [PATCH] native JSON encoder
From: =?utf-8?Q?Mattias_Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <86le5zdfbi.fsf@HIDDEN>
Date: Sat, 30 Mar 2024 15:22:34 +0100
Content-Transfer-Encoding: quoted-printable
Message-Id: <E07F73AC-A127-4E6D-A86F-0FB303F2BB48@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> <86le5zdfbi.fsf@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
X-Mailer: Apple Mail (2.3654.120.0.1.15)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

30 mars 2024 kl. 14.22 skrev Eli Zaretskii <eliz@HIDDEN>:

> This should be a call to memory_full, no?  Or if we must signal this
> error here, at least make the error message more specific: mention
> JSON or somesuch.

It's academic, but memory_full is fine.

> I'd prefer a more specific error message here, like
>=20
>  JSON does not allow Inf or NaN

Sure.

> Last, but not least: should we have a json-available-p function that
> always returns non-nil, for better backward-compatibility?  Otherwise,
> code out there might decide to use json.elm which is not what we want.

Yes, keep json-available-p (that always returns t) for compatibility. We =
could declare it obsolete but it's not very important.

I made the changes above and installed it on master, as well as a =
sweeping removal of all things Jansson.





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 30 Mar 2024 13:23:12 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 30 09:23:12 2024
Received: from localhost ([127.0.0.1]:44203 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rqYfv-0007pi-MA
	for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 09:23:12 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:38214)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1rqYfs-0007pF-QE
 for 70007 <at> debbugs.gnu.org; Sat, 30 Mar 2024 09:23:10 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1rqYfl-0000Lr-7g; Sat, 30 Mar 2024 09:23:01 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=JJuw+ORI8zlhnvoIR7WneDY5qSTINoXJ1znBHt+RqZ0=; b=nQ51RTkW+ustSJ+YXq/P
 CBtrqjkBronKAd7CcrDNWmuUPSZILLAWwLv6MvucASQmVvg/Tl67bvHMWGFAEfzh/Ywd/EAC0+VoD
 oDGjW8DdxTxvfXVP2GsQYXwacKM+mQ4R3ihAh3rCXiy2XRlt9fMz68wcdjeB+WbdQCehwV4JrTEKk
 6i1QiMTSx+IiNePtCd0iAYbN8ql+18X/Q7HgRc6wYR8SpimMI1gXfkfMl/cc1sHp/X/r6ZcSBGAVK
 exQ7Tt0yQZ3hLQ3VQJ1y5Gg4DIchWpyK5973Ya0nSQQyEu/3Iw/htnWLIX82WxB1ur7doxjtHBtZI
 9am/nJibPI1ySg==;
Date: Sat, 30 Mar 2024 16:22:57 +0300
Message-Id: <86le5zdfbi.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Mattias =?utf-8?Q?Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN> (message from
 Mattias =?utf-8?Q?Engdeg=C3=A5rd?= on Sat, 30 Mar 2024 12:41:31 +0100)
Subject: Re: bug#70007: [PATCH] native JSON encoder
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
 <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: Mattias Engdegård <mattias.engdegard@HIDDEN>
> Date: Sat, 30 Mar 2024 12:41:31 +0100
> Cc: casouri@HIDDEN,
>  70007 <at> debbugs.gnu.org
> 
> 29 mars 2024 kl. 07.04 skrev Eli Zaretskii <eliz@HIDDEN>:
> 
> > OK.  FTR, I'm not in favor of validation of unibyte strings, I just
> > suggest that we treat them as plain-ASCII: pass them through without
> > any validation, leaving the validation to the callers.
> 
> Actually we are more or less forced to validate unibyte strings as long as the serialiser returns multibyte. Which we agree that it probably shouldn't, but I'd first like to take some time to ensure that returning unibyte won't break anything.

Yes, I was writing about the state of affairs when we change the
serializer to emit unibyte strings.

> Thank you for pushing the new JSON parser to master. I've rebased my patch and cleaned it up a bit, and it now removes all uses of Jansson from json.c. Since the change involves removing some Windows-specific code, perhaps you would like to check that it still compiles on that platform, if you have the time?

It builds and passes the tests, thanks.  But I have a couple of minor
nits below.

> +static struct symset_tbl *
> +make_symset_table (int bits, struct symset_tbl *up)
> +{
> +  int maxbits = min (SIZE_WIDTH - 2 - (word_size < 8 ? 2 : 3), 32);
> +  if (bits > maxbits)
> +    error ("out of memory");	/* Will never happen in practice.  */

This should be a call to memory_full, no?  Or if we must signal this
error here, at least make the error message more specific: mention
JSON or somesuch.

> +{
> +  double x = XFLOAT_DATA (f);
> +  if (isinf (x) || isnan (x))
> +    signal_error ("not a finite number", f);

I'd prefer a more specific error message here, like

  JSON does not allow Inf or NaN

Last, but not least: should we have a json-available-p function that
always returns non-nil, for better backward-compatibility?  Otherwise,
code out there might decide to use json.elm which is not what we want.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 30 Mar 2024 11:41:45 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 30 07:41:45 2024
Received: from localhost ([127.0.0.1]:44093 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rqX5l-0002Zj-27
	for submit <at> debbugs.gnu.org; Sat, 30 Mar 2024 07:41:45 -0400
Received: from mail-lf1-x12c.google.com ([2a00:1450:4864:20::12c]:45304)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mattias.engdegard@HIDDEN>) id 1rqX5h-0002ZO-N2
 for 70007 <at> debbugs.gnu.org; Sat, 30 Mar 2024 07:41:43 -0400
Received: by mail-lf1-x12c.google.com with SMTP id
 2adb3069b0e04-515d55ab035so436967e87.2
 for <70007 <at> debbugs.gnu.org>; Sat, 30 Mar 2024 04:41:39 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1711798894; x=1712403694; darn=debbugs.gnu.org;
 h=references:to:cc:in-reply-to:date:subject:mime-version:message-id
 :from:sender:from:to:cc:subject:date:message-id:reply-to;
 bh=lhlkbrTrtEy4QIRhwP4fVRhgXE+g2kJyYlI/Eum8JFo=;
 b=TlmIoGdaCDpPMC+i390ku4TXGnG48yVpzH5fIEBlIcHe3LtpgMQkuCRnTSZav/hHzg
 wHqWkWwT/aUYGDaNb2lrfOSPpwCWhp4lo3WjBdWgHsNEhO/lmYQyWqJVyLMiizLpSdxe
 TIPpS/kF96XezGJXsdVd4ANb4x7fKoKF0InpVua8gw9k+VuEs9F1ebjDOoUoLSmiFCww
 6sW1uMlCS6T6dMiRO7XNXWWjSSnT6knjbp1ZwaR88LvHP41RCpYEBWB5YEDrK7h4c/rD
 FPd+tKTOFPMyoMbyLrWN5umbQdfhO0G/6EzYTJS5VTFpC0XSORpaezPxk/2549NXn/Wm
 AtdA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711798894; x=1712403694;
 h=references:to:cc:in-reply-to:date:subject:mime-version:message-id
 :from:sender:x-gm-message-state:from:to:cc:subject:date:message-id
 :reply-to;
 bh=lhlkbrTrtEy4QIRhwP4fVRhgXE+g2kJyYlI/Eum8JFo=;
 b=PvOp8gwXopoc/bAHf06J6wnzYHinmsuufEDC7nkYyw979HhEYZHtDn2b6K2wc7A3Nf
 sedRfGmSXyz2WXr8Znl1bVn2afQBM1IYwaFmIh15vVpiUNDAWZzyt6oniWnohxvDCeyg
 MYj3Opcc15IJfhyVO0cCfYE/syohQ1GWRSzilwNlADtuAFMfeLpmUzRjQoTyuJ76chS0
 3PfJaS6pcn0YcfiBe5HS+aVZGnDNVJSuiQhhWP4UpFvmZBhdQWhXWaFM6CJU6mljD6CL
 AtzyPy5toD3dOFX3mP0FsSALesqdYf7DDVklgmT3S35Dp+NUPrWO092e056BBI8VEFcx
 ZBXw==
X-Forwarded-Encrypted: i=1;
 AJvYcCVPGBbVMfpx7Rd31f3wxB4TrpxGk4n4lxJkwLtjpEqd1VtqbNaz07SQHvvPrrgJEpeqAHfIO1ttEPyjHSziP1UXqKsGE5M=
X-Gm-Message-State: AOJu0Yyg8LvqFKzO4gXzj7XlWKMwVYaYahE5q9nCb1Y3Nwo6epAwuuS+
 WKMrSipQ5nlbZhYQniGNVPRuuhhr1oMMtofY14LMMcMTOpdOM+Pd
X-Google-Smtp-Source: AGHT+IGbJuAQ29ZS+E+efEMOzv7jspHD8pS23dmSetiCWlrWHREYWSecAuvXGh/c5CsIySYTzY5rfg==
X-Received: by 2002:ac2:5fb1:0:b0:516:a010:f1c0 with SMTP id
 s17-20020ac25fb1000000b00516a010f1c0mr467048lfe.63.1711798893264; 
 Sat, 30 Mar 2024 04:41:33 -0700 (PDT)
Received: from smtpclient.apple (c80-217-1-132.bredband.tele2.se.
 [80.217.1.132]) by smtp.gmail.com with ESMTPSA id
 t9-20020a195f09000000b00515bad4cd0asm898443lfb.155.2024.03.30.04.41.32
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Sat, 30 Mar 2024 04:41:32 -0700 (PDT)
From: =?utf-8?Q?Mattias_Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
Message-Id: <3139C8FE-5C67-4FE3-B940-F449DA73E76C@HIDDEN>
Content-Type: multipart/mixed;
 boundary="Apple-Mail=_558A8A9C-18B2-4CE8-A0C1-865EBAE3B503"
Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.15\))
Subject: Re: bug#70007: [PATCH] native JSON encoder
Date: Sat, 30 Mar 2024 12:41:31 +0100
In-Reply-To: <86cyrdfuai.fsf@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> <86cyrdfuai.fsf@HIDDEN>
X-Mailer: Apple Mail (2.3654.120.0.1.15)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)


--Apple-Mail=_558A8A9C-18B2-4CE8-A0C1-865EBAE3B503
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii

29 mars 2024 kl. 07.04 skrev Eli Zaretskii <eliz@HIDDEN>:

> OK.  FTR, I'm not in favor of validation of unibyte strings, I just
> suggest that we treat them as plain-ASCII: pass them through without
> any validation, leaving the validation to the callers.

Actually we are more or less forced to validate unibyte strings as long =
as the serialiser returns multibyte. Which we agree that it probably =
shouldn't, but I'd first like to take some time to ensure that returning =
unibyte won't break anything.

Thank you for pushing the new JSON parser to master. I've rebased my =
patch and cleaned it up a bit, and it now removes all uses of Jansson =
from json.c. Since the change involves removing some Windows-specific =
code, perhaps you would like to check that it still compiles on that =
platform, if you have the time?

Otherwise I'll push it to master, and will remain ready to make any =
further adjustments necessary. We can then remove all remaining Jansson =
references (configuration, installation notes, etc), and make the =
required NEWS and manual changes.


--Apple-Mail=_558A8A9C-18B2-4CE8-A0C1-865EBAE3B503
Content-Disposition: attachment;
	filename=0001-New-JSON-encoder-bug-70007.patch
Content-Type: application/octet-stream;
	x-unix-mode=0644;
	name="0001-New-JSON-encoder-bug-70007.patch"
Content-Transfer-Encoding: quoted-printable

=46rom=204b2f5d8b55946c55838793046944b5680a19ba01=20Mon=20Sep=2017=20=
00:00:00=202001=0AFrom:=20=3D?UTF-8?q?Mattias=3D20Engdeg=3DC3=3DA5rd?=3D=20=
<mattiase@HIDDEN>=0ADate:=20Tue,=2026=20Mar=202024=2016:44:09=20+0100=0A=
Subject:=20[PATCH]=20New=20JSON=20encoder=20(bug#70007)=0A=0AIt=20is=20=
in=20general=20at=20least=202x=20faster=20than=20the=20old=20encoder=20=
and=20does=20not=0Adepend=20on=20any=20external=20library.=20=20Using=20=
our=20own=20code=20also=20gives=20us=0Acontrol=20over=20translation=20=
details:=20for=20example,=20we=20now=20have=20full=0Abignum=20support=20=
and=20tighter=20float=20formatting.=0A=0A*=20src/json.c=20(json_delete,=20=
json_initialized,=20init_json_functions)=0A(json_malloc,=20json_free,=20=
init_json,=20json_out_of_memory)=0A(json_releae_object,=20=
check_string_without_embedded_nulls,=20json_check)=0A(json_check_utf8,=20=
lisp_to_json_nonscalar_1,=20lisp_to_json_nonscalar)=0A(lisp_to_json,=20=
json_available_p,=20ensure_json_available,=20json_insert)=0A=
(json_handle_nonlocal_exit,=20json_insert_callback):=0ARemove.=20=20=
Remaining=20uses=20updated.=0A*=20src/json.c=20(json_out_t,=20symset_t,=20=
struct=20symset_tbl)=0A(symset_size,=20make_symset_table,=20push_symset,=20=
pop_symset)=0A(cleanup_symset_tables,=20symset_hash,=20symset_expand,=20=
symset_add)=0A(json_out_grow_buf,=20cleanup_json_out,=20json_make_room,=20=
JSON_OUT_STR)=0A(json_out_str,=20json_out_byte,=20json_out_fixnum,=20=
string_not_unicode)=0A(json_plain_char,=20json_out_string,=20=
json_out_nest,=20json_out_unnest)=0A(json_out_object_cons,=20=
json_out_object_hash),=20json_out_array)=0A(json_out_float,=20=
json_out_bignum,=20json_out_something)=0A(json_out_to_string,=20=
json_serialize):=20New.=0A(Fjson_serialize,=20Fjson_insert):=0ANew=20=
JSON=20encoder=20implementation.=0A*=20test/src/json-tests.el=20=
(json-serialize/object-with-duplicate-keys)=0A(json-serialize/string):=20=
Update=20tests.=0A---=0A=20src/emacs.c=20=20=20=20=20=20=20=20=20=20=20=20=
|=20=20=20=204=20-=0A=20src/json.c=20=20=20=20=20=20=20=20=20=20=20=20=20=
|=201071=20++++++++++++++++++++--------------------=0A=20src/lisp.h=20=20=
=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=201=20-=0A=20src/print.c=20=20=
=20=20=20=20=20=20=20=20=20=20|=20=20=20=201=20+=0A=20=
test/src/json-tests.el=20|=20=20=2041=20+-=0A=205=20files=20changed,=20=
581=20insertions(+),=20537=20deletions(-)=0A=0Adiff=20--git=20=
a/src/emacs.c=20b/src/emacs.c=0Aindex=2087f12d3fa86..4a34bb06425=20=
100644=0A---=20a/src/emacs.c=0A+++=20b/src/emacs.c=0A@@=20-2013,10=20=
+2013,6=20@@=20main=20(int=20argc,=20char=20**argv)=0A=20=20=20=
init_random=20();=0A=20=20=20init_xfaces=20();=0A=20=0A-#if=20defined=20=
HAVE_JSON=20&&=20!defined=20WINDOWSNT=0A-=20=20init_json=20();=0A-#endif=0A=
-=0A=20=20=20if=20(!initialized)=0A=20=20=20=20=20syms_of_comp=20();=0A=20=
=0Adiff=20--git=20a/src/json.c=20b/src/json.c=0Aindex=20=
afc48c59d5a..711744138b8=20100644=0A---=20a/src/json.c=0A+++=20=
b/src/json.c=0A@@=20-25,189=20+25,10=20@@=20Copyright=20(C)=202017-2024=20=
Free=20Software=20Foundation,=20Inc.=0A=20#include=20<stdlib.h>=0A=20=
#include=20<math.h>=0A=20=0A-#include=20<jansson.h>=0A-=0A=20#include=20=
"lisp.h"=0A=20#include=20"buffer.h"=0A=20#include=20"coding.h"=0A=20=0A=
-#ifdef=20WINDOWSNT=0A-#=20include=20<windows.h>=0A-#=20include=20=
"w32common.h"=0A-#=20include=20"w32.h"=0A-=0A-DEF_DLL_FN=20(void,=20=
json_set_alloc_funcs,=0A-=09=20=20=20=20(json_malloc_t=20malloc_fn,=20=
json_free_t=20free_fn));=0A-DEF_DLL_FN=20(void,=20json_delete,=20(json_t=20=
*json));=0A-DEF_DLL_FN=20(json_t=20*,=20json_array,=20(void));=0A=
-DEF_DLL_FN=20(int,=20json_array_append_new,=20(json_t=20*array,=20=
json_t=20*value));=0A-DEF_DLL_FN=20(size_t,=20json_array_size,=20(const=20=
json_t=20*array));=0A-DEF_DLL_FN=20(json_t=20*,=20json_object,=20=
(void));=0A-DEF_DLL_FN=20(int,=20json_object_set_new,=0A-=09=20=20=20=20=
(json_t=20*object,=20const=20char=20*key,=20json_t=20*value));=0A=
-DEF_DLL_FN=20(json_t=20*,=20json_null,=20(void));=0A-DEF_DLL_FN=20=
(json_t=20*,=20json_true,=20(void));=0A-DEF_DLL_FN=20(json_t=20*,=20=
json_false,=20(void));=0A-DEF_DLL_FN=20(json_t=20*,=20json_integer,=20=
(json_int_t=20value));=0A-DEF_DLL_FN=20(json_t=20*,=20json_real,=20=
(double=20value));=0A-DEF_DLL_FN=20(json_t=20*,=20json_stringn,=20(const=20=
char=20*value,=20size_t=20len));=0A-DEF_DLL_FN=20(char=20*,=20=
json_dumps,=20(const=20json_t=20*json,=20size_t=20flags));=0A-DEF_DLL_FN=20=
(int,=20json_dump_callback,=0A-=09=20=20=20=20(const=20json_t=20*json,=20=
json_dump_callback_t=20callback,=20void=20*data,=0A-=09=20=20=20=20=20=
size_t=20flags));=0A-DEF_DLL_FN=20(json_t=20*,=20json_object_get,=20=
(const=20json_t=20*object,=20const=20char=20*key));=0A-=0A-/*=20This=20=
is=20called=20by=20json_decref,=20which=20is=20an=20inline=20function.=20=
=20*/=0A-void=20json_delete(json_t=20*json)=0A-{=0A-=20=20fn_json_delete=20=
(json);=0A-}=0A-=0A-static=20bool=20json_initialized;=0A-=0A-static=20=
bool=0A-init_json_functions=20(void)=0A-{=0A-=20=20HMODULE=20library=20=3D=
=20w32_delayed_load=20(Qjson);=0A-=0A-=20=20if=20(!library)=0A-=20=20=20=20=
return=20false;=0A-=0A-=20=20LOAD_DLL_FN=20(library,=20=
json_set_alloc_funcs);=0A-=20=20LOAD_DLL_FN=20(library,=20json_delete);=0A=
-=20=20LOAD_DLL_FN=20(library,=20json_array);=0A-=20=20LOAD_DLL_FN=20=
(library,=20json_array_append_new);=0A-=20=20LOAD_DLL_FN=20(library,=20=
json_array_size);=0A-=20=20LOAD_DLL_FN=20(library,=20json_object);=0A-=20=
=20LOAD_DLL_FN=20(library,=20json_object_set_new);=0A-=20=20LOAD_DLL_FN=20=
(library,=20json_null);=0A-=20=20LOAD_DLL_FN=20(library,=20json_true);=0A=
-=20=20LOAD_DLL_FN=20(library,=20json_false);=0A-=20=20LOAD_DLL_FN=20=
(library,=20json_integer);=0A-=20=20LOAD_DLL_FN=20(library,=20=
json_real);=0A-=20=20LOAD_DLL_FN=20(library,=20json_stringn);=0A-=20=20=
LOAD_DLL_FN=20(library,=20json_dumps);=0A-=20=20LOAD_DLL_FN=20(library,=20=
json_dump_callback);=0A-=20=20LOAD_DLL_FN=20(library,=20=
json_object_get);=0A-=0A-=20=20init_json=20();=0A-=0A-=20=20return=20=
true;=0A-}=0A-=0A-#define=20json_set_alloc_funcs=20=
fn_json_set_alloc_funcs=0A-#define=20json_array=20fn_json_array=0A=
-#define=20json_array_append_new=20fn_json_array_append_new=0A-#define=20=
json_array_size=20fn_json_array_size=0A-#define=20json_object=20=
fn_json_object=0A-#define=20json_object_set_new=20fn_json_object_set_new=0A=
-#define=20json_null=20fn_json_null=0A-#define=20json_true=20=
fn_json_true=0A-#define=20json_false=20fn_json_false=0A-#define=20=
json_integer=20fn_json_integer=0A-#define=20json_real=20fn_json_real=0A=
-#define=20json_stringn=20fn_json_stringn=0A-#define=20json_dumps=20=
fn_json_dumps=0A-#define=20json_dump_callback=20fn_json_dump_callback=0A=
-#define=20json_object_get=20fn_json_object_get=0A-=0A-#endif=09/*=20=
WINDOWSNT=20*/=0A-=0A-/*=20We=20install=20a=20custom=20allocator=20so=20=
that=20we=20can=20avoid=20objects=20larger=0A-=20=20=20than=20=
PTRDIFF_MAX.=20=20Such=20objects=20wouldn't=20play=20well=20with=20the=20=
rest=20of=0A-=20=20=20Emacs's=20codebase,=20which=20generally=20uses=20=
ptrdiff_t=20for=20sizes=20and=0A-=20=20=20indices.=20=20The=20other=20=
functions=20in=20this=20file=20also=20generally=20assume=0A-=20=20=20=
that=20size_t=20values=20never=20exceed=20PTRDIFF_MAX.=0A-=0A-=20=20=20=
In=20addition,=20we=20need=20to=20use=20a=20custom=20allocator=20because=20=
on=0A-=20=20=20MS-Windows=20we=20replace=20malloc/free=20with=20our=20=
own=20functions,=20see=0A-=20=20=20w32heap.c,=20so=20we=20must=20force=20=
the=20library=20to=20use=20our=20allocator,=20or=0A-=20=20=20else=20we=20=
won't=20be=20able=20to=20free=20storage=20allocated=20by=20the=20=
library.=20=20*/=0A-=0A-static=20void=20*=0A-json_malloc=20(size_t=20=
size)=0A-{=0A-=20=20if=20(size=20>=20PTRDIFF_MAX)=0A-=20=20=20=20{=0A-=20=
=20=20=20=20=20errno=20=3D=20ENOMEM;=0A-=20=20=20=20=20=20return=20NULL;=0A=
-=20=20=20=20}=0A-=20=20return=20malloc=20(size);=0A-}=0A-=0A-static=20=
void=0A-json_free=20(void=20*ptr)=0A-{=0A-=20=20free=20(ptr);=0A-}=0A-=0A=
-void=0A-init_json=20(void)=0A-{=0A-=20=20json_set_alloc_funcs=20=
(json_malloc,=20json_free);=0A-}=0A-=0A-/*=20Note=20that=20all=20callers=20=
of=20make_string_from_utf8=20and=20build_string_from_utf8=0A-=20=20=20=
below=20either=20pass=20only=20value=20UTF-8=20strings=20or=20use=20the=20=
functionf=20for=0A-=20=20=20formatting=20error=20messages;=20in=20the=20=
latter=20case=20correctness=20isn't=0A-=20=20=20critical.=20=20*/=0A-=0A=
-/*=20Return=20a=20unibyte=20string=20containing=20the=20sequence=20of=20=
UTF-8=20encoding=0A-=20=20=20units=20of=20the=20UTF-8=20representation=20=
of=20STRING.=20=20If=20STRING=20does=20not=0A-=20=20=20represent=20a=20=
sequence=20of=20Unicode=20scalar=20values,=20return=20a=20string=20with=0A=
-=20=20=20unspecified=20contents.=20=20*/=0A-=0A-static=20Lisp_Object=0A=
-json_encode=20(Lisp_Object=20string)=0A-{=0A-=20=20/*=20FIXME:=20Raise=20=
an=20error=20if=20STRING=20is=20not=20a=20scalar=20value=0A-=20=20=20=20=20=
sequence.=20=20*/=0A-=20=20return=20encode_string_utf_8=20(string,=20=
Qnil,=20false,=20Qt,=20Qt);=0A-}=0A-=0A-static=20AVOID=0A=
-json_out_of_memory=20(void)=0A-{=0A-=20=20xsignal0=20=
(Qjson_out_of_memory);=0A-}=0A-=0A-static=20void=0A-json_release_object=20=
(void=20*object)=0A-{=0A-=20=20json_decref=20(object);=0A-}=0A-=0A-/*=20=
Signal=20an=20error=20if=20OBJECT=20is=20not=20a=20string,=20or=20if=20=
OBJECT=20contains=0A-=20=20=20embedded=20null=20characters.=20=20*/=0A-=0A=
-static=20void=0A-check_string_without_embedded_nulls=20(Lisp_Object=20=
object)=0A-{=0A-=20=20CHECK_STRING=20(object);=0A-=20=20CHECK_TYPE=20=
(memchr=20(SDATA=20(object),=20'\0',=20SBYTES=20(object))=20=3D=3D=20=
NULL,=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
Qstring_without_embedded_nulls_p,=20object);=0A-}=0A-=0A-/*=20Signal=20=
an=20error=20of=20type=20`json-out-of-memory'=20if=20OBJECT=20is=0A-=20=20=
=20NULL.=20=20*/=0A-=0A-static=20json_t=20*=0A-json_check=20(json_t=20=
*object)=0A-{=0A-=20=20if=20(object=20=3D=3D=20NULL)=0A-=20=20=20=20=
json_out_of_memory=20();=0A-=20=20return=20object;=0A-}=0A-=0A-/*=20If=20=
STRING=20is=20not=20a=20valid=20UTF-8=20string,=20signal=20an=20error=20=
of=20type=0A-=20=20=20`wrong-type-argument'.=20=20STRING=20must=20be=20a=20=
unibyte=20string.=20=20*/=0A-=0A-static=20void=0A-json_check_utf8=20=
(Lisp_Object=20string)=0A-{=0A-=20=20CHECK_TYPE=20(utf8_string_p=20=
(string),=20Qutf_8_string_p,=20string);=0A-}=0A-=0A=20enum=20=
json_object_type=20{=0A=20=20=20json_object_hashtable,=0A=20=20=20=
json_object_alist,=0A@@=20-226,179=20+47,6=20@@=20json_check_utf8=20=
(Lisp_Object=20string)=0A=20=20=20Lisp_Object=20false_object;=0A=20};=0A=20=
=0A-static=20json_t=20*lisp_to_json=20(Lisp_Object,=0A-=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
const=20struct=20json_configuration=20*conf);=0A-=0A-/*=20Convert=20a=20=
Lisp=20object=20to=20a=20nonscalar=20JSON=20object=20(array=20or=20=
object).=20=20*/=0A-=0A-static=20json_t=20*=0A-lisp_to_json_nonscalar_1=20=
(Lisp_Object=20lisp,=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20const=20struct=20json_configuration=20*conf)=0A=
-{=0A-=20=20json_t=20*json;=0A-=20=20specpdl_ref=20count;=0A-=0A-=20=20=
if=20(VECTORP=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20ptrdiff_t=20=
size=20=3D=20ASIZE=20(lisp);=0A-=20=20=20=20=20=20json=20=3D=20=
json_check=20(json_array=20());=0A-=20=20=20=20=20=20count=20=3D=20=
SPECPDL_INDEX=20();=0A-=20=20=20=20=20=20record_unwind_protect_ptr=20=
(json_release_object,=20json);=0A-=20=20=20=20=20=20for=20(ptrdiff_t=20i=20=
=3D=200;=20i=20<=20size;=20++i)=0A-=20=20=20=20=20=20=20=20{=0A-=20=20=20=
=20=20=20=20=20=20=20int=20status=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=3D=20json_array_append_new=20(json,=20lisp_to_json=20(AREF=20(lisp,=20=
i),=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20conf));=0A-=20=20=20=20=20=20=20=20=20=20=
if=20(status=20=3D=3D=20-1)=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
json_out_of_memory=20();=0A-=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20=
eassert=20(json_array_size=20(json)=20=3D=3D=20size);=0A-=20=20=20=20}=0A=
-=20=20else=20if=20(HASH_TABLE_P=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=
=20=20struct=20Lisp_Hash_Table=20*h=20=3D=20XHASH_TABLE=20(lisp);=0A-=20=20=
=20=20=20=20json=20=3D=20json_check=20(json_object=20());=0A-=20=20=20=20=
=20=20count=20=3D=20SPECPDL_INDEX=20();=0A-=20=20=20=20=20=20=
record_unwind_protect_ptr=20(json_release_object,=20json);=0A-=20=20=20=20=
=20=20DOHASH=20(h,=20key,=20v)=0A-=20=20=20=20=20=20=20=20{=0A-=09=20=20=
CHECK_STRING=20(key);=0A-=09=20=20Lisp_Object=20ekey=20=3D=20json_encode=20=
(key);=0A-=09=20=20/*=20We=20can't=20specify=20the=20length,=20so=20the=20=
string=20must=20be=0A-=09=20=20=20=20=20null-terminated.=20=20*/=0A-=09=20=
=20check_string_without_embedded_nulls=20(ekey);=0A-=09=20=20const=20=
char=20*key_str=20=3D=20SSDATA=20(ekey);=0A-=09=20=20/*=20Reject=20=
duplicate=20keys.=20=20These=20are=20possible=20if=20the=20hash=0A-=09=20=
=20=20=20=20table=20test=20is=20not=20`equal'.=20=20*/=0A-=09=20=20if=20=
(json_object_get=20(json,=20key_str)=20!=3D=20NULL)=0A-=09=20=20=20=20=
wrong_type_argument=20(Qjson_value_p,=20lisp);=0A-=09=20=20int=20status=0A=
-=09=20=20=20=20=3D=20json_object_set_new=20(json,=20key_str,=0A-=09=09=09=
=09=20=20=20lisp_to_json=20(v,=20conf));=0A-=09=20=20if=20(status=20=3D=3D=
=20-1)=0A-=09=20=20=20=20{=0A-=09=20=20=20=20=20=20/*=20A=20failure=20=
can=20be=20caused=20either=20by=20an=20invalid=20key=20or=0A-=09=09=20by=20=
low=20memory.=20=20*/=0A-=09=20=20=20=20=20=20json_check_utf8=20(ekey);=0A=
-=09=20=20=20=20=20=20json_out_of_memory=20();=0A-=09=20=20=20=20}=0A-=09=
}=0A-=20=20=20=20}=0A-=20=20else=20if=20(NILP=20(lisp))=0A-=20=20=20=20=
return=20json_check=20(json_object=20());=0A-=20=20else=20if=20(CONSP=20=
(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20Lisp_Object=20tail=20=3D=20=
lisp;=0A-=20=20=20=20=20=20json=20=3D=20json_check=20(json_object=20());=0A=
-=20=20=20=20=20=20count=20=3D=20SPECPDL_INDEX=20();=0A-=20=20=20=20=20=20=
record_unwind_protect_ptr=20(json_release_object,=20json);=0A-=20=20=20=20=
=20=20bool=20is_plist=20=3D=20!CONSP=20(XCAR=20(tail));=0A-=20=20=20=20=20=
=20FOR_EACH_TAIL=20(tail)=0A-=20=20=20=20=20=20=20=20{=0A-=20=20=20=20=20=
=20=20=20=20=20const=20char=20*key_str;=0A-=20=20=20=20=20=20=20=20=20=20=
Lisp_Object=20value;=0A-=20=20=20=20=20=20=20=20=20=20Lisp_Object=20=
key_symbol;=0A-=20=20=20=20=20=20=20=20=20=20if=20(is_plist)=0A-=20=20=20=
=20=20=20=20=20=20=20=20=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
key_symbol=20=3D=20XCAR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20tail=20=3D=20XCDR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20CHECK_CONS=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
value=20=3D=20XCAR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=0A=
-=20=20=20=20=20=20=20=20=20=20else=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20Lisp_Object=20pair=20=3D=20=
XCAR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20CHECK_CONS=20=
(pair);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20key_symbol=20=3D=20=
XCAR=20(pair);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20value=20=3D=20=
XCDR=20(pair);=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=
=20=20=20=20=20CHECK_SYMBOL=20(key_symbol);=0A-=20=20=20=20=20=20=20=20=20=
=20Lisp_Object=20key=20=3D=20SYMBOL_NAME=20(key_symbol);=0A-=20=20=20=20=20=
=20=20=20=20=20/*=20We=20can't=20specify=20the=20length,=20so=20the=20=
string=20must=20be=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=
null-terminated.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20=
check_string_without_embedded_nulls=20(key);=0A-=20=20=20=20=20=20=20=20=20=
=20key_str=20=3D=20SSDATA=20(key);=0A-=20=20=20=20=20=20=20=20=20=20/*=20=
In=20plists,=20ensure=20leading=20":"=20in=20keys=20is=20stripped.=20=20=
It=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20will=20be=20reconstructed=20=
later=20in=20`json_to_lisp'.*/=0A-=20=20=20=20=20=20=20=20=20=20if=20=
(is_plist=20&&=20':'=20=3D=3D=20key_str[0]=20&&=20key_str[1])=0A-=20=20=20=
=20=20=20=20=20=20=20=20=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
key_str=20=3D=20&key_str[1];=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=0A=
-=20=20=20=20=20=20=20=20=20=20/*=20Only=20add=20element=20if=20key=20is=20=
not=20already=20present.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20if=20=
(json_object_get=20(json,=20key_str)=20=3D=3D=20NULL)=0A-=20=20=20=20=20=20=
=20=20=20=20=20=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20int=20=
status=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=3D=20=
json_object_set_new=20(json,=20key_str,=20lisp_to_json=20(value,=0A-=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20conf));=0A-=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20if=20(status=20=3D=3D=20-1)=0A-=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20json_out_of_memory=20();=0A-=20=20=20=20=
=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=
=20CHECK_LIST_END=20(tail,=20lisp);=0A-=20=20=20=20}=0A-=20=20else=0A-=20=
=20=20=20wrong_type_argument=20(Qjson_value_p,=20lisp);=0A-=0A-=20=20=
clear_unwind_protect=20(count);=0A-=20=20unbind_to=20(count,=20Qnil);=0A=
-=20=20return=20json;=0A-}=0A-=0A-/*=20Convert=20LISP=20to=20a=20=
nonscalar=20JSON=20object=20(array=20or=20object).=20=20Signal=0A-=20=20=20=
an=20error=20of=20type=20`wrong-type-argument'=20if=20LISP=20is=20not=20=
a=20vector,=0A-=20=20=20hashtable,=20alist,=20or=20plist.=20=20*/=0A-=0A=
-static=20json_t=20*=0A-lisp_to_json_nonscalar=20(Lisp_Object=20lisp,=0A=
-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
const=20struct=20json_configuration=20*conf)=0A-{=0A-=20=20if=20=
(++lisp_eval_depth=20>=20max_lisp_eval_depth)=0A-=20=20=20=20xsignal0=20=
(Qjson_object_too_deep);=0A-=20=20json_t=20*json=20=3D=20=
lisp_to_json_nonscalar_1=20(lisp,=20conf);=0A-=20=20--lisp_eval_depth;=0A=
-=20=20return=20json;=0A-}=0A-=0A-/*=20Convert=20LISP=20to=20any=20JSON=20=
object.=20=20Signal=20an=20error=20of=20type=0A-=20=20=20=
`wrong-type-argument'=20if=20the=20type=20of=20LISP=20can't=20be=20=
converted=20to=20a=0A-=20=20=20JSON=20object.=20=20*/=0A-=0A-static=20=
json_t=20*=0A-lisp_to_json=20(Lisp_Object=20lisp,=20const=20struct=20=
json_configuration=20*conf)=0A-{=0A-=20=20if=20(EQ=20(lisp,=20=
conf->null_object))=0A-=20=20=20=20return=20json_check=20(json_null=20=
());=0A-=20=20else=20if=20(EQ=20(lisp,=20conf->false_object))=0A-=20=20=20=
=20return=20json_check=20(json_false=20());=0A-=20=20else=20if=20(EQ=20=
(lisp,=20Qt))=0A-=20=20=20=20return=20json_check=20(json_true=20());=0A-=20=
=20else=20if=20(INTEGERP=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20=
intmax_t=20low=20=3D=20TYPE_MINIMUM=20(json_int_t);=0A-=20=20=20=20=20=20=
intmax_t=20high=20=3D=20TYPE_MAXIMUM=20(json_int_t);=0A-=20=20=20=20=20=20=
intmax_t=20value=20=3D=20check_integer_range=20(lisp,=20low,=20high);=0A=
-=20=20=20=20=20=20return=20json_check=20(json_integer=20(value));=0A-=20=
=20=20=20}=0A-=20=20else=20if=20(FLOATP=20(lisp))=0A-=20=20=20=20return=20=
json_check=20(json_real=20(XFLOAT_DATA=20(lisp)));=0A-=20=20else=20if=20=
(STRINGP=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20Lisp_Object=20=
encoded=20=3D=20json_encode=20(lisp);=0A-=20=20=20=20=20=20json_t=20=
*json=20=3D=20json_stringn=20(SSDATA=20(encoded),=20SBYTES=20(encoded));=0A=
-=20=20=20=20=20=20if=20(json=20=3D=3D=20NULL)=0A-=20=20=20=20=20=20=20=20=
{=0A-=20=20=20=20=20=20=20=20=20=20/*=20A=20failure=20can=20be=20caused=20=
either=20by=20an=20invalid=20string=20or=20by=0A-=20=20=20=20=20=20=20=20=
=20=20=20=20=20low=20memory.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20=
json_check_utf8=20(encoded);=0A-=20=20=20=20=20=20=20=20=20=20=
json_out_of_memory=20();=0A-=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20=
return=20json;=0A-=20=20=20=20}=0A-=0A-=20=20/*=20LISP=20now=20must=20be=20=
a=20vector,=20hashtable,=20alist,=20or=20plist.=20=20*/=0A-=20=20return=20=
lisp_to_json_nonscalar=20(lisp,=20conf);=0A-}=0A-=0A=20static=20void=0A=20=
json_parse_args=20(ptrdiff_t=20nargs,=0A=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20Lisp_Object=20*args,=0A@@=20-450,158=20+98,533=20@@=20=
json_parse_args=20(ptrdiff_t=20nargs,=0A=20=20=20}=0A=20}=0A=20=0A=
-static=20bool=0A-json_available_p=20(void)=0A+/*=20FIXME:=20Remove=20=
completely.=20=20*/=0A+DEFUN=20("json--available-p",=20=
Fjson__available_p,=20Sjson__available_p,=200,=200,=20NULL,=0A+=20=20=20=20=
=20=20=20doc:=20/*=20Return=20non-nil=20if=20libjansson=20is=20available=20=
(internal=20use=20only).=20=20*/)=0A+=20=20(void)=0A=20{=0A-#ifdef=20=
WINDOWSNT=0A-=20=20if=20(!json_initialized)=0A-=20=20=20=20{=0A-=20=20=20=
=20=20=20Lisp_Object=20status;=0A-=20=20=20=20=20=20json_initialized=20=3D=
=20init_json_functions=20();=0A-=20=20=20=20=20=20status=20=3D=20=
json_initialized=20?=20Qt=20:=20Qnil;=0A-=20=20=20=20=20=20=
Vlibrary_cache=20=3D=20Fcons=20(Fcons=20(Qjson,=20status),=20=
Vlibrary_cache);=0A-=20=20=20=20}=0A-=20=20return=20json_initialized;=0A=
-#else=20=20/*=20!WINDOWSNT=20*/=0A-=20=20return=20true;=0A-#endif=0A+=20=
=20return=20Qt;=0A=20}=0A=20=0A-#ifdef=20WINDOWSNT=0A+/*=20JSON=20=
encoding=20context.=20=20*/=0A+typedef=20struct=20{=0A+=20=20char=20=
*buf;=0A+=20=20ptrdiff_t=20size;=09=20=20=20=20=20=20/*=20number=20of=20=
bytes=20in=20buf=20*/=0A+=20=20ptrdiff_t=20capacity;=09=20=20=20=20=20=20=
/*=20allocated=20size=20of=20buf=20*/=0A+=20=20ptrdiff_t=20chars_delta;=20=
=20=20=20=20=20/*=20size=20-=20{number=20of=20characters=20in=20buf}=20=
*/=0A+=0A+=20=20int=20maxdepth;=0A+=20=20struct=20symset_tbl=20=
*ss_table;=09/*=20table=20used=20by=20containing=20object=20*/=0A+=20=20=
struct=20json_configuration=20conf;=0A+}=20json_out_t;=0A+=0A+/*=20Set=20=
of=20symbols.=20=20*/=0A+typedef=20struct=20{=0A+=20=20ptrdiff_t=20=
count;=09=09/*=20symbols=20in=20table=20*/=0A+=20=20int=20bits;=09=09=09=
/*=20log2(table=20size)=20*/=0A+=20=20struct=20symset_tbl=20*table;=09/*=20=
heap-allocated=20table=20*/=0A+}=20symset_t;=0A+=0A+struct=20symset_tbl=0A=
+{=0A+=20=20/*=20Table=20used=20by=20the=20containing=20object=20if=20=
any,=20so=20that=20we=20can=20free=20all=0A+=20=20=20=20=20tables=20if=20=
an=20error=20occurs.=20=20*/=0A+=20=20struct=20symset_tbl=20*up;=0A+=20=20=
/*=20Table=20of=20symbols=20(2**bits=20elements),=20Qunbound=20where=20=
unused.=20=20*/=0A+=20=20Lisp_Object=20entries[];=0A+};=0A+=0A+static=20=
inline=20ptrdiff_t=0A+symset_size=20(int=20bits)=0A+{=0A+=20=20return=20=
(ptrdiff_t)1=20<<=20bits;=0A+}=0A+=0A+static=20struct=20symset_tbl=20*=0A=
+make_symset_table=20(int=20bits,=20struct=20symset_tbl=20*up)=0A+{=0A+=20=
=20int=20maxbits=20=3D=20min=20(SIZE_WIDTH=20-=202=20-=20(word_size=20<=20=
8=20?=202=20:=203),=2032);=0A+=20=20if=20(bits=20>=20maxbits)=0A+=20=20=20=
=20error=20("out=20of=20memory");=09/*=20Will=20never=20happen=20in=20=
practice.=20=20*/=0A+=20=20struct=20symset_tbl=20*st=20=3D=20xnmalloc=20=
(sizeof=20*st->entries=20<<=20bits,=20sizeof=20*st);=0A+=20=20st->up=20=3D=
=20up;=0A+=20=20ptrdiff_t=20size=20=3D=20symset_size=20(bits);=0A+=20=20=
for=20(ptrdiff_t=20i=20=3D=200;=20i=20<=20size;=20i++)=0A+=20=20=20=20=
st->entries[i]=20=3D=20Qunbound;=0A+=20=20return=20st;=0A+}=0A+=0A+/*=20=
Create=20a=20new=20symset=20to=20use=20for=20a=20new=20object.=20=20*/=0A=
+static=20symset_t=0A+push_symset=20(json_out_t=20*jo)=0A+{=0A+=20=20int=20=
bits=20=3D=204;=0A+=20=20struct=20symset_tbl=20*tbl=20=3D=20=
make_symset_table=20(bits,=20jo->ss_table);=0A+=20=20jo->ss_table=20=3D=20=
tbl;=0A+=20=20return=20(symset_t){=20.count=20=3D=200,=20.bits=20=3D=20=
bits,=20.table=20=3D=20tbl=20};=0A+}=0A+=0A+/*=20Destroy=20the=20current=20=
symset.=20=20*/=0A=20static=20void=0A-ensure_json_available=20(void)=0A=
+pop_symset=20(json_out_t=20*jo,=20symset_t=20*ss)=0A=20{=0A-=20=20if=20=
(!json_available_p=20())=0A-=20=20=20=20Fsignal=20(Qjson_unavailable,=0A=
-=09=20=20=20=20=20list1=20(build_unibyte_string=20("jansson=20library=20=
not=20found")));=0A+=20=20jo->ss_table=20=3D=20ss->table->up;=0A+=20=20=
xfree=20(ss->table);=0A=20}=0A-#endif=0A=20=0A-DEFUN=20=
("json--available-p",=20Fjson__available_p,=20Sjson__available_p,=200,=20=
0,=20NULL,=0A-=20=20=20=20=20=20=20doc:=20/*=20Return=20non-nil=20if=20=
libjansson=20is=20available=20(internal=20use=20only).=20=20*/)=0A-=20=20=
(void)=0A+/*=20Remove=20all=20heap-allocated=20symset=20tables,=20in=20=
case=20an=20error=20occurred.=20=20*/=0A+static=20void=0A=
+cleanup_symset_tables=20(struct=20symset_tbl=20*st)=0A=20{=0A-=20=20=
return=20json_available_p=20()=20?=20Qt=20:=20Qnil;=0A+=20=20while=20=
(st)=0A+=20=20=20=20{=0A+=20=20=20=20=20=20struct=20symset_tbl=20*up=20=3D=
=20st->up;=0A+=20=20=20=20=20=20xfree=20(st);=0A+=20=20=20=20=20=20st=20=
=3D=20up;=0A+=20=20=20=20}=0A=20}=0A=20=0A-DEFUN=20("json-serialize",=20=
Fjson_serialize,=20Sjson_serialize,=201,=20MANY,=0A-=20=20=20=20=20=20=20=
NULL,=0A-=20=20=20=20=20=20=20doc:=20/*=20Return=20the=20JSON=20=
representation=20of=20OBJECT=20as=20a=20string.=0A+static=20inline=20=
uint32_t=0A+symset_hash=20(Lisp_Object=20sym,=20int=20bits)=0A+{=0A+=20=20=
return=20knuth_hash=20(reduce_emacs_uint_to_hash_hash=20(XHASH=20(sym)),=20=
bits);=0A+}=0A=20=0A-OBJECT=20must=20be=20t,=20a=20number,=20string,=20=
vector,=20hashtable,=20alist,=20plist,=0A-or=20the=20Lisp=20equivalents=20=
to=20the=20JSON=20null=20and=20false=20values,=20and=20its=0A-elements=20=
must=20recursively=20consist=20of=20the=20same=20kinds=20of=20values.=20=20=
t=20will=0A-be=20converted=20to=20the=20JSON=20true=20value.=20=20=
Vectors=20will=20be=20converted=20to=0A-JSON=20arrays,=20whereas=20=
hashtables,=20alists=20and=20plists=20are=20converted=20to=0A-JSON=20=
objects.=20=20Hashtable=20keys=20must=20be=20strings=20without=20=
embedded=20null=0A-characters=20and=20must=20be=20unique=20within=20each=20=
object.=20=20Alist=20and=20plist=0A-keys=20must=20be=20symbols;=20if=20a=20=
key=20is=20duplicate,=20the=20first=20instance=20is=0A-used.=0A+/*=20=
Enlarge=20the=20table=20used=20by=20a=20symset.=20=20*/=0A+static=20=
NO_INLINE=20void=0A+symset_expand=20(symset_t=20*ss)=0A+{=0A+=20=20=
struct=20symset_tbl=20*old_table=20=3D=20ss->table;=0A+=20=20int=20=
oldbits=20=3D=20ss->bits;=0A+=20=20ptrdiff_t=20oldsize=20=3D=20=
symset_size=20(oldbits);=0A+=20=20int=20bits=20=3D=20oldbits=20+=201;=0A=
+=20=20ss->bits=20=3D=20bits;=0A+=20=20ss->table=20=3D=20=
make_symset_table=20(bits,=20old_table->up);=0A+=20=20/*=20Move=20all=20=
entries=20from=20the=20old=20table=20to=20the=20new=20one.=20=20*/=0A+=20=
=20ptrdiff_t=20mask=20=3D=20symset_size=20(bits)=20-=201;=0A+=20=20=
struct=20symset_tbl=20*tbl=20=3D=20ss->table;=0A+=20=20for=20(ptrdiff_t=20=
i=20=3D=200;=20i=20<=20oldsize;=20i++)=0A+=20=20=20=20{=0A+=20=20=20=20=20=
=20Lisp_Object=20sym=20=3D=20old_table->entries[i];=0A+=20=20=20=20=20=20=
if=20(!BASE_EQ=20(sym,=20Qunbound))=0A+=09{=0A+=09=20=20ptrdiff_t=20j=20=
=3D=20symset_hash=20(sym,=20bits);=0A+=09=20=20while=20(!BASE_EQ=20=
(tbl->entries[j],=20Qunbound))=0A+=09=20=20=20=20j=20=3D=20(j=20+=201)=20=
&=20mask;=0A+=09=20=20tbl->entries[j]=20=3D=20sym;=0A+=09}=0A+=20=20=20=20=
}=0A+=20=20xfree=20(old_table);=0A+}=0A=20=0A-The=20Lisp=20equivalents=20=
to=20the=20JSON=20null=20and=20false=20values=20are=0A-configurable=20in=20=
the=20arguments=20ARGS,=20a=20list=20of=20keyword/argument=20pairs:=0A=
+/*=20If=20sym=20is=20in=20ss,=20return=20false;=20otherwise=20add=20it=20=
and=20return=20true.=0A+=20=20=20Comparison=20is=20done=20by=20strict=20=
identity.=20=20*/=0A+static=20inline=20bool=0A+symset_add=20(json_out_t=20=
*jo,=20symset_t=20*ss,=20Lisp_Object=20sym)=0A+{=0A+=20=20/*=20Make=20=
sure=20we=20don't=20fill=20more=20than=20half=20of=20the=20table.=20=20=
*/=0A+=20=20if=20(ss->count=20>=3D=20(symset_size=20(ss->bits)=20>>=20=
1))=0A+=20=20=20=20{=0A+=20=20=20=20=20=20symset_expand=20(ss);=0A+=20=20=
=20=20=20=20jo->ss_table=20=3D=20ss->table;=0A+=20=20=20=20}=0A=20=0A=
-The=20keyword=20argument=20`:null-object'=20specifies=20which=20object=20=
to=20use=0A-to=20represent=20a=20JSON=20null=20value.=20=20It=20defaults=20=
to=20`:null'.=0A+=20=20struct=20symset_tbl=20*tbl=20=3D=20ss->table;=0A+=20=
=20ptrdiff_t=20mask=20=3D=20symset_size=20(ss->bits)=20-=201;=0A+=20=20=
for=20(ptrdiff_t=20i=20=3D=20symset_hash=20(sym,=20ss->bits);=20;=20i=20=
=3D=20(i=20+=201)=20&=20mask)=0A+=20=20=20=20{=0A+=20=20=20=20=20=20=
Lisp_Object=20s=20=3D=20tbl->entries[i];=0A+=20=20=20=20=20=20if=20=
(BASE_EQ=20(s,=20sym))=0A+=09return=20false;=09=09/*=20Previous=20=
occurrence=20found.=20=20*/=0A+=20=20=20=20=20=20if=20(BASE_EQ=20(s,=20=
Qunbound))=0A+=09{=0A+=09=20=20/*=20Not=20in=20set,=20add=20it.=20=20*/=0A=
+=09=20=20tbl->entries[i]=20=3D=20sym;=0A+=09=20=20ss->count++;=0A+=09=20=
=20return=20true;=0A+=09}=0A+=20=20=20=20}=0A+}=0A=20=0A-The=20keyword=20=
argument=20`:false-object'=20specifies=20which=20object=20to=20use=20to=0A=
-represent=20a=20JSON=20false=20value.=20=20It=20defaults=20to=20=
`:false'.=0A+static=20NO_INLINE=20void=0A+json_out_grow_buf=20=
(json_out_t=20*jo,=20ptrdiff_t=20bytes)=0A+{=0A+=20=20ptrdiff_t=20need=20=
=3D=20jo->size=20+=20bytes;=0A+=20=20ptrdiff_t=20new_size=20=3D=20max=20=
(jo->capacity,=20512);=0A+=20=20while=20(new_size=20<=20need)=0A+=20=20=20=
=20new_size=20<<=3D=201;=0A+=20=20jo->buf=20=3D=20xrealloc=20(jo->buf,=20=
new_size);=0A+=20=20jo->capacity=20=3D=20new_size;=0A+}=0A=20=0A-In=20=
you=20specify=20the=20same=20value=20for=20`:null-object'=20and=20=
`:false-object',=0A-a=20potentially=20ambiguous=20situation,=20the=20=
JSON=20output=20will=20not=20contain=0A-any=20JSON=20false=20values.=0A=
-usage:=20(json-serialize=20OBJECT=20&rest=20ARGS)=20=20*/)=0A-=20=20=20=20=
=20(ptrdiff_t=20nargs,=20Lisp_Object=20*args)=0A+static=20void=0A=
+cleanup_json_out=20(void=20*arg)=0A=20{=0A-=20=20specpdl_ref=20count=20=
=3D=20SPECPDL_INDEX=20();=0A+=20=20json_out_t=20*jo=20=3D=20arg;=0A+=20=20=
xfree=20(jo->buf);=0A+=20=20jo->buf=20=3D=20NULL;=0A+=20=20=
cleanup_symset_tables=20(jo->ss_table);=0A+}=0A=20=0A-#ifdef=20WINDOWSNT=0A=
-=20=20ensure_json_available=20();=0A-#endif=0A+/*=20Make=20room=20for=20=
`bytes`=20more=20bytes=20in=20buffer.=20=20*/=0A+static=20void=0A=
+json_make_room=20(json_out_t=20*jo,=20ptrdiff_t=20bytes)=0A+{=0A+=20=20=
if=20(bytes=20>=20jo->capacity=20-=20jo->size)=0A+=20=20=20=20=
json_out_grow_buf=20(jo,=20bytes);=0A+}=0A=20=0A-=20=20struct=20=
json_configuration=20conf=20=3D=0A-=20=20=20=20{json_object_hashtable,=20=
json_array_array,=20QCnull,=20QCfalse};=0A-=20=20json_parse_args=20=
(nargs=20-=201,=20args=20+=201,=20&conf,=20false);=0A+#define=20=
JSON_OUT_STR(jo,=20str)=20(json_out_str=20(jo,=20str,=20sizeof=20(str)=20=
-=201))=0A=20=0A-=20=20json_t=20*json=20=3D=20lisp_to_json=20(args[0],=20=
&conf);=0A-=20=20record_unwind_protect_ptr=20(json_release_object,=20=
json);=0A+/*=20Add=20`bytes`=20bytes=20from=20`str`=20to=20the=20buffer.=20=
=20*/=0A+static=20void=0A+json_out_str=20(json_out_t=20*jo,=20const=20=
char=20*str,=20size_t=20bytes)=0A+{=0A+=20=20json_make_room=20(jo,=20=
bytes);=0A+=20=20memcpy=20(jo->buf=20+=20jo->size,=20str,=20bytes);=0A+=20=
=20jo->size=20+=3D=20bytes;=0A+}=0A=20=0A-=20=20char=20*string=20=3D=20=
json_dumps=20(json,=20JSON_COMPACT=20|=20JSON_ENCODE_ANY);=0A-=20=20if=20=
(string=20=3D=3D=20NULL)=0A-=20=20=20=20json_out_of_memory=20();=0A-=20=20=
record_unwind_protect_ptr=20(json_free,=20string);=0A+static=20void=0A=
+json_out_byte=20(json_out_t=20*jo,=20unsigned=20char=20c)=0A+{=0A+=20=20=
json_make_room=20(jo,=201);=0A+=20=20jo->buf[jo->size++]=20=3D=20c;=0A+}=0A=
=20=0A-=20=20return=20unbind_to=20(count,=20build_string_from_utf8=20=
(string));=0A+static=20void=0A+json_out_fixnum=20(json_out_t=20*jo,=20=
EMACS_INT=20x)=0A+{=0A+=20=20char=20buf[INT_BUFSIZE_BOUND=20=
(EMACS_INT)];=0A+=20=20char=20*end=20=3D=20buf=20+=20sizeof=20buf;=0A+=20=
=20char=20*p=20=3D=20fixnum_to_string=20(x,=20buf,=20end);=0A+=20=20=
json_out_str=20(jo,=20p,=20end=20-=20p);=0A=20}=0A=20=0A-struct=20=
json_buffer_and_size=0A+static=20AVOID=0A+string_not_unicode=20=
(Lisp_Object=20obj)=0A=20{=0A-=20=20const=20char=20*buffer;=0A-=20=20=
ptrdiff_t=20size;=0A-=20=20/*=20This=20tracks=20how=20many=20bytes=20=
were=20inserted=20by=20the=20callback=20since=0A-=20=20=20=20=20=
json_dump_callback=20was=20called.=20=20*/=0A-=20=20ptrdiff_t=20=
inserted_bytes;=0A+=20=20/*=20FIXME:=20this=20is=20just=20for=20=
compatibility=20with=20existing=20tests,=20it's=20not=0A+=20=20=20=20=20=
a=20very=20descriptive=20error.=20=20*/=0A+=20=20wrong_type_argument=20=
(Qjson_value_p,=20obj);=0A+}=0A+=0A+static=20const=20unsigned=20char=20=
json_plain_char[256]=20=3D=20{=0A+=20=20/*=2032=20chars/line:=201=20for=20=
printable=20ASCII=20+=20DEL=20except=20"=20and=20\,=200=20elsewhere=20*/=0A=
+=20=200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20=
/*=2000-1f=20*/=0A+=20=20=
1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,=20/*=20=
20-3f=20*/=0A+=20=20=
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,=20/*=20=
40-5f=20*/=0A+=20=20=
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,=20/*=20=
60-7f=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
80-9f=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
a0-bf=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
c0-df=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
e0-ff=20*/=0A=20};=0A=20=0A-static=20Lisp_Object=0A-json_insert=20(void=20=
*data)=0A+static=20void=0A+json_out_string=20(json_out_t=20*jo,=20=
Lisp_Object=20str,=20int=20skip)=0A+{=0A+=20=20/*=20FIXME:=20this=20code=20=
is=20slow,=20make=20faster!=20*/=0A+=0A+=20=20static=20const=20char=20=
hexchar[16]=20=3D=20"0123456789ABCDEF";=0A+=20=20ptrdiff_t=20len=20=3D=20=
SBYTES=20(str);=0A+=20=20json_make_room=20(jo,=20len=20+=202);=0A+=20=20=
json_out_byte=20(jo,=20'"');=0A+=20=20unsigned=20char=20*p=20=3D=20SDATA=20=
(str);=0A+=20=20unsigned=20char=20*end=20=3D=20p=20+=20len;=0A+=20=20p=20=
+=3D=20skip;=0A+=20=20while=20(p=20<=20end)=0A+=20=20=20=20{=0A+=20=20=20=
=20=20=20unsigned=20char=20c=20=3D=20*p;=0A+=20=20=20=20=20=20if=20=
(json_plain_char[c])=0A+=09{=0A+=09=20=20json_out_byte=20(jo,=20c);=0A+=09=
=20=20p++;=0A+=09}=0A+=20=20=20=20=20=20else=20if=20(c=20>=200x7f)=0A+=09=
{=0A+=09=20=20if=20(STRING_MULTIBYTE=20(str))=0A+=09=20=20=20=20{=0A+=09=20=
=20=20=20=20=20int=20n;=0A+=09=20=20=20=20=20=20if=20(c=20<=3D=200xc1)=0A=
+=09=09string_not_unicode=20(str);=0A+=09=20=20=20=20=20=20if=20(c=20<=3D=20=
0xdf)=0A+=09=09n=20=3D=202;=0A+=09=20=20=20=20=20=20else=20if=20(c=20<=3D=20=
0xef)=0A+=09=09{=0A+=09=09=20=20int=20v=20=3D=20(((c=20&=200x0f)=20<<=20=
12)=0A+=09=09=09=20=20=20+=20((p[1]=20&=200x3f)=20<<=206)=20+=20(p[2]=20=
&=200x3f));=0A+=09=09=20=20if=20(char_surrogate_p=20(v))=0A+=09=09=20=20=20=
=20string_not_unicode=20(str);=0A+=09=09=20=20n=20=3D=203;=0A+=09=09}=0A=
+=09=20=20=20=20=20=20else=20if=20(c=20<=3D=200xf7)=0A+=09=09{=0A+=09=09=20=
=20int=20v=20=3D=20(((c=20&=200x07)=20<<=2018)=0A+=09=09=09=20=20=20+=20=
((p[1]=20&=200x3f)=20<<=2012)=0A+=09=09=09=20=20=20+=20((p[2]=20&=20=
0x3f)=20<<=206)=0A+=09=09=09=20=20=20+=20(p[3]=20&=200x3f));=0A+=09=09=20=
=20if=20(v=20>=20MAX_UNICODE_CHAR)=0A+=09=09=20=20=20=20=
string_not_unicode=20(str);=0A+=09=09=20=20n=20=3D=204;=0A+=09=09}=0A+=09=
=20=20=20=20=20=20else=0A+=09=09string_not_unicode=20(str);=0A+=09=20=20=20=
=20=20=20json_out_str=20(jo,=20(const=20char=20*)p,=20n);=0A+=09=20=20=20=
=20=20=20jo->chars_delta=20+=3D=20n=20-=201;=0A+=09=20=20=20=20=20=20p=20=
+=3D=20n;=0A+=09=20=20=20=20}=0A+=09=20=20else=0A+=09=20=20=20=20=
string_not_unicode=20(str);=0A+=09}=0A+=20=20=20=20=20=20else=0A+=09{=0A=
+=09=20=20json_out_byte=20(jo,=20'\\');=0A+=09=20=20switch=20(c)=0A+=09=20=
=20=20=20{=0A+=09=20=20=20=20case=20'"':=0A+=09=20=20=20=20case=20'\\':=20=
json_out_byte=20(jo,=20c);=20break;=0A+=09=20=20=20=20case=20'\b':=20=
json_out_byte=20(jo,=20'b');=20break;=0A+=09=20=20=20=20case=20'\t':=20=
json_out_byte=20(jo,=20't');=20break;=0A+=09=20=20=20=20case=20'\n':=20=
json_out_byte=20(jo,=20'n');=20break;=0A+=09=20=20=20=20case=20'\f':=20=
json_out_byte=20(jo,=20'f');=20break;=0A+=09=20=20=20=20case=20'\r':=20=
json_out_byte=20(jo,=20'r');=20break;=0A+=09=20=20=20=20default:=0A+=09=20=
=20=20=20=20=20{=0A+=09=09char=20hex[5]=20=3D=20{=20'u',=20'0',=20'0',=0A=
+=09=09=09=09hexchar[c=20>>=204],=20hexchar[c=20&=200xf]=20};=0A+=09=09=
json_out_str=20(jo,=20hex,=205);=0A+=09=09break;=0A+=09=20=20=20=20=20=20=
}=0A+=09=20=20=20=20}=0A+=09=20=20p++;=0A+=09}=0A+=20=20=20=20}=0A+=20=20=
json_out_byte=20(jo,=20'"');=0A+}=0A+=0A+static=20void=0A+json_out_nest=20=
(json_out_t=20*jo)=0A+{=0A+=20=20--jo->maxdepth;=0A+=20=20if=20=
(jo->maxdepth=20<=200)=0A+=20=20=20=20error=20("Maximum=20JSON=20=
serialisation=20depth=20exceeded");=0A+}=0A+=0A+static=20void=0A=
+json_out_unnest=20(json_out_t=20*jo)=0A=20{=0A-=20=20struct=20=
json_buffer_and_size=20*buffer_and_size=20=3D=20data;=0A-=20=20ptrdiff_t=20=
len=20=3D=20buffer_and_size->size;=0A-=20=20ptrdiff_t=20inserted_bytes=20=
=3D=20buffer_and_size->inserted_bytes;=0A-=20=20ptrdiff_t=20gap_size=20=3D=
=20GAP_SIZE=20-=20inserted_bytes;=0A+=20=20++jo->maxdepth;=0A+}=0A=20=0A=
-=20=20/*=20Enlarge=20the=20gap=20if=20necessary.=20=20*/=0A-=20=20if=20=
(gap_size=20<=20len)=0A-=20=20=20=20make_gap=20(len=20-=20gap_size);=0A=
+static=20void=20json_out_something=20(json_out_t=20*jo,=20Lisp_Object=20=
obj);=0A=20=0A-=20=20/*=20Copy=20this=20chunk=20of=20data=20into=20the=20=
gap.=20=20*/=0A-=20=20memcpy=20((char=20*)=20BEG_ADDR=20+=20PT_BYTE=20-=20=
BEG_BYTE=20+=20inserted_bytes,=0A-=09=20=20buffer_and_size->buffer,=20=
len);=0A-=20=20buffer_and_size->inserted_bytes=20+=3D=20len;=0A-=20=20=
return=20Qnil;=0A+static=20void=0A+json_out_object_cons=20(json_out_t=20=
*jo,=20Lisp_Object=20obj)=0A+{=0A+=20=20json_out_nest=20(jo);=0A+=20=20=
symset_t=20ss=20=3D=20push_symset=20(jo);=0A+=20=20json_out_byte=20(jo,=20=
'{');=0A+=20=20bool=20is_alist=20=3D=20CONSP=20(XCAR=20(obj));=0A+=20=20=
bool=20first=20=3D=20true;=0A+=20=20Lisp_Object=20tail=20=3D=20obj;=0A+=20=
=20FOR_EACH_TAIL=20(tail)=0A+=20=20=20=20{=0A+=20=20=20=20=20=20=
Lisp_Object=20key;=0A+=20=20=20=20=20=20Lisp_Object=20value;=0A+=20=20=20=
=20=20=20if=20(is_alist)=0A+=09{=0A+=09=20=20Lisp_Object=20pair=20=3D=20=
XCAR=20(tail);=0A+=09=20=20CHECK_CONS=20(pair);=0A+=09=20=20key=20=3D=20=
XCAR=20(pair);=0A+=09=20=20value=20=3D=20XCDR=20(pair);=0A+=09}=0A+=20=20=
=20=20=20=20else=0A+=09{=0A+=09=20=20key=20=3D=20XCAR=20(tail);=0A+=09=20=
=20tail=20=3D=20XCDR=20(tail);=0A+=09=20=20CHECK_CONS=20(tail);=0A+=09=20=
=20value=20=3D=20XCAR=20(tail);=0A+=09}=0A+=20=20=20=20=20=20key=20=3D=20=
maybe_remove_pos_from_symbol=20(key);=0A+=20=20=20=20=20=20CHECK_TYPE=20=
(BARE_SYMBOL_P=20(key),=20Qsymbolp,=20key);=0A+=0A+=20=20=20=20=20=20if=20=
(symset_add=20(jo,=20&ss,=20key))=0A+=09{=0A+=09=20=20if=20(!first)=0A+=09=
=20=20=20=20json_out_byte=20(jo,=20',');=0A+=09=20=20first=20=3D=20=
false;=0A+=0A+=09=20=20Lisp_Object=20key_str=20=3D=20SYMBOL_NAME=20=
(key);=0A+=09=20=20const=20char=20*str=20=3D=20SSDATA=20(key_str);=0A+=09=
=20=20/*=20Skip=20leading=20':'=20in=20plist=20keys.=20=20*/=0A+=09=20=20=
int=20skip=20=3D=20!is_alist=20&&=20str[0]=20=3D=3D=20':'=20&&=20str[1]=20=
?=201=20:=200;=0A+=09=20=20json_out_string=20(jo,=20key_str,=20skip);=0A=
+=09=20=20json_out_byte=20(jo,=20':');=0A+=09=20=20json_out_something=20=
(jo,=20value);=0A+=09}=0A+=20=20=20=20}=0A+=20=20CHECK_LIST_END=20(tail,=20=
obj);=0A+=20=20json_out_byte=20(jo,=20'}');=0A+=20=20pop_symset=20(jo,=20=
&ss);=0A+=20=20json_out_unnest=20(jo);=0A=20}=0A=20=0A-static=20=
Lisp_Object=0A-json_handle_nonlocal_exit=20(enum=20nonlocal_exit=20type,=20=
Lisp_Object=20data)=0A+static=20void=0A+json_out_object_hash=20=
(json_out_t=20*jo,=20Lisp_Object=20obj)=0A=20{=0A-=20=20switch=20(type)=0A=
+=20=20json_out_nest=20(jo);=0A+=20=20json_out_byte=20(jo,=20'{');=0A+=20=
=20struct=20Lisp_Hash_Table=20*h=20=3D=20XHASH_TABLE=20(obj);=0A+=20=20=
bool=20first=20=3D=20true;=0A+=20=20DOHASH=20(h,=20k,=20v)=0A=20=20=20=20=
=20{=0A-=20=20=20=20case=20NONLOCAL_EXIT_SIGNAL:=0A-=20=20=20=20=20=20=
return=20data;=0A-=20=20=20=20case=20NONLOCAL_EXIT_THROW:=0A-=20=20=20=20=
=20=20return=20Fcons=20(Qno_catch,=20data);=0A-=20=20=20=20default:=0A-=20=
=20=20=20=20=20eassume=20(false);=0A+=20=20=20=20=20=20if=20(!first)=0A+=09=
json_out_byte=20(jo,=20',');=0A+=20=20=20=20=20=20first=20=3D=20false;=0A=
+=20=20=20=20=20=20CHECK_STRING=20(k);=0A+=20=20=20=20=20=20/*=20It's=20=
the=20user's=20responsibility=20to=20ensure=20that=20hash=20keys=20are=0A=
+=09=20unique;=20we=20don't=20check=20for=20it.=20=20*/=0A+=20=20=20=20=20=
=20json_out_string=20(jo,=20k,=200);=0A+=20=20=20=20=20=20json_out_byte=20=
(jo,=20':');=0A+=20=20=20=20=20=20json_out_something=20(jo,=20v);=0A=20=20=
=20=20=20}=0A+=20=20json_out_byte=20(jo,=20'}');=0A+=20=20=
json_out_unnest=20(jo);=0A+=0A=20}=0A=20=0A-struct=20json_insert_data=0A=
+static=20void=0A+json_out_array=20(json_out_t=20*jo,=20Lisp_Object=20=
obj)=0A=20{=0A-=20=20/*=20This=20tracks=20how=20many=20bytes=20were=20=
inserted=20by=20the=20callback=20since=0A-=20=20=20=20=20=
json_dump_callback=20was=20called.=20=20*/=0A-=20=20ptrdiff_t=20=
inserted_bytes;=0A-=20=20/*=20nil=20if=20json_insert=20succeeded,=20=
otherwise=20the=20symbol=0A-=20=20=20=20=20Qcatch_all_memory_full=20or=20=
a=20cons=20(ERROR-SYMBOL=20.=20ERROR-DATA).=20=20*/=0A-=20=20Lisp_Object=20=
error;=0A-};=0A+=20=20json_out_nest=20(jo);=0A+=20=20json_out_byte=20=
(jo,=20'[');=0A+=20=20ptrdiff_t=20n=20=3D=20ASIZE=20(obj);=0A+=20=20for=20=
(ptrdiff_t=20i=20=3D=200;=20i=20<=20n;=20i++)=0A+=20=20=20=20{=0A+=20=20=20=
=20=20=20if=20(i=20>=200)=0A+=09json_out_byte=20(jo,=20',');=0A+=20=20=20=
=20=20=20json_out_something=20(jo,=20AREF=20(obj,=20i));=0A+=20=20=20=20=
}=0A+=20=20json_out_byte=20(jo,=20']');=0A+=20=20json_out_unnest=20(jo);=0A=
+}=0A=20=0A-/*=20Callback=20for=20json_dump_callback=20that=20inserts=20=
a=20JSON=20representation=0A-=20=20=20as=20a=20unibyte=20string=20into=20=
the=20gap.=20=20DATA=20must=20point=20to=20a=20structure=0A-=20=20=20of=20=
type=20json_insert_data.=20=20This=20function=20may=20not=20exit=20=
nonlocally.=0A-=20=20=20It=20catches=20all=20nonlocal=20exits=20and=20=
stores=20them=20in=20data->error=20for=0A-=20=20=20reraising.=20=20*/=0A=
+static=20void=0A+json_out_float=20(json_out_t=20*jo,=20Lisp_Object=20f)=0A=
+{=0A+=20=20double=20x=20=3D=20XFLOAT_DATA=20(f);=0A+=20=20if=20(isinf=20=
(x)=20||=20isnan=20(x))=0A+=20=20=20=20signal_error=20("not=20a=20finite=20=
number",=20f);=0A+=20=20/*=20As=20luck=20has=20it,=20float_to_string=20=
emits=20correct=20JSON=20float=20syntax=20for=0A+=20=20=20=20=20all=20=
numbers=20(because=20Vfloat_output_format=20is=20Qnil).=20=20*/=0A+=20=20=
json_make_room=20(jo,=20FLOAT_TO_STRING_BUFSIZE);=0A+=20=20int=20n=20=3D=20=
float_to_string=20(jo->buf=20+=20jo->size,=20x);=0A+=20=20jo->size=20+=3D=20=
n;=0A+}=0A=20=0A-static=20int=0A-json_insert_callback=20(const=20char=20=
*buffer,=20size_t=20size,=20void=20*data)=0A+static=20void=0A=
+json_out_bignum=20(json_out_t=20*jo,=20Lisp_Object=20x)=0A=20{=0A-=20=20=
struct=20json_insert_data=20*d=20=3D=20data;=0A-=20=20struct=20=
json_buffer_and_size=20buffer_and_size=0A-=20=20=20=20=3D=20{.buffer=20=3D=
=20buffer,=20.size=20=3D=20size,=20.inserted_bytes=20=3D=20=
d->inserted_bytes};=0A-=20=20d->error=20=3D=20internal_catch_all=20=
(json_insert,=20&buffer_and_size,=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
json_handle_nonlocal_exit);=0A-=20=20d->inserted_bytes=20=3D=20=
buffer_and_size.inserted_bytes;=0A-=20=20return=20NILP=20(d->error)=20?=20=
0=20:=20-1;=0A+=20=20int=20base=20=3D=2010;=0A+=20=20ptrdiff_t=20size=20=
=3D=20bignum_bufsize=20(x,=20base);=0A+=20=20json_make_room=20(jo,=20=
size);=0A+=20=20int=20n=20=3D=20bignum_to_c_string=20(jo->buf=20+=20=
jo->size,=20size,=20x,=20base);=0A+=20=20jo->size=20+=3D=20n;=0A+}=0A+=0A=
+static=20void=0A+json_out_something=20(json_out_t=20*jo,=20Lisp_Object=20=
obj)=0A+{=0A+=20=20if=20(EQ=20(obj,=20jo->conf.null_object))=0A+=20=20=20=
=20JSON_OUT_STR=20(jo,=20"null");=0A+=20=20else=20if=20(EQ=20(obj,=20=
jo->conf.false_object))=0A+=20=20=20=20JSON_OUT_STR=20(jo,=20"false");=0A=
+=20=20else=20if=20(EQ=20(obj,=20Qt))=0A+=20=20=20=20JSON_OUT_STR=20(jo,=20=
"true");=0A+=20=20else=20if=20(NILP=20(obj))=0A+=20=20=20=20JSON_OUT_STR=20=
(jo,=20"{}");=0A+=20=20else=20if=20(FIXNUMP=20(obj))=0A+=20=20=20=20=
json_out_fixnum=20(jo,=20XFIXNUM=20(obj));=0A+=20=20else=20if=20(STRINGP=20=
(obj))=0A+=20=20=20=20json_out_string=20(jo,=20obj,=200);=0A+=20=20else=20=
if=20(CONSP=20(obj))=0A+=20=20=20=20json_out_object_cons=20(jo,=20obj);=0A=
+=20=20else=20if=20(FLOATP=20(obj))=0A+=20=20=20=20json_out_float=20(jo,=20=
obj);=0A+=20=20else=20if=20(HASH_TABLE_P=20(obj))=0A+=20=20=20=20=
json_out_object_hash=20(jo,=20obj);=0A+=20=20else=20if=20(VECTORP=20=
(obj))=0A+=20=20=20=20json_out_array=20(jo,=20obj);=0A+=20=20else=20if=20=
(BIGNUMP=20(obj))=0A+=20=20=20=20json_out_bignum=20(jo,=20obj);=0A+=20=20=
else=0A+=20=20=20=20wrong_type_argument=20(Qjson_value_p,=20obj);=0A+}=0A=
+=0A+static=20Lisp_Object=0A+json_out_to_string=20(json_out_t=20*jo)=0A=
+{=0A+=20=20/*=20FIXME:=20should=20this=20be=20a=20unibyte=20or=20=
multibyte=20string?=0A+=20=20=20=20=20Right=20now=20we=20make=20a=20=
multibyte=20string=20for=20test=20compatibility,=0A+=20=20=20=20=20but=20=
we=20are=20really=20encoding=20so=20unibyte=20would=20make=20more=20=
sense.=20=20*/=0A+=20=20ptrdiff_t=20nchars=20=3D=20jo->size=20-=20=
jo->chars_delta;=0A+=20=20return=20make_multibyte_string=20(jo->buf,=20=
nchars,=20jo->size);=0A+}=0A+=0A+static=20void=0A+json_serialize=20=
(json_out_t=20*jo,=20Lisp_Object=20object,=0A+=09=09ptrdiff_t=20nargs,=20=
Lisp_Object=20*args)=0A+{=0A+=20=20*jo=20=3D=20(json_out_t)=20{=0A+=20=20=
=20=20/*=20The=20maximum=20nesting=20depth=20allowed=20should=20be=20=
sufficient=20for=20most=0A+=20=20=20=20=20=20=20uses=20but=20could=20be=20=
raised=20if=20necessary.=20=20(The=20default=20maximum=0A+=20=20=20=20=20=
=20=20depth=20for=20JSON_checker=20is=2020.)=20=20*/=0A+=20=20=20=20=
.maxdepth=20=3D=2050,=0A+=20=20=20=20.conf=20=3D=20=
{json_object_hashtable,=20json_array_array,=20QCnull,=20QCfalse}=0A+=20=20=
};=0A+=20=20json_parse_args=20(nargs,=20args,=20&jo->conf,=20false);=0A+=20=
=20record_unwind_protect_ptr=20(cleanup_json_out,=20jo);=0A+=0A+=20=20/*=20=
Make=20float=20conversion=20independent=20of=20float-output-format.=20=20=
*/=0A+=20=20if=20(!NILP=20(Vfloat_output_format))=0A+=20=20=20=20=
specbind=20(Qfloat_output_format,=20Qnil);=0A+=0A+=20=20=
json_out_something=20(jo,=20object);=0A+}=0A+=0A+DEFUN=20=
("json-serialize",=20Fjson_serialize,=20Sjson_serialize,=201,=20MANY,=0A=
+=20=20=20=20=20=20=20NULL,=0A+=20=20=20=20=20=20=20doc:=20/*=20Return=20=
the=20JSON=20representation=20of=20OBJECT=20as=20a=20string.=0A+=0A=
+OBJECT=20must=20be=20t,=20a=20number,=20string,=20vector,=20hashtable,=20=
alist,=20plist,=0A+or=20the=20Lisp=20equivalents=20to=20the=20JSON=20=
null=20and=20false=20values,=20and=20its=0A+elements=20must=20=
recursively=20consist=20of=20the=20same=20kinds=20of=20values.=20=20t=20=
will=0A+be=20converted=20to=20the=20JSON=20true=20value.=20=20Vectors=20=
will=20be=20converted=20to=0A+JSON=20arrays,=20whereas=20hashtables,=20=
alists=20and=20plists=20are=20converted=20to=0A+JSON=20objects.=20=20=
Hashtable=20keys=20must=20be=20strings,=20unique=20within=20each=20=
object.=0A+Alist=20and=20plist=20keys=20must=20be=20symbols;=20if=20a=20=
key=20is=20duplicate,=20the=20first=0A+instance=20is=20used.=20=20A=20=
leading=20colon=20in=20plist=20keys=20is=20elided.=0A+=0A+The=20Lisp=20=
equivalents=20to=20the=20JSON=20null=20and=20false=20values=20are=0A=
+configurable=20in=20the=20arguments=20ARGS,=20a=20list=20of=20=
keyword/argument=20pairs:=0A+=0A+The=20keyword=20argument=20=
`:null-object'=20specifies=20which=20object=20to=20use=0A+to=20represent=20=
a=20JSON=20null=20value.=20=20It=20defaults=20to=20`:null'.=0A+=0A+The=20=
keyword=20argument=20`:false-object'=20specifies=20which=20object=20to=20=
use=20to=0A+represent=20a=20JSON=20false=20value.=20=20It=20defaults=20=
to=20`:false'.=0A+=0A+In=20you=20specify=20the=20same=20value=20for=20=
`:null-object'=20and=20`:false-object',=0A+a=20potentially=20ambiguous=20=
situation,=20the=20JSON=20output=20will=20not=20contain=0A+any=20JSON=20=
false=20values.=0A+usage:=20(json-serialize=20OBJECT=20&rest=20ARGS)=20=20=
*/)=0A+=20=20=20=20=20(ptrdiff_t=20nargs,=20Lisp_Object=20*args)=0A+{=0A=
+=20=20specpdl_ref=20count=20=3D=20SPECPDL_INDEX=20();=0A+=20=20=
json_out_t=20jo;=0A+=20=20json_serialize=20(&jo,=20args[0],=20nargs=20-=20=
1,=20args=20+=201);=0A+=20=20return=20unbind_to=20(count,=20=
json_out_to_string=20(&jo));=0A=20}=0A=20=0A=20DEFUN=20("json-insert",=20=
Fjson_insert,=20Sjson_insert,=201,=20MANY,=0A@@=20-614,71=20+637,52=20@@=20=
DEFUN=20("json-insert",=20Fjson_insert,=20Sjson_insert,=201,=20MANY,=0A=20=
=20=20=20=20=20(ptrdiff_t=20nargs,=20Lisp_Object=20*args)=0A=20{=0A=20=20=
=20specpdl_ref=20count=20=3D=20SPECPDL_INDEX=20();=0A+=20=20json_out_t=20=
jo;=0A+=20=20json_serialize=20(&jo,=20args[0],=20nargs=20-=201,=20args=20=
+=201);=0A=20=0A-#ifdef=20WINDOWSNT=0A-=20=20ensure_json_available=20();=0A=
-#endif=0A-=0A-=20=20struct=20json_configuration=20conf=20=3D=0A-=20=20=20=
=20{json_object_hashtable,=20json_array_array,=20QCnull,=20QCfalse};=0A-=20=
=20json_parse_args=20(nargs=20-=201,=20args=20+=201,=20&conf,=20false);=0A=
-=0A-=20=20json_t=20*json=20=3D=20lisp_to_json=20(args[0],=20&conf);=0A-=20=
=20record_unwind_protect_ptr=20(json_release_object,=20json);=0A+=20=20=
/*=20FIXME:=20All=20the=20work=20below=20just=20to=20insert=20a=20string=20=
into=20a=20buffer?=20=20*/=0A=20=0A=20=20=20prepare_to_modify_buffer=20=
(PT,=20PT,=20NULL);=0A=20=20=20move_gap_both=20(PT,=20PT_BYTE);=0A-=20=20=
struct=20json_insert_data=20data;=0A-=20=20data.inserted_bytes=20=3D=20=
0;=0A-=20=20/*=20Could=20have=20used=20json_dumpb,=20but=20that=20became=20=
available=20only=20in=0A-=20=20=20=20=20Jansson=202.10,=20whereas=20we=20=
want=20to=20support=202.7=20and=20upward.=20=20*/=0A-=20=20int=20status=20=
=3D=20json_dump_callback=20(json,=20json_insert_callback,=20&data,=0A-=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20JSON_COMPACT=20|=20JSON_ENCODE_ANY);=0A-=20=20=
if=20(status=20=3D=3D=20-1)=0A-=20=20=20=20{=0A-=20=20=20=20=20=20if=20=
(CONSP=20(data.error))=0A-=20=20=20=20=20=20=20=20xsignal=20(XCAR=20=
(data.error),=20XCDR=20(data.error));=0A-=20=20=20=20=20=20else=0A-=20=20=
=20=20=20=20=20=20json_out_of_memory=20();=0A-=20=20=20=20}=0A+=20=20if=20=
(GAP_SIZE=20<=20jo.size)=0A+=20=20=20=20make_gap=20(jo.size=20-=20=
GAP_SIZE);=0A+=20=20memcpy=20((char=20*)=20BEG_ADDR=20+=20PT_BYTE=20-=20=
BEG_BYTE,=20jo.buf,=20jo.size);=0A+=0A+=20=20/*=20No=20need=20to=20keep=20=
allocation=20beyond=20this=20point.=20=20*/=0A+=20=20unbind_to=20(count,=20=
Qnil);=0A=20=0A=20=20=20ptrdiff_t=20inserted=20=3D=200;=0A-=20=20=
ptrdiff_t=20inserted_bytes=20=3D=20data.inserted_bytes;=0A-=20=20if=20=
(inserted_bytes=20>=200)=0A+=20=20ptrdiff_t=20inserted_bytes=20=3D=20=
jo.size;=0A+=0A+=20=20/*=20If=20required,=20decode=20the=20stuff=20we've=20=
read=20into=20the=20gap.=20=20*/=0A+=20=20struct=20coding_system=20=
coding;=0A+=20=20/*=20JSON=20strings=20are=20UTF-8=20encoded=20strings.=20=
=20*/=0A+=20=20setup_coding_system=20(Qutf_8_unix,=20&coding);=0A+=20=20=
coding.dst_multibyte=20=3D=20!NILP=20(BVAR=20(current_buffer,=0A+=09=09=09=
=09=20=20=20=20=20=20enable_multibyte_characters));=0A+=20=20if=20=
(CODING_MAY_REQUIRE_DECODING=20(&coding))=0A=20=20=20=20=20{=0A-=20=20=20=
=20=20=20/*=20If=20required,=20decode=20the=20stuff=20we've=20read=20=
into=20the=20gap.=20=20*/=0A-=20=20=20=20=20=20struct=20coding_system=20=
coding;=0A-=20=20=20=20=20=20/*=20JSON=20strings=20are=20UTF-8=20encoded=20=
strings.=20=20If=20for=20some=20reason=0A-=09=20the=20text=20returned=20=
by=20the=20Jansson=20library=20includes=20invalid=0A-=09=20byte=20=
sequences,=20they=20will=20be=20represented=20by=20raw=20bytes=20in=20=
the=0A-=09=20buffer=20text.=20=20*/=0A-=20=20=20=20=20=20=
setup_coding_system=20(Qutf_8_unix,=20&coding);=0A-=20=20=20=20=20=20=
coding.dst_multibyte=20=3D=0A-=09!NILP=20(BVAR=20(current_buffer,=20=
enable_multibyte_characters));=0A-=20=20=20=20=20=20if=20=
(CODING_MAY_REQUIRE_DECODING=20(&coding))=0A-=09{=0A-=20=20=20=20=20=20=20=
=20=20=20/*=20Now=20we=20have=20all=20the=20new=20bytes=20at=20the=20=
beginning=20of=20the=20gap,=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=
but=20`decode_coding_gap`=20needs=20them=20at=20the=20end=20of=20the=20=
gap,=20so=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20we=20need=20to=20=
move=20them.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20memmove=20=
(GAP_END_ADDR=20-=20inserted_bytes,=20GPT_ADDR,=20inserted_bytes);=0A-=09=
=20=20decode_coding_gap=20(&coding,=20inserted_bytes);=0A-=09=20=20=
inserted=20=3D=20coding.produced_char;=0A-=09}=0A-=20=20=20=20=20=20else=0A=
-=09{=0A-=20=20=20=20=20=20=20=20=20=20/*=20Make=20the=20inserted=20text=20=
part=20of=20the=20buffer,=20as=20unibyte=20text.=20=20*/=0A-=20=20=20=20=20=
=20=20=20=20=20eassert=20(NILP=20(BVAR=20(current_buffer,=20=
enable_multibyte_characters)));=0A-=20=20=20=20=20=20=20=20=20=20=
insert_from_gap_1=20(inserted_bytes,=20inserted_bytes,=20false);=0A-=0A-=09=
=20=20/*=20The=20target=20buffer=20is=20unibyte,=20so=20we=20don't=20=
need=20to=20decode.=20=20*/=0A-=09=20=20invalidate_buffer_caches=20=
(current_buffer,=0A-=09=09=09=09=20=20=20=20PT,=20PT=20+=20=
inserted_bytes);=0A-=09=20=20adjust_after_insert=20(PT,=20PT_BYTE,=0A-=09=
=09=09=20=20=20=20=20=20=20PT=20+=20inserted_bytes,=0A-=09=09=09=20=20=20=
=20=20=20=20PT_BYTE=20+=20inserted_bytes,=0A-=09=09=09=20=20=20=20=20=20=20=
inserted_bytes);=0A-=09=20=20inserted=20=3D=20inserted_bytes;=0A-=09}=0A=
+=20=20=20=20=20=20/*=20Now=20we=20have=20all=20the=20new=20bytes=20at=20=
the=20beginning=20of=20the=20gap,=0A+=09=20but=20`decode_coding_gap`=20=
needs=20them=20at=20the=20end=20of=20the=20gap,=20so=0A+=09=20we=20need=20=
to=20move=20them.=20=20*/=0A+=20=20=20=20=20=20memmove=20(GAP_END_ADDR=20=
-=20inserted_bytes,=20GPT_ADDR,=20inserted_bytes);=0A+=20=20=20=20=20=20=
decode_coding_gap=20(&coding,=20inserted_bytes);=0A+=20=20=20=20=20=20=
inserted=20=3D=20coding.produced_char;=0A+=20=20=20=20}=0A+=20=20else=0A=
+=20=20=20=20{=0A+=20=20=20=20=20=20/*=20Make=20the=20inserted=20text=20=
part=20of=20the=20buffer,=20as=20unibyte=20text.=20=20*/=0A+=20=20=20=20=20=
=20eassert=20(NILP=20(BVAR=20(current_buffer,=20=
enable_multibyte_characters)));=0A+=20=20=20=20=20=20insert_from_gap_1=20=
(inserted_bytes,=20inserted_bytes,=20false);=0A+=0A+=20=20=20=20=20=20/*=20=
The=20target=20buffer=20is=20unibyte,=20so=20we=20don't=20need=20to=20=
decode.=20=20*/=0A+=20=20=20=20=20=20invalidate_buffer_caches=20=
(current_buffer,=0A+=09=09=09=09PT,=20PT=20+=20inserted_bytes);=0A+=20=20=
=20=20=20=20adjust_after_insert=20(PT,=20PT_BYTE,=0A+=09=09=09=20=20=20=
PT=20+=20inserted_bytes,=0A+=09=09=09=20=20=20PT_BYTE=20+=20=
inserted_bytes,=0A+=09=09=09=20=20=20inserted_bytes);=0A+=20=20=20=20=20=20=
inserted=20=3D=20inserted_bytes;=0A=20=20=20=20=20}=0A=20=0A=20=20=20/*=20=
Call=20after-change=20hooks.=20=20*/=0A@@=20-690,7=20+694,26=20@@=20=
DEFUN=20("json-insert",=20Fjson_insert,=20Sjson_insert,=201,=20MANY,=0A=20=
=20=20=20=20=20=20SET_PT_BOTH=20(PT=20+=20inserted,=20PT_BYTE=20+=20=
inserted_bytes);=0A=20=20=20=20=20}=0A=20=0A-=20=20return=20unbind_to=20=
(count,=20Qnil);=0A+=20=20return=20Qnil;=0A+}=0A+=0A+=0A+/*=20Note=20=
that=20all=20callers=20of=20make_string_from_utf8=20and=20=
build_string_from_utf8=0A+=20=20=20below=20either=20pass=20only=20value=20=
UTF-8=20strings=20or=20use=20the=20function=20for=0A+=20=20=20formatting=20=
error=20messages;=20in=20the=20latter=20case=20correctness=20isn't=0A+=20=
=20=20critical.=20=20*/=0A+=0A+/*=20Return=20a=20unibyte=20string=20=
containing=20the=20sequence=20of=20UTF-8=20encoding=0A+=20=20=20units=20=
of=20the=20UTF-8=20representation=20of=20STRING.=20=20If=20STRING=20does=20=
not=0A+=20=20=20represent=20a=20sequence=20of=20Unicode=20scalar=20=
values,=20return=20a=20string=20with=0A+=20=20=20unspecified=20contents.=20=
=20*/=0A+=0A+static=20Lisp_Object=0A+json_encode=20(Lisp_Object=20=
string)=0A+{=0A+=20=20/*=20FIXME:=20Raise=20an=20error=20if=20STRING=20=
is=20not=20a=20scalar=20value=0A+=20=20=20=20=20sequence.=20=20*/=0A+=20=20=
return=20encode_string_utf_8=20(string,=20Qnil,=20false,=20Qt,=20Qt);=0A=20=
}=0A=20=0A=20#define=20JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE=2064=0A=
@@=20-1894,7=20+1917,6=20@@=20syms_of_json=20(void)=0A=20=20=20DEFSYM=20=
(QCnull,=20":null");=0A=20=20=20DEFSYM=20(QCfalse,=20":false");=0A=20=0A=
-=20=20DEFSYM=20(Qstring_without_embedded_nulls_p,=20=
"string-without-embedded-nulls-p");=0A=20=20=20DEFSYM=20(Qjson_value_p,=20=
"json-value-p");=0A=20=0A=20=20=20DEFSYM=20(Qjson_error,=20=
"json-error");=0A@@=20-1907,7=20+1929,6=20@@=20syms_of_json=20(void)=0A=20=
=20=20DEFSYM=20(Qjson_invalid_surrogate_error,=20=
"json-invalid-surrogate-error")=0A=20=20=20DEFSYM=20=
(Qjson_number_out_of_range,=20"json-number-out-of-range-error")=0A=20=20=20=
DEFSYM=20(Qjson_escape_sequence_error,=20"json-escape-sequence-error")=0A=
-=20=20DEFSYM=20(Qjson_unavailable,=20"json-unavailable");=0A=20=20=20=
define_error=20(Qjson_error,=20"generic=20JSON=20error",=20Qerror);=0A=20=
=20=20define_error=20(Qjson_out_of_memory,=0A=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20"not=20enough=20memory=20for=20creating=20JSON=20=
object",=20Qjson_error);=0Adiff=20--git=20a/src/lisp.h=20b/src/lisp.h=0A=
index=20f066c876619..7c4bd435cd8=20100644=0A---=20a/src/lisp.h=0A+++=20=
b/src/lisp.h=0A@@=20-4327,7=20+4327,6=20@@=20verify=20(FLT_RADIX=20=3D=3D=20=
2=20||=20FLT_RADIX=20=3D=3D=2016);=0A=20=0A=20#ifdef=20HAVE_JSON=0A=20/*=20=
Defined=20in=20json.c.=20=20*/=0A-extern=20void=20init_json=20(void);=0A=20=
extern=20void=20syms_of_json=20(void);=0A=20#endif=0A=20=0Adiff=20--git=20=
a/src/print.c=20b/src/print.c=0Aindex=2076c577ec800..0d867b89395=20=
100644=0A---=20a/src/print.c=0A+++=20b/src/print.c=0A@@=20-2859,6=20=
+2859,7=20@@=20syms_of_print=20(void)=0A=20A=20value=20of=20nil=20means=20=
to=20use=20the=20shortest=20notation=0A=20that=20represents=20the=20=
number=20without=20losing=20information.=20=20*/);=0A=20=20=20=
Vfloat_output_format=20=3D=20Qnil;=0A+=20=20DEFSYM=20=
(Qfloat_output_format,=20"float-output-format");=0A=20=0A=20=20=20=
DEFVAR_BOOL=20("print-integers-as-characters",=20=
print_integers_as_characters,=0A=20=09=20=20=20=20=20=20=20doc:=20/*=20=
Non-nil=20means=20integers=20are=20printed=20using=20characters=20=
syntax.=0Adiff=20--git=20a/test/src/json-tests.el=20=
b/test/src/json-tests.el=0Aindex=20dffc6291ca1..e5cbe8bff5c=20100644=0A=
---=20a/test/src/json-tests.el=0A+++=20b/test/src/json-tests.el=0A@@=20=
-126,11=20+126,38=20@@=20json-serialize/object=0A=20=0A=20(ert-deftest=20=
json-serialize/object-with-duplicate-keys=20()=0A=20=20=20(skip-unless=20=
(fboundp=20'json-serialize))=0A-=20=20(let=20((table=20(make-hash-table=20=
:test=20#'eq)))=0A-=20=20=20=20(puthash=20(copy-sequence=20"abc")=20[1=20=
2=20t]=20table)=0A-=20=20=20=20(puthash=20(copy-sequence=20"abc")=20=
:null=20table)=0A-=20=20=20=20(should=20(equal=20(hash-table-count=20=
table)=202))=0A-=20=20=20=20(should-error=20(json-serialize=20table)=20=
:type=20'wrong-type-argument)))=0A+=0A+=20=20(dolist=20(n=20'(1=205=2020=20=
100))=0A+=20=20=20=20(let=20((symbols=20(mapcar=20(lambda=20(i)=20=
(make-symbol=20(format=20"s%d"=20i)))=0A+=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(number-sequence=201=20=
n)))=0A+=20=20=20=20=20=20=20=20=20=20(expected=20(concat=20"{"=0A+=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20(mapconcat=20(lambda=20(i)=20(format=20"\"s%d\":%d"=20i=20i))=0A+=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20(number-sequence=201=20n)=20",")=0A+=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20"}")))=0A+=20=20=20=20=20=20;;=20alist=0A+=20=20=20=20=20=20=
(should=20(equal=20(json-serialize=0A+=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20(append=0A+=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20(cl-mapcar=20#'cons=0A+=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20symbols=20(number-sequence=201=20n))=0A+=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(cl-mapcar=20#'cons=0A+=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20symbols=20(number-sequence=201001=20(+=201000=20=
n)))))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
expected))=0A+=20=20=20=20=20=20;;=20plist=0A+=20=20=20=20=20=20(should=20=
(equal=20(json-serialize=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20(append=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20(cl-mapcan=20#'list=0A+=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20symbols=20(number-sequence=201=20n))=0A+=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20(cl-mapcan=20#'list=0A+=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20symbols=20(number-sequence=201001=20(+=201000=20n)))))=0A=
+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
expected))))=0A+=0A+=20=20;;=20We=20don't=20check=20for=20duplicated=20=
keys=20in=20hash=20tables.=0A+=20=20;;=20(let=20((table=20=
(make-hash-table=20:test=20#'eq)))=0A+=20=20;;=20=20=20(puthash=20=
(copy-sequence=20"abc")=20[1=202=20t]=20table)=0A+=20=20;;=20=20=20=
(puthash=20(copy-sequence=20"abc")=20:null=20table)=0A+=20=20;;=20=20=20=
(should=20(equal=20(hash-table-count=20table)=202))=0A+=20=20;;=20=20=20=
(should-error=20(json-serialize=20table)=20:type=20=
'wrong-type-argument))=0A+=20=20)=0A=20=0A=20(ert-deftest=20=
json-parse-string/object=20()=0A=20=20=20(skip-unless=20(fboundp=20=
'json-parse-string))=0A@@=20-173,8=20+200,8=20@@=20json-serialize/string=0A=
=20=20=20(should=20(equal=20(json-serialize=20=
["\nasd=D1=84=D1=8B=D0=B2\u001f\u007ffgh\t"])=0A=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20"[\"\\nasd=D1=84=D1=8B=D0=B2\\u001F\u007ffgh\\t=
\"]"))=0A=20=20=20(should=20(equal=20(json-serialize=20["a\0b"])=20=
"[\"a\\u0000b\"]"))=0A-=20=20;;=20FIXME:=20Is=20this=20the=20right=20=
behavior?=0A-=20=20(should=20(equal=20(json-serialize=20=
["\u00C4\xC3\x84"])=20"[\"\u00C4\u00C4\"]")))=0A+=20=20(should-error=20=
(json-serialize=20["\xC3\x84"]))=0A+=20=20(should-error=20=
(json-serialize=20["\u00C4\xC3\x84"])))=0A=20=0A=20(ert-deftest=20=
json-serialize/invalid-unicode=20()=0A=20=20=20(skip-unless=20(fboundp=20=
'json-serialize))=0A--=20=0A2.32.0=20(Apple=20Git-132)=0A=0A=

--Apple-Mail=_558A8A9C-18B2-4CE8-A0C1-865EBAE3B503--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 29 Mar 2024 06:04:35 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 29 02:04:35 2024
Received: from localhost ([127.0.0.1]:41557 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rq5Lu-00072o-Q6
	for submit <at> debbugs.gnu.org; Fri, 29 Mar 2024 02:04:35 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:53230)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1rq5Lr-00072R-3F
 for 70007 <at> debbugs.gnu.org; Fri, 29 Mar 2024 02:04:32 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1rq5Lk-0005jH-Hg; Fri, 29 Mar 2024 02:04:24 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=LJGz29EtHIsjOMQS50Y2nyTyk+WbIEHXWhRlA8QKnYc=; b=B+JgiLlULygMsQ+dYJNE
 EPP2QFBmAe6p0Jlff6RkUNk2h6Bi6JwfdmH7DbZrzshFt2SGoVBV6AuomkXPJ22mZ/965pf/XDqU0
 G+NVFP4XxfI0xB9OJbGxro9OnvVUscakmZY1oODsw34GqqVi44NByv4MyJoYHl1Ncr6/0C5ksbz59
 Xm4bSrdNSlyqXkLj3+7/BUoQlZ/eRUWOyWtm+cAA0Tq4Jf2iabYVE0PR/W4W7CyaizrpmxYPt0Nw2
 XADimL04uydoUPejjPS7bGVwogJ+ZQmvtl50O168ggpgtlJpCjkTzgmc6Z3ctmhPy6fRiQ/9wTyJH
 cekiWei+/pE9/w==;
Date: Fri, 29 Mar 2024 09:04:21 +0300
Message-Id: <86cyrdfuai.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Mattias =?utf-8?Q?Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN> (message from
 Mattias =?utf-8?Q?Engdeg=C3=A5rd?= on Thu, 28 Mar 2024 21:59:38 +0100)
Subject: Re: bug#70007: [PATCH] native JSON encoder
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
 <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: Mattias Engdegård <mattias.engdegard@HIDDEN>
> Date: Thu, 28 Mar 2024 21:59:38 +0100
> Cc: casouri@HIDDEN,
>  70007 <at> debbugs.gnu.org
> 
> 27 mars 2024 kl. 20.05 skrev Eli Zaretskii <eliz@HIDDEN>:
> 
> >>> This rejects unibyte non-ASCII strings, AFAU, in which case I suggest
> >>> to think whether we really want that.  E.g., why is it wrong to encode
> >>> a string to UTF-8, and then send it to JSON?
> >> 
> >> The way I see it, that would break the JSON abstraction: it transports strings of Unicode characters, not strings of bytes.
> > 
> > What's the difference?  AFAIU, JSON expects UTF-8 encoded strings, and
> > whether that is used as a sequence of bytes or a sequence of
> > characters is in the eyes of the beholder: the bytestream is the same,
> > only the interpretation changes.
> 
> Well no -- JSON transports Unicode strings: the JSON serialiser takes a Unicode string as input and outputs a byte sequence; the JSON parser takes a byte sequence and returns a Unicode string (assuming we are just interested in strings).
> 
> That the transport format uses UTF-8 is unrelated;

It is not unrelated.  A JSON stream is AFAIK supposed to have strings
represented in UTF-8 encoding.  When a Lisp program produces a JSON
stream, all that should matter to it is that any string there has a
valid UTF-8 sequence; where and how that sequence was obtained is of
secondary importance.

> if the user hands an encoded byte sequence to us then it seems more likely that it's a mistake.

We don't know that.  Since Emacs lets Lisp programs produce unibyte
UTF-8 encoded strings very easily, a program could do just that, for
whatever reasons.  Unless we have very serious reasons not to allow
UTF-8 sequences produced by something other than the JSON serializer
itself (and I think we don't), we should not prohibit it.  The Emacs
spirit is to let bad Lisp program enough rope to hang themselves if
that allows legitimate programs do their job more easily and flexibly.

> After all, it cannot have come from a received JSON message.

It could have, if it was encoded by the calling Lisp program.  It
could also have been received from another source, in unibyte form
that is nonetheless valid UTF-8.  If we force non-ASCII strings to be
multibyte, Lisp programs will be unable to take a unibyte UTF-8 string
received from an external source and plug it directly into an object
to be serialized into JSON; instead, they will have to decode the
string, then let the serializer encode it back -- a clear waste of CPU
cycles.

> I think it was just an another artefact of the old implementation. That code incorrectly used encode_string_utf_8 even on non-ASCII unibyte strings and trusted Jansson to validate the result. That resulted in a lot of wasted work and some strange strings getting accepted.

I'm not talking about the old implementation.  I was not completely
happy with it, either, and in particular with its insistence of
signaling errors due to encoding issues.  I think this is not our
business in this case: the responsibility for submitting a valid UTF-8
sequence, when we get a unibyte string, is on the caller.

> While it's theoretically possible that there are users with code relying on this behaviour, I can't find any evidence for it in the packages that I've looked at.

Once again, my bother is not about some code that expects us to encode
UTF-8 byte sequences -- doing that is definitely not TRT.  What I
would like to see is that unibyte strings are passed through
unchanged, so that valid UTF-8 strings will be okay, and invalid ones
will produce invalid JSON.  This is better than signaling errors,
IMNSHO, and in particular is more in-line with how Emacs handles
unibyte strings elsewhere.

> > I didn't suggest to decode the input string, not at all.  I suggested
> > to allow unibyte strings, and process them just like you process
> > pure-ASCII strings, leaving it to the caller to make sure the string
> > has only valid UTF-8 sequences.
> 
> Users of this raw-bytes-input feature (if they exist at all) previously had their input validated by Jansson. While mistakes would probably be detected at the other end I'm not sure it's a good idea.

Why not?  Once again, if we get a unibyte string, the onus is on the
caller to verify it's valid UTF-8, or suffer the consequences.

> >  Forcing callers to decode such
> > strings is IMO too harsh and largely unjustified.
> 
> We usually force them to do so in most other contexts. To take a random example, `princ` doesn't work with encoded strings. But it's rarely a problem.

There are many examples to the contrary.  For example, primitives that
deal with file names can accept both multibyte and unibyte encoded
strings.

> Let's see how testing goes. We'll find a solution no matter what, pass-through or separate slow-path validation, if it turns out that we really need to after all.

OK.  FTR, I'm not in favor of validation of unibyte strings, I just
suggest that we treat them as plain-ASCII: pass them through without
any validation, leaving the validation to the callers.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 28 Mar 2024 20:59:52 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 28 16:59:52 2024
Received: from localhost ([127.0.0.1]:41240 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rpwql-0005XA-Qm
	for submit <at> debbugs.gnu.org; Thu, 28 Mar 2024 16:59:52 -0400
Received: from mail-lf1-x12a.google.com ([2a00:1450:4864:20::12a]:58371)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mattias.engdegard@HIDDEN>) id 1rpwqh-0005Wv-C9
 for 70007 <at> debbugs.gnu.org; Thu, 28 Mar 2024 16:59:51 -0400
Received: by mail-lf1-x12a.google.com with SMTP id
 2adb3069b0e04-512bde3d197so1029786e87.0
 for <70007 <at> debbugs.gnu.org>; Thu, 28 Mar 2024 13:59:46 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1711659580; x=1712264380; darn=debbugs.gnu.org;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:from:to:cc:subject
 :date:message-id:reply-to;
 bh=4Tuv6+7kjKZCcxEEJiwBcy1o0tt9jJ0qwO60l/ePvzc=;
 b=MK/CcA52KiRVr6otf1ykYjmIZ2EYVCO34hiwg2d0Fq3TBPOpr9Ar14wkOO6GqR5PGP
 7pmKnKIos3leRlyO+jd9/QCUvYNzuFIaMFI71jyoGuYzHSVrePk32t7efu5FALYzXN+w
 PoU80/6Hkv9NmoZT2fLtIxbeWE4VV3mmThpxz+UXBwAMubKnLytXVJY/YmfQoQuC/0QR
 ZpZX+hV+qjROPR9gpS44KyCamutBC9PtLJ+evDwM8mn1ZsX7CuIpfFSQ2kl7UT56pqmU
 xzZy12o9viq1rJM007Xly2E9UIHkwPYHBnVG8KfAm9exYCBdgQxp0TRK6MZ53XpQej5R
 Kl/w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711659580; x=1712264380;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:x-gm-message-state
 :from:to:cc:subject:date:message-id:reply-to;
 bh=4Tuv6+7kjKZCcxEEJiwBcy1o0tt9jJ0qwO60l/ePvzc=;
 b=r0BrcHB/dK7Z94Vntgq2vX4SgqDPe2HmmYlQB+S1FUmx6YQAq3g257hVhdTcnJrmyk
 mggAsRGIF1iYaXR2bGH+P1rm5CoW1YMKkV6Y9Vw8QE9jjVmaSu5+UPBVPihC2jnuMI0G
 hIyORnuOyev5DA0symdSEXqFtLvYIwHMrFw/7YGxnMIhKUQexJirk7NkXHflE4FNOyrt
 mzF4SMCn+Pcxm0KOT9l65bgjKX0WsOavuSAzvMASDPIY/3vBZu88KQ3mw7rLaz2GOT25
 f5zwgG3pOuBzLsfkQapTN7OuSVHXwKElbClhTmP8QgB1oqUEKCp4NbFIGdx3MrNBTPjI
 +3eg==
X-Forwarded-Encrypted: i=1;
 AJvYcCXL1toMhB7T6v8NLyvdXOTflZtdI4JqJFRlnEYn8YZqnFOWQPoaaoRJzKmHgjj/zWbYP2QlhazX7elkIM9leRZekB9Nsys=
X-Gm-Message-State: AOJu0YxUKp34oPNjnlPwLg3ih2+PYmbUazmxaeBeBDsRgiNCXodK5huU
 j4O5xSx03EPmsA+viwECY9zGUQtLTX0biIJb9wD1JtyNILluHadV
X-Google-Smtp-Source: AGHT+IGRvp+WedSJeTQ7Myaxj4wZCsW+VeH9DOpp9xit6y0lr9eHRpV16Xex7yVwiOoRG8oIjo0Nbw==
X-Received: by 2002:ac2:5e62:0:b0:515:ab7f:b13e with SMTP id
 a2-20020ac25e62000000b00515ab7fb13emr408226lfr.33.1711659579551; 
 Thu, 28 Mar 2024 13:59:39 -0700 (PDT)
Received: from smtpclient.apple (c80-217-1-132.bredband.tele2.se.
 [80.217.1.132]) by smtp.gmail.com with ESMTPSA id
 z14-20020a056512308e00b00515c9605ea5sm297828lfd.261.2024.03.28.13.59.38
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Thu, 28 Mar 2024 13:59:39 -0700 (PDT)
Content-Type: text/plain;
	charset=us-ascii
Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.15\))
Subject: Re: bug#70007: [PATCH] native JSON encoder
From: =?utf-8?Q?Mattias_Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <8634sbijfx.fsf@HIDDEN>
Date: Thu, 28 Mar 2024 21:59:38 +0100
Content-Transfer-Encoding: quoted-printable
Message-Id: <2CF47DA5-A65B-47C4-A28A-6FEE1469BD13@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> <8634sbijfx.fsf@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
X-Mailer: Apple Mail (2.3654.120.0.1.15)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

27 mars 2024 kl. 20.05 skrev Eli Zaretskii <eliz@HIDDEN>:

>>> This rejects unibyte non-ASCII strings, AFAU, in which case I =
suggest
>>> to think whether we really want that.  E.g., why is it wrong to =
encode
>>> a string to UTF-8, and then send it to JSON?
>>=20
>> The way I see it, that would break the JSON abstraction: it =
transports strings of Unicode characters, not strings of bytes.
>=20
> What's the difference?  AFAIU, JSON expects UTF-8 encoded strings, and
> whether that is used as a sequence of bytes or a sequence of
> characters is in the eyes of the beholder: the bytestream is the same,
> only the interpretation changes.

Well no -- JSON transports Unicode strings: the JSON serialiser takes a =
Unicode string as input and outputs a byte sequence; the JSON parser =
takes a byte sequence and returns a Unicode string (assuming we are just =
interested in strings).

That the transport format uses UTF-8 is unrelated; if the user hands an =
encoded byte sequence to us then it seems more likely that it's a =
mistake. After all, it cannot have come from a received JSON message.

I think it was just an another artefact of the old implementation. That =
code incorrectly used encode_string_utf_8 even on non-ASCII unibyte =
strings and trusted Jansson to validate the result. That resulted in a =
lot of wasted work and some strange strings getting accepted.

While it's theoretically possible that there are users with code relying =
on this behaviour, I can't find any evidence for it in the packages that =
I've looked at.

> I didn't suggest to decode the input string, not at all.  I suggested
> to allow unibyte strings, and process them just like you process
> pure-ASCII strings, leaving it to the caller to make sure the string
> has only valid UTF-8 sequences.

Users of this raw-bytes-input feature (if they exist at all) previously =
had their input validated by Jansson. While mistakes would probably be =
detected at the other end I'm not sure it's a good idea.

>  Forcing callers to decode such
> strings is IMO too harsh and largely unjustified.

We usually force them to do so in most other contexts. To take a random =
example, `princ` doesn't work with encoded strings. But it's rarely a =
problem.

Let's see how testing goes. We'll find a solution no matter what, =
pass-through or separate slow-path validation, if it turns out that we =
really need to after all.





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 28 Mar 2024 19:16:49 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 28 15:16:49 2024
Received: from localhost ([127.0.0.1]:41163 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rpvF3-0007nu-HP
	for submit <at> debbugs.gnu.org; Thu, 28 Mar 2024 15:16:49 -0400
Received: from out-175.mta0.migadu.com ([2001:41d0:1004:224b::af]:63157)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <theo@HIDDEN>) id 1rpvF1-0007nV-8f
 for 70007 <at> debbugs.gnu.org; Thu, 28 Mar 2024 15:16:48 -0400
X-Report-Abuse: Please report any abuse attempt to abuse@HIDDEN and
 include these headers.
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=thornhill.no;
 s=key1; t=1711653399;
 h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
 to:to:cc:cc:mime-version:mime-version:content-type:content-type:
 content-transfer-encoding:content-transfer-encoding:
 in-reply-to:in-reply-to:references:references;
 bh=PYkWCq5l64nbppyOfCrm10eoeQh5uZxf7Rzy198dAeM=;
 b=KL9oh+U/fNNGZDQGwKI2etf7vuo81gQxipLiWcI37KKuJnNTJVjbuzMq0IESXWZ/WKSCqg
 uNfoPCdZ3yaIMlQVZ8hYEPlw9LOIP1b6dk/PXyMsmLD3XBesW5FRYgSeUkLHbwPqcxM2vY
 2R67/p1tb3k+h8lwCT1s3wOYrO0Hk7yz6MxG3fa7c6/iT91M6P+76EeXmNVj3CJbzWF9Zo
 kdMh1EaH5OEL4il3nl/sTcuMBBD8eexdtGZtRCitiF4GSpdYTDaEP1I3IGPB+4wN1x2QdL
 XjrRSo3Q+A7yzmhu5fVcwZw7FaP1EJOx4mPt2dR9kSGOJoYBTA5X0iEveJa3Rw==
From: Theodor Thornhill <theo@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
Subject: Re: bug#70007: [PATCH] native JSON encoder
In-Reply-To: <86wmpphrg7.fsf@HIDDEN> (Eli Zaretskii's message of "Tue, 26 Mar
 2024 18:46:00 +0200")
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN>
Date: Thu, 28 Mar 2024 20:16:35 +0100
Message-ID: <87y1a29nfw.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Migadu-Flow: FLOW_OUT
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: Mattias =?utf-8?Q?Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>,
 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Eli Zaretskii <eliz@HIDDEN> writes:

>> From: Mattias Engdeg=C3=A5rd <mattias.engdegard@HIDDEN>
>> Date: Tue, 26 Mar 2024 16:33:52 +0100
>>=20
>> If we replace the lisp-to-JSON encoder with native code, we would not ne=
ed the jansson library for it and it would be faster.
>>=20
>> There is ongoing work on a JSON-to-lisp parser, but the author has made =
it clear that he does not have time to write an encoder, so I spent a morni=
ng mashing up the attached patch.
>
> Thanks for working on this.
>
>> It generally produces the same result as the old code, except:
>>=20
>> - The old code incorrectly accepted strings with non-Unicode characters =
(raw bytes). There is no reason to do this; JSON is UTF-8 only.
>
> Would it complicate the code not to reject raw bytes?  I'd like to
> avoid incompatibilities if it's practical.  Also, Emacs traditionally
> doesn't reject raw bytes, leaving that to the application or the user.
>
>> I'd be very happy if someone could test it with packages that use this i=
nterface (json-serialise, json-insert).
>
> Yes, please.

I've been using this along with the json-to-lisp parser for some time
now, and I'm really happy to see these improvements. Thanks a lot!

I haven't seen any issues thus far, and emacs is much more responsive.

I hope both of these patches will soon arrive on emacs 30.

I'll continue using and testing both until then.

Thanks,
Theo




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 27 Mar 2024 19:06:09 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Mar 27 15:06:09 2024
Received: from localhost ([127.0.0.1]:38365 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rpYbB-0003XH-8N
	for submit <at> debbugs.gnu.org; Wed, 27 Mar 2024 15:06:09 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:59828)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1rpYb6-0003WD-Dh
 for 70007 <at> debbugs.gnu.org; Wed, 27 Mar 2024 15:06:08 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1rpYb0-0006pj-MF; Wed, 27 Mar 2024 15:05:58 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=JBZvqtiPMK2msP7EgwbC0yr3SlJzHU0GwNOc4LflgCI=; b=k3AqXy8Y2fypq/WdxWhT
 T21UVDXrKQFxlQoXxjd7vRYbmqYdn6LdAOdt+TNzOFk4QnGihTCoX5kIPSj6vcb7j81xWKCEZjgLL
 98Vq7sYUEwS/TRGx4Q4aKUmqABe/uWDBeUERZVVfFbxY2C5GFx6NiSU3YrU0LcqrQj2IGDtcLEbN1
 0rrTJJ38AHbpS4eYVUysDqzQJXZuQR4ebQ6On3UhZP4CBxx+WYBJCw/2JOj9zy/iOAD/0C1PZBiyO
 ibNESWF0NhVMVRb9/ZVbodyqYBP5/sAZF7acTs7n9nMeXf41ekG9nmKR6zUBzea9qF4bwP52GpgzT
 E8hu93odxJXqug==;
Date: Wed, 27 Mar 2024 21:05:54 +0200
Message-Id: <8634sbijfx.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Mattias =?utf-8?Q?Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN> (message from
 Mattias =?utf-8?Q?Engdeg=C3=A5rd?= on Wed, 27 Mar 2024 19:57:24 +0100)
Subject: Re: bug#70007: [PATCH] native JSON encoder
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
 <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 70007
Cc: casouri@HIDDEN, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: Mattias Engdegård <mattias.engdegard@HIDDEN>
> Date: Wed, 27 Mar 2024 19:57:24 +0100
> Cc: Yuan Fu <casouri@HIDDEN>,
>  70007 <at> debbugs.gnu.org
> 
> Eli, thank you for your comments!

Thanks for working on this in the first place.

> > This rejects unibyte non-ASCII strings, AFAU, in which case I suggest
> > to think whether we really want that.  E.g., why is it wrong to encode
> > a string to UTF-8, and then send it to JSON?
> 
> The way I see it, that would break the JSON abstraction: it transports strings of Unicode characters, not strings of bytes.

What's the difference?  AFAIU, JSON expects UTF-8 encoded strings, and
whether that is used as a sequence of bytes or a sequence of
characters is in the eyes of the beholder: the bytestream is the same,
only the interpretation changes.  So I'm not sure I understand how
this would break the assumption.

> A user who for some reason has a string of bytes that encode Unicode characters can just decode it in order to prove it to us. It's not the JSON encoder's job to decode the user's strings.

I didn't suggest to decode the input string, not at all.  I suggested
to allow unibyte strings, and process them just like you process
pure-ASCII strings, leaving it to the caller to make sure the string
has only valid UTF-8 sequences.  Forcing callers to decode such
strings is IMO too harsh and largely unjustified.

> (It would also be a pain to deal with and risks slowing down the string serialiser even if it's a case that never happens.)

I don't understand why.  Once again, I'm just talking about passing
the bytes through as you do with ASCII characters.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 27 Mar 2024 18:57:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Mar 27 14:57:39 2024
Received: from localhost ([127.0.0.1]:38360 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rpYSx-0002uI-3k
	for submit <at> debbugs.gnu.org; Wed, 27 Mar 2024 14:57:39 -0400
Received: from mail-lf1-x130.google.com ([2a00:1450:4864:20::130]:46144)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mattias.engdegard@HIDDEN>) id 1rpYSt-0002tc-Fq
 for 70007 <at> debbugs.gnu.org; Wed, 27 Mar 2024 14:57:37 -0400
Received: by mail-lf1-x130.google.com with SMTP id
 2adb3069b0e04-512e39226efso76026e87.0
 for <70007 <at> debbugs.gnu.org>; Wed, 27 Mar 2024 11:57:35 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1711565847; x=1712170647; darn=debbugs.gnu.org;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:from:to:cc:subject
 :date:message-id:reply-to;
 bh=yn6up81U/LxJJM14IRSJXShzBsuckqKmsBet6jsHqsQ=;
 b=Au3IAkKex5/qOF3NvsWbeZjrFUL33JQoUCYztCfQepG1ncLwgcMX5AfKUCw4+gq2Dx
 t/3jbxFi14yh5E1CvFEd7ooh51VZRbd0e6mTjqGkSsNkFE+w+XEvisazUAdWwsPS+Vqm
 TkC1vKhotyobQv9UcomB3KpuFNP1lH/diRll4pGhchR8FfK+zlciB9la4LkasSy/U5O6
 o0eDI8FDvLHboviz0BShJhuSqHXtbGWVJRliHOP0F7ZSTQNmC0T7UmWg7FzSKvscRVyl
 0GZTom3o0r6aeDwrrdV8GPOw/gvdqxykZs3yAyeKNaAiGlo6WoZkUSxpPJ7C7dtr13qj
 aKvA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711565847; x=1712170647;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:x-gm-message-state
 :from:to:cc:subject:date:message-id:reply-to;
 bh=yn6up81U/LxJJM14IRSJXShzBsuckqKmsBet6jsHqsQ=;
 b=hunh9J9xPG3BMKg4l90LufP7KJaB8NOz1pK5X15vR6iBA+OpESzKQlS2NuJ2cSUdFv
 6csPdvkoYJ9CPJBENBKiob13iZGnFodboLUCJKav2XcyHGafG+l/rE5Li65P3jV0nIFq
 BtFckGwuAqw2VXuy/Mycgi1czYUinSYV6QGkj6uDkwsYTKHmFz2NCG9B9voK3hxd6RNQ
 adbrODpsXE9aS1mUqBEF6rfBzX98aLhlp7OpI9WQJaakxxm6uxMCKTfzblSfaSGRChBf
 xSTH497y5EIs9wgMPux5U/XONUsxqsOTBiiPx8kVrdxLHsKpD8dqJPzX1QMwJ6MSBpfl
 i5HA==
X-Forwarded-Encrypted: i=1;
 AJvYcCUQszLLiKM2v+KEhFsY6jBtp3VrxwDRh7Qj9LR9O8MW1eBNYhw7rW6UXa8vMk/FJ3uh0R5phNGkBTdJnPgFTgJHQLeY85Y=
X-Gm-Message-State: AOJu0Yz+Ys9Zm+F5V8vTKDs20eWEjN3t5IbdJAG5vJzDGtIIOplHIbWE
 hRNUMf6x+o8VJ/nsy7yt17D0827TI/LzWeuPmUm+I8EVfku1XHYO
X-Google-Smtp-Source: AGHT+IFthrONboqDSxnd80YkfjlW2VR+WYFiREKmjTRqmZEuDPDnhOTxjnkk+6+CnsZJmifo8eUfvQ==
X-Received: by 2002:a05:6512:289:b0:515:8159:788d with SMTP id
 j9-20020a056512028900b005158159788dmr214313lfp.64.1711565846982; 
 Wed, 27 Mar 2024 11:57:26 -0700 (PDT)
Received: from smtpclient.apple (c80-217-1-132.bredband.tele2.se.
 [80.217.1.132]) by smtp.gmail.com with ESMTPSA id
 c42-20020a05651223aa00b00515ac42651dsm1287909lfv.257.2024.03.27.11.57.25
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Wed, 27 Mar 2024 11:57:26 -0700 (PDT)
Content-Type: text/plain;
	charset=us-ascii
Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.15\))
Subject: Re: bug#70007: [PATCH] native JSON encoder
From: =?utf-8?Q?Mattias_Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <864jcrindg.fsf@HIDDEN>
Date: Wed, 27 Mar 2024 19:57:24 +0100
Content-Transfer-Encoding: quoted-printable
Message-Id: <291DD5F1-85B8-4647-A40A-EBBD4C51E253@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> <864jcrindg.fsf@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
X-Mailer: Apple Mail (2.3654.120.0.1.15)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: Yuan Fu <casouri@HIDDEN>, 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Eli, thank you for your comments!

27 mars 2024 kl. 18.40 skrev Eli Zaretskii <eliz@HIDDEN>:

>> +/* JSON encoding context */
>=20
> This is not our comment style.

I'll go through the code and clean up all comments.

>> +typedef struct {
>> +  char *buf;
>> +  ptrdiff_t size;		/* number of bytes in buf */
>> +  ptrdiff_t capacity;		/* allocated size of buf */
>> +  ptrdiff_t chars_delta;        /* size - {number of Unicode chars =
in buf} */
>=20
> When you say "Unicode chars", what do you mean? characters or bytes?
> If characters, then why do you need to qualify them with "Unicode"?

Characters. Will clarify.

>> +  Lisp_Object entries[];
>                        ^^
> Is this portable enough?

Something I'd like to know, too. We rely on C99 in many other aspects. =
Are there still compilers that are important to us but don't get this =
right?

10 years ago this was apparently an issue for IBM XL C 12.1, but modern =
versions are based on Clang. We could take our chances here; obviously =
we'll change it if someone complains but it seems unlikely. What do you =
think?

> I'd add an assertion here that BITS is not large enough to produce =
zero.

I'll deal with that in some way or another.

> This rejects unibyte non-ASCII strings, AFAU, in which case I suggest
> to think whether we really want that.  E.g., why is it wrong to encode
> a string to UTF-8, and then send it to JSON?

The way I see it, that would break the JSON abstraction: it transports =
strings of Unicode characters, not strings of bytes. A user who for some =
reason has a string of bytes that encode Unicode characters can just =
decode it in order to prove it to us. It's not the JSON encoder's job to =
decode the user's strings.

(It would also be a pain to deal with and risks slowing down the string =
serialiser even if it's a case that never happens.)

> Is JSON unable to handle Inf and NaN?

That's right.

>> +  /* FIXME: should this be a unibyte or multibyte string?
>> +     Right now we make a multibyte string for test compatibility,
>> +     but we are really encoding so unibyte would make more sense.  =
*/
>=20
> I indeed think this should be a unibyte string, because otherwise
> writing it to a file or a process will/might encode it, which would be
> wrong.

I would prefer that, too, but used multibyte for compatibility with the =
old code and so that its tests pass.
It should probably be a separate change if we decide that unibyte is =
better here.

>> +  json_out_t jo =3D {
>> +    .maxdepth =3D 25,
>=20
> Is this arbitrary, or is it what JSON expects?  If arbitrary, should
> it be customizable? should it be documented?

It's semi-arbitrary but reasonable: the JSON_checker at json.org uses a =
maximum depth of 20 by default, and many implementations use its test =
suite. RFC-8259 states that the maximum depth is =
implementation-dependent.

It's hardly worth making this into a parameter for the user to adjust =
but I'll clarify the code.

>> +  /* FIXME: Do we really need to do all this work below to insert a =
string?
>> +     Is there no function already written?  I must be missing =
something.  */
>=20
> There is no function.  All the insert_from_* functions in insdel.c do
> something similar.

Thank you for confirming that. Looks like we could use some abstraction =
then.





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 27 Mar 2024 17:41:12 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Mar 27 13:41:12 2024
Received: from localhost ([127.0.0.1]:38330 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rpXGy-0004zc-1a
	for submit <at> debbugs.gnu.org; Wed, 27 Mar 2024 13:41:12 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:54384)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1rpXGv-0004z2-8D
 for 70007 <at> debbugs.gnu.org; Wed, 27 Mar 2024 13:41:10 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1rpXGp-00049j-Lw; Wed, 27 Mar 2024 13:41:03 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=9lKA/lbeTmHfzoDN2Q3IdM36nHNW+nHMueGQJfW9b8M=; b=K00PW1IB/eSdtCrA1h6y
 nazFcV/1puV2UYZq+2XqMTUqAepcFJL76DbmU81ihpGJAmJ2kLfPiv/qZoclpKOLJKypZTE7DR6iU
 Q3X/eICqWqyL/jqfPwISLj6n7qNDxZwhexXoX+n0yZ0/S7ymRAT2L3Q+gPoQpA6UneGC56KA3Ld2C
 YJiJC3Ztyhe+DxogqxW90ooYPXmIziF1c7cV8gTzPzKPoCIpzrrXvKIvsyHacEqqz4fCnSfhtNZww
 4fgtMGyQiHUgbf46sFRNCtLuLE3itL83aRULYi1xl+uBgnkDcbvLG7EZFVIJYwIFtTDzUT6Hb3ca9
 0xutc4SXGULxNQ==;
Date: Wed, 27 Mar 2024 19:40:59 +0200
Message-Id: <864jcrindg.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Mattias =?utf-8?Q?Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>,
 Yuan Fu <casouri@HIDDEN>
In-Reply-To: <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN> (message from
 Mattias =?utf-8?Q?Engdeg=C3=A5rd?= on Wed, 27 Mar 2024 16:49:53 +0100)
Subject: Re: bug#70007: [PATCH] native JSON encoder
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
 <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 70007
Cc: 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: Mattias Engdegård <mattias.engdegard@HIDDEN>
> Date: Wed, 27 Mar 2024 16:49:53 +0100
> Cc: 70007 <at> debbugs.gnu.org
> 
> Here is an updated patch. It now ignores duplicated keys in objects represented by alists and plists, just like the old encoder. (I didn't include this in the first draft out of fear it would be slow and complicated, but it turned out just to be complicated.)
> 
> The performance is still acceptable, which means at least 2x the speed of the Jansson-based encoder.

Thanks.  A few initial comments and questions, based on a very cursory
reading.

> +/* JSON encoding context */

This is not our comment style.

> +typedef struct {
> +  char *buf;
> +  ptrdiff_t size;		/* number of bytes in buf */
> +  ptrdiff_t capacity;		/* allocated size of buf */
> +  ptrdiff_t chars_delta;        /* size - {number of Unicode chars in buf} */

When you say "Unicode chars", what do you mean? characters or bytes?
If characters, then why do you need to qualify them with "Unicode"?

> +struct symset_tbl
> +{
> +  /* Table used by the containing object if any, so that we can easily
> +     all tables if an error occurs.  */
> +  struct symset_tbl *up;
> +  /* Table of symbols (2**bits entries), Qunbound where unused.  */
> +  Lisp_Object entries[];
                        ^^
Is this portable enough?

> +static struct symset_tbl *
> +alloc_symset_table (int bits)
> +{
> +  struct symset_tbl *st = xmalloc (sizeof *st + (sizeof *st->entries << bits));
> +  int size = 1 << bits;

I'd add an assertion here that BITS is not large enough to produce zero.

> +/* Enlarge the table used by a symset. */
                                        ^^
Two spaces there, please.

> +static NO_INLINE void
> +symset_expand (symset_t *ss)
> +{
> +  struct symset_tbl *old_table = ss->table;
> +  int oldbits = ss->bits;
> +  int oldsize = 1 << oldbits;

I'd add an assertion here about the magnitude of BITS.

> +  while (p < end)
> +    {
> +      unsigned char c = *p;
> +      if (json_plain_char[c])
> +	{
> +	  json_out_byte (jo, c);
> +	  p++;
> +	}
> +      else if (c > 0x7f)
> +	{
> +	  if (STRING_MULTIBYTE (str))
> +	    {
> +	      int n;
> +	      if (c <= 0xc1)
> +		string_not_unicode (str);
> +	      if (c <= 0xdf)
> +		n = 2;
> +	      else if (c <= 0xef)
> +		{
> +		  int v = (((c & 0x0f) << 12)
> +			   + ((p[1] & 0x3f) << 6) + (p[2] & 0x3f));
> +		  if (char_surrogate_p (v))
> +		    string_not_unicode (str);
> +		  n = 3;
> +		}
> +	      else if (c <= 0xf7)
> +		{
> +		  int v = (((c & 0x07) << 18)
> +			   + ((p[1] & 0x3f) << 12)
> +			   + ((p[2] & 0x3f) << 6)
> +			   + (p[3] & 0x3f));
> +		  if (v > MAX_UNICODE_CHAR)
> +		    string_not_unicode (str);
> +		  n = 4;
> +		}
> +	      else
> +		string_not_unicode (str);
> +	      json_out_str (jo, (const char *)p, n);
> +	      jo->chars_delta += n - 1;
> +	      p += n;
> +	    }
> +	  else
> +	    string_not_unicode (str);

This rejects unibyte non-ASCII strings, AFAU, in which case I suggest
to think whether we really want that.  E.g., why is it wrong to encode
a string to UTF-8, and then send it to JSON?

> +static void
> +json_out_float (json_out_t *jo, Lisp_Object f)
> +{
> +  double x = XFLOAT_DATA (f);
> +  if (isinf (x) || isnan (x))
> +    signal_error ("not a finite number", f);

Is JSON unable to handle Inf and NaN?

> +static Lisp_Object
> +json_out_string_result (json_out_t *jo)
> +{
> +  /* FIXME: should this be a unibyte or multibyte string?
> +     Right now we make a multibyte string for test compatibility,
> +     but we are really encoding so unibyte would make more sense.  */

I indeed think this should be a unibyte string, because otherwise
writing it to a file or a process will/might encode it, which would be
wrong.

> +  json_out_t jo = {
> +    .maxdepth = 25,

Is this arbitrary, or is it what JSON expects?  If arbitrary, should
it be customizable? should it be documented?

> +  /* FIXME: Do we really need to do all this work below to insert a string?
> +     Is there no function already written?  I must be missing something.  */

There is no function.  All the insert_from_* functions in insdel.c do
something similar.

Btw, shouldn't json-insert call treesit_record_change?  Yuan?




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 27 Mar 2024 15:50:05 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Mar 27 11:50:05 2024
Received: from localhost ([127.0.0.1]:38214 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rpVXQ-0004ZN-Hv
	for submit <at> debbugs.gnu.org; Wed, 27 Mar 2024 11:50:04 -0400
Received: from mail-lf1-x132.google.com ([2a00:1450:4864:20::132]:60542)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mattias.engdegard@HIDDEN>) id 1rpVXN-0004YB-5Y
 for 70007 <at> debbugs.gnu.org; Wed, 27 Mar 2024 11:50:02 -0400
Received: by mail-lf1-x132.google.com with SMTP id
 2adb3069b0e04-513e89d0816so8514488e87.0
 for <70007 <at> debbugs.gnu.org>; Wed, 27 Mar 2024 08:50:00 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1711554595; x=1712159395; darn=debbugs.gnu.org;
 h=references:to:cc:in-reply-to:date:subject:mime-version:message-id
 :from:sender:from:to:cc:subject:date:message-id:reply-to;
 bh=lP9/Mtc5lDk9Bh9CDr+RvAHZqYeHtr66KCBQMaEwfdM=;
 b=JDOea/pZWnjoS9ZTnWw+jN9iCSWr9YYgwPeW5QT4vaDSvsGCZ0pbPFQ9DfIx/AXhmA
 lrusCVVfpSPcCyZmCRWJdClLQCx1li4706423bUcMkA2Z/kgtEf2kuiO5cZc1tANZFrG
 rgu1xIfA4QEnZRPVGMoQlsitG2cMDUjiZYe4RQl6eHNePJ9FHOULPX0KkW9mqehxBswz
 Rf948CBH37R4jvItjhVdy45ZiyHentyspTGhgUuMpk6E5Q4Sx0ahxp5SkvKOD17ZdDzp
 IRAgqiXppwPvyFgLx1WQ4UO6iPXKtxPpUQrc3gMSFeobslYAptjXulxlcY6yqoQJLPuD
 r5Dg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711554595; x=1712159395;
 h=references:to:cc:in-reply-to:date:subject:mime-version:message-id
 :from:sender:x-gm-message-state:from:to:cc:subject:date:message-id
 :reply-to;
 bh=lP9/Mtc5lDk9Bh9CDr+RvAHZqYeHtr66KCBQMaEwfdM=;
 b=UVlqwzzIyFB7zc/MrqvA53JKTis0AU0ujfIC+JyIXG6QpHJxXt2sz0TKoN57/i7xZ+
 xV2GpOc4r+laQ132Z5r9GtowOtOnwVCLL/qDeVGMeKF6Eh2gvLoM6+VW/Bgv1ENBLDkQ
 EJHSH8jwrxdZtfFxtR1qyI6BcDdHbBvvG06hPFS6VnAHdS/z0OUPLLHu1yodk3ucEbFX
 hSub4/fCkUxBjEf/2f8MDo74hYdEr7RTivLLFJPzK5P5dbGmo0VlcBiJJYIcdlZXufHC
 htjakukPz1SYjXtSQHXuC2c2xfy7jXCVlVqo5PjvhFZavkGm31OHFDjE+UOKB1OR6TWe
 tzXg==
X-Gm-Message-State: AOJu0YzKdxfJJ500QFTT3wDuA2QVmVvr0g+tZGEAPm4phndtdcrZUZcY
 UxpnXahT4APtOhXBe+LG/wVXZt0IkEdLacBz321qz7qa64+vxgf1
X-Google-Smtp-Source: AGHT+IH5vWNAMGrGnCnD9dAM4+opD+LVibrexN+tiKpD3l7XABPd7yMxUfmcJHN/pro0UCESqDwkbQ==
X-Received: by 2002:a05:6512:1cd:b0:514:b4ca:f478 with SMTP id
 f13-20020a05651201cd00b00514b4caf478mr1255633lfp.39.1711554594583; 
 Wed, 27 Mar 2024 08:49:54 -0700 (PDT)
Received: from smtpclient.apple (c80-217-1-132.bredband.tele2.se.
 [80.217.1.132]) by smtp.gmail.com with ESMTPSA id
 c11-20020a056512238b00b00515ae2cbefesm1046802lfv.247.2024.03.27.08.49.53
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Wed, 27 Mar 2024 08:49:53 -0700 (PDT)
From: =?utf-8?Q?Mattias_Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
Message-Id: <4589243D-C11A-45C1-AF3E-6F4A5BADEB54@HIDDEN>
Content-Type: multipart/mixed;
 boundary="Apple-Mail=_E4201434-B8C0-4597-91DC-3456766FB664"
Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.15\))
Subject: Re: bug#70007: [PATCH] native JSON encoder
Date: Wed, 27 Mar 2024 16:49:53 +0100
In-Reply-To: <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN> <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
X-Mailer: Apple Mail (2.3654.120.0.1.15)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)


--Apple-Mail=_E4201434-B8C0-4597-91DC-3456766FB664
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii

Here is an updated patch. It now ignores duplicated keys in objects =
represented by alists and plists, just like the old encoder. (I didn't =
include this in the first draft out of fear it would be slow and =
complicated, but it turned out just to be complicated.)

The performance is still acceptable, which means at least 2x the speed =
of the Jansson-based encoder.


--Apple-Mail=_E4201434-B8C0-4597-91DC-3456766FB664
Content-Disposition: attachment;
	filename=json-serialise.diff
Content-Type: application/octet-stream;
	x-unix-mode=0644;
	name="json-serialise.diff"
Content-Transfer-Encoding: quoted-printable

diff=20--git=20a/src/json.c=20b/src/json.c=0Aindex=20=
e849ccaf722..b853dec3b21=20100644=0A---=20a/src/json.c=0A+++=20=
b/src/json.c=0A@@=20-23,6=20+23,7=20@@=20Copyright=20(C)=202017-2024=20=
Free=20Software=20Foundation,=20Inc.=0A=20#include=20<stddef.h>=0A=20=
#include=20<stdint.h>=0A=20#include=20<stdlib.h>=0A+#include=20<math.h>=0A=
=20=0A=20#include=20<jansson.h>=0A=20=0A@@=20-231,12=20+232,6=20@@=20=
json_encode=20(Lisp_Object=20string)=0A=20=20=20return=20=
encode_string_utf_8=20(string,=20Qnil,=20false,=20Qt,=20Qt);=0A=20}=0A=20=
=0A-static=20AVOID=0A-json_out_of_memory=20(void)=0A-{=0A-=20=20xsignal0=20=
(Qjson_out_of_memory);=0A-}=0A-=0A=20/*=20Signal=20a=20Lisp=20error=20=
corresponding=20to=20the=20JSON=20ERROR.=20=20*/=0A=20=0A=20static=20=
AVOID=0A@@=20-289,26=20+284,6=20@@=20check_string_without_embedded_nulls=20=
(Lisp_Object=20object)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
Qstring_without_embedded_nulls_p,=20object);=0A=20}=0A=20=0A-/*=20Signal=20=
an=20error=20of=20type=20`json-out-of-memory'=20if=20OBJECT=20is=0A-=20=20=
=20NULL.=20=20*/=0A-=0A-static=20json_t=20*=0A-json_check=20(json_t=20=
*object)=0A-{=0A-=20=20if=20(object=20=3D=3D=20NULL)=0A-=20=20=20=20=
json_out_of_memory=20();=0A-=20=20return=20object;=0A-}=0A-=0A-/*=20If=20=
STRING=20is=20not=20a=20valid=20UTF-8=20string,=20signal=20an=20error=20=
of=20type=0A-=20=20=20`wrong-type-argument'.=20=20STRING=20must=20be=20a=20=
unibyte=20string.=20=20*/=0A-=0A-static=20void=0A-json_check_utf8=20=
(Lisp_Object=20string)=0A-{=0A-=20=20CHECK_TYPE=20(utf8_string_p=20=
(string),=20Qutf_8_string_p,=20string);=0A-}=0A-=0A=20enum=20=
json_object_type=20{=0A=20=20=20json_object_hashtable,=0A=20=20=20=
json_object_alist,=0A@@=20-327,179=20+302,6=20@@=20json_check_utf8=20=
(Lisp_Object=20string)=0A=20=20=20Lisp_Object=20false_object;=0A=20};=0A=20=
=0A-static=20json_t=20*lisp_to_json=20(Lisp_Object,=0A-=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
const=20struct=20json_configuration=20*conf);=0A-=0A-/*=20Convert=20a=20=
Lisp=20object=20to=20a=20nonscalar=20JSON=20object=20(array=20or=20=
object).=20=20*/=0A-=0A-static=20json_t=20*=0A-lisp_to_json_nonscalar_1=20=
(Lisp_Object=20lisp,=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20const=20struct=20json_configuration=20*conf)=0A=
-{=0A-=20=20json_t=20*json;=0A-=20=20specpdl_ref=20count;=0A-=0A-=20=20=
if=20(VECTORP=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20ptrdiff_t=20=
size=20=3D=20ASIZE=20(lisp);=0A-=20=20=20=20=20=20json=20=3D=20=
json_check=20(json_array=20());=0A-=20=20=20=20=20=20count=20=3D=20=
SPECPDL_INDEX=20();=0A-=20=20=20=20=20=20record_unwind_protect_ptr=20=
(json_release_object,=20json);=0A-=20=20=20=20=20=20for=20(ptrdiff_t=20i=20=
=3D=200;=20i=20<=20size;=20++i)=0A-=20=20=20=20=20=20=20=20{=0A-=20=20=20=
=20=20=20=20=20=20=20int=20status=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=3D=20json_array_append_new=20(json,=20lisp_to_json=20(AREF=20(lisp,=20=
i),=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20conf));=0A-=20=20=20=20=20=20=20=20=20=20=
if=20(status=20=3D=3D=20-1)=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
json_out_of_memory=20();=0A-=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20=
eassert=20(json_array_size=20(json)=20=3D=3D=20size);=0A-=20=20=20=20}=0A=
-=20=20else=20if=20(HASH_TABLE_P=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=
=20=20struct=20Lisp_Hash_Table=20*h=20=3D=20XHASH_TABLE=20(lisp);=0A-=20=20=
=20=20=20=20json=20=3D=20json_check=20(json_object=20());=0A-=20=20=20=20=
=20=20count=20=3D=20SPECPDL_INDEX=20();=0A-=20=20=20=20=20=20=
record_unwind_protect_ptr=20(json_release_object,=20json);=0A-=20=20=20=20=
=20=20DOHASH=20(h,=20key,=20v)=0A-=20=20=20=20=20=20=20=20{=0A-=09=20=20=
CHECK_STRING=20(key);=0A-=09=20=20Lisp_Object=20ekey=20=3D=20json_encode=20=
(key);=0A-=09=20=20/*=20We=20can't=20specify=20the=20length,=20so=20the=20=
string=20must=20be=0A-=09=20=20=20=20=20null-terminated.=20=20*/=0A-=09=20=
=20check_string_without_embedded_nulls=20(ekey);=0A-=09=20=20const=20=
char=20*key_str=20=3D=20SSDATA=20(ekey);=0A-=09=20=20/*=20Reject=20=
duplicate=20keys.=20=20These=20are=20possible=20if=20the=20hash=0A-=09=20=
=20=20=20=20table=20test=20is=20not=20`equal'.=20=20*/=0A-=09=20=20if=20=
(json_object_get=20(json,=20key_str)=20!=3D=20NULL)=0A-=09=20=20=20=20=
wrong_type_argument=20(Qjson_value_p,=20lisp);=0A-=09=20=20int=20status=0A=
-=09=20=20=20=20=3D=20json_object_set_new=20(json,=20key_str,=0A-=09=09=09=
=09=20=20=20lisp_to_json=20(v,=20conf));=0A-=09=20=20if=20(status=20=3D=3D=
=20-1)=0A-=09=20=20=20=20{=0A-=09=20=20=20=20=20=20/*=20A=20failure=20=
can=20be=20caused=20either=20by=20an=20invalid=20key=20or=0A-=09=09=20by=20=
low=20memory.=20=20*/=0A-=09=20=20=20=20=20=20json_check_utf8=20(ekey);=0A=
-=09=20=20=20=20=20=20json_out_of_memory=20();=0A-=09=20=20=20=20}=0A-=09=
}=0A-=20=20=20=20}=0A-=20=20else=20if=20(NILP=20(lisp))=0A-=20=20=20=20=
return=20json_check=20(json_object=20());=0A-=20=20else=20if=20(CONSP=20=
(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20Lisp_Object=20tail=20=3D=20=
lisp;=0A-=20=20=20=20=20=20json=20=3D=20json_check=20(json_object=20());=0A=
-=20=20=20=20=20=20count=20=3D=20SPECPDL_INDEX=20();=0A-=20=20=20=20=20=20=
record_unwind_protect_ptr=20(json_release_object,=20json);=0A-=20=20=20=20=
=20=20bool=20is_plist=20=3D=20!CONSP=20(XCAR=20(tail));=0A-=20=20=20=20=20=
=20FOR_EACH_TAIL=20(tail)=0A-=20=20=20=20=20=20=20=20{=0A-=20=20=20=20=20=
=20=20=20=20=20const=20char=20*key_str;=0A-=20=20=20=20=20=20=20=20=20=20=
Lisp_Object=20value;=0A-=20=20=20=20=20=20=20=20=20=20Lisp_Object=20=
key_symbol;=0A-=20=20=20=20=20=20=20=20=20=20if=20(is_plist)=0A-=20=20=20=
=20=20=20=20=20=20=20=20=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
key_symbol=20=3D=20XCAR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20tail=20=3D=20XCDR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20CHECK_CONS=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
value=20=3D=20XCAR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=0A=
-=20=20=20=20=20=20=20=20=20=20else=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20Lisp_Object=20pair=20=3D=20=
XCAR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20CHECK_CONS=20=
(pair);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20key_symbol=20=3D=20=
XCAR=20(pair);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20value=20=3D=20=
XCDR=20(pair);=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=
=20=20=20=20=20CHECK_SYMBOL=20(key_symbol);=0A-=20=20=20=20=20=20=20=20=20=
=20Lisp_Object=20key=20=3D=20SYMBOL_NAME=20(key_symbol);=0A-=20=20=20=20=20=
=20=20=20=20=20/*=20We=20can't=20specify=20the=20length,=20so=20the=20=
string=20must=20be=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=
null-terminated.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20=
check_string_without_embedded_nulls=20(key);=0A-=20=20=20=20=20=20=20=20=20=
=20key_str=20=3D=20SSDATA=20(key);=0A-=20=20=20=20=20=20=20=20=20=20/*=20=
In=20plists,=20ensure=20leading=20":"=20in=20keys=20is=20stripped.=20=20=
It=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20will=20be=20reconstructed=20=
later=20in=20`json_to_lisp'.*/=0A-=20=20=20=20=20=20=20=20=20=20if=20=
(is_plist=20&&=20':'=20=3D=3D=20key_str[0]=20&&=20key_str[1])=0A-=20=20=20=
=20=20=20=20=20=20=20=20=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
key_str=20=3D=20&key_str[1];=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=0A=
-=20=20=20=20=20=20=20=20=20=20/*=20Only=20add=20element=20if=20key=20is=20=
not=20already=20present.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20if=20=
(json_object_get=20(json,=20key_str)=20=3D=3D=20NULL)=0A-=20=20=20=20=20=20=
=20=20=20=20=20=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20int=20=
status=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=3D=20=
json_object_set_new=20(json,=20key_str,=20lisp_to_json=20(value,=0A-=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20conf));=0A-=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20if=20(status=20=3D=3D=20-1)=0A-=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20json_out_of_memory=20();=0A-=20=20=20=20=
=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=
=20CHECK_LIST_END=20(tail,=20lisp);=0A-=20=20=20=20}=0A-=20=20else=0A-=20=
=20=20=20wrong_type_argument=20(Qjson_value_p,=20lisp);=0A-=0A-=20=20=
clear_unwind_protect=20(count);=0A-=20=20unbind_to=20(count,=20Qnil);=0A=
-=20=20return=20json;=0A-}=0A-=0A-/*=20Convert=20LISP=20to=20a=20=
nonscalar=20JSON=20object=20(array=20or=20object).=20=20Signal=0A-=20=20=20=
an=20error=20of=20type=20`wrong-type-argument'=20if=20LISP=20is=20not=20=
a=20vector,=0A-=20=20=20hashtable,=20alist,=20or=20plist.=20=20*/=0A-=0A=
-static=20json_t=20*=0A-lisp_to_json_nonscalar=20(Lisp_Object=20lisp,=0A=
-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
const=20struct=20json_configuration=20*conf)=0A-{=0A-=20=20if=20=
(++lisp_eval_depth=20>=20max_lisp_eval_depth)=0A-=20=20=20=20xsignal0=20=
(Qjson_object_too_deep);=0A-=20=20json_t=20*json=20=3D=20=
lisp_to_json_nonscalar_1=20(lisp,=20conf);=0A-=20=20--lisp_eval_depth;=0A=
-=20=20return=20json;=0A-}=0A-=0A-/*=20Convert=20LISP=20to=20any=20JSON=20=
object.=20=20Signal=20an=20error=20of=20type=0A-=20=20=20=
`wrong-type-argument'=20if=20the=20type=20of=20LISP=20can't=20be=20=
converted=20to=20a=0A-=20=20=20JSON=20object.=20=20*/=0A-=0A-static=20=
json_t=20*=0A-lisp_to_json=20(Lisp_Object=20lisp,=20const=20struct=20=
json_configuration=20*conf)=0A-{=0A-=20=20if=20(EQ=20(lisp,=20=
conf->null_object))=0A-=20=20=20=20return=20json_check=20(json_null=20=
());=0A-=20=20else=20if=20(EQ=20(lisp,=20conf->false_object))=0A-=20=20=20=
=20return=20json_check=20(json_false=20());=0A-=20=20else=20if=20(EQ=20=
(lisp,=20Qt))=0A-=20=20=20=20return=20json_check=20(json_true=20());=0A-=20=
=20else=20if=20(INTEGERP=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20=
intmax_t=20low=20=3D=20TYPE_MINIMUM=20(json_int_t);=0A-=20=20=20=20=20=20=
intmax_t=20high=20=3D=20TYPE_MAXIMUM=20(json_int_t);=0A-=20=20=20=20=20=20=
intmax_t=20value=20=3D=20check_integer_range=20(lisp,=20low,=20high);=0A=
-=20=20=20=20=20=20return=20json_check=20(json_integer=20(value));=0A-=20=
=20=20=20}=0A-=20=20else=20if=20(FLOATP=20(lisp))=0A-=20=20=20=20return=20=
json_check=20(json_real=20(XFLOAT_DATA=20(lisp)));=0A-=20=20else=20if=20=
(STRINGP=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20Lisp_Object=20=
encoded=20=3D=20json_encode=20(lisp);=0A-=20=20=20=20=20=20json_t=20=
*json=20=3D=20json_stringn=20(SSDATA=20(encoded),=20SBYTES=20(encoded));=0A=
-=20=20=20=20=20=20if=20(json=20=3D=3D=20NULL)=0A-=20=20=20=20=20=20=20=20=
{=0A-=20=20=20=20=20=20=20=20=20=20/*=20A=20failure=20can=20be=20caused=20=
either=20by=20an=20invalid=20string=20or=20by=0A-=20=20=20=20=20=20=20=20=
=20=20=20=20=20low=20memory.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20=
json_check_utf8=20(encoded);=0A-=20=20=20=20=20=20=20=20=20=20=
json_out_of_memory=20();=0A-=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20=
return=20json;=0A-=20=20=20=20}=0A-=0A-=20=20/*=20LISP=20now=20must=20be=20=
a=20vector,=20hashtable,=20alist,=20or=20plist.=20=20*/=0A-=20=20return=20=
lisp_to_json_nonscalar=20(lisp,=20conf);=0A-}=0A-=0A=20static=20void=0A=20=
json_parse_args=20(ptrdiff_t=20nargs,=0A=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20Lisp_Object=20*args,=0A@@=20-585,124=20+387,498=20=
@@=20DEFUN=20("json--available-p",=20Fjson__available_p,=20=
Sjson__available_p,=200,=200,=20NULL,=0A=20=20=20return=20=
json_available_p=20()=20?=20Qt=20:=20Qnil;=0A=20}=0A=20=0A-DEFUN=20=
("json-serialize",=20Fjson_serialize,=20Sjson_serialize,=201,=20MANY,=0A=
-=20=20=20=20=20=20=20NULL,=0A-=20=20=20=20=20=20=20doc:=20/*=20Return=20=
the=20JSON=20representation=20of=20OBJECT=20as=20a=20string.=0A+/*=20=
JSON=20encoding=20context=20*/=0A+typedef=20struct=20{=0A+=20=20char=20=
*buf;=0A+=20=20ptrdiff_t=20size;=09=09/*=20number=20of=20bytes=20in=20=
buf=20*/=0A+=20=20ptrdiff_t=20capacity;=09=09/*=20allocated=20size=20of=20=
buf=20*/=0A+=20=20ptrdiff_t=20chars_delta;=20=20=20=20=20=20=20=20/*=20=
size=20-=20{number=20of=20Unicode=20chars=20in=20buf}=20*/=0A+=0A+=20=20=
int=20maxdepth;=0A+=20=20struct=20symset_tbl=20*ss_table;=09/*=20table=20=
used=20by=20containing=20object=20*/=0A+=20=20struct=20=
json_configuration=20conf;=0A+}=20json_out_t;=0A+=0A+/*=20Set=20of=20=
symbols=20*/=0A+typedef=20struct=20{=0A+=20=20int=20count;=09=09=09/*=20=
symbols=20in=20table=20*/=0A+=20=20int=20bits;=09=09=09/*=20log2(table=20=
size)=20*/=0A+=20=20struct=20symset_tbl=20*table;=09/*=20heap-allocated=20=
table=20*/=0A+}=20symset_t;=0A+=0A+struct=20symset_tbl=0A+{=0A+=20=20/*=20=
Table=20used=20by=20the=20containing=20object=20if=20any,=20so=20that=20=
we=20can=20easily=0A+=20=20=20=20=20all=20tables=20if=20an=20error=20=
occurs.=20=20*/=0A+=20=20struct=20symset_tbl=20*up;=0A+=20=20/*=20Table=20=
of=20symbols=20(2**bits=20entries),=20Qunbound=20where=20unused.=20=20*/=0A=
+=20=20Lisp_Object=20entries[];=0A+};=0A=20=0A-OBJECT=20must=20be=20t,=20=
a=20number,=20string,=20vector,=20hashtable,=20alist,=20plist,=0A-or=20=
the=20Lisp=20equivalents=20to=20the=20JSON=20null=20and=20false=20=
values,=20and=20its=0A-elements=20must=20recursively=20consist=20of=20=
the=20same=20kinds=20of=20values.=20=20t=20will=0A-be=20converted=20to=20=
the=20JSON=20true=20value.=20=20Vectors=20will=20be=20converted=20to=0A=
-JSON=20arrays,=20whereas=20hashtables,=20alists=20and=20plists=20are=20=
converted=20to=0A-JSON=20objects.=20=20Hashtable=20keys=20must=20be=20=
strings=20without=20embedded=20null=0A-characters=20and=20must=20be=20=
unique=20within=20each=20object.=20=20Alist=20and=20plist=0A-keys=20must=20=
be=20symbols;=20if=20a=20key=20is=20duplicate,=20the=20first=20instance=20=
is=0A-used.=0A+static=20struct=20symset_tbl=20*=0A+alloc_symset_table=20=
(int=20bits)=0A+{=0A+=20=20struct=20symset_tbl=20*st=20=3D=20xmalloc=20=
(sizeof=20*st=20+=20(sizeof=20*st->entries=20<<=20bits));=0A+=20=20int=20=
size=20=3D=201=20<<=20bits;=0A+=20=20for=20(ptrdiff_t=20i=20=3D=200;=20i=20=
<=20size;=20i++)=0A+=20=20=20=20st->entries[i]=20=3D=20Qunbound;=0A+=20=20=
return=20st;=0A+}=0A=20=0A-The=20Lisp=20equivalents=20to=20the=20JSON=20=
null=20and=20false=20values=20are=0A-configurable=20in=20the=20arguments=20=
ARGS,=20a=20list=20of=20keyword/argument=20pairs:=0A+/*=20Create=20a=20=
new=20symset=20to=20use=20for=20a=20new=20object.=20=20*/=0A+static=20=
symset_t=0A+push_symset=20(json_out_t=20*jo)=0A+{=0A+=20=20int=20bits=20=
=3D=204;=0A+=20=20struct=20symset_tbl=20*tbl=20=3D=20alloc_symset_table=20=
(bits);=0A+=20=20tbl->up=20=3D=20jo->ss_table;=0A+=20=20jo->ss_table=20=3D=
=20tbl;=0A+=20=20return=20(symset_t){=20.count=20=3D=200,=20.bits=20=3D=20=
4,=20.table=20=3D=20tbl=20};=0A+}=0A=20=0A-The=20keyword=20argument=20=
`:null-object'=20specifies=20which=20object=20to=20use=0A-to=20represent=20=
a=20JSON=20null=20value.=20=20It=20defaults=20to=20`:null'.=0A+/*=20=
Destroy=20the=20current=20symset.=20=20*/=0A+static=20void=0A+pop_symset=20=
(json_out_t=20*jo,=20symset_t=20*ss)=0A+{=0A+=20=20jo->ss_table=20=3D=20=
ss->table->up;=0A+=20=20xfree=20(ss->table);=0A+}=0A=20=0A-The=20keyword=20=
argument=20`:false-object'=20specifies=20which=20object=20to=20use=20to=0A=
-represent=20a=20JSON=20false=20value.=20=20It=20defaults=20to=20=
`:false'.=0A+/*=20Remove=20all=20heap-allocated=20symset=20tables,=20in=20=
case=20an=20error=20occurred.=20=20*/=0A+static=20void=0A=
+cleanup_symset_tables=20(struct=20symset_tbl=20*st)=0A+{=0A+=20=20while=20=
(st)=0A+=20=20=20=20{=0A+=20=20=20=20=20=20struct=20symset_tbl=20*up=20=3D=
=20st->up;=0A+=20=20=20=20=20=20xfree=20(st);=0A+=20=20=20=20=20=20st=20=
=3D=20up;=0A+=20=20=20=20}=0A+}=0A=20=0A-In=20you=20specify=20the=20same=20=
value=20for=20`:null-object'=20and=20`:false-object',=0A-a=20potentially=20=
ambiguous=20situation,=20the=20JSON=20output=20will=20not=20contain=0A=
-any=20JSON=20false=20values.=0A-usage:=20(json-serialize=20OBJECT=20=
&rest=20ARGS)=20=20*/)=0A-=20=20=20=20=20(ptrdiff_t=20nargs,=20=
Lisp_Object=20*args)=0A+static=20inline=20uint32_t=0A+symset_hash=20=
(Lisp_Object=20sym,=20int=20bits)=0A=20{=0A-=20=20specpdl_ref=20count=20=
=3D=20SPECPDL_INDEX=20();=0A+=20=20return=20knuth_hash=20=
(reduce_emacs_uint_to_hash_hash=20(XHASH=20(sym)),=20bits);=0A+}=0A=20=0A=
-#ifdef=20WINDOWSNT=0A-=20=20ensure_json_available=20();=0A-#endif=0A+/*=20=
Enlarge=20the=20table=20used=20by=20a=20symset.=20*/=0A+static=20=
NO_INLINE=20void=0A+symset_expand=20(symset_t=20*ss)=0A+{=0A+=20=20=
struct=20symset_tbl=20*old_table=20=3D=20ss->table;=0A+=20=20int=20=
oldbits=20=3D=20ss->bits;=0A+=20=20int=20oldsize=20=3D=201=20<<=20=
oldbits;=0A+=20=20int=20bits=20=3D=20oldbits=20+=201;=0A+=20=20ss->bits=20=
=3D=20bits;=0A+=20=20ss->table=20=3D=20alloc_symset_table=20(bits);=0A+=20=
=20ss->table->up=20=3D=20old_table->up;=0A+=20=20/*=20Move=20all=20=
entries=20from=20the=20old=20table=20to=20the=20new=20one.=20=20*/=0A+=20=
=20int=20mask=20=3D=20(1=20<<=20bits)=20-=201;=0A+=20=20struct=20=
symset_tbl=20*tbl=20=3D=20ss->table;=0A+=20=20for=20(ptrdiff_t=20i=20=3D=20=
0;=20i=20<=20oldsize;=20i++)=0A+=20=20=20=20{=0A+=20=20=20=20=20=20=
Lisp_Object=20sym=20=3D=20old_table->entries[i];=0A+=20=20=20=20=20=20if=20=
(!BASE_EQ=20(sym,=20Qunbound))=0A+=09{=0A+=09=20=20ptrdiff_t=20j=20=3D=20=
symset_hash=20(sym,=20bits);=0A+=09=20=20while=20(!BASE_EQ=20=
(tbl->entries[j],=20Qunbound))=0A+=09=20=20=20=20j=20=3D=20(j=20+=201)=20=
&=20mask;=0A+=09=20=20tbl->entries[j]=20=3D=20sym;=0A+=09}=0A+=20=20=20=20=
}=0A+=20=20xfree=20(old_table);=0A+}=0A=20=0A-=20=20struct=20=
json_configuration=20conf=20=3D=0A-=20=20=20=20{json_object_hashtable,=20=
json_array_array,=20QCnull,=20QCfalse};=0A-=20=20json_parse_args=20=
(nargs=20-=201,=20args=20+=201,=20&conf,=20false);=0A+/*=20If=20sym=20is=20=
in=20ss,=20return=20false;=20otherwise=20add=20it=20and=20return=20true.=0A=
+=20=20=20Comparison=20is=20done=20by=20strict=20identity.=20=20*/=0A=
+static=20inline=20bool=0A+symset_add=20(json_out_t=20*jo,=20symset_t=20=
*ss,=20Lisp_Object=20sym)=0A+{=0A+=20=20/*=20Make=20sure=20we=20don't=20=
fill=20more=20than=20half=20of=20the=20table.=20=20*/=0A+=20=20if=20=
(ss->count=20*=202=20>=3D=20(1=20<<=20ss->bits))=0A+=20=20=20=20{=0A+=20=20=
=20=20=20=20symset_expand=20(ss);=0A+=20=20=20=20=20=20jo->ss_table=20=3D=20=
ss->table;=0A+=20=20=20=20}=0A+=0A+=20=20struct=20symset_tbl=20*tbl=20=3D=20=
ss->table;=0A+=20=20int=20mask=20=3D=20(1=20<<=20ss->bits)=20-=201;=0A+=20=
=20for=20(ptrdiff_t=20i=20=3D=20symset_hash=20(sym,=20ss->bits);=20;=20i=20=
=3D=20(i=20+=201)=20&=20mask)=0A+=20=20=20=20{=0A+=20=20=20=20=20=20=
Lisp_Object=20s=20=3D=20tbl->entries[i];=0A+=20=20=20=20=20=20if=20=
(BASE_EQ=20(s,=20sym))=0A+=09return=20false;=09=09/*=20Previous=20=
occurrence=20found.=20=20*/=0A+=20=20=20=20=20=20if=20(BASE_EQ=20(s,=20=
Qunbound))=0A+=09{=0A+=09=20=20/*=20Not=20in=20set,=20add=20it.=20=20*/=0A=
+=09=20=20tbl->entries[i]=20=3D=20sym;=0A+=09=20=20ss->count++;=0A+=09=20=
=20return=20true;=0A+=09}=0A+=20=20=20=20}=0A+}=0A=20=0A-=20=20json_t=20=
*json=20=3D=20lisp_to_json=20(args[0],=20&conf);=0A-=20=20=
record_unwind_protect_ptr=20(json_release_object,=20json);=0A+static=20=
NO_INLINE=20void=0A+json_out_grow=20(json_out_t=20*jo,=20ptrdiff_t=20=
bytes)=0A+{=0A+=20=20ptrdiff_t=20need=20=3D=20jo->size=20+=20bytes;=0A+=20=
=20ptrdiff_t=20new_size=20=3D=20max=20(need,=20512);=0A+=20=20while=20=
(new_size=20<=20need)=0A+=20=20=20=20new_size=20<<=3D=201;=0A+=20=20=
jo->buf=20=3D=20xrealloc=20(jo->buf,=20new_size);=0A+=20=20jo->capacity=20=
=3D=20new_size;=0A+}=0A=20=0A-=20=20char=20*string=20=3D=20json_dumps=20=
(json,=20JSON_COMPACT=20|=20JSON_ENCODE_ANY);=0A-=20=20if=20(string=20=3D=3D=
=20NULL)=0A-=20=20=20=20json_out_of_memory=20();=0A-=20=20=
record_unwind_protect_ptr=20(json_free,=20string);=0A+static=20void=0A=
+cleanup_json_out=20(void=20*arg)=0A+{=0A+=20=20json_out_t=20*jo=20=3D=20=
arg;=0A+=20=20xfree=20(jo->buf);=0A+=20=20cleanup_symset_tables=20=
(jo->ss_table);=0A+}=0A=20=0A-=20=20return=20unbind_to=20(count,=20=
build_string_from_utf8=20(string));=0A+/*=20Make=20room=20for=20`bytes`=20=
more=20bytes=20in=20buffer.=20=20*/=0A+static=20void=0A+json_make_room=20=
(json_out_t=20*jo,=20ptrdiff_t=20bytes)=0A+{=0A+=20=20if=20(bytes=20>=20=
jo->capacity=20-=20jo->size)=0A+=20=20=20=20json_out_grow=20(jo,=20=
bytes);=0A=20}=0A=20=0A-struct=20json_buffer_and_size=0A+#define=20=
JSON_OUT_STR(jo,=20str)=20(json_out_str=20(jo,=20str,=20sizeof=20(str)=20=
-=201))=0A+=0A+/*=20Add=20`bytes`=20bytes=20from=20`str`=20to=20the=20=
buffer.=20=20*/=0A+static=20void=0A+json_out_str=20(json_out_t=20*jo,=20=
const=20char=20*str,=20size_t=20bytes)=0A=20{=0A-=20=20const=20char=20=
*buffer;=0A-=20=20ptrdiff_t=20size;=0A-=20=20/*=20This=20tracks=20how=20=
many=20bytes=20were=20inserted=20by=20the=20callback=20since=0A-=20=20=20=
=20=20json_dump_callback=20was=20called.=20=20*/=0A-=20=20ptrdiff_t=20=
inserted_bytes;=0A+=20=20json_make_room=20(jo,=20bytes);=0A+=20=20memcpy=20=
(jo->buf=20+=20jo->size,=20str,=20bytes);=0A+=20=20jo->size=20+=3D=20=
bytes;=0A+}=0A+=0A+static=20void=0A+json_out_byte=20(json_out_t=20*jo,=20=
unsigned=20char=20c)=0A+{=0A+=20=20json_make_room=20(jo,=201);=0A+=20=20=
jo->buf[jo->size++]=20=3D=20c;=0A+}=0A+=0A+static=20void=0A=
+json_out_fixnum=20(json_out_t=20*jo,=20EMACS_INT=20x)=0A+{=0A+=20=20=
char=20buf[INT_BUFSIZE_BOUND=20(EMACS_INT)];=0A+=20=20char=20*end=20=3D=20=
buf=20+=20sizeof=20buf;=0A+=20=20char=20*p=20=3D=20fixnum_to_string=20=
(x,=20buf,=20end);=0A+=20=20json_out_str=20(jo,=20p,=20end=20-=20p);=0A=
+}=0A+=0A+static=20AVOID=0A+string_not_unicode=20(Lisp_Object=20obj)=0A=
+{=0A+=20=20/*=20FIXME:=20for=20test=20compatibility,=20not=20a=20very=20=
descriptive=20error=20*/=0A+=20=20wrong_type_argument=20(Qjson_value_p,=20=
obj);=0A+}=0A+=0A+static=20unsigned=20char=20json_plain_char[256]=20=3D=20=
{=0A+=20=20/*=2032=20chars/line:=201=20for=20printable=20ASCII=20+=20DEL=20=
except=20"=20and=20\,=200=20elsewhere=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
00-1f=20*/=0A+=20=20=
1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,=20/*=20=
20-3f=20*/=0A+=20=20=
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,=20/*=20=
40-5f=20*/=0A+=20=20=
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,=20/*=20=
60-7f=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
80-9f=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
a0-bf=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
c0-df=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
e0-ff=20*/=0A=20};=0A=20=0A-static=20Lisp_Object=0A-json_insert=20(void=20=
*data)=0A+static=20void=0A+json_out_string=20(json_out_t=20*jo,=20=
Lisp_Object=20str,=20int=20skip)=0A=20{=0A-=20=20struct=20=
json_buffer_and_size=20*buffer_and_size=20=3D=20data;=0A-=20=20ptrdiff_t=20=
len=20=3D=20buffer_and_size->size;=0A-=20=20ptrdiff_t=20inserted_bytes=20=
=3D=20buffer_and_size->inserted_bytes;=0A-=20=20ptrdiff_t=20gap_size=20=3D=
=20GAP_SIZE=20-=20inserted_bytes;=0A-=0A-=20=20/*=20Enlarge=20the=20gap=20=
if=20necessary.=20=20*/=0A-=20=20if=20(gap_size=20<=20len)=0A-=20=20=20=20=
make_gap=20(len=20-=20gap_size);=0A-=0A-=20=20/*=20Copy=20this=20chunk=20=
of=20data=20into=20the=20gap.=20=20*/=0A-=20=20memcpy=20((char=20*)=20=
BEG_ADDR=20+=20PT_BYTE=20-=20BEG_BYTE=20+=20inserted_bytes,=0A-=09=20=20=
buffer_and_size->buffer,=20len);=0A-=20=20=
buffer_and_size->inserted_bytes=20+=3D=20len;=0A-=20=20return=20Qnil;=0A=
+=20=20/*=20FIXME:=20this=20code=20is=20slow,=20make=20faster!=20*/=0A+=0A=
+=20=20static=20const=20char=20hexchar[16]=20=3D=20"0123456789ABCDEF";=0A=
+=20=20ptrdiff_t=20len=20=3D=20SBYTES=20(str);=0A+=20=20json_make_room=20=
(jo,=20len=20+=202);=0A+=20=20json_out_byte=20(jo,=20'"');=0A+=20=20=
unsigned=20char=20*p=20=3D=20SDATA=20(str);=0A+=20=20unsigned=20char=20=
*end=20=3D=20p=20+=20len;=0A+=20=20p=20+=3D=20skip;=0A+=20=20while=20(p=20=
<=20end)=0A+=20=20=20=20{=0A+=20=20=20=20=20=20unsigned=20char=20c=20=3D=20=
*p;=0A+=20=20=20=20=20=20if=20(json_plain_char[c])=0A+=09{=0A+=09=20=20=
json_out_byte=20(jo,=20c);=0A+=09=20=20p++;=0A+=09}=0A+=20=20=20=20=20=20=
else=20if=20(c=20>=200x7f)=0A+=09{=0A+=09=20=20if=20(STRING_MULTIBYTE=20=
(str))=0A+=09=20=20=20=20{=0A+=09=20=20=20=20=20=20int=20n;=0A+=09=20=20=20=
=20=20=20if=20(c=20<=3D=200xc1)=0A+=09=09string_not_unicode=20(str);=0A+=09=
=20=20=20=20=20=20if=20(c=20<=3D=200xdf)=0A+=09=09n=20=3D=202;=0A+=09=20=20=
=20=20=20=20else=20if=20(c=20<=3D=200xef)=0A+=09=09{=0A+=09=09=20=20int=20=
v=20=3D=20(((c=20&=200x0f)=20<<=2012)=0A+=09=09=09=20=20=20+=20((p[1]=20=
&=200x3f)=20<<=206)=20+=20(p[2]=20&=200x3f));=0A+=09=09=20=20if=20=
(char_surrogate_p=20(v))=0A+=09=09=20=20=20=20string_not_unicode=20=
(str);=0A+=09=09=20=20n=20=3D=203;=0A+=09=09}=0A+=09=20=20=20=20=20=20=
else=20if=20(c=20<=3D=200xf7)=0A+=09=09{=0A+=09=09=20=20int=20v=20=3D=20=
(((c=20&=200x07)=20<<=2018)=0A+=09=09=09=20=20=20+=20((p[1]=20&=200x3f)=20=
<<=2012)=0A+=09=09=09=20=20=20+=20((p[2]=20&=200x3f)=20<<=206)=0A+=09=09=09=
=20=20=20+=20(p[3]=20&=200x3f));=0A+=09=09=20=20if=20(v=20>=20=
MAX_UNICODE_CHAR)=0A+=09=09=20=20=20=20string_not_unicode=20(str);=0A+=09=
=09=20=20n=20=3D=204;=0A+=09=09}=0A+=09=20=20=20=20=20=20else=0A+=09=09=
string_not_unicode=20(str);=0A+=09=20=20=20=20=20=20json_out_str=20(jo,=20=
(const=20char=20*)p,=20n);=0A+=09=20=20=20=20=20=20jo->chars_delta=20+=3D=20=
n=20-=201;=0A+=09=20=20=20=20=20=20p=20+=3D=20n;=0A+=09=20=20=20=20}=0A+=09=
=20=20else=0A+=09=20=20=20=20string_not_unicode=20(str);=0A+=09}=0A+=20=20=
=20=20=20=20else=0A+=09{=0A+=09=20=20json_out_byte=20(jo,=20'\\');=0A+=09=
=20=20switch=20(c)=0A+=09=20=20=20=20{=0A+=09=20=20=20=20case=20'"':=0A+=09=
=20=20=20=20case=20'\\':=20json_out_byte=20(jo,=20c);=20break;=0A+=09=20=20=
=20=20case=20'\b':=20json_out_byte=20(jo,=20'b');=20break;=0A+=09=20=20=20=
=20case=20'\t':=20json_out_byte=20(jo,=20't');=20break;=0A+=09=20=20=20=20=
case=20'\n':=20json_out_byte=20(jo,=20'n');=20break;=0A+=09=20=20=20=20=
case=20'\f':=20json_out_byte=20(jo,=20'f');=20break;=0A+=09=20=20=20=20=
case=20'\r':=20json_out_byte=20(jo,=20'r');=20break;=0A+=09=20=20=20=20=
default:=0A+=09=20=20=20=20=20=20{=0A+=09=09char=20hex[5]=20=3D=20{=20=
'u',=20'0',=20'0',=0A+=09=09=09=09hexchar[c=20>>=204],=20hexchar[c=20&=20=
0xf]=20};=0A+=09=09json_out_str=20(jo,=20hex,=205);=0A+=09=09break;=0A+=09=
=20=20=20=20=20=20}=0A+=09=20=20=20=20}=0A+=09=20=20p++;=0A+=09}=0A+=20=20=
=20=20}=0A+=20=20json_out_byte=20(jo,=20'"');=0A=20}=0A=20=0A-static=20=
Lisp_Object=0A-json_handle_nonlocal_exit=20(enum=20nonlocal_exit=20type,=20=
Lisp_Object=20data)=0A+static=20void=0A+json_out_nest=20(json_out_t=20=
*jo)=0A+{=0A+=20=20--jo->maxdepth;=0A+=20=20if=20(jo->maxdepth=20<=200)=0A=
+=20=20=20=20error=20("Maximum=20JSON=20serialisation=20depth=20=
exceeded");=0A+}=0A+=0A+static=20void=0A+json_out_unnest=20(json_out_t=20=
*jo)=0A=20{=0A-=20=20switch=20(type)=0A+=20=20++jo->maxdepth;=0A+}=0A+=0A=
+static=20void=20json_out_something=20(json_out_t=20*jo,=20Lisp_Object=20=
obj);=0A+=0A+static=20void=0A+json_out_object_cons=20(json_out_t=20*jo,=20=
Lisp_Object=20obj)=0A+{=0A+=20=20json_out_nest=20(jo);=0A+=20=20symset_t=20=
ss=20=3D=20push_symset=20(jo);=0A+=20=20json_out_byte=20(jo,=20'{');=0A+=20=
=20bool=20is_alist=20=3D=20CONSP=20(XCAR=20(obj));=0A+=20=20bool=20first=20=
=3D=20true;=0A+=20=20Lisp_Object=20tail=20=3D=20obj;=0A+=20=20=
FOR_EACH_TAIL=20(tail)=0A=20=20=20=20=20{=0A-=20=20=20=20case=20=
NONLOCAL_EXIT_SIGNAL:=0A-=20=20=20=20=20=20return=20data;=0A-=20=20=20=20=
case=20NONLOCAL_EXIT_THROW:=0A-=20=20=20=20=20=20return=20Fcons=20=
(Qno_catch,=20data);=0A-=20=20=20=20default:=0A-=20=20=20=20=20=20=
eassume=20(false);=0A+=20=20=20=20=20=20Lisp_Object=20key;=0A+=20=20=20=20=
=20=20Lisp_Object=20value;=0A+=20=20=20=20=20=20if=20(is_alist)=0A+=09{=0A=
+=09=20=20Lisp_Object=20pair=20=3D=20XCAR=20(tail);=0A+=09=20=20=
CHECK_CONS=20(pair);=0A+=09=20=20key=20=3D=20XCAR=20(pair);=0A+=09=20=20=
value=20=3D=20XCDR=20(pair);=0A+=09}=0A+=20=20=20=20=20=20else=0A+=09{=0A=
+=09=20=20key=20=3D=20XCAR=20(tail);=0A+=09=20=20tail=20=3D=20XCDR=20=
(tail);=0A+=09=20=20CHECK_CONS=20(tail);=0A+=09=20=20value=20=3D=20XCAR=20=
(tail);=0A+=09}=0A+=20=20=20=20=20=20key=20=3D=20=
maybe_remove_pos_from_symbol=20(key);=0A+=20=20=20=20=20=20CHECK_TYPE=20=
(BARE_SYMBOL_P=20(key),=20Qsymbolp,=20key);=0A+=0A+=20=20=20=20=20=20if=20=
(symset_add=20(jo,=20&ss,=20key))=0A+=09{=0A+=09=20=20if=20(!first)=0A+=09=
=20=20=20=20json_out_byte=20(jo,=20',');=0A+=09=20=20first=20=3D=20=
false;=0A+=0A+=09=20=20Lisp_Object=20key_str=20=3D=20SYMBOL_NAME=20=
(key);=0A+=09=20=20const=20char=20*str=20=3D=20SSDATA=20(key_str);=0A+=09=
=20=20/*=20Skip=20leading=20':'=20in=20plist=20keys.=20=20*/=0A+=09=20=20=
int=20skip=20=3D=20!is_alist=20&&=20str[0]=20=3D=3D=20':'=20&&=20str[1]=20=
?=201=20:=200;=0A+=09=20=20json_out_string=20(jo,=20key_str,=20skip);=0A=
+=09=20=20json_out_byte=20(jo,=20':');=0A+=09=20=20json_out_something=20=
(jo,=20value);=0A+=09}=0A+=20=20=20=20}=0A+=20=20CHECK_LIST_END=20(tail,=20=
obj);=0A+=20=20json_out_byte=20(jo,=20'}');=0A+=20=20pop_symset=20(jo,=20=
&ss);=0A+=20=20json_out_unnest=20(jo);=0A+}=0A+=0A+static=20void=0A=
+json_out_object_hash=20(json_out_t=20*jo,=20Lisp_Object=20obj)=0A+{=0A+=20=
=20json_out_nest=20(jo);=0A+=20=20json_out_byte=20(jo,=20'{');=0A+=20=20=
struct=20Lisp_Hash_Table=20*h=20=3D=20XHASH_TABLE=20(obj);=0A+=20=20bool=20=
first=20=3D=20true;=0A+=20=20DOHASH=20(h,=20k,=20v)=0A+=20=20=20=20{=0A+=20=
=20=20=20=20=20if=20(!first)=0A+=09json_out_byte=20(jo,=20',');=0A+=20=20=
=20=20=20=20first=20=3D=20false;=0A+=20=20=20=20=20=20/*=20FIXME:=20do=20=
we=20care=20about=20dup=20keys=20here?=20(probably=20not)=20*/=0A+=20=20=20=
=20=20=20CHECK_STRING=20(k);=0A+=20=20=20=20=20=20json_out_string=20(jo,=20=
k,=200);=0A+=20=20=20=20=20=20json_out_byte=20(jo,=20':');=0A+=20=20=20=20=
=20=20json_out_something=20(jo,=20v);=0A=20=20=20=20=20}=0A+=20=20=
json_out_byte=20(jo,=20'}');=0A+=20=20json_out_unnest=20(jo);=0A+=0A=20}=0A=
=20=0A-struct=20json_insert_data=0A+static=20void=0A+json_out_array=20=
(json_out_t=20*jo,=20Lisp_Object=20obj)=0A=20{=0A-=20=20/*=20This=20=
tracks=20how=20many=20bytes=20were=20inserted=20by=20the=20callback=20=
since=0A-=20=20=20=20=20json_dump_callback=20was=20called.=20=20*/=0A-=20=
=20ptrdiff_t=20inserted_bytes;=0A-=20=20/*=20nil=20if=20json_insert=20=
succeeded,=20otherwise=20the=20symbol=0A-=20=20=20=20=20=
Qcatch_all_memory_full=20or=20a=20cons=20(ERROR-SYMBOL=20.=20=
ERROR-DATA).=20=20*/=0A-=20=20Lisp_Object=20error;=0A-};=0A+=20=20=
json_out_nest=20(jo);=0A+=20=20json_out_byte=20(jo,=20'[');=0A+=20=20=
ptrdiff_t=20n=20=3D=20ASIZE=20(obj);=0A+=20=20for=20(ptrdiff_t=20i=20=3D=20=
0;=20i=20<=20n;=20i++)=0A+=20=20=20=20{=0A+=20=20=20=20=20=20if=20(i=20>=20=
0)=0A+=09json_out_byte=20(jo,=20',');=0A+=20=20=20=20=20=20=
json_out_something=20(jo,=20AREF=20(obj,=20i));=0A+=20=20=20=20}=0A+=20=20=
json_out_byte=20(jo,=20']');=0A+=20=20json_out_unnest=20(jo);=0A+}=0A=20=0A=
-/*=20Callback=20for=20json_dump_callback=20that=20inserts=20a=20JSON=20=
representation=0A-=20=20=20as=20a=20unibyte=20string=20into=20the=20gap.=20=
=20DATA=20must=20point=20to=20a=20structure=0A-=20=20=20of=20type=20=
json_insert_data.=20=20This=20function=20may=20not=20exit=20nonlocally.=0A=
-=20=20=20It=20catches=20all=20nonlocal=20exits=20and=20stores=20them=20=
in=20data->error=20for=0A-=20=20=20reraising.=20=20*/=0A+static=20void=0A=
+json_out_float=20(json_out_t=20*jo,=20Lisp_Object=20f)=0A+{=0A+=20=20=
double=20x=20=3D=20XFLOAT_DATA=20(f);=0A+=20=20if=20(isinf=20(x)=20||=20=
isnan=20(x))=0A+=20=20=20=20signal_error=20("not=20a=20finite=20number",=20=
f);=0A+=20=20json_make_room=20(jo,=20FLOAT_TO_STRING_BUFSIZE);=0A+=20=20=
int=20n=20=3D=20float_to_string=20(jo->buf=20+=20jo->size,=20x);=0A+=20=20=
jo->size=20+=3D=20n;=0A+}=0A=20=0A-static=20int=0A-json_insert_callback=20=
(const=20char=20*buffer,=20size_t=20size,=20void=20*data)=0A+static=20=
void=0A+json_out_bignum=20(json_out_t=20*jo,=20Lisp_Object=20x)=0A=20{=0A=
-=20=20struct=20json_insert_data=20*d=20=3D=20data;=0A-=20=20struct=20=
json_buffer_and_size=20buffer_and_size=0A-=20=20=20=20=3D=20{.buffer=20=3D=
=20buffer,=20.size=20=3D=20size,=20.inserted_bytes=20=3D=20=
d->inserted_bytes};=0A-=20=20d->error=20=3D=20internal_catch_all=20=
(json_insert,=20&buffer_and_size,=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
json_handle_nonlocal_exit);=0A-=20=20d->inserted_bytes=20=3D=20=
buffer_and_size.inserted_bytes;=0A-=20=20return=20NILP=20(d->error)=20?=20=
0=20:=20-1;=0A+=20=20int=20base=20=3D=2010;=0A+=20=20ptrdiff_t=20size=20=
=3D=20bignum_bufsize=20(x,=20base);=0A+=20=20json_make_room=20(jo,=20=
size);=0A+=20=20int=20n=20=3D=20bignum_to_c_string=20(jo->buf=20+=20=
jo->size,=20size,=20x,=20base);=0A+=20=20jo->size=20+=3D=20n;=0A+}=0A+=0A=
+static=20void=0A+json_out_something=20(json_out_t=20*jo,=20Lisp_Object=20=
obj)=0A+{=0A+=20=20if=20(EQ=20(obj,=20jo->conf.null_object))=0A+=20=20=20=
=20JSON_OUT_STR=20(jo,=20"null");=0A+=20=20else=20if=20(EQ=20(obj,=20=
jo->conf.false_object))=0A+=20=20=20=20JSON_OUT_STR=20(jo,=20"false");=0A=
+=20=20else=20if=20(EQ=20(obj,=20Qt))=0A+=20=20=20=20JSON_OUT_STR=20(jo,=20=
"true");=0A+=20=20else=20if=20(NILP=20(obj))=0A+=20=20=20=20JSON_OUT_STR=20=
(jo,=20"{}");=0A+=20=20else=20if=20(FIXNUMP=20(obj))=0A+=20=20=20=20=
json_out_fixnum=20(jo,=20XFIXNUM=20(obj));=0A+=20=20else=20if=20(STRINGP=20=
(obj))=0A+=20=20=20=20json_out_string=20(jo,=20obj,=200);=0A+=20=20else=20=
if=20(CONSP=20(obj))=0A+=20=20=20=20json_out_object_cons=20(jo,=20obj);=0A=
+=20=20else=20if=20(FLOATP=20(obj))=0A+=20=20=20=20json_out_float=20(jo,=20=
obj);=0A+=20=20else=20if=20(HASH_TABLE_P=20(obj))=0A+=20=20=20=20=
json_out_object_hash=20(jo,=20obj);=0A+=20=20else=20if=20(VECTORP=20=
(obj))=0A+=20=20=20=20json_out_array=20(jo,=20obj);=0A+=20=20else=20if=20=
(BIGNUMP=20(obj))=0A+=20=20=20=20json_out_bignum=20(jo,=20obj);=0A+=20=20=
else=0A+=20=20=20=20wrong_type_argument=20(Qjson_value_p,=20obj);=0A+}=0A=
+=0A+static=20Lisp_Object=0A+json_out_string_result=20(json_out_t=20*jo)=0A=
+{=0A+=20=20/*=20FIXME:=20should=20this=20be=20a=20unibyte=20or=20=
multibyte=20string?=0A+=20=20=20=20=20Right=20now=20we=20make=20a=20=
multibyte=20string=20for=20test=20compatibility,=0A+=20=20=20=20=20but=20=
we=20are=20really=20encoding=20so=20unibyte=20would=20make=20more=20=
sense.=20=20*/=0A+=20=20ptrdiff_t=20nchars=20=3D=20jo->size=20-=20=
jo->chars_delta;=0A+=20=20return=20make_multibyte_string=20(jo->buf,=20=
nchars,=20jo->size);=0A+}=0A+=0A+DEFUN=20("json-serialize",=20=
Fjson_serialize,=20Sjson_serialize,=201,=20MANY,=0A+=20=20=20=20=20=20=20=
NULL,=0A+=20=20=20=20=20=20=20doc:=20/*=20Return=20the=20JSON=20=
representation=20of=20OBJECT=20as=20a=20string.=0A+=0A+OBJECT=20must=20=
be=20t,=20a=20number,=20string,=20vector,=20hashtable,=20alist,=20plist,=0A=
+or=20the=20Lisp=20equivalents=20to=20the=20JSON=20null=20and=20false=20=
values,=20and=20its=0A+elements=20must=20recursively=20consist=20of=20=
the=20same=20kinds=20of=20values.=20=20t=20will=0A+be=20converted=20to=20=
the=20JSON=20true=20value.=20=20Vectors=20will=20be=20converted=20to=0A=
+JSON=20arrays,=20whereas=20hashtables,=20alists=20and=20plists=20are=20=
converted=20to=0A+JSON=20objects.=20=20Hashtable=20keys=20must=20be=20=
strings=20and=20must=20be=20unique=20within=0A+each=20object.=20=20Alist=20=
and=20plist=20keys=20must=20be=20symbols;=20if=20a=20key=20is=20=
duplicate,=0A+the=20first=20instance=20is=20used.=0A+=0A+The=20Lisp=20=
equivalents=20to=20the=20JSON=20null=20and=20false=20values=20are=0A=
+configurable=20in=20the=20arguments=20ARGS,=20a=20list=20of=20=
keyword/argument=20pairs:=0A+=0A+The=20keyword=20argument=20=
`:null-object'=20specifies=20which=20object=20to=20use=0A+to=20represent=20=
a=20JSON=20null=20value.=20=20It=20defaults=20to=20`:null'.=0A+=0A+The=20=
keyword=20argument=20`:false-object'=20specifies=20which=20object=20to=20=
use=20to=0A+represent=20a=20JSON=20false=20value.=20=20It=20defaults=20=
to=20`:false'.=0A+=0A+In=20you=20specify=20the=20same=20value=20for=20=
`:null-object'=20and=20`:false-object',=0A+a=20potentially=20ambiguous=20=
situation,=20the=20JSON=20output=20will=20not=20contain=0A+any=20JSON=20=
false=20values.=0A+usage:=20(json-serialize=20OBJECT=20&rest=20ARGS)=20=20=
*/)=0A+=20=20=20=20=20(ptrdiff_t=20nargs,=20Lisp_Object=20*args)=0A+{=0A=
+=20=20json_out_t=20jo=20=3D=20{=0A+=20=20=20=20.maxdepth=20=3D=2025,=0A=
+=20=20=20=20.conf=20=3D=20{json_object_hashtable,=20json_array_array,=20=
QCnull,=20QCfalse}=0A+=20=20};=0A+=20=20json_parse_args=20(nargs=20-=20=
1,=20args=20+=201,=20&jo.conf,=20false);=0A+=20=20Lisp_Object=20object=20=
=3D=20args[0];=0A+=0A+=20=20specpdl_ref=20count=20=3D=20SPECPDL_INDEX=20=
();=0A+=20=20record_unwind_protect_ptr=20(cleanup_json_out,=20&jo);=0A+=20=
=20json_out_something=20(&jo,=20object);=0A+=20=20return=20unbind_to=20=
(count,=20json_out_string_result=20(&jo));=0A=20}=0A=20=0A=20DEFUN=20=
("json-insert",=20Fjson_insert,=20Sjson_insert,=201,=20MANY,=0A@@=20=
-714,72=20+890,61=20@@=20DEFUN=20("json-insert",=20Fjson_insert,=20=
Sjson_insert,=201,=20MANY,=0A=20usage:=20(json-insert=20OBJECT=20&rest=20=
ARGS)=20=20*/)=0A=20=20=20=20=20=20(ptrdiff_t=20nargs,=20Lisp_Object=20=
*args)=0A=20{=0A-=20=20specpdl_ref=20count=20=3D=20SPECPDL_INDEX=20();=0A=
+=20=20json_out_t=20jo=20=3D=20{=0A+=20=20=20=20.maxdepth=20=3D=2025,=0A=
+=20=20=20=20.conf=20=3D=20{json_object_hashtable,=20json_array_array,=20=
QCnull,=20QCfalse}=0A+=20=20};=0A+=20=20json_parse_args=20(nargs=20-=20=
1,=20args=20+=201,=20&jo.conf,=20false);=0A+=20=20Lisp_Object=20object=20=
=3D=20args[0];=0A=20=0A-#ifdef=20WINDOWSNT=0A-=20=20=
ensure_json_available=20();=0A-#endif=0A-=0A-=20=20struct=20=
json_configuration=20conf=20=3D=0A-=20=20=20=20{json_object_hashtable,=20=
json_array_array,=20QCnull,=20QCfalse};=0A-=20=20json_parse_args=20=
(nargs=20-=201,=20args=20+=201,=20&conf,=20false);=0A+=20=20specpdl_ref=20=
count=20=3D=20SPECPDL_INDEX=20();=0A+=20=20record_unwind_protect_ptr=20=
(cleanup_json_out,=20&jo);=0A+=20=20json_out_something=20(&jo,=20=
object);=0A=20=0A-=20=20json_t=20*json=20=3D=20lisp_to_json=20(args[0],=20=
&conf);=0A-=20=20record_unwind_protect_ptr=20(json_release_object,=20=
json);=0A+=20=20/*=20FIXME:=20Do=20we=20really=20need=20to=20do=20all=20=
this=20work=20below=20to=20insert=20a=20string?=0A+=20=20=20=20=20Is=20=
there=20no=20function=20already=20written?=20=20I=20must=20be=20missing=20=
something.=20=20*/=0A=20=0A=20=20=20prepare_to_modify_buffer=20(PT,=20=
PT,=20NULL);=0A=20=20=20move_gap_both=20(PT,=20PT_BYTE);=0A-=20=20struct=20=
json_insert_data=20data;=0A-=20=20data.inserted_bytes=20=3D=200;=0A-=20=20=
/*=20Could=20have=20used=20json_dumpb,=20but=20that=20became=20available=20=
only=20in=0A-=20=20=20=20=20Jansson=202.10,=20whereas=20we=20want=20to=20=
support=202.7=20and=20upward.=20=20*/=0A-=20=20int=20status=20=3D=20=
json_dump_callback=20(json,=20json_insert_callback,=20&data,=0A-=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20JSON_COMPACT=20|=20JSON_ENCODE_ANY);=0A-=20=20if=20=
(status=20=3D=3D=20-1)=0A-=20=20=20=20{=0A-=20=20=20=20=20=20if=20(CONSP=20=
(data.error))=0A-=20=20=20=20=20=20=20=20xsignal=20(XCAR=20(data.error),=20=
XCDR=20(data.error));=0A-=20=20=20=20=20=20else=0A-=20=20=20=20=20=20=20=20=
json_out_of_memory=20();=0A-=20=20=20=20}=0A+=20=20if=20(GAP_SIZE=20<=20=
jo.size)=0A+=20=20=20=20make_gap=20(jo.size=20-=20GAP_SIZE);=0A+=20=20=
memcpy=20((char=20*)=20BEG_ADDR=20+=20PT_BYTE=20-=20BEG_BYTE,=20jo.buf,=20=
jo.size);=0A+=0A+=20=20/*=20No=20need=20to=20keep=20allocation=20beyond=20=
this=20point.=20=20*/=0A+=20=20unbind_to=20(count,=20Qnil);=0A=20=0A=20=20=
=20ptrdiff_t=20inserted=20=3D=200;=0A-=20=20ptrdiff_t=20inserted_bytes=20=
=3D=20data.inserted_bytes;=0A-=20=20if=20(inserted_bytes=20>=200)=0A+=20=20=
ptrdiff_t=20inserted_bytes=20=3D=20jo.size;=0A+=0A+=20=20/*=20If=20=
required,=20decode=20the=20stuff=20we've=20read=20into=20the=20gap.=20=20=
*/=0A+=20=20struct=20coding_system=20coding;=0A+=20=20/*=20JSON=20=
strings=20are=20UTF-8=20encoded=20strings.=20=20*/=0A+=20=20=
setup_coding_system=20(Qutf_8_unix,=20&coding);=0A+=20=20=
coding.dst_multibyte=20=3D=20!NILP=20(BVAR=20(current_buffer,=0A+=09=09=09=
=09=20=20=20=20=20=20enable_multibyte_characters));=0A+=20=20if=20=
(CODING_MAY_REQUIRE_DECODING=20(&coding))=0A=20=20=20=20=20{=0A-=20=20=20=
=20=20=20/*=20If=20required,=20decode=20the=20stuff=20we've=20read=20=
into=20the=20gap.=20=20*/=0A-=20=20=20=20=20=20struct=20coding_system=20=
coding;=0A-=20=20=20=20=20=20/*=20JSON=20strings=20are=20UTF-8=20encoded=20=
strings.=20=20If=20for=20some=20reason=0A-=09=20the=20text=20returned=20=
by=20the=20Jansson=20library=20includes=20invalid=0A-=09=20byte=20=
sequences,=20they=20will=20be=20represented=20by=20raw=20bytes=20in=20=
the=0A-=09=20buffer=20text.=20=20*/=0A-=20=20=20=20=20=20=
setup_coding_system=20(Qutf_8_unix,=20&coding);=0A-=20=20=20=20=20=20=
coding.dst_multibyte=20=3D=0A-=09!NILP=20(BVAR=20(current_buffer,=20=
enable_multibyte_characters));=0A-=20=20=20=20=20=20if=20=
(CODING_MAY_REQUIRE_DECODING=20(&coding))=0A-=09{=0A-=20=20=20=20=20=20=20=
=20=20=20/*=20Now=20we=20have=20all=20the=20new=20bytes=20at=20the=20=
beginning=20of=20the=20gap,=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=
but=20`decode_coding_gap`=20needs=20them=20at=20the=20end=20of=20the=20=
gap,=20so=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20we=20need=20to=20=
move=20them.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20memmove=20=
(GAP_END_ADDR=20-=20inserted_bytes,=20GPT_ADDR,=20inserted_bytes);=0A-=09=
=20=20decode_coding_gap=20(&coding,=20inserted_bytes);=0A-=09=20=20=
inserted=20=3D=20coding.produced_char;=0A-=09}=0A-=20=20=20=20=20=20else=0A=
-=09{=0A-=20=20=20=20=20=20=20=20=20=20/*=20Make=20the=20inserted=20text=20=
part=20of=20the=20buffer,=20as=20unibyte=20text.=20=20*/=0A-=20=20=20=20=20=
=20=20=20=20=20eassert=20(NILP=20(BVAR=20(current_buffer,=20=
enable_multibyte_characters)));=0A-=20=20=20=20=20=20=20=20=20=20=
insert_from_gap_1=20(inserted_bytes,=20inserted_bytes,=20false);=0A-=0A-=09=
=20=20/*=20The=20target=20buffer=20is=20unibyte,=20so=20we=20don't=20=
need=20to=20decode.=20=20*/=0A-=09=20=20invalidate_buffer_caches=20=
(current_buffer,=0A-=09=09=09=09=20=20=20=20PT,=20PT=20+=20=
inserted_bytes);=0A-=09=20=20adjust_after_insert=20(PT,=20PT_BYTE,=0A-=09=
=09=09=20=20=20=20=20=20=20PT=20+=20inserted_bytes,=0A-=09=09=09=20=20=20=
=20=20=20=20PT_BYTE=20+=20inserted_bytes,=0A-=09=09=09=20=20=20=20=20=20=20=
inserted_bytes);=0A-=09=20=20inserted=20=3D=20inserted_bytes;=0A-=09}=0A=
+=20=20=20=20=20=20/*=20Now=20we=20have=20all=20the=20new=20bytes=20at=20=
the=20beginning=20of=20the=20gap,=0A+=09=20but=20`decode_coding_gap`=20=
needs=20them=20at=20the=20end=20of=20the=20gap,=20so=0A+=09=20we=20need=20=
to=20move=20them.=20=20*/=0A+=20=20=20=20=20=20memmove=20(GAP_END_ADDR=20=
-=20inserted_bytes,=20GPT_ADDR,=20inserted_bytes);=0A+=20=20=20=20=20=20=
decode_coding_gap=20(&coding,=20inserted_bytes);=0A+=20=20=20=20=20=20=
inserted=20=3D=20coding.produced_char;=0A+=20=20=20=20}=0A+=20=20else=0A=
+=20=20=20=20{=0A+=20=20=20=20=20=20/*=20Make=20the=20inserted=20text=20=
part=20of=20the=20buffer,=20as=20unibyte=20text.=20=20*/=0A+=20=20=20=20=20=
=20eassert=20(NILP=20(BVAR=20(current_buffer,=20=
enable_multibyte_characters)));=0A+=20=20=20=20=20=20insert_from_gap_1=20=
(inserted_bytes,=20inserted_bytes,=20false);=0A+=0A+=20=20=20=20=20=20/*=20=
The=20target=20buffer=20is=20unibyte,=20so=20we=20don't=20need=20to=20=
decode.=20=20*/=0A+=20=20=20=20=20=20invalidate_buffer_caches=20=
(current_buffer,=0A+=09=09=09=09PT,=20PT=20+=20inserted_bytes);=0A+=20=20=
=20=20=20=20adjust_after_insert=20(PT,=20PT_BYTE,=0A+=09=09=09=20=20=20=
PT=20+=20inserted_bytes,=0A+=09=09=09=20=20=20PT_BYTE=20+=20=
inserted_bytes,=0A+=09=09=09=20=20=20inserted_bytes);=0A+=20=20=20=20=20=20=
inserted=20=3D=20inserted_bytes;=0A=20=20=20=20=20}=0A=20=0A=20=20=20/*=20=
Call=20after-change=20hooks.=20=20*/=0A@@=20-791,7=20+956,7=20@@=20DEFUN=20=
("json-insert",=20Fjson_insert,=20Sjson_insert,=201,=20MANY,=0A=20=20=20=20=
=20=20=20SET_PT_BOTH=20(PT=20+=20inserted,=20PT_BYTE=20+=20=
inserted_bytes);=0A=20=20=20=20=20}=0A=20=0A-=20=20return=20unbind_to=20=
(count,=20Qnil);=0A+=20=20return=20Qnil;=0A=20}=0A=20=0A=20/*=20Convert=20=
a=20JSON=20object=20to=20a=20Lisp=20object.=20=20*/=0Adiff=20--git=20=
a/test/src/json-tests.el=20b/test/src/json-tests.el=0Aindex=20=
dffc6291ca1..351d909f05b=20100644=0A---=20a/test/src/json-tests.el=0A+++=20=
b/test/src/json-tests.el=0A@@=20-126,11=20+126,38=20@@=20=
json-serialize/object=0A=20=0A=20(ert-deftest=20=
json-serialize/object-with-duplicate-keys=20()=0A=20=20=20(skip-unless=20=
(fboundp=20'json-serialize))=0A-=20=20(let=20((table=20(make-hash-table=20=
:test=20#'eq)))=0A-=20=20=20=20(puthash=20(copy-sequence=20"abc")=20[1=20=
2=20t]=20table)=0A-=20=20=20=20(puthash=20(copy-sequence=20"abc")=20=
:null=20table)=0A-=20=20=20=20(should=20(equal=20(hash-table-count=20=
table)=202))=0A-=20=20=20=20(should-error=20(json-serialize=20table)=20=
:type=20'wrong-type-argument)))=0A+=0A+=20=20(dolist=20(n=20'(1=205=2020=20=
100))=0A+=20=20=20=20(let=20((symbols=20(mapcar=20(lambda=20(i)=20=
(make-symbol=20(format=20"s%d"=20i)))=0A+=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(number-sequence=201=20=
n)))=0A+=20=20=20=20=20=20=20=20=20=20(expected=20(concat=20"{"=0A+=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20(mapconcat=20(lambda=20(i)=20(format=20"\"s%d\":%d"=20i=20i))=0A+=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20(number-sequence=201=20n)=20",")=0A+=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20"}")))=0A+=20=20=20=20=20=20;;=20alist=0A+=20=20=20=20=20=20=
(should=20(equal=20(json-serialize=0A+=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20(append=0A+=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20(cl-mapcar=20#'cons=0A+=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20symbols=20(number-sequence=201=20n))=0A+=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(cl-mapcar=20#'cons=0A+=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20symbols=20(number-sequence=201001=20(+=201000=20=
n)))))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
expected))=0A+=20=20=20=20=20=20;;=20plist=0A+=20=20=20=20=20=20(should=20=
(equal=20(json-serialize=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20(append=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20(cl-mapcan=20#'list=0A+=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20symbols=20(number-sequence=201=20n))=0A+=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20(cl-mapcan=20#'list=0A+=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20symbols=20(number-sequence=201001=20(+=201000=20n)))))=0A=
+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
expected))))=0A+=0A+=20=20;;=20We=20don't=20check=20for=20duplicated=20=
keys=20in=20hash=20tables.=0A+=20=20;;=20(let=20((table=20=
(make-hash-table=20:test=20#'eq)))=0A+=20=20;;=20=20=20(puthash=20=
(copy-sequence=20"abc")=20[1=202=20t]=20table)=0A+=20=20;;=20=20=20=
(puthash=20(copy-sequence=20"abc")=20:null=20table)=0A+=20=20;;=20=20=20=
(should=20(equal=20(hash-table-count=20table)=202))=0A+=20=20;;=20=20=20=
(should-error=20(json-serialize=20table)=20:type=20=
'wrong-type-argument))=0A+=20=20)=0A=20=0A=20(ert-deftest=20=
json-parse-string/object=20()=0A=20=20=20(skip-unless=20(fboundp=20=
'json-parse-string))=0A@@=20-174,7=20+201,10=20@@=20=
json-serialize/string=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20"[\"\\nasd=D1=84=D1=8B=D0=B2\\u001F\u007ffgh\\t\"]"))=0A=20=20=20=
(should=20(equal=20(json-serialize=20["a\0b"])=20"[\"a\\u0000b\"]"))=0A=20=
=20=20;;=20FIXME:=20Is=20this=20the=20right=20behavior?=0A-=20=20(should=20=
(equal=20(json-serialize=20["\u00C4\xC3\x84"])=20"[\"\u00C4\u00C4\"]")))=0A=
+=20=20;;=20FIXME:=20(no=20it's=20not)=0A+=20=20;;=20(should=20(equal=20=
(json-serialize=20["\u00C4\xC3\x84"])=20"[\"\u00C4\u00C4\"]"))=0A+=20=20=
(should-error=20(json-serialize=20["\u00C4\xC3\x84"]))=0A+=20=20)=0A=20=0A=
=20(ert-deftest=20json-serialize/invalid-unicode=20()=0A=20=20=20=
(skip-unless=20(fboundp=20'json-serialize))=0A=

--Apple-Mail=_E4201434-B8C0-4597-91DC-3456766FB664--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 27 Mar 2024 12:46:27 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Mar 27 08:46:27 2024
Received: from localhost ([127.0.0.1]:36023 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rpSfj-0002ij-Af
	for submit <at> debbugs.gnu.org; Wed, 27 Mar 2024 08:46:27 -0400
Received: from mail-lj1-x234.google.com ([2a00:1450:4864:20::234]:44200)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mattias.engdegard@HIDDEN>) id 1rpSfh-0002ht-5k
 for 70007 <at> debbugs.gnu.org; Wed, 27 Mar 2024 08:46:25 -0400
Received: by mail-lj1-x234.google.com with SMTP id
 38308e7fff4ca-2d24a727f78so75800111fa.0
 for <70007 <at> debbugs.gnu.org>; Wed, 27 Mar 2024 05:46:24 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1711543579; x=1712148379; darn=debbugs.gnu.org;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:from:to:cc:subject
 :date:message-id:reply-to;
 bh=DztfssGyopG5qFfZJc3NT1p7c4+ClTaQwe0sm5q2yNU=;
 b=kp/VANVjBtHjQLfzS9g+WrAypj1+Rtwr7P0nlHzyaj5O9knxMaxsbwb9hW33GhT0PU
 3LcDQ1GFLvqSG+vrLl/lSmExdA3MAGDeuBobfv8cJK1pUUDZOOnhztIspNYi2lF5AF+M
 Ztf6UIghx5EfTy46goCuayS5jwrhuovPf0gMcuyICBIbTVyP0fPRp4nN8twRFri6O11J
 YRH8omj45bRqJ2oWihMAPI+JRrPz9g2rVW5DSKBx+lePxRw82B1lw6vRZRa1pFDqQEtn
 Lt+Rjk3csXKNnSOfIbDdV9xZ0pxI2spxz6WEpeFTWSKqTlNRoLKlTALvsapFsLYvvipD
 lWZg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711543579; x=1712148379;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:sender:x-gm-message-state
 :from:to:cc:subject:date:message-id:reply-to;
 bh=DztfssGyopG5qFfZJc3NT1p7c4+ClTaQwe0sm5q2yNU=;
 b=l9SiVN1XttAw3hAlGkE0NNV4U4oyhkvMzGxImDCK+VM88i6XKgc12tKPWpMP3JsDnF
 Va+Z+8O/TVMtOAxL7vdaiKBzOdkFAhzK6NYyx2hGJ7fsoi9f12LcGa6meoaMEP7DXMra
 dh57e1eBZRbGAqo6USv07GlrV89Mc5CYBXDCi2w0esTGnPOZyQose0tcw1uEp1UJlv/6
 craU/0InrTki2f4YjYV9hL+3XaJGqRUG/nQE0egT2bNoD5Go1hATFNL3PvgxJTnA5ZGo
 YaI1QIOLhMmR0XeHBIjkZnBpBWmog8tbc6pchMZAsc9jGmPBkC4HCcQfSCfLc95eKuK9
 kLBw==
X-Gm-Message-State: AOJu0YxVngko4dSHV7dLRKNa33E+QB7zFs2NIo5H+mxF+VM7SLSERojk
 z3HJ7PcDYMxPEQCY6+SS0XmYmndHoQ9uWiEXaTHWYxHFdN6Pa4Ku
X-Google-Smtp-Source: AGHT+IEqZ97Mt78jBdWdCLZoJgJE1qR7BvGLFGefVGKui+88aUzmfOy7CFDaZ6FXgvumv1K8Si9C1w==
X-Received: by 2002:a05:651c:1407:b0:2d4:3d86:54e2 with SMTP id
 u7-20020a05651c140700b002d43d8654e2mr3311688lje.27.1711543578637; 
 Wed, 27 Mar 2024 05:46:18 -0700 (PDT)
Received: from smtpclient.apple (c80-217-1-132.bredband.tele2.se.
 [80.217.1.132]) by smtp.gmail.com with ESMTPSA id
 a17-20020a2e8611000000b002d6afe0ba04sm2019145lji.74.2024.03.27.05.46.17
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Wed, 27 Mar 2024 05:46:17 -0700 (PDT)
Content-Type: text/plain;
	charset=utf-8
Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.15\))
Subject: Re: bug#70007: [PATCH] native JSON encoder
From: =?utf-8?Q?Mattias_Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <86wmpphrg7.fsf@HIDDEN>
Date: Wed, 27 Mar 2024 13:46:17 +0100
Content-Transfer-Encoding: quoted-printable
Message-Id: <C6944977-0CF9-4D19-9D92-EA1F086700D7@HIDDEN>
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
 <86wmpphrg7.fsf@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
X-Mailer: Apple Mail (2.3654.120.0.1.15)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 70007
Cc: 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

26 mars 2024 kl. 17.46 skrev Eli Zaretskii <eliz@HIDDEN>:

>> - The old code incorrectly accepted strings with non-Unicode =
characters (raw bytes). There is no reason to do this; JSON is UTF-8 =
only.
>=20
> Would it complicate the code not to reject raw bytes?  I'd like to
> avoid incompatibilities if it's practical.  Also, Emacs traditionally
> doesn't reject raw bytes, leaving that to the application or the user.

Actually I may have misrepresented the behaviour of the old encoder. It =
doesn't accept any raw bytes but only sequences that happen to form =
valid UTF-8. It's quite strange, and I don't really think this was ever =
intended, just a consequence of the implementation.

This means that it accepts an already encoded unibyte UTF-8 string:

  (json-serialize "\303\251") -> "\"=C3=A9\""

which is doubly odd since it's supposed to be encoding, but it ends up =
decoding the characters instead.
Even worse, it accepts mixtures of encoded and decoded chars:

  (json-serialize "=C3=A9\303\251") -> "\"=C3=A9=C3=A9\""

which is just bonkers.
So while we could try to replicate this 'interesting' behaviour it would =
definitely complicate the code and be of questionable use.

The JSON spec is quite clear that it's UTF-8 only. The only useful =
deviation that I can think of would be to allow unpaired surrogates =
(WTF-8) to pass through for transmission of Windows file names, but that =
would be an extension -- the old encoder doesn't permit those.





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at 70007 <at> debbugs.gnu.org:


Received: (at 70007) by debbugs.gnu.org; 26 Mar 2024 16:46:26 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Mar 26 12:46:26 2024
Received: from localhost ([127.0.0.1]:34791 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rp9wQ-0005LO-Gt
	for submit <at> debbugs.gnu.org; Tue, 26 Mar 2024 12:46:26 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:55670)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1rp9wO-0005Kr-0r
 for 70007 <at> debbugs.gnu.org; Tue, 26 Mar 2024 12:46:24 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1rp9wH-0008Ub-Q9; Tue, 26 Mar 2024 12:46:19 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=D8erITFuTYCwhWSH92t8Ii9tlmx8pFHA41qcO919Qv8=; b=A1rNwi8EwUDLuUNj+HJZ
 ho0Al2cQ0BHV+OGcq0Oizk2oaaMMP4HOsWKxzJbuY7zL8ET1O9nQ3Yv9nGKSfG2axHzAX+IxRaG3K
 h8+IcpkmBS/ixhCjLSfnGaU+y+vPulx3w2xJNajVIK1dvaV9wVZ1YenoFY2O8fDDv6nXrjM8jnyHz
 SzBprmeDNRMIyJDfxhfquC0LN+SUvdGtSlw+bLxuUnLpuFpZRiuXMCJi+6D5zZEsUBi8eQ+6CuPg0
 qKeYbYxdRYwysrnr+o32vNcH0dlU+ne4vkms/LQwb/kQxcOqYpQ5DcaM4Ndeb8Cng4nZfe4+RvH2w
 03H0h99Pb/7QEg==;
Date: Tue, 26 Mar 2024 18:46:00 +0200
Message-Id: <86wmpphrg7.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Mattias =?utf-8?Q?Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
In-Reply-To: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN> (message from
 Mattias =?utf-8?Q?Engdeg=C3=A5rd?= on Tue, 26 Mar 2024 16:33:52 +0100)
Subject: Re: bug#70007: [PATCH] native JSON encoder
References: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 70007
Cc: 70007 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: Mattias Engdegård <mattias.engdegard@HIDDEN>
> Date: Tue, 26 Mar 2024 16:33:52 +0100
> 
> If we replace the lisp-to-JSON encoder with native code, we would not need the jansson library for it and it would be faster.
> 
> There is ongoing work on a JSON-to-lisp parser, but the author has made it clear that he does not have time to write an encoder, so I spent a morning mashing up the attached patch.

Thanks for working on this.

> It generally produces the same result as the old code, except:
> 
> - The old code incorrectly accepted strings with non-Unicode characters (raw bytes). There is no reason to do this; JSON is UTF-8 only.

Would it complicate the code not to reject raw bytes?  I'd like to
avoid incompatibilities if it's practical.  Also, Emacs traditionally
doesn't reject raw bytes, leaving that to the application or the user.

> I'd be very happy if someone could test it with packages that use this interface (json-serialise, json-insert).

Yes, please.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 26 Mar 2024 15:34:32 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Mar 26 11:34:32 2024
Received: from localhost ([127.0.0.1]:34488 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1rp8op-00028V-Kg
	for submit <at> debbugs.gnu.org; Tue, 26 Mar 2024 11:34:31 -0400
Received: from lists.gnu.org ([2001:470:142::17]:35458)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mattias.engdegard@HIDDEN>) id 1rp8on-00027b-9P
 for submit <at> debbugs.gnu.org; Tue, 26 Mar 2024 11:34:30 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <mattias.engdegard@HIDDEN>)
 id 1rp8oQ-0000yM-Ok
 for bug-gnu-emacs@HIDDEN; Tue, 26 Mar 2024 11:34:08 -0400
Received: from mail-lj1-x22f.google.com ([2a00:1450:4864:20::22f])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <mattias.engdegard@HIDDEN>)
 id 1rp8oI-0006Il-4c
 for bug-gnu-emacs@HIDDEN; Tue, 26 Mar 2024 11:34:01 -0400
Received: by mail-lj1-x22f.google.com with SMTP id
 38308e7fff4ca-2d6ee81bc87so6440421fa.1
 for <bug-gnu-emacs@HIDDEN>; Tue, 26 Mar 2024 08:33:56 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1711467234; x=1712072034; darn=gnu.org;
 h=to:date:message-id:subject:mime-version:from:sender:from:to:cc
 :subject:date:message-id:reply-to;
 bh=QRkLtcr+EgvnDYUk8l8Y21pG2S4sv24IUJFjQ7aUOys=;
 b=I3DD68b7I1GN8VSiwVp/4f/htxSRUHYUh6R768JkjAk5h9yhUOeJS3rfY6XC8uwVOb
 7ozZaq2LC0+rYu7IcC5HhBkvvDohXv2/GFWeIxQ4p38g6cP0XRrWH0yqMbgqYjii6sCU
 v35oKjLD/jvPCxMp7SB9iV6o/eh2YTQfZxhLDt6ce/D1g87Q7ut1JoDa6z19+rWmRouR
 zvI4IrVZoKVqg+UpAMQhtQubys28L36mOoWIrw6D9Hx4Puokkvyr4iC6tIvtdjmYME8G
 /dt0Bqj3aqs+b/04toYscsSNI+7ePP5GE9VMDA87vSdJ9qJVeFJXy48qDPQBpCWRu9rx
 f9Rw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711467234; x=1712072034;
 h=to:date:message-id:subject:mime-version:from:sender
 :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
 bh=QRkLtcr+EgvnDYUk8l8Y21pG2S4sv24IUJFjQ7aUOys=;
 b=Bn4I3GE5tEYUTcdfzgoChydTfc/aCKRAKsSdLe7Xdnbb36olv8v6GzD+EBvb8bIs5x
 vjBy5lEMckGeNpcq3rtsmJOvbZNmf91UbZG1bFOFA6xrri7gwizzv3sDe54PAPifBGBV
 6L+YMVdTVCEeDHEOiR6/svwsvx+083snGNumruOTQ8m0JBgyQ4EOU10MoSJbYSq0/rc6
 XlTrQiZ5Dl+Br1LZP/HsB0LafKpBamjjunSNb+QaRLw9BUSE71lxLlDB0yZVUzEqIPs7
 ftJdhByL9XM5YgSl7SNFK95us+2IgvjE5Zz6C7XNXtDFbeBrJyhlkO3pcP2l3K+O4R8W
 4QsQ==
X-Gm-Message-State: AOJu0Yy060FSRlFbqS6eWmodcq6yaZ3iKizLgnISzAp7UCfupocvyNzy
 6npo9rHdedbxlKiFSOtUjcn+ZTSUTc+/uL3DIedtmFXxATRdP7EGO2hXoN6H
X-Google-Smtp-Source: AGHT+IEMmzZ3k0v2q3GovR/BVORH7TWPmui9//TuSSYNrk4ZKuC92QC5RmSg54I3jkfo1c7vKVWC2w==
X-Received: by 2002:a2e:960b:0:b0:2d4:6786:e8 with SMTP id
 v11-20020a2e960b000000b002d4678600e8mr6276025ljh.12.1711467233471; 
 Tue, 26 Mar 2024 08:33:53 -0700 (PDT)
Received: from smtpclient.apple (c80-217-1-132.bredband.tele2.se.
 [80.217.1.132]) by smtp.gmail.com with ESMTPSA id
 q126-20020a2e2a84000000b002d4764f825fsm1737761ljq.63.2024.03.26.08.33.52
 for <bug-gnu-emacs@HIDDEN>
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Tue, 26 Mar 2024 08:33:53 -0700 (PDT)
From: =?utf-8?Q?Mattias_Engdeg=C3=A5rd?= <mattias.engdegard@HIDDEN>
Content-Type: multipart/mixed;
 boundary="Apple-Mail=_7330F7C9-D7F2-4246-9F8E-A734AAA47A92"
Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.15\))
Subject: [PATCH] native JSON encoder
Message-Id: <1BF559D1-DB9F-4FEB-90ED-72E0EFD76424@HIDDEN>
Date: Tue, 26 Mar 2024 16:33:52 +0100
To: Emacs Bug Report <bug-gnu-emacs@HIDDEN>
X-Mailer: Apple Mail (2.3654.120.0.1.15)
Received-SPF: pass client-ip=2a00:1450:4864:20::22f;
 envelope-from=mattias.engdegard@HIDDEN; helo=mail-lj1-x22f.google.com
X-Spam_score_int: -20
X-Spam_score: -2.1
X-Spam_bar: --
X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001,
 RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: submit
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.0 (/)


--Apple-Mail=_7330F7C9-D7F2-4246-9F8E-A734AAA47A92
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii

If we replace the lisp-to-JSON encoder with native code, we would not =
need the jansson library for it and it would be faster.

There is ongoing work on a JSON-to-lisp parser, but the author has made =
it clear that he does not have time to write an encoder, so I spent a =
morning mashing up the attached patch.

It generally produces the same result as the old code, except:

- The old code incorrectly accepted strings with non-Unicode characters =
(raw bytes). There is no reason to do this; JSON is UTF-8 only.
- The old code spent a lot of time ensuring that object keys were =
unique. The new code doesn't: it's a garbage-in garbage-out type of =
situation.

The new code could do with some optimisation but it's already about =
twice as fast as the old code, sometimes more.

I'd be very happy if someone could test it with packages that use this =
interface (json-serialise, json-insert).


--Apple-Mail=_7330F7C9-D7F2-4246-9F8E-A734AAA47A92
Content-Disposition: attachment;
	filename=json-serialise.diff
Content-Type: application/octet-stream;
	x-unix-mode=0644;
	name="json-serialise.diff"
Content-Transfer-Encoding: quoted-printable

diff=20--git=20a/src/json.c=20b/src/json.c=0Aindex=20=
e849ccaf722..7fbe700e07c=20100644=0A---=20a/src/json.c=0A+++=20=
b/src/json.c=0A@@=20-23,6=20+23,7=20@@=20Copyright=20(C)=202017-2024=20=
Free=20Software=20Foundation,=20Inc.=0A=20#include=20<stddef.h>=0A=20=
#include=20<stdint.h>=0A=20#include=20<stdlib.h>=0A+#include=20<math.h>=0A=
=20=0A=20#include=20<jansson.h>=0A=20=0A@@=20-231,12=20+232,6=20@@=20=
json_encode=20(Lisp_Object=20string)=0A=20=20=20return=20=
encode_string_utf_8=20(string,=20Qnil,=20false,=20Qt,=20Qt);=0A=20}=0A=20=
=0A-static=20AVOID=0A-json_out_of_memory=20(void)=0A-{=0A-=20=20xsignal0=20=
(Qjson_out_of_memory);=0A-}=0A-=0A=20/*=20Signal=20a=20Lisp=20error=20=
corresponding=20to=20the=20JSON=20ERROR.=20=20*/=0A=20=0A=20static=20=
AVOID=0A@@=20-289,26=20+284,6=20@@=20check_string_without_embedded_nulls=20=
(Lisp_Object=20object)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
Qstring_without_embedded_nulls_p,=20object);=0A=20}=0A=20=0A-/*=20Signal=20=
an=20error=20of=20type=20`json-out-of-memory'=20if=20OBJECT=20is=0A-=20=20=
=20NULL.=20=20*/=0A-=0A-static=20json_t=20*=0A-json_check=20(json_t=20=
*object)=0A-{=0A-=20=20if=20(object=20=3D=3D=20NULL)=0A-=20=20=20=20=
json_out_of_memory=20();=0A-=20=20return=20object;=0A-}=0A-=0A-/*=20If=20=
STRING=20is=20not=20a=20valid=20UTF-8=20string,=20signal=20an=20error=20=
of=20type=0A-=20=20=20`wrong-type-argument'.=20=20STRING=20must=20be=20a=20=
unibyte=20string.=20=20*/=0A-=0A-static=20void=0A-json_check_utf8=20=
(Lisp_Object=20string)=0A-{=0A-=20=20CHECK_TYPE=20(utf8_string_p=20=
(string),=20Qutf_8_string_p,=20string);=0A-}=0A-=0A=20enum=20=
json_object_type=20{=0A=20=20=20json_object_hashtable,=0A=20=20=20=
json_object_alist,=0A@@=20-327,179=20+302,6=20@@=20json_check_utf8=20=
(Lisp_Object=20string)=0A=20=20=20Lisp_Object=20false_object;=0A=20};=0A=20=
=0A-static=20json_t=20*lisp_to_json=20(Lisp_Object,=0A-=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
const=20struct=20json_configuration=20*conf);=0A-=0A-/*=20Convert=20a=20=
Lisp=20object=20to=20a=20nonscalar=20JSON=20object=20(array=20or=20=
object).=20=20*/=0A-=0A-static=20json_t=20*=0A-lisp_to_json_nonscalar_1=20=
(Lisp_Object=20lisp,=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20const=20struct=20json_configuration=20*conf)=0A=
-{=0A-=20=20json_t=20*json;=0A-=20=20specpdl_ref=20count;=0A-=0A-=20=20=
if=20(VECTORP=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20ptrdiff_t=20=
size=20=3D=20ASIZE=20(lisp);=0A-=20=20=20=20=20=20json=20=3D=20=
json_check=20(json_array=20());=0A-=20=20=20=20=20=20count=20=3D=20=
SPECPDL_INDEX=20();=0A-=20=20=20=20=20=20record_unwind_protect_ptr=20=
(json_release_object,=20json);=0A-=20=20=20=20=20=20for=20(ptrdiff_t=20i=20=
=3D=200;=20i=20<=20size;=20++i)=0A-=20=20=20=20=20=20=20=20{=0A-=20=20=20=
=20=20=20=20=20=20=20int=20status=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=3D=20json_array_append_new=20(json,=20lisp_to_json=20(AREF=20(lisp,=20=
i),=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20conf));=0A-=20=20=20=20=20=20=20=20=20=20=
if=20(status=20=3D=3D=20-1)=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
json_out_of_memory=20();=0A-=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20=
eassert=20(json_array_size=20(json)=20=3D=3D=20size);=0A-=20=20=20=20}=0A=
-=20=20else=20if=20(HASH_TABLE_P=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=
=20=20struct=20Lisp_Hash_Table=20*h=20=3D=20XHASH_TABLE=20(lisp);=0A-=20=20=
=20=20=20=20json=20=3D=20json_check=20(json_object=20());=0A-=20=20=20=20=
=20=20count=20=3D=20SPECPDL_INDEX=20();=0A-=20=20=20=20=20=20=
record_unwind_protect_ptr=20(json_release_object,=20json);=0A-=20=20=20=20=
=20=20DOHASH=20(h,=20key,=20v)=0A-=20=20=20=20=20=20=20=20{=0A-=09=20=20=
CHECK_STRING=20(key);=0A-=09=20=20Lisp_Object=20ekey=20=3D=20json_encode=20=
(key);=0A-=09=20=20/*=20We=20can't=20specify=20the=20length,=20so=20the=20=
string=20must=20be=0A-=09=20=20=20=20=20null-terminated.=20=20*/=0A-=09=20=
=20check_string_without_embedded_nulls=20(ekey);=0A-=09=20=20const=20=
char=20*key_str=20=3D=20SSDATA=20(ekey);=0A-=09=20=20/*=20Reject=20=
duplicate=20keys.=20=20These=20are=20possible=20if=20the=20hash=0A-=09=20=
=20=20=20=20table=20test=20is=20not=20`equal'.=20=20*/=0A-=09=20=20if=20=
(json_object_get=20(json,=20key_str)=20!=3D=20NULL)=0A-=09=20=20=20=20=
wrong_type_argument=20(Qjson_value_p,=20lisp);=0A-=09=20=20int=20status=0A=
-=09=20=20=20=20=3D=20json_object_set_new=20(json,=20key_str,=0A-=09=09=09=
=09=20=20=20lisp_to_json=20(v,=20conf));=0A-=09=20=20if=20(status=20=3D=3D=
=20-1)=0A-=09=20=20=20=20{=0A-=09=20=20=20=20=20=20/*=20A=20failure=20=
can=20be=20caused=20either=20by=20an=20invalid=20key=20or=0A-=09=09=20by=20=
low=20memory.=20=20*/=0A-=09=20=20=20=20=20=20json_check_utf8=20(ekey);=0A=
-=09=20=20=20=20=20=20json_out_of_memory=20();=0A-=09=20=20=20=20}=0A-=09=
}=0A-=20=20=20=20}=0A-=20=20else=20if=20(NILP=20(lisp))=0A-=20=20=20=20=
return=20json_check=20(json_object=20());=0A-=20=20else=20if=20(CONSP=20=
(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20Lisp_Object=20tail=20=3D=20=
lisp;=0A-=20=20=20=20=20=20json=20=3D=20json_check=20(json_object=20());=0A=
-=20=20=20=20=20=20count=20=3D=20SPECPDL_INDEX=20();=0A-=20=20=20=20=20=20=
record_unwind_protect_ptr=20(json_release_object,=20json);=0A-=20=20=20=20=
=20=20bool=20is_plist=20=3D=20!CONSP=20(XCAR=20(tail));=0A-=20=20=20=20=20=
=20FOR_EACH_TAIL=20(tail)=0A-=20=20=20=20=20=20=20=20{=0A-=20=20=20=20=20=
=20=20=20=20=20const=20char=20*key_str;=0A-=20=20=20=20=20=20=20=20=20=20=
Lisp_Object=20value;=0A-=20=20=20=20=20=20=20=20=20=20Lisp_Object=20=
key_symbol;=0A-=20=20=20=20=20=20=20=20=20=20if=20(is_plist)=0A-=20=20=20=
=20=20=20=20=20=20=20=20=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
key_symbol=20=3D=20XCAR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20tail=20=3D=20XCDR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20CHECK_CONS=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
value=20=3D=20XCAR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=0A=
-=20=20=20=20=20=20=20=20=20=20else=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20Lisp_Object=20pair=20=3D=20=
XCAR=20(tail);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20CHECK_CONS=20=
(pair);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20key_symbol=20=3D=20=
XCAR=20(pair);=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20value=20=3D=20=
XCDR=20(pair);=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=
=20=20=20=20=20CHECK_SYMBOL=20(key_symbol);=0A-=20=20=20=20=20=20=20=20=20=
=20Lisp_Object=20key=20=3D=20SYMBOL_NAME=20(key_symbol);=0A-=20=20=20=20=20=
=20=20=20=20=20/*=20We=20can't=20specify=20the=20length,=20so=20the=20=
string=20must=20be=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=
null-terminated.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20=
check_string_without_embedded_nulls=20(key);=0A-=20=20=20=20=20=20=20=20=20=
=20key_str=20=3D=20SSDATA=20(key);=0A-=20=20=20=20=20=20=20=20=20=20/*=20=
In=20plists,=20ensure=20leading=20":"=20in=20keys=20is=20stripped.=20=20=
It=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20will=20be=20reconstructed=20=
later=20in=20`json_to_lisp'.*/=0A-=20=20=20=20=20=20=20=20=20=20if=20=
(is_plist=20&&=20':'=20=3D=3D=20key_str[0]=20&&=20key_str[1])=0A-=20=20=20=
=20=20=20=20=20=20=20=20=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
key_str=20=3D=20&key_str[1];=0A-=20=20=20=20=20=20=20=20=20=20=20=20}=0A=
-=20=20=20=20=20=20=20=20=20=20/*=20Only=20add=20element=20if=20key=20is=20=
not=20already=20present.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20if=20=
(json_object_get=20(json,=20key_str)=20=3D=3D=20NULL)=0A-=20=20=20=20=20=20=
=20=20=20=20=20=20{=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20int=20=
status=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=3D=20=
json_object_set_new=20(json,=20key_str,=20lisp_to_json=20(value,=0A-=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20conf));=0A-=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20if=20(status=20=3D=3D=20-1)=0A-=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20json_out_of_memory=20();=0A-=20=20=20=20=
=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=
=20CHECK_LIST_END=20(tail,=20lisp);=0A-=20=20=20=20}=0A-=20=20else=0A-=20=
=20=20=20wrong_type_argument=20(Qjson_value_p,=20lisp);=0A-=0A-=20=20=
clear_unwind_protect=20(count);=0A-=20=20unbind_to=20(count,=20Qnil);=0A=
-=20=20return=20json;=0A-}=0A-=0A-/*=20Convert=20LISP=20to=20a=20=
nonscalar=20JSON=20object=20(array=20or=20object).=20=20Signal=0A-=20=20=20=
an=20error=20of=20type=20`wrong-type-argument'=20if=20LISP=20is=20not=20=
a=20vector,=0A-=20=20=20hashtable,=20alist,=20or=20plist.=20=20*/=0A-=0A=
-static=20json_t=20*=0A-lisp_to_json_nonscalar=20(Lisp_Object=20lisp,=0A=
-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
const=20struct=20json_configuration=20*conf)=0A-{=0A-=20=20if=20=
(++lisp_eval_depth=20>=20max_lisp_eval_depth)=0A-=20=20=20=20xsignal0=20=
(Qjson_object_too_deep);=0A-=20=20json_t=20*json=20=3D=20=
lisp_to_json_nonscalar_1=20(lisp,=20conf);=0A-=20=20--lisp_eval_depth;=0A=
-=20=20return=20json;=0A-}=0A-=0A-/*=20Convert=20LISP=20to=20any=20JSON=20=
object.=20=20Signal=20an=20error=20of=20type=0A-=20=20=20=
`wrong-type-argument'=20if=20the=20type=20of=20LISP=20can't=20be=20=
converted=20to=20a=0A-=20=20=20JSON=20object.=20=20*/=0A-=0A-static=20=
json_t=20*=0A-lisp_to_json=20(Lisp_Object=20lisp,=20const=20struct=20=
json_configuration=20*conf)=0A-{=0A-=20=20if=20(EQ=20(lisp,=20=
conf->null_object))=0A-=20=20=20=20return=20json_check=20(json_null=20=
());=0A-=20=20else=20if=20(EQ=20(lisp,=20conf->false_object))=0A-=20=20=20=
=20return=20json_check=20(json_false=20());=0A-=20=20else=20if=20(EQ=20=
(lisp,=20Qt))=0A-=20=20=20=20return=20json_check=20(json_true=20());=0A-=20=
=20else=20if=20(INTEGERP=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20=
intmax_t=20low=20=3D=20TYPE_MINIMUM=20(json_int_t);=0A-=20=20=20=20=20=20=
intmax_t=20high=20=3D=20TYPE_MAXIMUM=20(json_int_t);=0A-=20=20=20=20=20=20=
intmax_t=20value=20=3D=20check_integer_range=20(lisp,=20low,=20high);=0A=
-=20=20=20=20=20=20return=20json_check=20(json_integer=20(value));=0A-=20=
=20=20=20}=0A-=20=20else=20if=20(FLOATP=20(lisp))=0A-=20=20=20=20return=20=
json_check=20(json_real=20(XFLOAT_DATA=20(lisp)));=0A-=20=20else=20if=20=
(STRINGP=20(lisp))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20Lisp_Object=20=
encoded=20=3D=20json_encode=20(lisp);=0A-=20=20=20=20=20=20json_t=20=
*json=20=3D=20json_stringn=20(SSDATA=20(encoded),=20SBYTES=20(encoded));=0A=
-=20=20=20=20=20=20if=20(json=20=3D=3D=20NULL)=0A-=20=20=20=20=20=20=20=20=
{=0A-=20=20=20=20=20=20=20=20=20=20/*=20A=20failure=20can=20be=20caused=20=
either=20by=20an=20invalid=20string=20or=20by=0A-=20=20=20=20=20=20=20=20=
=20=20=20=20=20low=20memory.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20=
json_check_utf8=20(encoded);=0A-=20=20=20=20=20=20=20=20=20=20=
json_out_of_memory=20();=0A-=20=20=20=20=20=20=20=20}=0A-=20=20=20=20=20=20=
return=20json;=0A-=20=20=20=20}=0A-=0A-=20=20/*=20LISP=20now=20must=20be=20=
a=20vector,=20hashtable,=20alist,=20or=20plist.=20=20*/=0A-=20=20return=20=
lisp_to_json_nonscalar=20(lisp,=20conf);=0A-}=0A-=0A=20static=20void=0A=20=
json_parse_args=20(ptrdiff_t=20nargs,=0A=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20Lisp_Object=20*args,=0A@@=20-585,6=20+387,332=20@@=20=
DEFUN=20("json--available-p",=20Fjson__available_p,=20=
Sjson__available_p,=200,=200,=20NULL,=0A=20=20=20return=20=
json_available_p=20()=20?=20Qt=20:=20Qnil;=0A=20}=0A=20=0A+/*=20JSON=20=
encoding=20context=20*/=0A+typedef=20struct=20{=0A+=20=20char=20*buf;=0A=
+=20=20ptrdiff_t=20size;=09=09/*=20number=20of=20bytes=20in=20buf=20*/=0A=
+=20=20ptrdiff_t=20capacity;=09=09/*=20allocated=20size=20of=20buf=20*/=0A=
+=20=20ptrdiff_t=20chars_delta;=20=20=20=20=20=20=20=20/*=20size=20-=20=
{number=20of=20Unicode=20chars=20in=20buf}=20*/=0A+=0A+=20=20int=20=
maxdepth;=0A+=20=20struct=20json_configuration=20conf;=0A+}=20=
json_out_t;=0A+=0A+static=20NO_INLINE=20void=0A+json_out_grow=20=
(json_out_t=20*jo,=20ptrdiff_t=20bytes)=0A+{=0A+=20=20ptrdiff_t=20need=20=
=3D=20jo->size=20+=20bytes;=0A+=20=20ptrdiff_t=20new_size=20=3D=20max=20=
(need,=20512);=0A+=20=20while=20(new_size=20<=20need)=0A+=20=20=20=20=
new_size=20<<=3D=201;=0A+=20=20jo->buf=20=3D=20xrealloc=20(jo->buf,=20=
new_size);=0A+=20=20jo->capacity=20=3D=20new_size;=0A+}=0A+=0A+static=20=
void=0A+cleanup_json_out=20(void=20*arg)=0A+{=0A+=20=20json_out_t=20*jo=20=
=3D=20arg;=0A+=20=20xfree=20(jo->buf);=0A+=20=20jo->buf=20=3D=20NULL;=0A=
+}=0A+=0A+/*=20Make=20room=20for=20`bytes`=20more=20bytes=20in=20buffer.=20=
=20*/=0A+static=20void=0A+json_make_room=20(json_out_t=20*jo,=20=
ptrdiff_t=20bytes)=0A+{=0A+=20=20if=20(bytes=20>=20jo->capacity=20-=20=
jo->size)=0A+=20=20=20=20json_out_grow=20(jo,=20bytes);=0A+}=0A+=0A=
+#define=20JSON_OUT_STR(jo,=20str)=20(json_out_str=20(jo,=20str,=20=
sizeof=20(str)=20-=201))=0A+=0A+/*=20Add=20`bytes`=20bytes=20from=20=
`str`=20to=20the=20buffer.=20=20*/=0A+static=20void=0A+json_out_str=20=
(json_out_t=20*jo,=20const=20char=20*str,=20size_t=20bytes)=0A+{=0A+=20=20=
json_make_room=20(jo,=20bytes);=0A+=20=20memcpy=20(jo->buf=20+=20=
jo->size,=20str,=20bytes);=0A+=20=20jo->size=20+=3D=20bytes;=0A+}=0A+=0A=
+static=20void=0A+json_out_byte=20(json_out_t=20*jo,=20unsigned=20char=20=
c)=0A+{=0A+=20=20json_make_room=20(jo,=201);=0A+=20=20=
jo->buf[jo->size++]=20=3D=20c;=0A+}=0A+=0A+static=20void=0A=
+json_out_fixnum=20(json_out_t=20*jo,=20EMACS_INT=20x)=0A+{=0A+=20=20=
char=20buf[INT_BUFSIZE_BOUND=20(EMACS_INT)];=0A+=20=20char=20*end=20=3D=20=
buf=20+=20sizeof=20buf;=0A+=20=20char=20*p=20=3D=20fixnum_to_string=20=
(x,=20buf,=20end);=0A+=20=20json_out_str=20(jo,=20p,=20end=20-=20p);=0A=
+}=0A+=0A+static=20AVOID=0A+string_not_unicode=20(Lisp_Object=20obj)=0A=
+{=0A+=20=20/*=20FIXME:=20for=20test=20compatibility,=20not=20a=20very=20=
descriptive=20error=20*/=0A+=20=20wrong_type_argument=20(Qjson_value_p,=20=
obj);=0A+}=0A+=0A+static=20unsigned=20char=20json_plain_char[256]=20=3D=20=
{=0A+=20=20/*=2032=20chars/line:=201=20for=20printable=20ASCII=20+=20DEL=20=
except=20"=20and=20\,=200=20elsewhere=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
00-1f=20*/=0A+=20=20=
1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,=20/*=20=
20-3f=20*/=0A+=20=20=
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,=20/*=20=
40-5f=20*/=0A+=20=20=
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,=20/*=20=
60-7f=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
80-9f=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
a0-bf=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
c0-df=20*/=0A+=20=20=
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,=20/*=20=
e0-ff=20*/=0A+};=0A+=0A+static=20void=0A+json_out_string=20(json_out_t=20=
*jo,=20Lisp_Object=20str,=20int=20skip)=0A+{=0A+=20=20/*=20FIXME:=20this=20=
code=20is=20slow,=20make=20faster!=20*/=0A+=0A+=20=20static=20const=20=
char=20hexchar[16]=20=3D=20"0123456789ABCDEF";=0A+=20=20ptrdiff_t=20len=20=
=3D=20SBYTES=20(str);=0A+=20=20json_make_room=20(jo,=20len=20+=202);=0A+=20=
=20json_out_byte=20(jo,=20'"');=0A+=20=20unsigned=20char=20*p=20=3D=20=
SDATA=20(str);=0A+=20=20unsigned=20char=20*end=20=3D=20p=20+=20len;=0A+=20=
=20p=20+=3D=20skip;=0A+=20=20while=20(p=20<=20end)=0A+=20=20=20=20{=0A+=20=
=20=20=20=20=20unsigned=20char=20c=20=3D=20*p;=0A+=20=20=20=20=20=20if=20=
(json_plain_char[c])=0A+=09{=0A+=09=20=20json_out_byte=20(jo,=20c);=0A+=09=
=20=20p++;=0A+=09}=0A+=20=20=20=20=20=20else=20if=20(c=20>=200x7f)=0A+=09=
{=0A+=09=20=20if=20(STRING_MULTIBYTE=20(str))=0A+=09=20=20=20=20{=0A+=09=20=
=20=20=20=20=20int=20n;=0A+=09=20=20=20=20=20=20if=20(c=20<=3D=200xc1)=0A=
+=09=09string_not_unicode=20(str);=0A+=09=20=20=20=20=20=20if=20(c=20<=3D=20=
0xdf)=0A+=09=09n=20=3D=202;=0A+=09=20=20=20=20=20=20else=20if=20(c=20<=3D=20=
0xef)=0A+=09=09{=0A+=09=09=20=20int=20v=20=3D=20(((c=20&=200x0f)=20<<=20=
12)=0A+=09=09=09=20=20=20+=20((p[1]=20&=200x3f)=20<<=206)=20+=20(p[2]=20=
&=200x3f));=0A+=09=09=20=20if=20(char_surrogate_p=20(v))=0A+=09=09=20=20=20=
=20string_not_unicode=20(str);=0A+=09=09=20=20n=20=3D=203;=0A+=09=09}=0A=
+=09=20=20=20=20=20=20else=20if=20(c=20<=3D=200xf7)=0A+=09=09{=0A+=09=09=20=
=20int=20v=20=3D=20(((c=20&=200x07)=20<<=2018)=0A+=09=09=09=20=20=20+=20=
((p[1]=20&=200x3f)=20<<=2012)=0A+=09=09=09=20=20=20+=20((p[2]=20&=20=
0x3f)=20<<=206)=0A+=09=09=09=20=20=20+=20(p[3]=20&=200x3f));=0A+=09=09=20=
=20if=20(v=20>=20MAX_UNICODE_CHAR)=0A+=09=09=20=20=20=20=
string_not_unicode=20(str);=0A+=09=09=20=20n=20=3D=204;=0A+=09=09}=0A+=09=
=20=20=20=20=20=20else=0A+=09=09string_not_unicode=20(str);=0A+=09=20=20=20=
=20=20=20json_out_str=20(jo,=20(const=20char=20*)p,=20n);=0A+=09=20=20=20=
=20=20=20jo->chars_delta=20+=3D=20n=20-=201;=0A+=09=20=20=20=20=20=20p=20=
+=3D=20n;=0A+=09=20=20=20=20}=0A+=09=20=20else=0A+=09=20=20=20=20=
string_not_unicode=20(str);=0A+=09}=0A+=20=20=20=20=20=20else=0A+=09{=0A=
+=09=20=20json_out_byte=20(jo,=20'\\');=0A+=09=20=20switch=20(c)=0A+=09=20=
=20=20=20{=0A+=09=20=20=20=20case=20'"':=0A+=09=20=20=20=20case=20'\\':=20=
json_out_byte=20(jo,=20c);=20break;=0A+=09=20=20=20=20case=20'\b':=20=
json_out_byte=20(jo,=20'b');=20break;=0A+=09=20=20=20=20case=20'\t':=20=
json_out_byte=20(jo,=20't');=20break;=0A+=09=20=20=20=20case=20'\n':=20=
json_out_byte=20(jo,=20'n');=20break;=0A+=09=20=20=20=20case=20'\f':=20=
json_out_byte=20(jo,=20'f');=20break;=0A+=09=20=20=20=20case=20'\r':=20=
json_out_byte=20(jo,=20'r');=20break;=0A+=09=20=20=20=20default:=0A+=09=20=
=20=20=20=20=20{=0A+=09=09char=20hex[5]=20=3D=20{=20'u',=20'0',=20'0',=0A=
+=09=09=09=09hexchar[c=20>>=204],=20hexchar[c=20&=200xf]=20};=0A+=09=09=
json_out_str=20(jo,=20hex,=205);=0A+=09=09break;=0A+=09=20=20=20=20=20=20=
}=0A+=09=20=20=20=20}=0A+=09=20=20p++;=0A+=09}=0A+=20=20=20=20}=0A+=20=20=
json_out_byte=20(jo,=20'"');=0A+}=0A+=0A+static=20void=0A+json_out_nest=20=
(json_out_t=20*jo)=0A+{=0A+=20=20--jo->maxdepth;=0A+=20=20if=20=
(jo->maxdepth=20<=200)=0A+=20=20=20=20error=20("Maximum=20JSON=20=
serialisation=20depth=20exceeded");=0A+}=0A+=0A+static=20void=0A=
+json_out_unnest=20(json_out_t=20*jo)=0A+{=0A+=20=20++jo->maxdepth;=0A+}=0A=
+=0A+static=20void=20json_out_something=20(json_out_t=20*jo,=20=
Lisp_Object=20obj);=0A+=0A+static=20void=0A+json_out_object_cons=20=
(json_out_t=20*jo,=20Lisp_Object=20obj)=0A+{=0A+=20=20json_out_nest=20=
(jo);=0A+=20=20json_out_byte=20(jo,=20'{');=0A+=20=20bool=20is_alist=20=3D=
=20CONSP=20(XCAR=20(obj));=0A+=20=20bool=20first=20=3D=20true;=0A+=20=20=
Lisp_Object=20tail=20=3D=20obj;=0A+=20=20FOR_EACH_TAIL=20(tail)=0A+=20=20=
=20=20{=0A+=20=20=20=20=20=20if=20(!first)=0A+=09json_out_byte=20(jo,=20=
',');=0A+=20=20=20=20=20=20first=20=3D=20false;=0A+=20=20=20=20=20=20=
Lisp_Object=20key_sym;=0A+=20=20=20=20=20=20Lisp_Object=20value;=0A+=20=20=
=20=20=20=20if=20(is_alist)=0A+=09{=0A+=09=20=20Lisp_Object=20pair=20=3D=20=
XCAR=20(tail);=0A+=09=20=20CHECK_CONS=20(pair);=0A+=09=20=20key_sym=20=3D=20=
XCAR=20(pair);=0A+=09=20=20value=20=3D=20XCDR=20(pair);=0A+=09}=0A+=20=20=
=20=20=20=20else=0A+=09{=0A+=09=20=20key_sym=20=3D=20XCAR=20(tail);=0A+=09=
=20=20tail=20=3D=20XCDR=20(tail);=0A+=09=20=20CHECK_CONS=20(tail);=0A+=09=
=20=20value=20=3D=20XCAR=20(tail);=0A+=09}=0A+=20=20=20=20=20=20/*=20=
FIXME:=20do=20we=20care=20about=20dup=20keys=20here?=20(probably=20not)=20=
*/=0A+=20=20=20=20=20=20CHECK_SYMBOL=20(key_sym);=0A+=20=20=20=20=20=20=
Lisp_Object=20key=20=3D=20SYMBOL_NAME=20(key_sym);=0A+=20=20=20=20=20=20=
const=20char=20*keystr=20=3D=20SSDATA=20(key);=0A+=20=20=20=20=20=20/*=20=
Skip=20leading=20':'=20in=20plist=20keys.=20=20*/=0A+=20=20=20=20=20=20=
int=20skip=20=3D=20!is_alist=20&&=20keystr[0]=20=3D=3D=20':'=20&&=20=
keystr[1]=20?=201=20:=200;=0A+=20=20=20=20=20=20json_out_string=20(jo,=20=
key,=20skip);=0A+=20=20=20=20=20=20json_out_byte=20(jo,=20':');=0A+=20=20=
=20=20=20=20json_out_something=20(jo,=20value);=0A+=20=20=20=20}=0A+=20=20=
CHECK_LIST_END=20(tail,=20obj);=0A+=20=20json_out_byte=20(jo,=20'}');=0A=
+=20=20json_out_unnest=20(jo);=0A+}=0A+=0A+static=20void=0A=
+json_out_object_hash=20(json_out_t=20*jo,=20Lisp_Object=20obj)=0A+{=0A+=20=
=20json_out_nest=20(jo);=0A+=20=20json_out_byte=20(jo,=20'{');=0A+=20=20=
struct=20Lisp_Hash_Table=20*h=20=3D=20XHASH_TABLE=20(obj);=0A+=20=20bool=20=
first=20=3D=20true;=0A+=20=20DOHASH=20(h,=20k,=20v)=0A+=20=20=20=20{=0A+=20=
=20=20=20=20=20if=20(!first)=0A+=09json_out_byte=20(jo,=20',');=0A+=20=20=
=20=20=20=20first=20=3D=20false;=0A+=20=20=20=20=20=20/*=20FIXME:=20do=20=
we=20care=20about=20dup=20keys=20here?=20(probably=20not)=20*/=0A+=20=20=20=
=20=20=20CHECK_STRING=20(k);=0A+=20=20=20=20=20=20json_out_string=20(jo,=20=
k,=200);=0A+=20=20=20=20=20=20json_out_byte=20(jo,=20':');=0A+=20=20=20=20=
=20=20json_out_something=20(jo,=20v);=0A+=20=20=20=20}=0A+=20=20=
json_out_byte=20(jo,=20'}');=0A+=20=20json_out_unnest=20(jo);=0A+=0A+}=0A=
+=0A+static=20void=0A+json_out_array=20(json_out_t=20*jo,=20Lisp_Object=20=
obj)=0A+{=0A+=20=20json_out_nest=20(jo);=0A+=20=20json_out_byte=20(jo,=20=
'[');=0A+=20=20ptrdiff_t=20n=20=3D=20ASIZE=20(obj);=0A+=20=20for=20=
(ptrdiff_t=20i=20=3D=200;=20i=20<=20n;=20i++)=0A+=20=20=20=20{=0A+=20=20=20=
=20=20=20if=20(i=20>=200)=0A+=09json_out_byte=20(jo,=20',');=0A+=20=20=20=
=20=20=20json_out_something=20(jo,=20AREF=20(obj,=20i));=0A+=20=20=20=20=
}=0A+=20=20json_out_byte=20(jo,=20']');=0A+=20=20json_out_unnest=20(jo);=0A=
+}=0A+=0A+static=20void=0A+json_out_float=20(json_out_t=20*jo,=20=
Lisp_Object=20f)=0A+{=0A+=20=20double=20x=20=3D=20XFLOAT_DATA=20(f);=0A+=20=
=20if=20(isinf=20(x)=20||=20isnan=20(x))=0A+=20=20=20=20signal_error=20=
("not=20a=20finite=20number",=20f);=0A+=20=20json_make_room=20(jo,=20=
FLOAT_TO_STRING_BUFSIZE);=0A+=20=20int=20n=20=3D=20float_to_string=20=
(jo->buf=20+=20jo->size,=20x);=0A+=20=20jo->size=20+=3D=20n;=0A+}=0A+=0A=
+static=20void=0A+json_out_bignum=20(json_out_t=20*jo,=20Lisp_Object=20=
x)=0A+{=0A+=20=20int=20base=20=3D=2010;=0A+=20=20ptrdiff_t=20size=20=3D=20=
bignum_bufsize=20(x,=20base);=0A+=20=20json_make_room=20(jo,=20size);=0A=
+=20=20int=20n=20=3D=20bignum_to_c_string=20(jo->buf=20+=20jo->size,=20=
size,=20x,=20base);=0A+=20=20jo->size=20+=3D=20n;=0A+}=0A+=0A+static=20=
void=0A+json_out_something=20(json_out_t=20*jo,=20Lisp_Object=20obj)=0A=
+{=0A+=20=20if=20(EQ=20(obj,=20jo->conf.null_object))=0A+=20=20=20=20=
JSON_OUT_STR=20(jo,=20"null");=0A+=20=20else=20if=20(EQ=20(obj,=20=
jo->conf.false_object))=0A+=20=20=20=20JSON_OUT_STR=20(jo,=20"false");=0A=
+=20=20else=20if=20(EQ=20(obj,=20Qt))=0A+=20=20=20=20JSON_OUT_STR=20(jo,=20=
"true");=0A+=20=20else=20if=20(NILP=20(obj))=0A+=20=20=20=20JSON_OUT_STR=20=
(jo,=20"{}");=0A+=20=20else=20if=20(FIXNUMP=20(obj))=0A+=20=20=20=20=
json_out_fixnum=20(jo,=20XFIXNUM=20(obj));=0A+=20=20else=20if=20(STRINGP=20=
(obj))=0A+=20=20=20=20json_out_string=20(jo,=20obj,=200);=0A+=20=20else=20=
if=20(CONSP=20(obj))=0A+=20=20=20=20json_out_object_cons=20(jo,=20obj);=0A=
+=20=20else=20if=20(FLOATP=20(obj))=0A+=20=20=20=20json_out_float=20(jo,=20=
obj);=0A+=20=20else=20if=20(HASH_TABLE_P=20(obj))=0A+=20=20=20=20=
json_out_object_hash=20(jo,=20obj);=0A+=20=20else=20if=20(VECTORP=20=
(obj))=0A+=20=20=20=20json_out_array=20(jo,=20obj);=0A+=20=20else=20if=20=
(BIGNUMP=20(obj))=0A+=20=20=20=20json_out_bignum=20(jo,=20obj);=0A+=20=20=
else=0A+=20=20=20=20wrong_type_argument=20(Qjson_value_p,=20obj);=0A+}=0A=
+=0A+static=20Lisp_Object=0A+json_out_string_result=20(json_out_t=20*jo)=0A=
+{=0A+=20=20/*=20FIXME:=20should=20this=20be=20a=20unibyte=20or=20=
multibyte=20string?=0A+=20=20=20=20=20Right=20now=20we=20make=20a=20=
multibyte=20string=20for=20test=20compatibility,=0A+=20=20=20=20=20but=20=
we=20are=20really=20encoding=20so=20unibyte=20would=20make=20more=20=
sense.=20=20*/=0A+=20=20ptrdiff_t=20nchars=20=3D=20jo->size=20-=20=
jo->chars_delta;=0A+=20=20return=20make_multibyte_string=20(jo->buf,=20=
nchars,=20jo->size);=0A+}=0A+=0A+/*=20FIXME:=20update=20doc=20string=20=
*/=0A=20DEFUN=20("json-serialize",=20Fjson_serialize,=20Sjson_serialize,=20=
1,=20MANY,=0A=20=20=20=20=20=20=20=20NULL,=0A=20=20=20=20=20=20=20=20=
doc:=20/*=20Return=20the=20JSON=20representation=20of=20OBJECT=20as=20a=20=
string.=0A@@=20-614,95=20+742,17=20@@=20DEFUN=20("json-serialize",=20=
Fjson_serialize,=20Sjson_serialize,=201,=20MANY,=0A=20usage:=20=
(json-serialize=20OBJECT=20&rest=20ARGS)=20=20*/)=0A=20=20=20=20=20=20=
(ptrdiff_t=20nargs,=20Lisp_Object=20*args)=0A=20{=0A-=20=20specpdl_ref=20=
count=20=3D=20SPECPDL_INDEX=20();=0A+=20=20json_out_t=20jo=20=3D=20{=0A+=20=
=20=20=20.maxdepth=20=3D=2025,=0A+=20=20=20=20.conf=20=3D=20=
{json_object_hashtable,=20json_array_array,=20QCnull,=20QCfalse}=0A+=20=20=
};=0A+=20=20json_parse_args=20(nargs=20-=201,=20args=20+=201,=20=
&jo.conf,=20false);=0A+=20=20Lisp_Object=20object=20=3D=20args[0];=0A=20=0A=
-#ifdef=20WINDOWSNT=0A-=20=20ensure_json_available=20();=0A-#endif=0A-=0A=
-=20=20struct=20json_configuration=20conf=20=3D=0A-=20=20=20=20=
{json_object_hashtable,=20json_array_array,=20QCnull,=20QCfalse};=0A-=20=20=
json_parse_args=20(nargs=20-=201,=20args=20+=201,=20&conf,=20false);=0A-=0A=
-=20=20json_t=20*json=20=3D=20lisp_to_json=20(args[0],=20&conf);=0A-=20=20=
record_unwind_protect_ptr=20(json_release_object,=20json);=0A-=0A-=20=20=
char=20*string=20=3D=20json_dumps=20(json,=20JSON_COMPACT=20|=20=
JSON_ENCODE_ANY);=0A-=20=20if=20(string=20=3D=3D=20NULL)=0A-=20=20=20=20=
json_out_of_memory=20();=0A-=20=20record_unwind_protect_ptr=20=
(json_free,=20string);=0A-=0A-=20=20return=20unbind_to=20(count,=20=
build_string_from_utf8=20(string));=0A-}=0A-=0A-struct=20=
json_buffer_and_size=0A-{=0A-=20=20const=20char=20*buffer;=0A-=20=20=
ptrdiff_t=20size;=0A-=20=20/*=20This=20tracks=20how=20many=20bytes=20=
were=20inserted=20by=20the=20callback=20since=0A-=20=20=20=20=20=
json_dump_callback=20was=20called.=20=20*/=0A-=20=20ptrdiff_t=20=
inserted_bytes;=0A-};=0A-=0A-static=20Lisp_Object=0A-json_insert=20(void=20=
*data)=0A-{=0A-=20=20struct=20json_buffer_and_size=20*buffer_and_size=20=
=3D=20data;=0A-=20=20ptrdiff_t=20len=20=3D=20buffer_and_size->size;=0A-=20=
=20ptrdiff_t=20inserted_bytes=20=3D=20buffer_and_size->inserted_bytes;=0A=
-=20=20ptrdiff_t=20gap_size=20=3D=20GAP_SIZE=20-=20inserted_bytes;=0A-=0A=
-=20=20/*=20Enlarge=20the=20gap=20if=20necessary.=20=20*/=0A-=20=20if=20=
(gap_size=20<=20len)=0A-=20=20=20=20make_gap=20(len=20-=20gap_size);=0A-=0A=
-=20=20/*=20Copy=20this=20chunk=20of=20data=20into=20the=20gap.=20=20*/=0A=
-=20=20memcpy=20((char=20*)=20BEG_ADDR=20+=20PT_BYTE=20-=20BEG_BYTE=20+=20=
inserted_bytes,=0A-=09=20=20buffer_and_size->buffer,=20len);=0A-=20=20=
buffer_and_size->inserted_bytes=20+=3D=20len;=0A-=20=20return=20Qnil;=0A=
-}=0A-=0A-static=20Lisp_Object=0A-json_handle_nonlocal_exit=20(enum=20=
nonlocal_exit=20type,=20Lisp_Object=20data)=0A-{=0A-=20=20switch=20=
(type)=0A-=20=20=20=20{=0A-=20=20=20=20case=20NONLOCAL_EXIT_SIGNAL:=0A-=20=
=20=20=20=20=20return=20data;=0A-=20=20=20=20case=20NONLOCAL_EXIT_THROW:=0A=
-=20=20=20=20=20=20return=20Fcons=20(Qno_catch,=20data);=0A-=20=20=20=20=
default:=0A-=20=20=20=20=20=20eassume=20(false);=0A-=20=20=20=20}=0A-}=0A=
-=0A-struct=20json_insert_data=0A-{=0A-=20=20/*=20This=20tracks=20how=20=
many=20bytes=20were=20inserted=20by=20the=20callback=20since=0A-=20=20=20=
=20=20json_dump_callback=20was=20called.=20=20*/=0A-=20=20ptrdiff_t=20=
inserted_bytes;=0A-=20=20/*=20nil=20if=20json_insert=20succeeded,=20=
otherwise=20the=20symbol=0A-=20=20=20=20=20Qcatch_all_memory_full=20or=20=
a=20cons=20(ERROR-SYMBOL=20.=20ERROR-DATA).=20=20*/=0A-=20=20Lisp_Object=20=
error;=0A-};=0A-=0A-/*=20Callback=20for=20json_dump_callback=20that=20=
inserts=20a=20JSON=20representation=0A-=20=20=20as=20a=20unibyte=20=
string=20into=20the=20gap.=20=20DATA=20must=20point=20to=20a=20structure=0A=
-=20=20=20of=20type=20json_insert_data.=20=20This=20function=20may=20not=20=
exit=20nonlocally.=0A-=20=20=20It=20catches=20all=20nonlocal=20exits=20=
and=20stores=20them=20in=20data->error=20for=0A-=20=20=20reraising.=20=20=
*/=0A-=0A-static=20int=0A-json_insert_callback=20(const=20char=20=
*buffer,=20size_t=20size,=20void=20*data)=0A-{=0A-=20=20struct=20=
json_insert_data=20*d=20=3D=20data;=0A-=20=20struct=20=
json_buffer_and_size=20buffer_and_size=0A-=20=20=20=20=3D=20{.buffer=20=3D=
=20buffer,=20.size=20=3D=20size,=20.inserted_bytes=20=3D=20=
d->inserted_bytes};=0A-=20=20d->error=20=3D=20internal_catch_all=20=
(json_insert,=20&buffer_and_size,=0A-=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
json_handle_nonlocal_exit);=0A-=20=20d->inserted_bytes=20=3D=20=
buffer_and_size.inserted_bytes;=0A-=20=20return=20NILP=20(d->error)=20?=20=
0=20:=20-1;=0A+=20=20specpdl_ref=20count=20=3D=20SPECPDL_INDEX=20();=0A+=20=
=20record_unwind_protect_ptr=20(cleanup_json_out,=20&jo);=0A+=20=20=
json_out_something=20(&jo,=20object);=0A+=20=20return=20unbind_to=20=
(count,=20json_out_string_result=20(&jo));=0A=20}=0A=20=0A=20DEFUN=20=
("json-insert",=20Fjson_insert,=20Sjson_insert,=201,=20MANY,=0A@@=20=
-714,72=20+764,61=20@@=20DEFUN=20("json-insert",=20Fjson_insert,=20=
Sjson_insert,=201,=20MANY,=0A=20usage:=20(json-insert=20OBJECT=20&rest=20=
ARGS)=20=20*/)=0A=20=20=20=20=20=20(ptrdiff_t=20nargs,=20Lisp_Object=20=
*args)=0A=20{=0A-=20=20specpdl_ref=20count=20=3D=20SPECPDL_INDEX=20();=0A=
+=20=20json_out_t=20jo=20=3D=20{=0A+=20=20=20=20.maxdepth=20=3D=2025,=0A=
+=20=20=20=20.conf=20=3D=20{json_object_hashtable,=20json_array_array,=20=
QCnull,=20QCfalse}=0A+=20=20};=0A+=20=20json_parse_args=20(nargs=20-=20=
1,=20args=20+=201,=20&jo.conf,=20false);=0A+=20=20Lisp_Object=20object=20=
=3D=20args[0];=0A=20=0A-#ifdef=20WINDOWSNT=0A-=20=20=
ensure_json_available=20();=0A-#endif=0A-=0A-=20=20struct=20=
json_configuration=20conf=20=3D=0A-=20=20=20=20{json_object_hashtable,=20=
json_array_array,=20QCnull,=20QCfalse};=0A-=20=20json_parse_args=20=
(nargs=20-=201,=20args=20+=201,=20&conf,=20false);=0A+=20=20specpdl_ref=20=
count=20=3D=20SPECPDL_INDEX=20();=0A+=20=20record_unwind_protect_ptr=20=
(cleanup_json_out,=20&jo);=0A+=20=20json_out_something=20(&jo,=20=
object);=0A=20=0A-=20=20json_t=20*json=20=3D=20lisp_to_json=20(args[0],=20=
&conf);=0A-=20=20record_unwind_protect_ptr=20(json_release_object,=20=
json);=0A+=20=20/*=20FIXME:=20Do=20we=20really=20need=20to=20do=20all=20=
this=20work=20below=20to=20insert=20a=20string?=0A+=20=20=20=20=20Is=20=
there=20no=20function=20already=20written?=20=20I=20must=20be=20missing=20=
something.=20=20*/=0A=20=0A=20=20=20prepare_to_modify_buffer=20(PT,=20=
PT,=20NULL);=0A=20=20=20move_gap_both=20(PT,=20PT_BYTE);=0A-=20=20struct=20=
json_insert_data=20data;=0A-=20=20data.inserted_bytes=20=3D=200;=0A-=20=20=
/*=20Could=20have=20used=20json_dumpb,=20but=20that=20became=20available=20=
only=20in=0A-=20=20=20=20=20Jansson=202.10,=20whereas=20we=20want=20to=20=
support=202.7=20and=20upward.=20=20*/=0A-=20=20int=20status=20=3D=20=
json_dump_callback=20(json,=20json_insert_callback,=20&data,=0A-=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20=20=20=20JSON_COMPACT=20|=20JSON_ENCODE_ANY);=0A-=20=20if=20=
(status=20=3D=3D=20-1)=0A-=20=20=20=20{=0A-=20=20=20=20=20=20if=20(CONSP=20=
(data.error))=0A-=20=20=20=20=20=20=20=20xsignal=20(XCAR=20(data.error),=20=
XCDR=20(data.error));=0A-=20=20=20=20=20=20else=0A-=20=20=20=20=20=20=20=20=
json_out_of_memory=20();=0A-=20=20=20=20}=0A+=20=20if=20(GAP_SIZE=20<=20=
jo.size)=0A+=20=20=20=20make_gap=20(jo.size=20-=20GAP_SIZE);=0A+=20=20=
memcpy=20((char=20*)=20BEG_ADDR=20+=20PT_BYTE=20-=20BEG_BYTE,=20jo.buf,=20=
jo.size);=0A+=0A+=20=20/*=20No=20need=20to=20keep=20allocation=20beyond=20=
this=20point.=20=20*/=0A+=20=20unbind_to=20(count,=20Qnil);=0A=20=0A=20=20=
=20ptrdiff_t=20inserted=20=3D=200;=0A-=20=20ptrdiff_t=20inserted_bytes=20=
=3D=20data.inserted_bytes;=0A-=20=20if=20(inserted_bytes=20>=200)=0A+=20=20=
ptrdiff_t=20inserted_bytes=20=3D=20jo.size;=0A+=0A+=20=20/*=20If=20=
required,=20decode=20the=20stuff=20we've=20read=20into=20the=20gap.=20=20=
*/=0A+=20=20struct=20coding_system=20coding;=0A+=20=20/*=20JSON=20=
strings=20are=20UTF-8=20encoded=20strings.=20=20*/=0A+=20=20=
setup_coding_system=20(Qutf_8_unix,=20&coding);=0A+=20=20=
coding.dst_multibyte=20=3D=20!NILP=20(BVAR=20(current_buffer,=0A+=09=09=09=
=09=20=20=20=20=20=20enable_multibyte_characters));=0A+=20=20if=20=
(CODING_MAY_REQUIRE_DECODING=20(&coding))=0A=20=20=20=20=20{=0A-=20=20=20=
=20=20=20/*=20If=20required,=20decode=20the=20stuff=20we've=20read=20=
into=20the=20gap.=20=20*/=0A-=20=20=20=20=20=20struct=20coding_system=20=
coding;=0A-=20=20=20=20=20=20/*=20JSON=20strings=20are=20UTF-8=20encoded=20=
strings.=20=20If=20for=20some=20reason=0A-=09=20the=20text=20returned=20=
by=20the=20Jansson=20library=20includes=20invalid=0A-=09=20byte=20=
sequences,=20they=20will=20be=20represented=20by=20raw=20bytes=20in=20=
the=0A-=09=20buffer=20text.=20=20*/=0A-=20=20=20=20=20=20=
setup_coding_system=20(Qutf_8_unix,=20&coding);=0A-=20=20=20=20=20=20=
coding.dst_multibyte=20=3D=0A-=09!NILP=20(BVAR=20(current_buffer,=20=
enable_multibyte_characters));=0A-=20=20=20=20=20=20if=20=
(CODING_MAY_REQUIRE_DECODING=20(&coding))=0A-=09{=0A-=20=20=20=20=20=20=20=
=20=20=20/*=20Now=20we=20have=20all=20the=20new=20bytes=20at=20the=20=
beginning=20of=20the=20gap,=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=
but=20`decode_coding_gap`=20needs=20them=20at=20the=20end=20of=20the=20=
gap,=20so=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20we=20need=20to=20=
move=20them.=20=20*/=0A-=20=20=20=20=20=20=20=20=20=20memmove=20=
(GAP_END_ADDR=20-=20inserted_bytes,=20GPT_ADDR,=20inserted_bytes);=0A-=09=
=20=20decode_coding_gap=20(&coding,=20inserted_bytes);=0A-=09=20=20=
inserted=20=3D=20coding.produced_char;=0A-=09}=0A-=20=20=20=20=20=20else=0A=
-=09{=0A-=20=20=20=20=20=20=20=20=20=20/*=20Make=20the=20inserted=20text=20=
part=20of=20the=20buffer,=20as=20unibyte=20text.=20=20*/=0A-=20=20=20=20=20=
=20=20=20=20=20eassert=20(NILP=20(BVAR=20(current_buffer,=20=
enable_multibyte_characters)));=0A-=20=20=20=20=20=20=20=20=20=20=
insert_from_gap_1=20(inserted_bytes,=20inserted_bytes,=20false);=0A-=0A-=09=
=20=20/*=20The=20target=20buffer=20is=20unibyte,=20so=20we=20don't=20=
need=20to=20decode.=20=20*/=0A-=09=20=20invalidate_buffer_caches=20=
(current_buffer,=0A-=09=09=09=09=20=20=20=20PT,=20PT=20+=20=
inserted_bytes);=0A-=09=20=20adjust_after_insert=20(PT,=20PT_BYTE,=0A-=09=
=09=09=20=20=20=20=20=20=20PT=20+=20inserted_bytes,=0A-=09=09=09=20=20=20=
=20=20=20=20PT_BYTE=20+=20inserted_bytes,=0A-=09=09=09=20=20=20=20=20=20=20=
inserted_bytes);=0A-=09=20=20inserted=20=3D=20inserted_bytes;=0A-=09}=0A=
+=20=20=20=20=20=20/*=20Now=20we=20have=20all=20the=20new=20bytes=20at=20=
the=20beginning=20of=20the=20gap,=0A+=09=20but=20`decode_coding_gap`=20=
needs=20them=20at=20the=20end=20of=20the=20gap,=20so=0A+=09=20we=20need=20=
to=20move=20them.=20=20*/=0A+=20=20=20=20=20=20memmove=20(GAP_END_ADDR=20=
-=20inserted_bytes,=20GPT_ADDR,=20inserted_bytes);=0A+=20=20=20=20=20=20=
decode_coding_gap=20(&coding,=20inserted_bytes);=0A+=20=20=20=20=20=20=
inserted=20=3D=20coding.produced_char;=0A+=20=20=20=20}=0A+=20=20else=0A=
+=20=20=20=20{=0A+=20=20=20=20=20=20/*=20Make=20the=20inserted=20text=20=
part=20of=20the=20buffer,=20as=20unibyte=20text.=20=20*/=0A+=20=20=20=20=20=
=20eassert=20(NILP=20(BVAR=20(current_buffer,=20=
enable_multibyte_characters)));=0A+=20=20=20=20=20=20insert_from_gap_1=20=
(inserted_bytes,=20inserted_bytes,=20false);=0A+=0A+=20=20=20=20=20=20/*=20=
The=20target=20buffer=20is=20unibyte,=20so=20we=20don't=20need=20to=20=
decode.=20=20*/=0A+=20=20=20=20=20=20invalidate_buffer_caches=20=
(current_buffer,=0A+=09=09=09=09PT,=20PT=20+=20inserted_bytes);=0A+=20=20=
=20=20=20=20adjust_after_insert=20(PT,=20PT_BYTE,=0A+=09=09=09=20=20=20=
PT=20+=20inserted_bytes,=0A+=09=09=09=20=20=20PT_BYTE=20+=20=
inserted_bytes,=0A+=09=09=09=20=20=20inserted_bytes);=0A+=20=20=20=20=20=20=
inserted=20=3D=20inserted_bytes;=0A=20=20=20=20=20}=0A=20=0A=20=20=20/*=20=
Call=20after-change=20hooks.=20=20*/=0A@@=20-791,7=20+830,7=20@@=20DEFUN=20=
("json-insert",=20Fjson_insert,=20Sjson_insert,=201,=20MANY,=0A=20=20=20=20=
=20=20=20SET_PT_BOTH=20(PT=20+=20inserted,=20PT_BYTE=20+=20=
inserted_bytes);=0A=20=20=20=20=20}=0A=20=0A-=20=20return=20unbind_to=20=
(count,=20Qnil);=0A+=20=20return=20Qnil;=0A=20}=0A=20=0A=20/*=20Convert=20=
a=20JSON=20object=20to=20a=20Lisp=20object.=20=20*/=0Adiff=20--git=20=
a/test/src/json-tests.el=20b/test/src/json-tests.el=0Aindex=20=
dffc6291ca1..c908c031a82=20100644=0A---=20a/test/src/json-tests.el=0A+++=20=
b/test/src/json-tests.el=0A@@=20-90,8=20+90,11=20@@=20=
json-serialize/object=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20"{\"abc\":[1,2,true],\"def\":null}"))=0A=20=20=20(should=20(equal=20=
(json-serialize=20nil)=20"{}"))=0A=20=20=20(should=20(equal=20=
(json-serialize=20'((abc)))=20"{\"abc\":{}}"))=0A-=20=20(should=20(equal=20=
(json-serialize=20'((a=20.=201)=20(b=20.=202)=20(a=20.=203)))=0A+=20=20=
(should=20(equal=20(json-serialize=20'((a=20.=201)=20(b=20.=202)))=0A=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20"{\"a\":1,\"b\":2}"))=0A=
+=20=20;;=20FIXME:=20we=20assume=20hash=20table=20keys=20to=20be=20=
unique=0A+=20=20;;=20(should=20(equal=20(json-serialize=20'((a=20.=201)=20=
(b=20.=202)=20(a=20.=203)))=0A+=20=20;;=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20"{\"a\":1,\"b\":2}"))=0A=20=20=20(should-error=20=
(json-serialize=20'(abc))=20:type=20'wrong-type-argument)=0A=20=20=20=
(should-error=20(json-serialize=20'((a=201)))=20:type=20=
'wrong-type-argument)=0A=20=20=20(should-error=20(json-serialize=20'((1=20=
.=202)))=20:type=20'wrong-type-argument)=0A@@=20-124,13=20+127,14=20@@=20=
json-serialize/object=0A=20\"detect-plist\":{\"bla\":\"ble\"}\=0A=20=
}")))=0A=20=0A-(ert-deftest=20json-serialize/object-with-duplicate-keys=20=
()=0A-=20=20(skip-unless=20(fboundp=20'json-serialize))=0A-=20=20(let=20=
((table=20(make-hash-table=20:test=20#'eq)))=0A-=20=20=20=20(puthash=20=
(copy-sequence=20"abc")=20[1=202=20t]=20table)=0A-=20=20=20=20(puthash=20=
(copy-sequence=20"abc")=20:null=20table)=0A-=20=20=20=20(should=20(equal=20=
(hash-table-count=20table)=202))=0A-=20=20=20=20(should-error=20=
(json-serialize=20table)=20:type=20'wrong-type-argument)))=0A+;;=20=
FIXME:=20we=20don't=20check=20for=20duplicate=20keys=0A+;;=20=
(ert-deftest=20json-serialize/object-with-duplicate-keys=20()=0A+;;=20=20=
=20(skip-unless=20(fboundp=20'json-serialize))=0A+;;=20=20=20(let=20=
((table=20(make-hash-table=20:test=20#'eq)))=0A+;;=20=20=20=20=20=
(puthash=20(copy-sequence=20"abc")=20[1=202=20t]=20table)=0A+;;=20=20=20=20=
=20(puthash=20(copy-sequence=20"abc")=20:null=20table)=0A+;;=20=20=20=20=20=
(should=20(equal=20(hash-table-count=20table)=202))=0A+;;=20=20=20=20=20=
(should-error=20(json-serialize=20table)=20:type=20=
'wrong-type-argument)))=0A=20=0A=20(ert-deftest=20=
json-parse-string/object=20()=0A=20=20=20(skip-unless=20(fboundp=20=
'json-parse-string))=0A@@=20-174,7=20+178,10=20@@=20=
json-serialize/string=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20"[\"\\nasd=D1=84=D1=8B=D0=B2\\u001F\u007ffgh\\t\"]"))=0A=20=20=20=
(should=20(equal=20(json-serialize=20["a\0b"])=20"[\"a\\u0000b\"]"))=0A=20=
=20=20;;=20FIXME:=20Is=20this=20the=20right=20behavior?=0A-=20=20(should=20=
(equal=20(json-serialize=20["\u00C4\xC3\x84"])=20"[\"\u00C4\u00C4\"]")))=0A=
+=20=20;;=20FIXME:=20(no=20it's=20not)=0A+=20=20;;=20(should=20(equal=20=
(json-serialize=20["\u00C4\xC3\x84"])=20"[\"\u00C4\u00C4\"]"))=0A+=20=20=
(should-error=20(json-serialize=20["\u00C4\xC3\x84"]))=0A+=20=20)=0A=20=0A=
=20(ert-deftest=20json-serialize/invalid-unicode=20()=0A=20=20=20=
(skip-unless=20(fboundp=20'json-serialize))=0A=

--Apple-Mail=_7330F7C9-D7F2-4246-9F8E-A734AAA47A92--




Acknowledgement sent to Mattias Engdegård <mattias.engdegard@HIDDEN>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs@HIDDEN. Full text available.
Report forwarded to bug-gnu-emacs@HIDDEN:
bug#70007; Package emacs. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Tue, 2 Apr 2024 17:30:04 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.