nasmlib: move filename_set_extension() into path.c

Move filename_set_extension() into path.c, so it has access to the
filesystem-specific character constants. This prevents something like:

	nasm-code.d/foobar

... from getting truncated to ...

	nasm-code.bin

... instead of producing ...

	nasm-code.d/foobar.bin

Make the extension character (normally '.') configurable; this MIGHT
be usable on RISCOS at some point, although it is not entirely clear
that trying to make sense of RISCOS paths actually is meaningful,
because RISCOS compiler chains seem to do all kinds of path
translation magic trying to behave like other operating systems... it
might simply be more trouble than it is worth, especially for a
non-x86 platform.

As a side bonus, this removes the only use of strrchrnul(), so that
function can be dropped.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel) 2025-12-15 09:52:13 -08:00
parent 795daf3d2d
commit ff7a315acb
8 changed files with 64 additions and 76 deletions

View File

@ -149,14 +149,14 @@ ZLIBOBJ = \
# Common library objects
LIBOBJ_COM = \
stdlib/snprintf.$(O) stdlib/vsnprintf.$(O) stdlib/strlcpy.$(O) \
stdlib/strnlen.$(O) stdlib/strrchrnul.$(O) \
stdlib/strnlen.$(O) \
\
nasmlib/ver.$(O) \
nasmlib/alloc.$(O) nasmlib/asprintf.$(O) \
nasmlib/crc32b.$(O) nasmlib/crc64.$(O) nasmlib/md5c.$(O) \
nasmlib/string.$(O) nasmlib/nctype.$(O) \
nasmlib/file.$(O) nasmlib/fileio.$(O) nasmlib/mmap.$(O) \
nasmlib/realpath.$(O) nasmlib/path.$(O) nasmlib/filename.$(O) \
nasmlib/realpath.$(O) nasmlib/path.$(O) \
nasmlib/ilog2.$(O) nasmlib/numstr.$(O) \
nasmlib/rlimit.$(O) \
nasmlib/zerobuf.$(O) nasmlib/bsi.$(O) \

View File

@ -100,14 +100,14 @@ ZLIBOBJ = \
# Common library objects
LIBOBJ_COM = \
stdlib\snprintf.obj stdlib\vsnprintf.obj stdlib\strlcpy.obj \
stdlib\strnlen.obj stdlib\strrchrnul.obj \
stdlib\strnlen.obj \
\
nasmlib\ver.obj \
nasmlib\alloc.obj nasmlib\asprintf.obj \
nasmlib\crc32b.obj nasmlib\crc64.obj nasmlib\md5c.obj \
nasmlib\string.obj nasmlib\nctype.obj \
nasmlib\file.obj nasmlib\fileio.obj nasmlib\mmap.obj \
nasmlib\realpath.obj nasmlib\path.obj nasmlib\filename.obj \
nasmlib\realpath.obj nasmlib\path.obj \
nasmlib\ilog2.obj nasmlib\numstr.obj \
nasmlib\rlimit.obj \
nasmlib\zerobuf.obj nasmlib\bsi.obj \

View File

@ -86,14 +86,14 @@ ZLIBOBJ = &
# Common library objects
LIBOBJ_COM = &
stdlib\snprintf.obj stdlib\vsnprintf.obj stdlib\strlcpy.obj &
stdlib\strnlen.obj stdlib\strrchrnul.obj &
stdlib\strnlen.obj &
&
nasmlib\ver.obj &
nasmlib\alloc.obj nasmlib\asprintf.obj &
nasmlib\crc32b.obj nasmlib\crc64.obj nasmlib\md5c.obj &
nasmlib\string.obj nasmlib\nctype.obj &
nasmlib\file.obj nasmlib\fileio.obj nasmlib\mmap.obj &
nasmlib\realpath.obj nasmlib\path.obj nasmlib\filename.obj &
nasmlib\realpath.obj nasmlib\path.obj &
nasmlib\ilog2.obj nasmlib\numstr.obj &
nasmlib\rlimit.obj &
nasmlib\zerobuf.obj nasmlib\bsi.obj &

View File

