Skip to content

Commit

Permalink
Eliminate all uses of strcasecmp()
Browse files Browse the repository at this point in the history
There weren't many uses and most can be done more efficiently.
  • Loading branch information
ojwb committed Mar 6, 2024
1 parent 14000ea commit a901cea
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 123 deletions.
29 changes: 1 addition & 28 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -244,40 +244,13 @@ dnl lround() with AC_CHECK_FUNCS, which just checks if it can be linked
dnl against. Some platforms are missing a prototype for lround(), so
dnl both checks are useful.
AC_CHECK_DECLS([lround], [], [], [[#include <math.h>]])
dnl check for strcasecmp here as well as below - this one is to get
dnl HAVE_STRCASECMP defined if appropriate (for img.c)
AC_CHECK_FUNCS([popen getpwuid lround strcasecmp hypot mmap])
AC_CHECK_FUNCS([popen getpwuid lround hypot mmap])

dnl Much faster than using getc()/putc(), at least on Linux.
AC_CHECK_FUNCS([getc_unlocked putc_unlocked])

AC_CHECK_FUNCS([setenv unsetenv])

dnl try to find a case-insensitive compare

strcasecmp=no
dnl The order of these tests is important.
AC_CHECK_FUNC(strcasecmp, [strcasecmp=strcasecmp])
if test no = "$strcasecmp"; then
AC_CHECK_FUNC(stricmp, [strcasecmp=stricmp])
fi
if test no = "$strcasecmp"; then
AC_CHECK_FUNC(strcmpi, [strcasecmp=strcmpi])
fi

AC_MSG_CHECKING([how to compare strings ignoring case])
case $strcasecmp in
no)
AC_LIBOBJ(strcasecmp)
AC_MSG_RESULT([using own implementation of strcasecmp]) ;;
strcasecmp)
AC_MSG_RESULT([strcasecmp]) ;;
*)
AC_DEFINE_UNQUOTED(strcasecmp, "$strcasecmp",
[strcasecmp define for systems which call it something else])
AC_MSG_RESULT([$strcasecmp]) ;;
esac

AC_PATH_PROG([JW], [jw], [$MISSING jw])
AC_ARG_VAR([JW], [jw from docbook-utils/docbook-tools])

Expand Down
33 changes: 18 additions & 15 deletions src/datain.c
Original file line number Diff line number Diff line change
Expand Up @@ -591,10 +591,6 @@ nextch_handling_eol(void)
}
}

#define LITLEN(S) (sizeof(S"") - 1)
#define has_ext(F,L,E) ((L) > LITLEN(E) + 1 &&\
(F)[(L) - LITLEN(E) - 1] == FNM_SEP_EXT &&\
strcasecmp((F) + (L) - LITLEN(E), E) == 0)
extern void
data_file(const char *pth, const char *fnm)
{
Expand All @@ -620,17 +616,24 @@ data_file(const char *pth, const char *fnm)
}

