From debbugs-submit-bounces@debbugs.gnu.org Fri Sep 21 08:57:06 2018 Received: (at submit) by debbugs.gnu.org; 21 Sep 2018 12:57:06 +0000 Received: from localhost ([127.0.0.1]:47735 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1g3KzZ-0007nO-Qo for submit@debbugs.gnu.org; Fri, 21 Sep 2018 08:57:05 -0400 Received: from eggs.gnu.org ([208.118.235.92]:49004) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1g3KzX-0007mv-Rm for submit@debbugs.gnu.org; Fri, 21 Sep 2018 08:57:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1g3KzR-0007Qk-SX for submit@debbugs.gnu.org; Fri, 21 Sep 2018 08:56:58 -0400 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org X-Spam-Level: X-Spam-Status: No, score=-0.5 required=5.0 tests=BAYES_05,T_DKIM_INVALID autolearn=disabled version=3.3.2 Received: from lists.gnu.org ([2001:4830:134:3::11]:59001) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1g3KzR-0007Qf-Nn for submit@debbugs.gnu.org; Fri, 21 Sep 2018 08:56:57 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41739) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1g3KzQ-0008DS-TN for bug-gnu-emacs@gnu.org; Fri, 21 Sep 2018 08:56:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1g3KzM-0007Ni-TT for bug-gnu-emacs@gnu.org; Fri, 21 Sep 2018 08:56:56 -0400 Received: from forward104o.mail.yandex.net ([37.140.190.179]:46761) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1g3KzM-0007Ie-Jk for bug-gnu-emacs@gnu.org; Fri, 21 Sep 2018 08:56:52 -0400 Received: from mxback14g.mail.yandex.net (mxback14g.mail.yandex.net [IPv6:2a02:6b8:0:1472:2741:0:8b7:93]) by forward104o.mail.yandex.net (Yandex) with ESMTP id 60CEC3D82DE2 for ; Fri, 21 Sep 2018 15:56:47 +0300 (MSK) Received: from smtp1j.mail.yandex.net (smtp1j.mail.yandex.net [2a02:6b8:0:801::ab]) by mxback14g.mail.yandex.net (nwsmtp/Yandex) with ESMTP id yCgHRnx2ov-ul8mZ4mw; Fri, 21 Sep 2018 15:56:47 +0300 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xuchunyang.me; s=mail; t=1537534607; bh=NHQL+XTDm1HhZyeKBZHvDx3Fj41+4SnelyUnZoz+doo=; h=From:To:Subject:Date:Message-ID; b=Lwj9wukvszhQwNHY3VIKspp+v3h3NNu2DzsYH/6nckpXWRN23WOhTq9lEwDh1vBpF xFOs5xIKkMD8e+Bi15Em62vXBzm/+JufmHTyA+SMHDS2XD8UCQ07qsHGDO1tYgd3y7 wps7NTJwiqSwtOZ7hD/GvDGcfRCnJdWX8q3sFJ9k= Received: by smtp1j.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id 5ihapQor8V-ujDOYPLA; Fri, 21 Sep 2018 15:56:46 +0300 (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client certificate not present) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xuchunyang.me; s=mail; t=1537534606; bh=NHQL+XTDm1HhZyeKBZHvDx3Fj41+4SnelyUnZoz+doo=; h=From:To:Subject:Date:Message-ID; b=rKqB97WnYAiozIIm0JkGTbUU84OCKCtdZZJNOnqi6QyYR3PY0YGEpLEEmeLTEjYRB UkmQt4fOXImQHkWe7Xy+FWAm6ua0LZUH3O9Vfw2L/Yn7TQAplii+uB2kSzFNImV44E mYWgiIAIpYTJeOdv+TRMftolmRdD6xouqiz9i98M= Authentication-Results: smtp1j.mail.yandex.net; dkim=pass header.i=@xuchunyang.me From: Xu Chunyang To: bug-gnu-emacs@gnu.org Subject: 27.0.50; json-parse-string doesn't have the equivalent of json.el's json-array-type Date: Fri, 21 Sep 2018 20:56:43 +0800 Message-ID: MIME-Version: 1.0 Content-Type: text/plain X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 2001:4830:134:3::11 X-Spam-Score: -4.0 (----) X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -5.0 (-----) Hello, We can parse JSON Array as Lisp List with json.el, e.g., (let ((json-array-type 'list)) (json-read-from-string "[1,2,3]")) ;; => (1 2 3) but the new json-parse-string doesn't have the equivalent, thus porting existing code to using json-parse-string might be difficult. From debbugs-submit-bounces@debbugs.gnu.org Thu Apr 11 12:26:37 2019 Received: (at 32793) by debbugs.gnu.org; 11 Apr 2019 16:26:37 +0000 Received: from localhost ([127.0.0.1]:55091 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEcX6-0000bN-Vz for submit@debbugs.gnu.org; Thu, 11 Apr 2019 12:26:37 -0400 Received: from mail-wm1-f43.google.com ([209.85.128.43]:38364) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEcX5-0000bA-DY for 32793@debbugs.gnu.org; Thu, 11 Apr 2019 12:26:36 -0400 Received: by mail-wm1-f43.google.com with SMTP id w15so7445081wmc.3 for <32793@debbugs.gnu.org>; Thu, 11 Apr 2019 09:26:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:subject:to:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=vRYCKGp4I6Lh9eXeCCZ9g6HsIfJ9IhAVGtG0q5TNU94=; b=qiU+3JhY94VmXw64w0CtldH/v5kCikbAP45owOCJ+u8GqbM2VKF9UEB00TO2tTQhy7 BjRrROxib/0iWuIwxV44YwSoP+TNQwu2K37O+tLdqHng5zA7CoyOhsrKENRyrI6dpLDI Hwcz5T8BemVtqfzc3cF0mWQ6tMeeQzyh95sPhhGig1p9H3nDHfJpefojKkHs4YEA8XJA F2CTnqGpW/sdbR17f9j06bJiyOojKQSeKcLrzfGBv83ShtpslRtTyMQ4QSHMfF4rzv8n vFSGAkdf9HapiFSli82fQxSEVa64lXKzhFIIjEGWNu4yhkV7ZCp1Kxpuc5hS22A1wrJt qv0w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:subject:to:references:from:message-id :date:user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=vRYCKGp4I6Lh9eXeCCZ9g6HsIfJ9IhAVGtG0q5TNU94=; b=qMxvAEoaWFJeyLqUC7ptJTLfyKOqPftBINrr3nHQp4GEOKZCHkyUmsify1bZJiXAS5 0pfYvKx1dHPwFXzAdHxNjk0NRCCc9OC0W2zZziLONOoHZyU+369lXnMIZkq6PWeqP1L4 6ABsinyJSUrVl+t/s0Z0B8Q/3RpvdcZXv+rDQENuzHD9psJ4Zk8q40ovNxUxJLI9zwBl f0InITBjfMqIAX9ytz2tpjTZyppKECd0ja+Qo18ABWCqBKGAKmnFtr8Kdc75gGjvGFHX +hKRFDFOWSLJE4kW9kLku1Fxo0oBhIZjUivpy4HS4NqRhMCGO5XpybZkc0ujnhERY+7O FJUw== X-Gm-Message-State: APjAAAU2q6pV4YwUr7iEBYyblulE6FBZj41iVXKNsTynWjxotG2ZHYde JwWYOhysEBnG26FrARHnBNRRwLuq X-Google-Smtp-Source: APXvYqxox/UAw5RA4+CFTB73ArJ/b3nQdm59QNvFcEtwZlKHxdm5YbVjw2jbnUdqmz8AJC25vhZQQQ== X-Received: by 2002:a7b:c111:: with SMTP id w17mr7339736wmi.6.1554999987390; Thu, 11 Apr 2019 09:26:27 -0700 (PDT) Received: from [192.168.0.195] ([109.110.245.170]) by smtp.googlemail.com with ESMTPSA id z7sm36312433wrt.10.2019.04.11.09.26.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 11 Apr 2019 09:26:25 -0700 (PDT) Subject: Re: bug#32793: 27.0.50; json-parse-string doesn't have the equivalent of json.el's json-array-type To: Xu Chunyang , 32793@debbugs.gnu.org References: From: Dmitry Gutov Message-ID: Date: Thu, 11 Apr 2019 19:26:23 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit X-Spam-Score: 0.2 (/) X-Debbugs-Envelope-To: 32793 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.8 (/) On 21.09.2018 15:56, Xu Chunyang wrote: > We can parse JSON Array as Lisp List with json.el, e.g., > > (let ((json-array-type 'list)) > (json-read-from-string "[1,2,3]")) > ;; => (1 2 3) > > but the new json-parse-string doesn't have the equivalent, thus porting > existing code to using json-parse-string might be difficult. I also stumbled on this problem when trying to port existing code to native JSON. It's kind of surprising, considering lists are more common in Elisp, and there's no JSON data structure that would correspond to them (so I can't simply return a different format from the backing server process, I'll have to convert). From debbugs-submit-bounces@debbugs.gnu.org Thu Apr 11 12:46:46 2019 Received: (at 32793) by debbugs.gnu.org; 11 Apr 2019 16:46:46 +0000 Received: from localhost ([127.0.0.1]:55106 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEcqa-00016M-CZ for submit@debbugs.gnu.org; Thu, 11 Apr 2019 12:46:44 -0400 Received: from eggs.gnu.org ([209.51.188.92]:54973) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEcqY-000167-5x for 32793@debbugs.gnu.org; Thu, 11 Apr 2019 12:46:42 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:59083) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hEcqS-0005G7-7k; Thu, 11 Apr 2019 12:46:36 -0400 Received: from [176.228.60.248] (port=3829 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1hEcqP-0004sP-Vc; Thu, 11 Apr 2019 12:46:36 -0400 Date: Thu, 11 Apr 2019 19:46:14 +0300 Message-Id: <83o95c4hih.fsf@gnu.org> From: Eli Zaretskii To: Dmitry Gutov In-reply-to: (message from Dmitry Gutov on Thu, 11 Apr 2019 19:26:23 +0300) Subject: Re: bug#32793: 27.0.50; json-parse-string doesn't have the equivalent of json.el's json-array-type References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 32793 Cc: mail@xuchunyang.me, 32793@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Dmitry Gutov > Date: Thu, 11 Apr 2019 19:26:23 +0300 > > On 21.09.2018 15:56, Xu Chunyang wrote: > > > We can parse JSON Array as Lisp List with json.el, e.g., > > > > (let ((json-array-type 'list)) > > (json-read-from-string "[1,2,3]")) > > ;; => (1 2 3) > > > > but the new json-parse-string doesn't have the equivalent, thus porting > > existing code to using json-parse-string might be difficult. > > I also stumbled on this problem when trying to port existing code to > native JSON. Sounds like a simple extension of the existing code, so patches are welcome to implement this feature. From debbugs-submit-bounces@debbugs.gnu.org Thu Apr 11 20:34:18 2019 Received: (at 32793) by debbugs.gnu.org; 12 Apr 2019 00:34:18 +0000 Received: from localhost ([127.0.0.1]:55320 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEk94-0003le-88 for submit@debbugs.gnu.org; Thu, 11 Apr 2019 20:34:18 -0400 Received: from mail-lf1-f42.google.com ([209.85.167.42]:40024) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEk91-0003lO-Q7 for 32793@debbugs.gnu.org; Thu, 11 Apr 2019 20:34:16 -0400 Received: by mail-lf1-f42.google.com with SMTP id a28so6100805lfo.7 for <32793@debbugs.gnu.org>; Thu, 11 Apr 2019 17:34:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=Qg+pggzIq8seuZKCHJMEfeBzrJWfT1RvRtFZUY0WV6k=; b=icGX51t0ljg420arPr2HdjkmJTIsdPPbCPdJIb1Z9ATrwNMchG0jW6NtbbZ/cNvwS2 MvJVTSdKqiyOLw/WnDzQN3DS3aZJW/4M9Ao5+irK1p2k1pymQ2aBMAx2lkq3q8eq4atb sYuiWOaHAVjmKSNXS1scr4n901CfZNXKNy2ZOSEKN+78VkvscWcDL88kk90r5911/ShY HYMO5au+5+OhFrj3SZapqilqVxWVaJ8DCigyNrDCX3Bvwu+k3bVFiqvDs8R8qF3xtDAv V//hHkDcIvIuwJy9jkQHHQiKiup87wm67V3u3ocYSvNIDPZwy5tBVBhBKQqUNjMsq5U7 1k1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:subject:to:cc:references:from:message-id :date:user-agent:mime-version:in-reply-to:content-language; bh=Qg+pggzIq8seuZKCHJMEfeBzrJWfT1RvRtFZUY0WV6k=; b=ECSoUnq6T2Dj4SSGGuKVxa3o/oeTzj754UO3VK6I/UqQzSy4Fty6qmY5q/rHlfDMkx EMNnACjdV9Dz5qBNaRV5Mf1eb6JpxZZ5Kp12OphOBzoNAjgJYUZnnVB+l5XdObKSTK2q RA/xfMd2svwk1P62qSDwJvZxULZJDIuPnQPIYKBMJtm6pih2rUWmJF/Aij6YLhKWMyTH 9ObRAAPwSRzUzV6Tp42HtjptJ6jEAS5OYNYEYahnzL54h7e6QTmZLfHpn2iD58QK3NYh I5kuzWGgSY8FfEeXIVBrtC0ZNWczIbF6IS0ocs5ZC7XoLDa/SKS06ub+ZK2UqbyKZy2P BudQ== X-Gm-Message-State: APjAAAU55/OU7Tl7aZSu4UFI0RE4+63aPPRQXCBYzqCau3t/TtwLXFXS GCxuKs5A1he1nSJf1q1X1KvpEgaR X-Google-Smtp-Source: APXvYqyjkL9j8TzjaN2mqmvFZeDeZ5ZCNoossLwhJBJDayYN/G0SWTqz8NQ+K+UPxj6yJJdTir1W3g== X-Received: by 2002:a19:ca55:: with SMTP id h21mr4121735lfj.43.1555029249579; Thu, 11 Apr 2019 17:34:09 -0700 (PDT) Received: from [192.168.1.3] ([185.105.174.23]) by smtp.googlemail.com with ESMTPSA id m3sm2430217lfh.94.2019.04.11.17.34.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 11 Apr 2019 17:34:07 -0700 (PDT) Subject: Re: bug#32793: 27.0.50; json-parse-string doesn't have the equivalent of json.el's json-array-type To: Eli Zaretskii References: <83o95c4hih.fsf@gnu.org> From: Dmitry Gutov Message-ID: <87b7460f-f3c8-1752-279b-ba7d25871f05@yandex.ru> Date: Fri, 12 Apr 2019 03:34:05 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 In-Reply-To: <83o95c4hih.fsf@gnu.org> Content-Type: multipart/mixed; boundary="------------3CB7B2C33FB909EA69F7AA26" Content-Language: en-US X-Spam-Score: 0.2 (/) X-Debbugs-Envelope-To: 32793 Cc: mail@xuchunyang.me, 32793@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.8 (/) This is a multi-part message in MIME format. --------------3CB7B2C33FB909EA69F7AA26 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit On 11.04.2019 19:46, Eli Zaretskii wrote: > Sounds like a simple extension of the existing code, so patches are > welcome to implement this feature. Very well, patch attached. What do you think? --------------3CB7B2C33FB909EA69F7AA26 Content-Type: text/x-patch; name="json-array-type.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="json-array-type.diff" diff --git a/src/json.c b/src/json.c index 5e1439f881..c6c5a1a9b1 100644 --- a/src/json.c +++ b/src/json.c @@ -337,8 +337,14 @@ enum json_object_type { json_object_plist }; +enum json_array_type { + json_array_array, + json_array_list +}; + struct json_configuration { enum json_object_type object_type; + enum json_array_type array_type; Lisp_Object null_object; Lisp_Object false_object; }; @@ -521,7 +527,7 @@ static void json_parse_args (ptrdiff_t nargs, Lisp_Object *args, struct json_configuration *conf, - bool configure_object_type) + bool configure_types) { if ((nargs % 2) != 0) wrong_type_argument (Qplistp, Flist (nargs, args)); @@ -531,7 +537,7 @@ json_parse_args (ptrdiff_t nargs, for (ptrdiff_t i = nargs; i > 0; i -= 2) { Lisp_Object key = args[i - 2]; Lisp_Object value = args[i - 1]; - if (configure_object_type && EQ (key, QCobject_type)) + if (configure_types && EQ (key, QCobject_type)) { if (EQ (value, Qhash_table)) conf->object_type = json_object_hashtable; @@ -542,12 +548,22 @@ json_parse_args (ptrdiff_t nargs, else wrong_choice (list3 (Qhash_table, Qalist, Qplist), value); } + else if (configure_types && EQ (key, QCarray_type)) + { + if (EQ (value, Qarray)) + conf->array_type = json_array_array; + else if (EQ (value, Qlist)) + conf->array_type = json_array_list; + else + wrong_choice (list2 (Qarray, Qlist), value); + } else if (EQ (key, QCnull_object)) conf->null_object = value; else if (EQ (key, QCfalse_object)) conf->false_object = value; - else if (configure_object_type) - wrong_choice (list3 (QCobject_type, + else if (configure_types) + wrong_choice (list4 (QCobject_type, + QCarray_type, QCnull_object, QCfalse_object), value); @@ -604,7 +620,8 @@ usage: (json-serialize OBJECT &rest ARGS) */) } #endif - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs - 1, args + 1, &conf, false); json_t *json = lisp_to_json_toplevel (args[0], &conf); @@ -701,7 +718,8 @@ usage: (json-insert OBJECT &rest ARGS) */) } #endif - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs - 1, args + 1, &conf, false); json_t *json = lisp_to_json (args[0], &conf); @@ -817,10 +835,30 @@ json_to_lisp (json_t *json, struct json_configuration *conf) size_t size = json_array_size (json); if (PTRDIFF_MAX < size) overflow_error (); - Lisp_Object result = make_vector (size, Qunbound); - for (ptrdiff_t i = 0; i < size; ++i) - ASET (result, i, - json_to_lisp (json_array_get (json, i), conf)); + Lisp_Object result; + switch (conf->array_type) + { + case json_array_array: + { + result = make_vector (size, Qunbound); + for (ptrdiff_t i = 0; i < size; ++i) + ASET (result, i, + json_to_lisp (json_array_get (json, i), conf)); + break; + } + case json_array_list: + { + result = Qnil; + for (ptrdiff_t i = 0; i < size; ++i) + result = Fcons (json_to_lisp (json_array_get (json, i), conf), + result); + result = Fnreverse (result); + break; + } + default: + /* Can't get here. */ + emacs_abort (); + } --lisp_eval_depth; return result; } @@ -946,7 +984,8 @@ usage: (json-parse-string STRING &rest ARGS) */) Lisp_Object string = args[0]; Lisp_Object encoded = json_encode (string); check_string_without_embedded_nuls (encoded); - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs - 1, args + 1, &conf, true); json_error_t error; @@ -1016,7 +1055,8 @@ usage: (json-parse-buffer &rest args) */) } #endif - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs, args, &conf, true); ptrdiff_t point = PT_BYTE; @@ -1095,10 +1135,12 @@ syms_of_json (void) Fput (Qjson_parse_string, Qside_effect_free, Qt); DEFSYM (QCobject_type, ":object-type"); + DEFSYM (QCarray_type, ":array-type"); DEFSYM (QCnull_object, ":null-object"); DEFSYM (QCfalse_object, ":false-object"); DEFSYM (Qalist, "alist"); DEFSYM (Qplist, "plist"); + DEFSYM (Qarray, "array"); defsubr (&Sjson_serialize); defsubr (&Sjson_insert); diff --git a/test/src/json-tests.el b/test/src/json-tests.el index 04f91f4abb..542eec11bf 100644 --- a/test/src/json-tests.el +++ b/test/src/json-tests.el @@ -117,6 +117,14 @@ 'json-tests--error (should (equal (json-parse-string input :object-type 'plist) '(:abc [9 :false] :def :null))))) +(ert-deftest json-parse-string/array () + (skip-unless (fboundp 'json-parse-string)) + (let ((input "[\"a\", 1, [\"b\", 2]]")) + (should (equal (json-parse-string input) + ["a" 1 ["b" 2]])) + (should (equal (json-parse-string input :array-type 'list) + '("a" 1 ("b" 2)))))) + (ert-deftest json-parse-string/string () (skip-unless (fboundp 'json-parse-string)) (should-error (json-parse-string "[\"formfeed\f\"]") :type 'json-parse-error) --------------3CB7B2C33FB909EA69F7AA26-- From debbugs-submit-bounces@debbugs.gnu.org Fri Apr 12 05:23:12 2019 Received: (at 32793) by debbugs.gnu.org; 12 Apr 2019 09:23:13 +0000 Received: from localhost ([127.0.0.1]:55462 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEsOu-0001xb-KQ for submit@debbugs.gnu.org; Fri, 12 Apr 2019 05:23:12 -0400 Received: from eggs.gnu.org ([209.51.188.92]:42043) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEsOs-0001xL-C7 for 32793@debbugs.gnu.org; Fri, 12 Apr 2019 05:23:11 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:45870) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hEsOm-0008D1-85; Fri, 12 Apr 2019 05:23:04 -0400 Received: from [176.228.60.248] (port=2337 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1hEsOl-0000Vn-Ht; Fri, 12 Apr 2019 05:23:04 -0400 Date: Fri, 12 Apr 2019 12:22:44 +0300 Message-Id: <83h8b3mvbv.fsf@gnu.org> From: Eli Zaretskii To: Dmitry Gutov In-reply-to: <87b7460f-f3c8-1752-279b-ba7d25871f05@yandex.ru> (message from Dmitry Gutov on Fri, 12 Apr 2019 03:34:05 +0300) Subject: Re: bug#32793: 27.0.50; json-parse-string doesn't have the equivalent of json.el's json-array-type References: <83o95c4hih.fsf@gnu.org> <87b7460f-f3c8-1752-279b-ba7d25871f05@yandex.ru> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 32793 Cc: mail@xuchunyang.me, 32793@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > Cc: mail@xuchunyang.me, 32793@debbugs.gnu.org > From: Dmitry Gutov > Date: Fri, 12 Apr 2019 03:34:05 +0300 > > > Sounds like a simple extension of the existing code, so patches are > > welcome to implement this feature. > > Very well, patch attached. > > What do you think? Thanks, some comments below. > +enum json_array_type { > + json_array_array, > + json_array_list > +}; > + > struct json_configuration { > enum json_object_type object_type; > + enum json_array_type array_type; > Lisp_Object null_object; > Lisp_Object false_object; > }; Can't say I like this conversion of Lisp symbols into C enumerations. I'd rather we used symbols (Qarray, Qlist, etc.), but I can understand why you did this as json.c already did for the other keyword values. > @@ -521,7 +527,7 @@ static void > json_parse_args (ptrdiff_t nargs, > Lisp_Object *args, > struct json_configuration *conf, > - bool configure_object_type) > + bool configure_types) If we are renaming this argument, let's do a better job: I think its name should have been parse_object_types. Come to think of this: why do we need this boolean at all? The callers which don't want :object-type parsed will ignore the result anyway, so it sounds like something we could just toss. > + case json_array_list: > + { > + result = Qnil; > + for (ptrdiff_t i = 0; i < size; ++i) > + result = Fcons (json_to_lisp (json_array_get (json, i), conf), > + result); > + result = Fnreverse (result); If you cons the list back to front, you can avoid the Fnreverse call, which will make this faster. Also, please insert a call to rarely_quit into the loop, as JSON vectors could be quite large, AFAIU. Finally, this needs documentation update: the doc strings of json-parse-string and json-parse-buffer, NEWS, and the ELisp manual. Thanks again for working on this. From debbugs-submit-bounces@debbugs.gnu.org Fri Apr 12 11:02:36 2019 Received: (at 32793) by debbugs.gnu.org; 12 Apr 2019 15:02:36 +0000 Received: from localhost ([127.0.0.1]:56617 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hExhL-0006B4-Rt for submit@debbugs.gnu.org; Fri, 12 Apr 2019 11:02:36 -0400 Received: from mail-wm1-f42.google.com ([209.85.128.42]:40033) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hExhI-0006Am-6X for 32793@debbugs.gnu.org; Fri, 12 Apr 2019 11:02:35 -0400 Received: by mail-wm1-f42.google.com with SMTP id z24so11501349wmi.5 for <32793@debbugs.gnu.org>; Fri, 12 Apr 2019 08:02:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=2S+uLBkeSxrE5Htd5QJI6nY+MjfMLaDZPgE3Gj97Nc0=; b=aQlMpKjUKm7PutnxhP9JwWIdzjeyovxqpWrSUyGHGdMppDuF3HJSrRc/75G0L2dutR +8eKHHSvdyP48ONV+Mesei7UdKqSN0/hH8gI0O50JJcOe/DVH3elK2cKvDUHd6MfD+BF WTc/cW6nr5R1dF8qY52Lo4ov1CWslgs4G041WZrmwMn/lq9RRJXBsfhy+YSEmv7+zUwj 3Ezn6Mj3e+Tjgicqgsp68Gic2BOhvmjKjrN+sqNCS9oD1766Mx0JdIjRgbBhMSaglZrA bv5sBj0FtJ7RtQbUA32GwQkGi+uknqj5BdXKROgxdb04RzYo2STKPAoYlQCTeVHQhIXN /Saw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:subject:to:cc:references:from:message-id :date:user-agent:mime-version:in-reply-to:content-language; bh=2S+uLBkeSxrE5Htd5QJI6nY+MjfMLaDZPgE3Gj97Nc0=; b=ao8x0S7B7MPQXwoskFKXNt8R2u1CrI14U6NkYLj5q98YXiGwffUnAtnxw1Fobhttro BYYb/BibLyEM5Et3M+TdAoIMM+l/Zzo6ogGHAQtDZzZQaar4M07YGWI8zStq8Bh44Dn2 oetZ0iDqz3GqgN7d/IRyXopv3RSRsQlp83aEYxhMxKYGb1ykHVFKTudaBg+HL3F9kw/o NGtrwsDYB8e2vaWeg351zGMVCz2EKyMDdjBbITAzAKsUxSJ0S1RLg0Q9XHvhNtPEA63g LYhso+9hbSrPrvGGCsg1YKPcz5i9c4aYrLcEbSp1ro8fd746ok8hddk7z9AEzKteoeBq TEmg== X-Gm-Message-State: APjAAAVHqb8EJplfKoJZCGxfxqUG9SYYewWboljZSfT57zrHE7LHfLyZ epsf7fi2m2ibIF/2pywZTzD3cKAJ X-Google-Smtp-Source: APXvYqzYDFtUxFjGDKqKG2wn4RRDOhhoVfDkKb1SHo7bVRoxVF6LiPQCqsiIC1RHFSslO0BK9DUXuw== X-Received: by 2002:a1c:d7:: with SMTP id 206mr11010089wma.69.1555081344794; Fri, 12 Apr 2019 08:02:24 -0700 (PDT) Received: from [192.168.0.195] ([109.110.245.170]) by smtp.googlemail.com with ESMTPSA id y132sm10620097wmg.38.2019.04.12.08.02.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 12 Apr 2019 08:02:23 -0700 (PDT) Subject: Re: bug#32793: 27.0.50; json-parse-string doesn't have the equivalent of json.el's json-array-type To: Eli Zaretskii References: <83o95c4hih.fsf@gnu.org> <87b7460f-f3c8-1752-279b-ba7d25871f05@yandex.ru> <83h8b3mvbv.fsf@gnu.org> From: Dmitry Gutov Message-ID: Date: Fri, 12 Apr 2019 18:02:22 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 In-Reply-To: <83h8b3mvbv.fsf@gnu.org> Content-Type: multipart/mixed; boundary="------------036AF5A65E9343719CAB20BA" Content-Language: en-US X-Spam-Score: 0.2 (/) X-Debbugs-Envelope-To: 32793 Cc: mail@xuchunyang.me, 32793@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.8 (/) This is a multi-part message in MIME format. --------------036AF5A65E9343719CAB20BA Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit On 12.04.2019 12:22, Eli Zaretskii wrote: > Can't say I like this conversion of Lisp symbols into C enumerations. > I'd rather we used symbols (Qarray, Qlist, etc.), but I can understand > why you did this as json.c already did for the other keyword values. I vaguely suspect it might help with performance. *shrug* Or not. >> @@ -521,7 +527,7 @@ static void >> json_parse_args (ptrdiff_t nargs, >> Lisp_Object *args, >> struct json_configuration *conf, >> - bool configure_object_type) >> + bool configure_types) > > If we are renaming this argument, let's do a better job: I think its > name should have been parse_object_types. OK. > Come to think of this: why do we need this boolean at all? The > callers which don't want :object-type parsed will ignore the result > anyway, so it sounds like something we could just toss. I'd rather we didn't accept argument we cannot handle, to avoid false expectations. For example with this patch we can parse a JSON array into a Lisp list. But there's no way to serialize a list back into a JSON array, yet. I looked at implementing it, just for completeness (it's not necessary for my use case, for now). But there's an ambiguity between lists and alists which is not trivial to solve (i.e. when object-type is alist and array-type is list, how do we determinine, quickly and reliably, that a given list is actually an alist?). So maybe leave it for the future. >> + case json_array_list: >> + { >> + result = Qnil; >> + for (ptrdiff_t i = 0; i < size; ++i) >> + result = Fcons (json_to_lisp (json_array_get (json, i), conf), >> + result); >> + result = Fnreverse (result); > > If you cons the list back to front, you can avoid the Fnreverse call, > which will make this faster. Done. No real performance impact that I can see, but it didn't hurt either. > Also, please insert a call to rarely_quit into the loop, as JSON > vectors could be quite large, AFAIU. Also done. In the json_array_array case as well, where it was missing, it seems. > Finally, this needs documentation update: the doc strings of > json-parse-string and json-parse-buffer, NEWS, and the ELisp manual. json-parse-buffer and NEWS don't need updating, I think. Otherwise, done, see the new patch. --------------036AF5A65E9343719CAB20BA Content-Type: text/x-patch; name="json-array-type.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="json-array-type.diff" diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 1ef836b8f9..b46ee64786 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -5167,6 +5167,11 @@ Parsing JSON keys; @code{alist} to use alists with symbols as keys; or @code{plist} to use plists with keyword symbols as keys. +@item :array-type +The value decides which Lisp object to use for representing a JSON +array. It can be either @code{array}, the default, to use Lisp +arrays; or @code{list} to use lists. + @item :null-object The value decides which Lisp object to use to represent the JSON keyword @code{null}. It defaults to the symbol @code{:null}. diff --git a/src/json.c b/src/json.c index 5e1439f881..1f45fe527f 100644 --- a/src/json.c +++ b/src/json.c @@ -337,8 +337,14 @@ enum json_object_type { json_object_plist }; +enum json_array_type { + json_array_array, + json_array_list +}; + struct json_configuration { enum json_object_type object_type; + enum json_array_type array_type; Lisp_Object null_object; Lisp_Object false_object; }; @@ -521,7 +527,7 @@ static void json_parse_args (ptrdiff_t nargs, Lisp_Object *args, struct json_configuration *conf, - bool configure_object_type) + bool parse_object_types) { if ((nargs % 2) != 0) wrong_type_argument (Qplistp, Flist (nargs, args)); @@ -531,7 +537,7 @@ json_parse_args (ptrdiff_t nargs, for (ptrdiff_t i = nargs; i > 0; i -= 2) { Lisp_Object key = args[i - 2]; Lisp_Object value = args[i - 1]; - if (configure_object_type && EQ (key, QCobject_type)) + if (parse_object_types && EQ (key, QCobject_type)) { if (EQ (value, Qhash_table)) conf->object_type = json_object_hashtable; @@ -542,12 +548,22 @@ json_parse_args (ptrdiff_t nargs, else wrong_choice (list3 (Qhash_table, Qalist, Qplist), value); } + else if (parse_object_types && EQ (key, QCarray_type)) + { + if (EQ (value, Qarray)) + conf->array_type = json_array_array; + else if (EQ (value, Qlist)) + conf->array_type = json_array_list; + else + wrong_choice (list2 (Qarray, Qlist), value); + } else if (EQ (key, QCnull_object)) conf->null_object = value; else if (EQ (key, QCfalse_object)) conf->false_object = value; - else if (configure_object_type) - wrong_choice (list3 (QCobject_type, + else if (parse_object_types) + wrong_choice (list4 (QCobject_type, + QCarray_type, QCnull_object, QCfalse_object), value); @@ -604,7 +620,8 @@ usage: (json-serialize OBJECT &rest ARGS) */) } #endif - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs - 1, args + 1, &conf, false); json_t *json = lisp_to_json_toplevel (args[0], &conf); @@ -701,7 +718,8 @@ usage: (json-insert OBJECT &rest ARGS) */) } #endif - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs - 1, args + 1, &conf, false); json_t *json = lisp_to_json (args[0], &conf); @@ -817,10 +835,35 @@ json_to_lisp (json_t *json, struct json_configuration *conf) size_t size = json_array_size (json); if (PTRDIFF_MAX < size) overflow_error (); - Lisp_Object result = make_vector (size, Qunbound); - for (ptrdiff_t i = 0; i < size; ++i) - ASET (result, i, - json_to_lisp (json_array_get (json, i), conf)); + Lisp_Object result; + switch (conf->array_type) + { + case json_array_array: + { + result = make_vector (size, Qunbound); + for (ptrdiff_t i = 0; i < size; ++i) + { + rarely_quit (i); + ASET (result, i, + json_to_lisp (json_array_get (json, i), conf)); + } + break; + } + case json_array_list: + { + result = Qnil; + for (ptrdiff_t i = size - 1; i >= 0; --i) + { + rarely_quit (i); + result = Fcons (json_to_lisp (json_array_get (json, i), conf), + result); + } + break; + } + default: + /* Can't get here. */ + emacs_abort (); + } --lisp_eval_depth; return result; } @@ -918,6 +961,9 @@ a list of keyword/argument pairs: The keyword argument `:object-type' specifies which Lisp type is used to represent objects; it can be `hash-table', `alist' or `plist'. +The keyword argument `:array-type' specifies which Lisp type is used +to represent arrays; it can be `array' or `list'. + The keyword argument `:null-object' specifies which object to use to represent a JSON null value. It defaults to `:null'. @@ -946,7 +992,8 @@ usage: (json-parse-string STRING &rest ARGS) */) Lisp_Object string = args[0]; Lisp_Object encoded = json_encode (string); check_string_without_embedded_nuls (encoded); - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs - 1, args + 1, &conf, true); json_error_t error; @@ -1016,7 +1063,8 @@ usage: (json-parse-buffer &rest args) */) } #endif - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs, args, &conf, true); ptrdiff_t point = PT_BYTE; @@ -1095,10 +1143,12 @@ syms_of_json (void) Fput (Qjson_parse_string, Qside_effect_free, Qt); DEFSYM (QCobject_type, ":object-type"); + DEFSYM (QCarray_type, ":array-type"); DEFSYM (QCnull_object, ":null-object"); DEFSYM (QCfalse_object, ":false-object"); DEFSYM (Qalist, "alist"); DEFSYM (Qplist, "plist"); + DEFSYM (Qarray, "array"); defsubr (&Sjson_serialize); defsubr (&Sjson_insert); diff --git a/test/src/json-tests.el b/test/src/json-tests.el index 04f91f4abb..542eec11bf 100644 --- a/test/src/json-tests.el +++ b/test/src/json-tests.el @@ -117,6 +117,14 @@ 'json-tests--error (should (equal (json-parse-string input :object-type 'plist) '(:abc [9 :false] :def :null))))) +(ert-deftest json-parse-string/array () + (skip-unless (fboundp 'json-parse-string)) + (let ((input "[\"a\", 1, [\"b\", 2]]")) + (should (equal (json-parse-string input) + ["a" 1 ["b" 2]])) + (should (equal (json-parse-string input :array-type 'list) + '("a" 1 ("b" 2)))))) + (ert-deftest json-parse-string/string () (skip-unless (fboundp 'json-parse-string)) (should-error (json-parse-string "[\"formfeed\f\"]") :type 'json-parse-error) --------------036AF5A65E9343719CAB20BA-- From debbugs-submit-bounces@debbugs.gnu.org Fri Apr 12 11:26:36 2019 Received: (at 32793) by debbugs.gnu.org; 12 Apr 2019 15:26:36 +0000 Received: from localhost ([127.0.0.1]:56628 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEy4Y-0006j6-IW for submit@debbugs.gnu.org; Fri, 12 Apr 2019 11:26:36 -0400 Received: from eggs.gnu.org ([209.51.188.92]:47431) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEy4W-0006iu-Ee for 32793@debbugs.gnu.org; Fri, 12 Apr 2019 11:26:33 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:34162) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hEy4Q-0004K2-NW; Fri, 12 Apr 2019 11:26:26 -0400 Received: from [176.228.60.248] (port=4931 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1hEy4N-0004hJ-60; Fri, 12 Apr 2019 11:26:26 -0400 Date: Fri, 12 Apr 2019 18:26:03 +0300 Message-Id: <83zhovkzxw.fsf@gnu.org> From: Eli Zaretskii To: Dmitry Gutov In-reply-to: (message from Dmitry Gutov on Fri, 12 Apr 2019 18:02:22 +0300) Subject: Re: bug#32793: 27.0.50; json-parse-string doesn't have the equivalent of json.el's json-array-type References: <83o95c4hih.fsf@gnu.org> <87b7460f-f3c8-1752-279b-ba7d25871f05@yandex.ru> <83h8b3mvbv.fsf@gnu.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 32793 Cc: mail@xuchunyang.me, 32793@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > Cc: mail@xuchunyang.me, 32793@debbugs.gnu.org > From: Dmitry Gutov > Date: Fri, 12 Apr 2019 18:02:22 +0300 > > > Come to think of this: why do we need this boolean at all? The > > callers which don't want :object-type parsed will ignore the result > > anyway, so it sounds like something we could just toss. > > I'd rather we didn't accept argument we cannot handle, to avoid false > expectations. > > For example with this patch we can parse a JSON array into a Lisp list. > > But there's no way to serialize a list back into a JSON array, yet. This argument is meaningless for serializing, I think. But OK. > >> + for (ptrdiff_t i = 0; i < size; ++i) > >> + result = Fcons (json_to_lisp (json_array_get (json, i), conf), > >> + result); > >> + result = Fnreverse (result); > > > > If you cons the list back to front, you can avoid the Fnreverse call, > > which will make this faster. > > Done. No real performance impact that I can see, but it didn't hurt either. You just didn't try an array big enough for this to matter. > > Also, please insert a call to rarely_quit into the loop, as JSON > > vectors could be quite large, AFAIU. > > Also done. In the json_array_array case as well, where it was missing, > it seems. I don't mind, although in that case the loop just assigns value to a vector that was already consed. > json-parse-buffer and NEWS don't need updating, I think. They don't? Why not? > Otherwise, done, see the new patch. LGTM, with the above question, and this one gotcha: > @@ -918,6 +961,9 @@ a list of keyword/argument pairs: > The keyword argument `:object-type' specifies which Lisp type is used > to represent objects; it can be `hash-table', `alist' or `plist'. > > +The keyword argument `:array-type' specifies which Lisp type is used > +to represent arrays; it can be `array' or `list'. Please say here that 'array' is the default. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Fri Apr 12 11:45:59 2019 Received: (at 32793) by debbugs.gnu.org; 12 Apr 2019 15:45:59 +0000 Received: from localhost ([127.0.0.1]:56635 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEyNK-0007D4-UY for submit@debbugs.gnu.org; Fri, 12 Apr 2019 11:45:59 -0400 Received: from mail-wr1-f46.google.com ([209.85.221.46]:35023) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hEyNI-0007Cq-Gx for 32793@debbugs.gnu.org; Fri, 12 Apr 2019 11:45:57 -0400 Received: by mail-wr1-f46.google.com with SMTP id w1so12564056wrp.2 for <32793@debbugs.gnu.org>; Fri, 12 Apr 2019 08:45:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=QSntuX5AqPUUwMa7Mh/wnWb/QqxedXjhQlLdWzfr0+Q=; b=oveyqs9wBTWkPO2hw5LSggI2qqSUDRxIJeLU3FlZ3P1wW2Lq5e1TeVZU+y16nfg6GN hfznYjfOuqVWoYoFCD15UqCgOFDgt1AuWmxYpHdwlSsxD5mx9OvIj4kXbAx/fIw8E7EC rYZq7OdN/bGjcBhaGqz5mO+Wa+6n7ZA4xyZUrG/SZVehhdIQqu+YcAyZUeyJr7hqmv5s P2r0kE4TyfwQSetCixTOw4/+A5jVChI9DnRu5ju5uTM1g/SK+EXFFYGBlclR463wbJED MLLgT/TaqIwhFJ5iFWe49ItB8ZfKNEFQLA7JfknqmOZ6KfbQZ3fnLGif1TzDre/IreOx Y/3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:subject:to:cc:references:from:message-id :date:user-agent:mime-version:in-reply-to:content-language; bh=QSntuX5AqPUUwMa7Mh/wnWb/QqxedXjhQlLdWzfr0+Q=; b=JSeeRfjT5fBS5PzPVqZdrgcR54XN6icD9udZgl1wHuA48q3SzUJNZIpZI1gLooXhA9 ZJcK2flS9XN3SlL9X8aKTXRe4kqKeUQohtuseg22KBpNSvk4WXbM2Q9JcNhnhiiSGdOl UG339gK3MIxTaafllpuooDpFZdXBRybcKV7sd9e6nR5VM1Ed058RyG2KfMuv9SB+tZG/ KKN1YnX0TvZivVi26fyciystiLiKLr943wdM1I6YY8pLqfD6tC5ZB8HrQHofARJuXL0n VfOYaP305ani3kjMd5Xjcx5JGLirUMULyCcc4bmYmo8T/CU+IE1VLR9k3PIvo0MPeRvw C0Vw== X-Gm-Message-State: APjAAAXGBpok0yxaDMlr+3snExzDo5hvaKNaPXbrp5wxRk2M1//FnuFa KFZjycqntScxVgEdhQmmZE8S9bfP X-Google-Smtp-Source: APXvYqwq0HYUWAYKdxgUFpk3zyJhYN1S2ajx57jNCmgWTfMGign+TFN//XZDCFGK0R5msypEsppm5g== X-Received: by 2002:adf:afe1:: with SMTP id y33mr37964770wrd.288.1555083950397; Fri, 12 Apr 2019 08:45:50 -0700 (PDT) Received: from [192.168.0.195] ([109.110.245.170]) by smtp.googlemail.com with ESMTPSA id y125sm13805737wmc.39.2019.04.12.08.45.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 12 Apr 2019 08:45:49 -0700 (PDT) Subject: Re: bug#32793: 27.0.50; json-parse-string doesn't have the equivalent of json.el's json-array-type To: Eli Zaretskii References: <83o95c4hih.fsf@gnu.org> <87b7460f-f3c8-1752-279b-ba7d25871f05@yandex.ru> <83h8b3mvbv.fsf@gnu.org> <83zhovkzxw.fsf@gnu.org> From: Dmitry Gutov Message-ID: <676213b7-64ba-e141-d4cd-bb3f859cd092@yandex.ru> Date: Fri, 12 Apr 2019 18:45:46 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 In-Reply-To: <83zhovkzxw.fsf@gnu.org> Content-Type: multipart/mixed; boundary="------------6C3CC0677551A4445BAFDA1B" Content-Language: en-US X-Spam-Score: 0.2 (/) X-Debbugs-Envelope-To: 32793 Cc: mail@xuchunyang.me, 32793@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.8 (/) This is a multi-part message in MIME format. --------------6C3CC0677551A4445BAFDA1B Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit On 12.04.2019 18:26, Eli Zaretskii wrote: > This argument is meaningless for serializing, I think. But OK. I wouldn't be so sure. For instance, one could attempt to resolve the alist-list conflict using a combination of :object-type and :array-type parameters. This isn't going to work, at least not yet. It's better to fail earlier. > You just didn't try an array big enough for this to matter. My array was big enough for the switch from json.el to json.c to make a real difference. Anyway, it depends on how "big" the elements inside the array are as well. In my case they're fairly complex too. > I don't mind, although in that case the loop just assigns value to a > vector that was already consed. It also calls json_to_lisp (json_array_get (json, i), conf) in that loop. >> json-parse-buffer and NEWS don't need updating, I think. > > They don't? Why not? There was no json.c in Emacs 26. NEWS describes the changes from the previous release, and the current entry only lists the public functions. json-parse-buffer doesn't enumerate the keyword arguments either. >> +The keyword argument `:array-type' specifies which Lisp type is used >> +to represent arrays; it can be `array' or `list'. > > Please say here that 'array' is the default. OK. I've had to update the preceding paragraph as well. Good to install? --------------6C3CC0677551A4445BAFDA1B Content-Type: text/x-patch; name="json-array-type.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="json-array-type.diff" diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 1ef836b8f9..b46ee64786 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -5167,6 +5167,11 @@ Parsing JSON keys; @code{alist} to use alists with symbols as keys; or @code{plist} to use plists with keyword symbols as keys. +@item :array-type +The value decides which Lisp object to use for representing a JSON +array. It can be either @code{array}, the default, to use Lisp +arrays; or @code{list} to use lists. + @item :null-object The value decides which Lisp object to use to represent the JSON keyword @code{null}. It defaults to the symbol @code{:null}. diff --git a/src/json.c b/src/json.c index 5e1439f881..eb323b498c 100644 --- a/src/json.c +++ b/src/json.c @@ -337,8 +337,14 @@ enum json_object_type { json_object_plist }; +enum json_array_type { + json_array_array, + json_array_list +}; + struct json_configuration { enum json_object_type object_type; + enum json_array_type array_type; Lisp_Object null_object; Lisp_Object false_object; }; @@ -521,7 +527,7 @@ static void json_parse_args (ptrdiff_t nargs, Lisp_Object *args, struct json_configuration *conf, - bool configure_object_type) + bool parse_object_types) { if ((nargs % 2) != 0) wrong_type_argument (Qplistp, Flist (nargs, args)); @@ -531,7 +537,7 @@ json_parse_args (ptrdiff_t nargs, for (ptrdiff_t i = nargs; i > 0; i -= 2) { Lisp_Object key = args[i - 2]; Lisp_Object value = args[i - 1]; - if (configure_object_type && EQ (key, QCobject_type)) + if (parse_object_types && EQ (key, QCobject_type)) { if (EQ (value, Qhash_table)) conf->object_type = json_object_hashtable; @@ -542,12 +548,22 @@ json_parse_args (ptrdiff_t nargs, else wrong_choice (list3 (Qhash_table, Qalist, Qplist), value); } + else if (parse_object_types && EQ (key, QCarray_type)) + { + if (EQ (value, Qarray)) + conf->array_type = json_array_array; + else if (EQ (value, Qlist)) + conf->array_type = json_array_list; + else + wrong_choice (list2 (Qarray, Qlist), value); + } else if (EQ (key, QCnull_object)) conf->null_object = value; else if (EQ (key, QCfalse_object)) conf->false_object = value; - else if (configure_object_type) - wrong_choice (list3 (QCobject_type, + else if (parse_object_types) + wrong_choice (list4 (QCobject_type, + QCarray_type, QCnull_object, QCfalse_object), value); @@ -604,7 +620,8 @@ usage: (json-serialize OBJECT &rest ARGS) */) } #endif - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs - 1, args + 1, &conf, false); json_t *json = lisp_to_json_toplevel (args[0], &conf); @@ -701,7 +718,8 @@ usage: (json-insert OBJECT &rest ARGS) */) } #endif - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs - 1, args + 1, &conf, false); json_t *json = lisp_to_json (args[0], &conf); @@ -817,10 +835,35 @@ json_to_lisp (json_t *json, struct json_configuration *conf) size_t size = json_array_size (json); if (PTRDIFF_MAX < size) overflow_error (); - Lisp_Object result = make_vector (size, Qunbound); - for (ptrdiff_t i = 0; i < size; ++i) - ASET (result, i, - json_to_lisp (json_array_get (json, i), conf)); + Lisp_Object result; + switch (conf->array_type) + { + case json_array_array: + { + result = make_vector (size, Qunbound); + for (ptrdiff_t i = 0; i < size; ++i) + { + rarely_quit (i); + ASET (result, i, + json_to_lisp (json_array_get (json, i), conf)); + } + break; + } + case json_array_list: + { + result = Qnil; + for (ptrdiff_t i = size - 1; i >= 0; --i) + { + rarely_quit (i); + result = Fcons (json_to_lisp (json_array_get (json, i), conf), + result); + } + break; + } + default: + /* Can't get here. */ + emacs_abort (); + } --lisp_eval_depth; return result; } @@ -916,7 +959,12 @@ error of type `json-parse-error' is signaled. The arguments ARGS are a list of keyword/argument pairs: The keyword argument `:object-type' specifies which Lisp type is used -to represent objects; it can be `hash-table', `alist' or `plist'. +to represent objects; it can be `hash-table', `alist' or `plist'. It +defaults to `hash-table'. + +The keyword argument `:array-type' specifies which Lisp type is used +to represent arrays; it can be `array' or `list'. It defaults to +`array'. The keyword argument `:null-object' specifies which object to use to represent a JSON null value. It defaults to `:null'. @@ -946,7 +994,8 @@ usage: (json-parse-string STRING &rest ARGS) */) Lisp_Object string = args[0]; Lisp_Object encoded = json_encode (string); check_string_without_embedded_nuls (encoded); - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs - 1, args + 1, &conf, true); json_error_t error; @@ -1016,7 +1065,8 @@ usage: (json-parse-buffer &rest args) */) } #endif - struct json_configuration conf = {json_object_hashtable, QCnull, QCfalse}; + struct json_configuration conf = + {json_object_hashtable, json_array_array, QCnull, QCfalse}; json_parse_args (nargs, args, &conf, true); ptrdiff_t point = PT_BYTE; @@ -1095,10 +1145,12 @@ syms_of_json (void) Fput (Qjson_parse_string, Qside_effect_free, Qt); DEFSYM (QCobject_type, ":object-type"); + DEFSYM (QCarray_type, ":array-type"); DEFSYM (QCnull_object, ":null-object"); DEFSYM (QCfalse_object, ":false-object"); DEFSYM (Qalist, "alist"); DEFSYM (Qplist, "plist"); + DEFSYM (Qarray, "array"); defsubr (&Sjson_serialize); defsubr (&Sjson_insert); diff --git a/test/src/json-tests.el b/test/src/json-tests.el index 04f91f4abb..542eec11bf 100644 --- a/test/src/json-tests.el +++ b/test/src/json-tests.el @@ -117,6 +117,14 @@ 'json-tests--error (should (equal (json-parse-string input :object-type 'plist) '(:abc [9 :false] :def :null))))) +(ert-deftest json-parse-string/array () + (skip-unless (fboundp 'json-parse-string)) + (let ((input "[\"a\", 1, [\"b\", 2]]")) + (should (equal (json-parse-string input) + ["a" 1 ["b" 2]])) + (should (equal (json-parse-string input :array-type 'list) + '("a" 1 ("b" 2)))))) + (ert-deftest json-parse-string/string () (skip-unless (fboundp 'json-parse-string)) (should-error (json-parse-string "[\"formfeed\f\"]") :type 'json-parse-error) --------------6C3CC0677551A4445BAFDA1B-- From debbugs-submit-bounces@debbugs.gnu.org Fri Apr 12 13:43:08 2019 Received: (at 32793) by debbugs.gnu.org; 12 Apr 2019 17:43:08 +0000 Received: from localhost ([127.0.0.1]:56672 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hF0Ci-0001eF-5h for submit@debbugs.gnu.org; Fri, 12 Apr 2019 13:43:08 -0400 Received: from eggs.gnu.org ([209.51.188.92]:49800) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hF0Cg-0001dl-2t for 32793@debbugs.gnu.org; Fri, 12 Apr 2019 13:43:06 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:37462) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hF0Ca-0001VR-JD; Fri, 12 Apr 2019 13:43:00 -0400 Received: from [176.228.60.248] (port=1515 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1hF0CZ-0006Oy-Qy; Fri, 12 Apr 2019 13:43:00 -0400 Date: Fri, 12 Apr 2019 20:42:43 +0300 Message-Id: <83y34fktm4.fsf@gnu.org> From: Eli Zaretskii To: Dmitry Gutov In-reply-to: <676213b7-64ba-e141-d4cd-bb3f859cd092@yandex.ru> (message from Dmitry Gutov on Fri, 12 Apr 2019 18:45:46 +0300) Subject: Re: bug#32793: 27.0.50; json-parse-string doesn't have the equivalent of json.el's json-array-type References: <83o95c4hih.fsf@gnu.org> <87b7460f-f3c8-1752-279b-ba7d25871f05@yandex.ru> <83h8b3mvbv.fsf@gnu.org> <83zhovkzxw.fsf@gnu.org> <676213b7-64ba-e141-d4cd-bb3f859cd092@yandex.ru> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 32793 Cc: mail@xuchunyang.me, 32793@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > Cc: mail@xuchunyang.me, 32793@debbugs.gnu.org > From: Dmitry Gutov > Date: Fri, 12 Apr 2019 18:45:46 +0300 > > Good to install? Yes, thanks. From debbugs-submit-bounces@debbugs.gnu.org Fri Apr 12 18:36:51 2019 Received: (at 32793-done) by debbugs.gnu.org; 12 Apr 2019 22:36:51 +0000 Received: from localhost ([127.0.0.1]:56919 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hF4mw-00009a-SO for submit@debbugs.gnu.org; Fri, 12 Apr 2019 18:36:51 -0400 Received: from mail-lf1-f48.google.com ([209.85.167.48]:45018) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hF4mu-00009M-HK for 32793-done@debbugs.gnu.org; Fri, 12 Apr 2019 18:36:48 -0400 Received: by mail-lf1-f48.google.com with SMTP id h18so8606319lfj.11 for <32793-done@debbugs.gnu.org>; Fri, 12 Apr 2019 15:36:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=26QuTTaJIHVSTtfCdlLRW/iJAPmo67CLwZFeEg1rmHk=; b=IpwmnbuJsyI8F6s+S5n0gWJ0iGpVNE2iyg68LIsrce5HOxfjb6AxSPDj6WqSWa2O1y viCUFHO+CDA4WB+pRPoBKKKLx0VyCKW5ZXUZDmOn5dIIev8ipUgIcG+ALu1FUsAs0y+v 2sxYxmq/6gGMSKwqCo+RXkpDMGPx5cMP5LiJ88zbIwEW5jzw60gkBYB/nOsdf8jK3lTT hLppK32LA5kGHjrGlAVNB44FFiOkofDoNKxH3YvDOifcTinth3VN+wib6IDhxCvuwJpz 8A6Kp51OAgzcIjjJOESZewQstOeCFjLEkNCZBKLe/jQ4qnC27SuwxM8w8USzKAPWUu+4 caqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:subject:to:cc:references:from:message-id :date:user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=26QuTTaJIHVSTtfCdlLRW/iJAPmo67CLwZFeEg1rmHk=; b=W6vtWIZeQVYP8yhZOLIZ/YrL3/aAiEkQtozOYVaqLpwwgC7JOAO0EEVKmgheGXVYuw giOga6/EgCB2osFsUno/JKDS+jHp7tWbbYJdJeSsHshKazAu67WE2skXaRzJQ1pGXm2T 2Za6c8aKB0icXyQSfl8PNMyIYEkP6HmO7gkVc6Yft0dL6RQ9mKiQkzOPKmQ8IpNHhjX7 /xQ1JU8kGi7M7GhfHzkQWEaxaF5fJSSK+MbotkxM9lfsld+VpN3P9h+ZPkNeitzHy3Po Em5b5c9qKRA141C1khRYMmL9vJ4pK1FUqLeYgmFwiI0zu57XqyyrRjJR6K/VMnInBgpt fInQ== X-Gm-Message-State: APjAAAX731XLBweT/QD+1TinNDnOoTjXX+amK1EveUXL/W6p5gF2PYyp htael5I2iGomBUJgxBmMg0vIbO+o X-Google-Smtp-Source: APXvYqwD+cv/6Z+p/uWCDH/M037timWvQZKdRd/GZ13aT+s9paixbkmUuDEHwNcXWFR4vZgpaT6Skw== X-Received: by 2002:a19:6619:: with SMTP id a25mr32844712lfc.21.1555108602069; Fri, 12 Apr 2019 15:36:42 -0700 (PDT) Received: from [192.168.1.3] ([185.105.174.23]) by smtp.googlemail.com with ESMTPSA id j10sm3573799lfc.56.2019.04.12.15.36.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 12 Apr 2019 15:36:41 -0700 (PDT) Subject: Re: bug#32793: 27.0.50; json-parse-string doesn't have the equivalent of json.el's json-array-type To: Eli Zaretskii References: <83o95c4hih.fsf@gnu.org> <87b7460f-f3c8-1752-279b-ba7d25871f05@yandex.ru> <83h8b3mvbv.fsf@gnu.org> <83zhovkzxw.fsf@gnu.org> <676213b7-64ba-e141-d4cd-bb3f859cd092@yandex.ru> <83y34fktm4.fsf@gnu.org> From: Dmitry Gutov Message-ID: Date: Sat, 13 Apr 2019 01:36:39 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 In-Reply-To: <83y34fktm4.fsf@gnu.org> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit X-Spam-Score: 0.2 (/) X-Debbugs-Envelope-To: 32793-done Cc: mail@xuchunyang.me, 32793-done@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.8 (/) On 12.04.2019 20:42, Eli Zaretskii wrote: >> Good to install? > > Yes, thanks. Thank you. Pushed to master, closing. From unknown Sat Aug 16 16:17:42 2025 Received: (at fakecontrol) by fakecontrolmessage; To: internal_control@debbugs.gnu.org From: Debbugs Internal Request Subject: Internal Control Message-Id: bug archived. Date: Sat, 11 May 2019 11:24:05 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator