+ if (skipping)
+ lookup_value = NULL;
+ else switch (fmt)
+ {
+ case extract_basic:
+ lookup_value = field_number_set
+ ? expand_gettokened(field_number, sub[1], sub[2])
+ : expand_getkeyed(sub[0], sub[1]);
+ break;
+
+ case extract_json:
+ {
+ uschar * s, * item;
+ const uschar * list;
+
+ /* Array: Bracket-enclosed and comma-separated.
+ Object: Brace-enclosed, comma-sep list of name:value pairs */
+
+ if (!(s = dewrap(sub[1], field_number_set ? US"[]" : US"{}")))
+ {
+ expand_string_message =
+ string_sprintf("%s wrapping %s for extract json",
+ expand_string_message,
+ field_number_set ? "array" : "object");
+ goto EXPAND_FAILED_CURLY;
+ }
+
+ list = s;
+ if (field_number_set)
+ {
+ if (field_number <= 0)
+ {
+ expand_string_message = US"first argument of \"extract\" must "
+ "be greater than zero";
+ goto EXPAND_FAILED;
+ }
+ while (field_number > 0 && (item = json_nextinlist(&list)))
+ field_number--;
+ s = item;
+ lookup_value = s;
+ while (*s) s++;
+ while (--s >= lookup_value && isspace(*s)) *s = '\0';
+ }
+ else
+ {
+ lookup_value = NULL;
+ while ((item = json_nextinlist(&list)))
+ {
+ /* Item is: string name-sep value. string is quoted.
+ Dequote the string and compare with the search key. */
+
+ if (!(item = dewrap(item, US"\"\"")))
+ {
+ expand_string_message =
+ string_sprintf("%s wrapping string key for extract json",
+ expand_string_message);
+ goto EXPAND_FAILED_CURLY;
+ }
+ if (Ustrcmp(item, sub[0]) == 0) /*XXX should be a UTF8-compare */
+ {
+ s = item + strlen(item) + 1;
+ while (isspace(*s)) s++;
+ if (*s != ':')
+ {
+ expand_string_message = string_sprintf(
+ "missing object value-separator for extract json");
+ goto EXPAND_FAILED_CURLY;
+ }
+ s++;
+ while (isspace(*s)) s++;
+ lookup_value = s;
+ break;
+ }
+ }
+ }
+ }
+ }