www.digitalmars.com         C & C++   DMDScript  

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

reply d-bugmail puremagic.com writes:

           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:
       #include <string.h>

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

       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.

       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.

       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:

cdunn2001 gmail.com changed:

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

------- Comment #1 from cdunn2001 gmail.com  2007-08-14 20:10 -------
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