len = strlen(filename);
// Compass .clp is the same format as .dat, but contains loop-closed
// data. This might be useful to read if you want to keep existing
// stations at the same adjusted positions, for example to be able to
// draw extensions on an existing drawn-up survey. Or if you managed
// to lose the original .dat but still have the .clp.
if (has_ext(filename, len, "dat")) {
fmt = FMT_DAT;
} else if (has_ext(filename, len, "clp")) {
fmt = FMT_CLP;
} else if (has_ext(filename, len, "mak")) {
fmt = FMT_MAK;
if (len > 4 && filename[len - 4] == FNM_SEP_EXT) {
char ext[3];
for (int i = 0; i <3; ++i) {
ext[i] = tolower((unsigned char)filename[len - 3 + i]);
}
// Compass .clp is the same format as .dat, but contains
// loop-closed data. This might be useful to read if you want to
// keep existing stations at the same adjusted positions, for
// example to be able to draw extensions on an existing drawn-up
// survey. Or if you managed to lose the original .dat but still
// have the .clp.
if (memcmp(ext, "dat", 3) == 0) {
fmt = FMT_DAT;
} else if (memcmp(ext, "clp", 3) == 0) {
fmt = FMT_CLP;
} else if (memcmp(ext, "mak", 3) == 0) {
fmt = FMT_MAK;
}
}

file_store = file;
Expand Down
81 changes: 37 additions & 44 deletions src/img.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
# endif
# define TIMEFMT "%a,%Y.%m.%d %H:%M:%S %Z"
# define EXT_SVX_3D "3d"
# define EXT_SVX_POS "pos"
# define FNM_SEP_EXT '.'
# define METRES_PER_FOOT 0.3048 /* exact value */
# define xosmalloc(L) malloc((L))
Expand Down Expand Up @@ -273,29 +272,14 @@ my_lround(double x) {
}
#endif

/* portable case insensitive string compare */
#if defined(strcasecmp) || defined(HAVE_STRCASECMP)
# define my_strcasecmp strcasecmp
#else
static int my_strcasecmp(const char *s1, const char *s2) {
unsigned char c1, c2;
do {
c1 = *s1++;
c2 = *s2++;
} while (c1 && toupper(c1) == toupper(c2));
/* now calculate real difference */
return c1 - c2;
}
#endif

unsigned int img_output_version = IMG_VERSION_MAX;

static img_errcode img_errno = IMG_NONE;

#define FILEID "Survex 3D Image File"

#define EXT_PLT "plt"
#define EXT_PLF "plf"
/* Encode extension into integer for fast testing. */
#define EXT3(C1, C2, C3) (((C3) << 16) | ((C2) << 8) | (C1))

/* Attempt to string paste to ensure we are passed a literal string */
#define LITLEN(S) (sizeof(S"") - 1)
Expand Down Expand Up @@ -559,10 +543,6 @@ buf_included(img *pimg, const char *buf, size_t len)
return pimg->survey_len == len && memcmp(buf, pimg->survey, len) == 0;
}

#define has_ext(F,L,E) ((L) > LITLEN(E) + 1 &&\
(F)[(L) - LITLEN(E) - 1] == FNM_SEP_EXT &&\
my_strcasecmp((F) + (L) - LITLEN(E), E) == 0)

