www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 1393] New: Phobos needs strnlen()

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1393

           Summary: Phobos needs strnlen()
           Product: D
           Version: 1.015
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: Phobos
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: cdunn2001 gmail.com


std.c.string needs strnlen().  Here is why:

struct Person{
  char name[32];
  char addr[128];
};

A bunch of these could be stored on disk.  After loading, we want to compare
'name' to another array.  But how?  We can use strncmp(), but we need to know
the length of 'name'.  It is NOT 32.  We cannot use strlen() safely on 'name'
because it might not be null-terminated.

We need to do this:
---
int compare(char[] lhs, char[] rhs){
  char* lptr = cast(char*)lhs;
  char* rptr = cast(char*)rhs;
  ulong len_lhs = strnlen(lptr, lhs.length);
  ulong len_rhs = strnlen(rptr, rhs.length);
  int comp = std.c.string.strncmp(lptr, rptr, min!(uint)(len_lhs, len_rhs));
  if (comp) return comp;
  if (len_lhs < len_rhs) return -1;
  else if (len_lhs > len_rhs) return 1;
  else return 0;
}

bool foo(Person* p){
  return !compare(p.name, "Christopher");
}
---
Of course, std.string.strlen(char[] s) could also be useful.  It should return
the length to the first null, or s.length.  And my compare() function could be
there too.  But those are not critical.  strnlen() is.  If it's not there,
people will use strlen() and cause buffer overflows.

From the Linux man page:
------------------------
SYNOPSIS
       #include <string.h>

       size_t strnlen(const char *s, size_t maxlen);

DESCRIPTION
       The  strnlen  function  returns  the number of characters in the string
       pointed to by s, not including the terminating '\0' character,  but  at
       most  maxlen.  In  doing  this,  strnlen looks only at the first maxlen
       characters at s and never beyond s+maxlen.

RETURN VALUE
       The strnlen function returns strlen(s), if that is less than maxlen, or
       maxlen  if there is no '\0' character among the first maxlen characters
       pointed to by s.

CONFORMING TO
       This function is a GNU extension.
-----------

And here is a simple implementation:

ulong strnlen(char* s, ulong maxlen){
  for(ulong i=0; i<maxlen; ++i){
    if (!s[i]) return i;
  }
  return maxlen;
}

[I used ulong, since a UNIX string could be an entire file.]


-- 
Jul 31 2007
parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1393


cdunn2001 gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |WORKSFORME





Derek Parnell suggested slicing as a solution:


import std.string;

/** Return a slice of the leftmost portion of 'x'
    up to but not including the first 'c' */
string lefts(string x, char c)
{
    int p;
    p = std.string.find(x,c);
    if (p < 0)
        p = x.length;
    return x[0..p];
}

int compare(string lhs, string rhs, char d = '\0')
{
    return std.string.cmp( lefts(lhs,d), lefts(rhs,d) );
}

and use it like ...

   char[32] NameA = '\0';
   char[56] NameB = '\0';

   NameA[0..5] = "derek";
   NameB[0..7] = "parnell";
   result = compare(NameA, NameB);


This is simple enough for me.


-- 
Aug 14 2007