Message ID | 83414a2b-bfad-4381-8903-152ec0552e88@suse.com |
---|---|
State | New |
Headers |
Return-Path: <binutils-bounces~patchwork=sourceware.org@sourceware.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4B3343857C63 for <patchwork@sourceware.org>; Mon, 27 Jan 2025 16:02:14 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4B3343857C63 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=suse.com header.i=@suse.com header.a=rsa-sha256 header.s=google header.b=dv6sY8pr X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-ed1-x52f.google.com (mail-ed1-x52f.google.com [IPv6:2a00:1450:4864:20::52f]) by sourceware.org (Postfix) with ESMTPS id E8A513858289 for <binutils@sourceware.org>; Mon, 27 Jan 2025 15:50:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E8A513858289 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=suse.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=suse.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org E8A513858289 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::52f ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1737993003; cv=none; b=U4/DRndaLGaKGGse9Xu2QoAa618jaPaKoJ206AVuOc4GhZRG6pT7XN6lHetb32vIeMBUNjF5C4mrMAqImarI2y8ubODcdYiKQEpZMmrH7XN8FRXMHKtISKJLzHuwjhAp/Uz23nkMWi//fE3H543Xe0h/MyE7S+QyhLJ2P/AhZjk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1737993003; c=relaxed/simple; bh=WsmGRUjjTHT3CiTabuC2/y4wst/4dH2hoZwyXVSsytI=; h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:From:To; b=Ayzt361OqHfHqTaWKpIbh3+VCIy964xsC3gl+eHUvCjp6N7RFHTQ8DIJz/2Z0F1dg7t1bybc+Xlu1Jl0Z0dkxRFPz8tYm32bsvlANUKIzrZlmc0Fwq96Q9zs6vjtyNqIhAUV2LnBUCJhudL+k7/HrWEkPUySwTRcxFXWPvCogg8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E8A513858289 Received: by mail-ed1-x52f.google.com with SMTP id 4fb4d7f45d1cf-5da135d3162so7461576a12.3 for <binutils@sourceware.org>; Mon, 27 Jan 2025 07:50:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=google; t=1737993001; x=1738597801; darn=sourceware.org; h=content-transfer-encoding:in-reply-to:autocrypt:cc:content-language :references:to:from:subject:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=zeVmTGNwo/TeNLgQS4mMLNkL8IRtPfYHGdYqUmFG7gU=; b=dv6sY8prQfAY7M2Zxpio8pMWRYxLlP2PRnbs8VjD8x1pXizChlztxlqnOSDbd96fN/ rCPUhdQx4ozaHWLkAwourom5MJoawe0WV2pYgkhvMslD6v9Pj2K8k2nmuyIlSyK30sF5 1VckQUcDuCyl7CzYpgrUC3+K7hF4V1iBfbmpEtV9NfAb92HTNDO/ULrFOaPXT2HYXOe8 mPD3PoqJYehIVmd6DmBhnXf2xTjWGlEqrGDQDZUm++FBkyE4b7XA6PqzmbIK0NWdx2ZG 4M2/8l4Wm0vajAijYyX90wFcYLLiTCZ9AHilh0zhazCnAr96in4gI2oi0fz3cXI689iy 8JUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737993001; x=1738597801; h=content-transfer-encoding:in-reply-to:autocrypt:cc:content-language :references:to:from:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=zeVmTGNwo/TeNLgQS4mMLNkL8IRtPfYHGdYqUmFG7gU=; b=jiGkye20JudFBJuvtOl7GNPMc+4QrhlFn6JR2Vf0TKMOWXY6myaho/hnKVVSS5krWs t+ssT7SkNmo8Uh5PbtluolW2K+GZv47ZmlC4GtGvofTINjYdxSgw06e+cwVwfNMzsp6g 4Y8ng29cixWZpkEn8yCL4PAP0vV9u0Mo97OgHyUuss4j+dKWZgGKp35Q+9ZoI0O0STdQ C7vrLlWtWVcY0x4by0eoaDPdGn81j0G88sOpU5Qxjk4vN3uqdVUdndv+aRvWKkfeLXmD bcsKZHJqjdsQasRfGymjNhIwxjHVIauUa6eSZ7SEurj59GMs5sPQ0Xoa2XSuyMyj4bg1 gbGQ== X-Gm-Message-State: AOJu0Yy8d60Aye1xpxtPS+6iA0jsMd5H0761ZjB2S3pDktZlCYl5SO62 xl+K4wXbE1lkqe5XzrCQei+fYCUsJuTlPYNru4DaJ2yHbKgeuDAtb8gkZNDTbP03qhQeZpBa5DA = X-Gm-Gg: ASbGnct9KffIQZDhbVjj1Q5urqZ/ADvJUv3V2eAx/lglzq5mjjXVKAOkL0Qc9ORn1t9 HSlINwV2hwSx/kO2LKx/XcEq7Kqi5aPWrkiYpflUsESzONlVZS+rBwAaEDyCzJRGTAqZk17iU4o 10qkiSTOLxDGaazNx57/KW2ohsz6+pbWqilXAU8+/V2XOF5Ghk56kjuRmYem4BV8d5aRRbo1yq0 9AxvthzZLkR26GRPoOmwwcv0DnvBf98l0RU0+pkTCkKT5W/yBhj6IQXeaeVaG/v3Nmp2YdxuUxz ll3z3DKHgo6pJA7OfqrwAwJPFco7IWFFvEjpL1ADIjh7C6jR/M0om3yPAtHiS5qyuA== X-Google-Smtp-Source: AGHT+IEDoIxEqpY5gdO0URE21Gqq0+ePPStSgKL8kBqTtAClKCMwT1qHNV29sNN/lHv5+AjpSGWlOg== X-Received: by 2002:a05:6402:3551:b0:5d1:1f1:a283 with SMTP id 4fb4d7f45d1cf-5db7d2dc3f1mr36856802a12.4.1737993001057; Mon, 27 Jan 2025 07:50:01 -0800 (PST) Received: from [10.156.60.236] (ip-037-024-206-209.um08.pools.vodafone-ip.de. [37.24.206.209]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5dc2ea16e7asm3138272a12.42.2025.01.27.07.50.00 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 27 Jan 2025 07:50:00 -0800 (PST) Message-ID: <83414a2b-bfad-4381-8903-152ec0552e88@suse.com> Date: Mon, 27 Jan 2025 16:50:00 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: [PATCH v2 05/65] Arm: use is_whitespace() From: Jan Beulich <jbeulich@suse.com> To: Binutils <binutils@sourceware.org> References: <2316ac5c-7870-4b46-9c80-eaecaef93a31@suse.com> Content-Language: en-US Cc: Nick Clifton <nickc@redhat.com>, "ramana.radhakrishnan@arm.com" <ramana.radhakrishnan@arm.com>, Richard Earnshaw <rearnsha@arm.com> Autocrypt: addr=jbeulich@suse.com; keydata= xsDiBFk3nEQRBADAEaSw6zC/EJkiwGPXbWtPxl2xCdSoeepS07jW8UgcHNurfHvUzogEq5xk hu507c3BarVjyWCJOylMNR98Yd8VqD9UfmX0Hb8/BrA+Hl6/DB/eqGptrf4BSRwcZQM32aZK 7Pj2XbGWIUrZrd70x1eAP9QE3P79Y2oLrsCgbZJfEwCgvz9JjGmQqQkRiTVzlZVCJYcyGGsD /0tbFCzD2h20ahe8rC1gbb3K3qk+LpBtvjBu1RY9drYk0NymiGbJWZgab6t1jM7sk2vuf0Py O9Hf9XBmK0uE9IgMaiCpc32XV9oASz6UJebwkX+zF2jG5I1BfnO9g7KlotcA/v5ClMjgo6Gl MDY4HxoSRu3i1cqqSDtVlt+AOVBJBACrZcnHAUSuCXBPy0jOlBhxPqRWv6ND4c9PH1xjQ3NP nxJuMBS8rnNg22uyfAgmBKNLpLgAGVRMZGaGoJObGf72s6TeIqKJo/LtggAS9qAUiuKVnygo 3wjfkS9A3DRO+SpU7JqWdsveeIQyeyEJ/8PTowmSQLakF+3fote9ybzd880fSmFuIEJldWxp Y2ggPGpiZXVsaWNoQHN1c2UuY29tPsJgBBMRAgAgBQJZN5xEAhsDBgsJCAcDAgQVAggDBBYC AwECHgECF4AACgkQoDSui/t3IH4J+wCfQ5jHdEjCRHj23O/5ttg9r9OIruwAn3103WUITZee e7Sbg12UgcQ5lv7SzsFNBFk3nEQQCACCuTjCjFOUdi5Nm244F+78kLghRcin/awv+IrTcIWF hUpSs1Y91iQQ7KItirz5uwCPlwejSJDQJLIS+QtJHaXDXeV6NI0Uef1hP20+y8qydDiVkv6l IreXjTb7DvksRgJNvCkWtYnlS3mYvQ9NzS9PhyALWbXnH6sIJd2O9lKS1Mrfq+y0IXCP10eS FFGg+Av3IQeFatkJAyju0PPthyTqxSI4lZYuJVPknzgaeuJv/2NccrPvmeDg6Coe7ZIeQ8Yj t0ARxu2xytAkkLCel1Lz1WLmwLstV30g80nkgZf/wr+/BXJW/oIvRlonUkxv+IbBM3dX2OV8 AmRv1ySWPTP7AAMFB/9PQK/VtlNUJvg8GXj9ootzrteGfVZVVT4XBJkfwBcpC/XcPzldjv+3 HYudvpdNK3lLujXeA5fLOH+Z/G9WBc5pFVSMocI71I8bT8lIAzreg0WvkWg5V2WZsUMlnDL9 mpwIGFhlbM3gfDMs7MPMu8YQRFVdUvtSpaAs8OFfGQ0ia3LGZcjA6Ik2+xcqscEJzNH+qh8V m5jjp28yZgaqTaRbg3M/+MTbMpicpZuqF4rnB0AQD12/3BNWDR6bmh+EkYSMcEIpQmBM51qM EKYTQGybRCjpnKHGOxG0rfFY1085mBDZCH5Kx0cl0HVJuQKC+dV2ZY5AqjcKwAxpE75MLFkr wkkEGBECAAkFAlk3nEQCGwwACgkQoDSui/t3IH7nnwCfcJWUDUFKdCsBH/E5d+0ZnMQi+G0A nAuWpQkjM1ASeQwSHEeAWPgskBQL In-Reply-To: <2316ac5c-7870-4b46-9c80-eaecaef93a31@suse.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-3022.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list <binutils.sourceware.org> List-Unsubscribe: <https://sourceware.org/mailman/options/binutils>, <mailto:binutils-request@sourceware.org?subject=unsubscribe> List-Archive: <https://sourceware.org/pipermail/binutils/> List-Post: <mailto:binutils@sourceware.org> List-Help: <mailto:binutils-request@sourceware.org?subject=help> List-Subscribe: <https://sourceware.org/mailman/listinfo/binutils>, <mailto:binutils-request@sourceware.org?subject=subscribe> Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org |
Series |
gas: whitespace handling
|
|
Commit Message
Jan Beulich
Jan. 27, 2025, 3:50 p.m. UTC
Wherever blanks are permissible in input, tabs ought to be permissible, too. This is particularly relevant when -f is passed to gas (alongside appropriate input). At the same time use is_end_of_stmt() instead of an open-coded nul char check. In parse_neon_type() be more aggressive and remove the special casing of certain characters altogether. The original default case simply having "break" can't have been correct. --- I don't think I see why parse_qfloat_immediate() checks for '\n'. If that was needed, "line" (really: statement) separators would need checking for, too. Yet an easy experiment demonstrates that this case is working correctly despite the lack of a check for ';'. The check for "0x" in parse_qfloat_immediate() seems fishy, too: If it was actually needed, "0X" would apparently also checking form. Yet again experimentally that's properly refused anyway, by atof_ieee() I guess. While for parse_neon_type() the change improves the handling of this set of (bad) examples (including the case of passing -f to gas): vcvt.bf016.f32 d0, q0 vcvt.bf16.f032 d0, q0 vcvt.b16.f32 d0, q0 vcvt.b f16.f32 d0, q0 vcvt.bf 16.f32 d0, q0 vcvt.bf16.f 32 d0, q0 vcvt.b f16.f32 d0, q0 vcvt.b 16.f32 d0, q0 vcvt.b 32.f32 d0, q0 vcvt.bf 16.f32 d0, q0 several are left which imo also ought to be rejected. Yet that will want sorting separately. --- v2: Also replace ISSPACE().
Comments
On 27/01/2025 15:50, Jan Beulich wrote: > Wherever blanks are permissible in input, tabs ought to be permissible, > too. This is particularly relevant when -f is passed to gas (alongside > appropriate input). At the same time use is_end_of_stmt() instead of an > open-coded nul char check. > > In parse_neon_type() be more aggressive and remove the special casing of > certain characters altogether. The original default case simply having > "break" can't have been correct. > --- > I don't think I see why parse_qfloat_immediate() checks for '\n'. If > that was needed, "line" (really: statement) separators would need > checking for, too. Yet an easy experiment demonstrates that this case is > working correctly despite the lack of a check for ';'. > > The check for "0x" in parse_qfloat_immediate() seems fishy, too: If it > was actually needed, "0X" would apparently also checking form. Yet again > experimentally that's properly refused anyway, by atof_ieee() I guess. > > While for parse_neon_type() the change improves the handling of this set > of (bad) examples (including the case of passing -f to gas): > > vcvt.bf016.f32 d0, q0 > vcvt.bf16.f032 d0, q0 > vcvt.b16.f32 d0, q0 > vcvt.b f16.f32 d0, q0 > vcvt.bf 16.f32 d0, q0 > vcvt.bf16.f 32 d0, q0 > vcvt.b f16.f32 d0, q0 > vcvt.b 16.f32 d0, q0 > vcvt.b 32.f32 d0, q0 > vcvt.bf 16.f32 d0, q0 > > several are left which imo also ought to be rejected. Yet that will want > sorting separately. > --- > v2: Also replace ISSPACE(). > > --- a/gas/config/tc-arm.c > +++ b/gas/config/tc-arm.c > @@ -1081,7 +1081,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXeEpP > > /* Separator character handling. */ > > -#define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0) > +#define skip_whitespace(str) do { if (is_whitespace (*(str))) ++(str); } while (0) > > enum fp_16bit_format > { > @@ -1510,13 +1510,9 @@ parse_neon_type (struct neon_type *type, > return FAIL; > } > goto done; > - case '0': case '1': case '2': case '3': case '4': > - case '5': case '6': case '7': case '8': case '9': > - case ' ': case '.': > + default: > as_bad (_("unexpected type character `b' -- did you mean `bf'?")); > return FAIL; > - default: > - break; > } This entire switch statement has now degenerated into 'f' or error. So I think it would be better to just replace it with an if-else. > break; > default: > @@ -5055,7 +5051,8 @@ set_fp16_format (int dummy ATTRIBUTE_UNU > new_format = ARM_FP16_FORMAT_DEFAULT; > > name = input_line_pointer; > - while (*input_line_pointer && !ISSPACE (*input_line_pointer)) > + while (!is_end_of_stmt (*input_line_pointer) > + && !is_whitespace (*input_line_pointer)) > input_line_pointer++; > > saved_char = *input_line_pointer; > @@ -5366,7 +5363,7 @@ parse_qfloat_immediate (char **ccp, int > return FAIL; > else > { > - for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++) > + for (; *fpnum != '\0' && !is_whitespace (*fpnum) && *fpnum != '\n'; fpnum++) > if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E') > { > found_fpchar = 1; > @@ -22450,7 +22447,7 @@ opcode_lookup (char **str) > /* Scan up to the end of the mnemonic, which must end in white space, > '.' (in unified mode, or for Neon/VFP instructions), or end of string. */ > for (base = end = *str; *end != '\0'; end++) > - if (*end == ' ' || *end == '.') > + if (is_whitespace (*end) || *end == '.') > break; > > if (end == base) > @@ -22481,7 +22478,7 @@ opcode_lookup (char **str) > if (parse_neon_type (&inst.vectype, str) == FAIL) > return NULL; > } > - else if (end[offset] != '\0' && end[offset] != ' ') > + else if (end[offset] != '\0' && !is_whitespace (end[offset])) > return NULL; > } > else > OK with that change. R.
On 27.01.2025 17:31, Richard Earnshaw (lists) wrote: > On 27/01/2025 15:50, Jan Beulich wrote: >> --- a/gas/config/tc-arm.c >> +++ b/gas/config/tc-arm.c >> @@ -1081,7 +1081,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXeEpP >> >> /* Separator character handling. */ >> >> -#define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0) >> +#define skip_whitespace(str) do { if (is_whitespace (*(str))) ++(str); } while (0) >> >> enum fp_16bit_format >> { >> @@ -1510,13 +1510,9 @@ parse_neon_type (struct neon_type *type, >> return FAIL; >> } >> goto done; >> - case '0': case '1': case '2': case '3': case '4': >> - case '5': case '6': case '7': case '8': case '9': >> - case ' ': case '.': >> + default: >> as_bad (_("unexpected type character `b' -- did you mean `bf'?")); >> return FAIL; >> - default: >> - break; >> } > > This entire switch statement has now degenerated into 'f' or error. So I think it would be better to just replace it with an if-else. I can do that, but in other projects I'm active we'd deliberately ask that switch() be used simply in the expectation that if any further character would want checking for, code churn would then be lower. If you're fine with the extra churn, I can of course adjust here. Jan
On 27/01/2025 16:55, Jan Beulich wrote: > On 27.01.2025 17:31, Richard Earnshaw (lists) wrote: >> On 27/01/2025 15:50, Jan Beulich wrote: >>> --- a/gas/config/tc-arm.c >>> +++ b/gas/config/tc-arm.c >>> @@ -1081,7 +1081,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXeEpP >>> >>> /* Separator character handling. */ >>> >>> -#define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0) >>> +#define skip_whitespace(str) do { if (is_whitespace (*(str))) ++(str); } while (0) >>> >>> enum fp_16bit_format >>> { >>> @@ -1510,13 +1510,9 @@ parse_neon_type (struct neon_type *type, >>> return FAIL; >>> } >>> goto done; >>> - case '0': case '1': case '2': case '3': case '4': >>> - case '5': case '6': case '7': case '8': case '9': >>> - case ' ': case '.': >>> + default: >>> as_bad (_("unexpected type character `b' -- did you mean `bf'?")); >>> return FAIL; >>> - default: >>> - break; >>> } >> >> This entire switch statement has now degenerated into 'f' or error. So I think it would be better to just replace it with an if-else. > > I can do that, but in other projects I'm active we'd deliberately ask > that switch() be used simply in the expectation that if any further > character would want checking for, code churn would then be lower. If > you're fine with the extra churn, I can of course adjust here. > > Jan Never say never, but I can't see other characters being needed here. I'll take that hit if it's needed at some point in the future. Note, we already don't handle this when parsing the numbers after an 'f', so we're not consistent anyway. I don't particularly like the error recovery here anyway, but that's another story. Printing "unexpected type character `b' -- did you mean `bf'?" is not exactly informative when there's so little context shown: it's not even as though 'bf' is the complete answer, the type is 'bf16'; but to do this even close to properly we'd need to tokenize the input and print the entire substring up to the next token separator. R.
--- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -1081,7 +1081,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXeEpP /* Separator character handling. */ -#define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0) +#define skip_whitespace(str) do { if (is_whitespace (*(str))) ++(str); } while (0) enum fp_16bit_format { @@ -1510,13 +1510,9 @@ parse_neon_type (struct neon_type *type, return FAIL; } goto done; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case ' ': case '.': + default: as_bad (_("unexpected type character `b' -- did you mean `bf'?")); return FAIL; - default: - break; } break; default: @@ -5055,7 +5051,8 @@ set_fp16_format (int dummy ATTRIBUTE_UNU new_format = ARM_FP16_FORMAT_DEFAULT; name = input_line_pointer; - while (*input_line_pointer && !ISSPACE (*input_line_pointer)) + while (!is_end_of_stmt (*input_line_pointer) + && !is_whitespace (*input_line_pointer)) input_line_pointer++; saved_char = *input_line_pointer; @@ -5366,7 +5363,7 @@ parse_qfloat_immediate (char **ccp, int return FAIL; else { - for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++) + for (; *fpnum != '\0' && !is_whitespace (*fpnum) && *fpnum != '\n'; fpnum++) if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E') { found_fpchar = 1; @@ -22450,7 +22447,7 @@ opcode_lookup (char **str) /* Scan up to the end of the mnemonic, which must end in white space, '.' (in unified mode, or for Neon/VFP instructions), or end of string. */ for (base = end = *str; *end != '\0'; end++) - if (*end == ' ' || *end == '.') + if (is_whitespace (*end) || *end == '.') break; if (end == base) @@ -22481,7 +22478,7 @@ opcode_lookup (char **str) if (parse_neon_type (&inst.vectype, str) == FAIL) return NULL; } - else if (end[offset] != '\0' && end[offset] != ' ') + else if (end[offset] != '\0' && !is_whitespace (end[offset])) return NULL; } else