img *
img_open_survey(const char *fnm, const char *survey)
{
Expand Down Expand Up @@ -1059,6 +1039,7 @@ img_read_stream_survey(FILE *stream, int (*close_func)(FILE*),
size_t len;
char buf[LITLEN(FILEID) + 9];
int ch;
UINT32_T ext;

if (stream == NULL) {
img_errno = IMG_FILENOTFOUND;
Expand Down Expand Up @@ -1152,18 +1133,29 @@ img_read_stream_survey(FILE *stream, int (*close_func)(FILE*),
pimg->pending = 0;

len = strlen(fnm);
if (has_ext(fnm, len, EXT_SVX_POS)) {
pos_file:
pimg->version = VERSION_SURVEX_POS;
pimg->datestamp = my_strdup(TIMENA);
if (!pimg->datestamp) {
goto out_of_memory_error;
}
pimg->start = 0;
goto successful_return;
/* Currently only 3 character extensions are tested below. */
ext = 0;
if (len > 4 && fnm[len - 4] == '.') {
/* Read extension and pack into ext. */
int i;
for (i = 1; i < 4; ++i) {
unsigned char ext_ch = fnm[len - i];
ext = (ext << 8) | tolower(ext_ch);
}
}
switch (ext) {
case EXT3('p', 'o', 's'): /* Survex .pos */
pos_file:
pimg->version = VERSION_SURVEX_POS;
pimg->datestamp = my_strdup(TIMENA);
if (!pimg->datestamp) {
goto out_of_memory_error;
}
pimg->start = 0;
goto successful_return;

if (has_ext(fnm, len, EXT_PLT) || has_ext(fnm, len, EXT_PLF)) {
case EXT3('p', 'l', 't'): /* Compass .plt */
case EXT3('p', 'l', 'f'): /* Compass .plf */ {
int result;
plt_file:
result = compass_plt_open(pimg);
Expand All @@ -1172,18 +1164,18 @@ img_read_stream_survey(FILE *stream, int (*close_func)(FILE*),
goto error;
}
goto successful_return;
}

/* Although these are often referred to as "CMAP .XYZ files", it seems
* that actually, the extension .XYZ isn't used, rather .SHT (shot
* variant, produced by CMAP v16 and later), .UNA (unadjusted) and
* .ADJ (adjusted) extensions are. Since img has long checked for
* .XYZ, we continue to do so in case anyone is relying on it.
*/
if (has_ext(fnm, len, "sht") ||
has_ext(fnm, len, "adj") ||
has_ext(fnm, len, "una") ||
has_ext(fnm, len, "xyz")) {
}

/* Although these are often referred to as "CMAP .XYZ files", it seems
* that actually, the extension .XYZ isn't used, rather .SHT (shot
* variant, produced by CMAP v16 and later), .UNA (unadjusted) and .ADJ
* (adjusted) extensions are. Since img has long checked for .XYZ, we
* continue to do so in case anyone is relying on it.
*/
case EXT3('s', 'h', 't'): /* CMAP .sht */
case EXT3('a', 'd', 'j'): /* CMAP .adj */
case EXT3('u', 'n', 'a'): /* CMAP .una */
case EXT3('x', 'y', 'z'): /* CMAP .xyz */ {
int result;
xyz_file:
result = cmap_xyz_open(pimg);
Expand All @@ -1192,6 +1184,7 @@ img_read_stream_survey(FILE *stream, int (*close_func)(FILE*),
goto error;
}
goto successful_return;
}
}

if (fread(buf, LITLEN(FILEID) + 1, 1, pimg->fh) != 1 ||
Expand Down
3 changes: 0 additions & 3 deletions src/msvc/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
#endif

/* strcasecmp define for systems which call it something else */
#define strcasecmp stricmp

/* Define if you have the mktime function. */
#define HAVE_MKTIME 1

Expand Down
30 changes: 0 additions & 30 deletions src/strcasecmp.c

This file was deleted.

16 changes: 13 additions & 3 deletions src/survexport.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Convert a processed survey data file to another format.
*/

/* Copyright (C) 1994-2004,2008,2010,2011,2013,2014,2018,2020,2022 Olly Betts
/* Copyright (C) 1994-2024 Olly Betts
* Copyright (C) 2004 John Pybus (SVG Output code)
*
* This program is free software; you can redistribute it and/or modify
Expand All @@ -26,6 +26,7 @@

#define MSG_SETUP_PROJ_SEARCH_PATH 1

#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -63,7 +64,10 @@ main(int argc, char **argv)
{
/* Default to .pos output if installed as 3dtopos. */
char* progname = baseleaf_from_fnm(argv[0]);
if (strcasecmp(progname, "3dtopos") == 0) {
for (char * p = progname; *p; ++p) {
*p = tolower((unsigned char)*p);
}
if (strcmp(progname, "3dtopos") == 0) {
format = FMT_POS;
}
osfree(progname);
Expand Down Expand Up @@ -389,11 +393,17 @@ main(int argc, char **argv)
if (format == FMT_MAX_PLUS_ONE_) {
// Select format based on extension.
size_t len = strlen(fnm_out);
// Length of longest extension of interest.
constexpr size_t MAX_EXT_LEN = 4;
char ext[MAX_EXT_LEN + 2];
for (size_t i = 0; i < MAX_EXT_LEN + 2; ++i) {
ext[i] = tolower((unsigned char)fnm_out[len - (MAX_EXT_LEN + 1) + i]);
}
for (size_t i = 0; i < FMT_MAX_PLUS_ONE_; ++i) {
const auto& info = export_format_info[i];
size_t l = strlen(info.extension);
if (len > l + 1 &&
strcasecmp(fnm_out + len - l, info.extension) == 0) {
strcmp(ext + MAX_EXT_LEN + 1 - l, info.extension) == 0) {
format = export_format(i);
break;
}
Expand Down

0 comments on commit a901cea

Please sign in to comment.