@ -197,7 +197,6 @@ AC_CHECK_FUNCS(strcasecmp stricmp)
AC_CHECK_FUNCS(strncasecmp strnicmp)
AC_CHECK_FUNCS(strsep)
AC_CHECK_FUNCS(strnlen)
AC_CHECK_FUNCS(strrchrnul)
AC_CHECK_FUNCS(iscntrl)
AC_CHECK_FUNCS(isascii)
AC_CHECK_FUNCS(mempcpy)
@ -229,7 +228,6 @@ PA_HAVE_FUNC(__builtin_unreachable,())
PA_FUNC_SNPRINTF
PA_FUNC_VSNPRINTF
AC_CHECK_FUNCS([strlcpy])
AC_CHECK_FUNCS([strrchrnul])
dnl These types are POSIX-specific, and Windows does it differently...
AC_CHECK_TYPES([struct stat], [AC_CHECK_FUNCS([stat fstat])])
@ -246,7 +244,6 @@ AC_CHECK_DECLS(strnicmp)
AC_CHECK_DECLS(strsep)
AC_CHECK_DECLS(strlcpy)
AC_CHECK_DECLS(strnlen)
AC_CHECK_DECLS(strrchrnul)
dnl Check for missing types
AC_TYPE_UINTMAX_T

View File

@ -177,10 +177,6 @@ int vsnprintf(char *, size_t, const char *, va_list);
size_t strlcpy(char *, const char *, size_t);
#endif
#if !defined(HAVE_STRCHRNUL) || !HAVE_DECL_STRCHRNUL
char * pure_func strrchrnul(const char *, int);
#endif
/* C++ and C23 have bool, false, and true as proper keywords */
#if !defined(__cplusplus) && (__STDC_VERSION__ < 202311L)
# ifdef HAVE_STDBOOL_H

View File

@ -1,33 +0,0 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2017 The NASM Authors - All Rights Reserved */
/*
* nasmlib.c library routines for the Netwide Assembler
*/
#include "compiler.h"
#include "nasmlib.h"
#include "error.h"
/*
* Add/modify a filename extension, assumed to be a period-delimited
* field at the very end of the filename. Returns a newly allocated
* string buffer.
*/
const char *filename_set_extension(const char *inname, const char *extension)
{
const char *q = inname;
char *p;
size_t elen = strlen(extension);
size_t baselen;
q = strrchrnul(inname, '.'); /* find extension or end of string */
baselen = q - inname;
p = nasm_malloc(baselen + elen + 1);
memcpy(p, inname, baselen);
memcpy(p+baselen, extension, elen+1);
return p;
}

View File

@ -69,37 +69,39 @@
# define leaveonclean 0
# define leave_leading 1
#elif PATHSTYLE == PATH_VMS
/*
* VMS filenames may have ;version at the end. Assume we should count that
* as part of the filename anyway.
*/
# define separators ":]"
# define curdir "[]"
# define postext ";"
#else
/* No idea what to do here, do nothing. Feel free to add new ones. */
# define curdir ""
#endif
#ifndef extsep
# define extsep '.'
#endif
/*
* This is an inline, because most compilers can greatly simplify this
* for a fixed string, like we have here.
*/
static inline bool pure_func ismatch(const char *charset, char ch)
{
const char *p;
for (p = charset; *p; p++) {
if (ch == *p)
return true;
if (charset && *charset) {
const char *p;
for (p = charset; *p; p++) {
if (ch == *p)
return true;
}
}
return false;
}
static const char * pure_func first_filename_char(const char *path)
static inline const char * pure_func first_filename_char(const char *path)
{
#ifdef separators
const char *p = path + strlen(path);
const char *p = strchr(path, '\0');
while (p > path) {
if (ismatch(separators, p[-1]))
@ -178,3 +180,48 @@ char *nasm_catfile(const char *dir, const char *file)
return p;
#endif
}
/*
* Add/modify a filename extension. Returns a newly allocated
* string buffer. If the extension is not an empty string, the first
* character is replaced by the appropriate extsep for the filesystem.
*/
const char *filename_set_extension(const char *inname, const char *extension)
{
const char *nulp, *ep, *p;
char *outname, *q;
size_t elen = strlen(extension);
size_t baselen;
ep = nulp = strchr(inname, '\0');
for (p = nulp-1; p >= inname; p--) {
char c = *p;
if (c == extsep) {
/* Found the beginning of an existing extension */
ep = p;
break;
}
if (ismatch(separators, c)) {
/* Found the beginning of the file name */
ep = p+1;
break;
}
#ifdef postext
if (ismatch(postext, c)) {
/* Found the beginning of a character sequence
that should be stripped off; keep searching from here */
ep = p;
continue;
}
#endif
}
baselen = ep - inname;
q = outname = nasm_malloc(baselen + elen + 1);
q = mempcpy(q, inname, baselen);
if (*extension)
*q++ = extsep;
memcpy(q, extension+1, elen);
return outname;
}

View File

@ -1,19 +0,0 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 2017 The NASM Authors - All Rights Reserved */
#include "compiler.h"
#ifndef HAVE_STRRCHRNUL
char * pure_func strrchrnul(const char *s, int c)
{
char *p;
p = strrchr(s, c);
if (!p)
p = strchr(s, '\0');
return p;
}
#endif