mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Sergey Dmitrouk <sdmitrouk@accesssoftek.com>
To: <musl@lists.openwall.com>
Subject: [PATCH] conforming strverscmp() implementation
Date: Tue, 3 Mar 2015 12:45:07 +0200	[thread overview]
Message-ID: <20150303104507.GA5094@zx-spectrum> (raw)

[-- Attachment #1: Type: text/plain, Size: 984 bytes --]

Hi,

Attached is strverscmp() that should conform to what is described in
manual pages.  It's not actually a diff as it would be harder to read
in this case.

The idea is just as described in manuals (once you get what they mean):

1. Find point where strings differ as in current code, but keep track
   of locations of last seen numbers.
2. If numbers are both integers (that is they don't start with zero or
   it's a single zero) compare as in current implementation.
3. If only one of numbers is integer, the other one is smaller.
4. Otherwise, number with longer leading sequence of zeroes is smaller.
5. If leading zeroes match, compare characters following last zero in
   both strings.

I didn't see much comments in musl, so there is none in this file, but
can add some if requested.

Implementation is admittedly more sophisticated than current version for
the reason that all simpler approaches I tried fail for at least one of
possible comparison cases.

Regards,
Sergey

[-- Attachment #2: strverscmp.c --]
[-- Type: text/plain, Size: 1030 bytes --]

#define _GNU_SOURCE
#include <ctype.h>
#include <string.h>

int strverscmp(const char *l, const char *r)
{
	const char *ln=(isdigit(*l) ? l : NULL), *rn=(isdigit(*r) ? r : NULL);
	while (*l==*r) {
		if (!*l) return 0;

		if (isdigit(*l)) {
			if (ln == NULL) {
				ln = l; rn = r;
			}
		} else {
			ln = NULL; rn = NULL;
		}

		l++; r++;
	}

	if ((*l != '\0' && !isdigit(*l)) || (*r != '\0' && !isdigit(*r))) {
		ln = NULL; rn = NULL;
	}

	if (ln != NULL) {
		int intl=(*ln != '0' || !isdigit(*(ln + 1)));
		int intr=(*rn != '0' || !isdigit(*(rn + 1)));

		if (intl ^ intr) {
			return intl ? 1 : -1;
		} else if (intl) {
			size_t lenl=0, lenr=0;
			while (isdigit(l[lenl])) lenl++;
			while (isdigit(r[lenr])) lenr++;
			if (lenl==lenr) {
				return (*l - *r);
			} else if (lenl>lenr) {
				return 1;
			} else {
				return -1;
			}
		} else {
			size_t zl=0, zr=0;
			while (ln[zl]=='0') zl++;
			while (rn[zr]=='0') zr++;
			if (zl>zr) {
				return -1;
			} else if (zl<zr) {
				return 1;
			}
		}
	}

	return (*l - *r);
}

             reply	other threads:[~2015-03-03 10:45 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-03 10:45 Sergey Dmitrouk [this message]
2015-03-03 15:54 ` Rich Felker
2015-03-03 19:27   ` Sergey Dmitrouk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150303104507.GA5094@zx-spectrum \
    --to=sdmitrouk@accesssoftek.com \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).