Index: /pjproject/trunk/pjlib/include/pj/string.h
===================================================================
--- /pjproject/trunk/pjlib/include/pj/string.h	(revision 5519)
+++ /pjproject/trunk/pjlib/include/pj/string.h	(revision 5520)
@@ -475,4 +475,91 @@
 }
 
+
+/**
+ * Find the first index of character, in a string, that does not belong to a 
+ * set of characters.
+ *
+ * @param str	    The string.
+ * @param set_char  The string containing the set of characters. 
+ *
+ * @return the index of the first character in the str that doesn't belong to 
+ * set_char. If str starts with a character not in set_char, return 0.
+ */
+PJ_DECL(pj_ssize_t) pj_strspn(const pj_str_t *str, const pj_str_t *set_char);
+
+
+/**
+ * Find the first index of character, in a string, that does not belong to a
+ * set of characters.
+ *
+ * @param str	    The string.
+ * @param set_char  The string containing the set of characters.
+ *
+ * @return the index of the first character in the str that doesn't belong to
+ * set_char. If str starts with a character not in set_char, return 0.
+ */
+PJ_DECL(pj_ssize_t) pj_strspn2(const pj_str_t *str, const char *set_char);
+
+
+/**
+ * Find the first index of character, in a string, that belong to a set of 
+ * characters.
+ *
+ * @param str	    The string.
+ * @param set_char  The string containing the set of characters.
+ *
+ * @return the index of the first character in the str that belong to
+ * set_char. If no match is found, return the length of str.
+ */
+PJ_DECL(pj_ssize_t) pj_strcspn(const pj_str_t *str, const pj_str_t *set_char);
+
+
+/**
+ * Find the first index of character, in a string, that belong to a set of
+ * characters.
+ *
+ * @param str	    The string.
+ * @param set_char  The string containing the set of characters.
+ *
+ * @return the index of the first character in the str that belong to
+ * set_char. If no match is found, return the length of str.
+ */
+PJ_DECL(pj_ssize_t) pj_strcspn2(const pj_str_t *str, const char *set_char);
+
+
+/**
+ * Find tokens from a string using the delimiter.
+ *
+ * @param str	    The string.
+ * @param delim	    The string containing the delimiter. It might contain 
+ *		    multiple character treated as unique set. If same character
+ *		    was found on the set, it will be skipped.
+ * @param tok	    The string containing the token.
+ * @param start_idx The search will start from this index.
+ *
+ * @return the index of token from the str, or the length of the str
+ * if the token is not found.
+ */
+PJ_DECL(pj_ssize_t) pj_strtok(const pj_str_t *str, const pj_str_t *delim,
+			      pj_str_t *tok, pj_size_t start_idx);
+
+
+/**
+ * Find tokens from a string using the delimiter.
+ *
+ * @param str	    The string.
+ * @param delim	    The string containing the delimiter. It might contain
+ *		    multiple character treated as unique set. If same character
+ *		    was found on the set, it will be skipped.
+ * @param tok	    The string containing the token.
+ * @param start_idx The search will start from this index.
+ *
+ * @return the index of token from the str, or the length of the str
+ * if the token is not found.
+ */
+PJ_DECL(pj_ssize_t) pj_strtok2(const pj_str_t *str, const char *delim,
+			       pj_str_t *tok, pj_size_t start_idx);
+
+
 /**
  * Find the occurence of a substring substr in string str.
Index: /pjproject/trunk/pjlib/src/pj/os_info.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/os_info.c	(revision 5519)
+++ /pjproject/trunk/pjlib/src/pj/os_info.c	(revision 5520)
@@ -99,8 +99,9 @@
 
 static pj_uint32_t parse_version(char *str)
-{
-    char *tok;
-    int i, maxtok;
+{    
+    int i, maxtok, found_idx;
     pj_uint32_t version = 0;
+    pj_str_t in_str = pj_str(str);
+    pj_str_t token, delim;
     
     while (*str && !pj_isdigit(*str))
@@ -108,13 +109,16 @@
 
     maxtok = 4;
-    for (tok = strtok(str, ".-"), i=0; tok && i<maxtok;
-	 ++i, tok=strtok(NULL, ".-"))
+    delim = pj_str(".-");
+    for (found_idx = pj_strtok(&in_str, &delim, &token, 0), i=0; 
+	 found_idx != in_str.slen && i < maxtok;
+	 ++i, found_idx = pj_strtok(&in_str, &delim, &token, 
+	                            found_idx + token.slen))
     {
 	int n;
 
-	if (!pj_isdigit(*tok))
+	if (!pj_isdigit(*token.ptr))
 	    break;
 	
-	n = atoi(tok);
+	n = atoi(token.ptr);
 	version |= (n << ((3-i)*8));
     }
Index: /pjproject/trunk/pjlib/src/pj/string.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/string.c	(revision 5519)
+++ /pjproject/trunk/pjlib/src/pj/string.c	(revision 5520)
@@ -29,4 +29,111 @@
 #endif
 
+PJ_DEF(pj_ssize_t) pj_strspn(const pj_str_t *str, const pj_str_t *set_char)
+{
+    pj_ssize_t i, j, count = 0;
+    for (i = 0; i < str->slen; i++) {
+	if (count != i) 
+	    break;
+
+	for (j = 0; j < set_char->slen; j++) {
+	    if (str->ptr[i] == set_char->ptr[j])
+		count++;
+	}
+    }
+    return count;
+}
+
+
+PJ_DEF(pj_ssize_t) pj_strspn2(const pj_str_t *str, const char *set_char)
+{
+    pj_ssize_t i, j, count = 0;
+    for (i = 0; i < str->slen; i++) {
+	if (count != i)
+	    break;
+
+	for (j = 0; set_char[j] != 0; j++) {
+	    if (str->ptr[i] == set_char[j])
+		count++;
+	}
+    }
+    return count;
+}
+
+
+PJ_DEF(pj_ssize_t) pj_strcspn(const pj_str_t *str, const pj_str_t *set_char)
+{
+    pj_ssize_t i, j;
+    for (i = 0; i < str->slen; i++) {
+	for (j = 0; j < set_char->slen; j++) {
+	    if (str->ptr[i] == set_char->ptr[j])
+		return i;
+	}
+    }
+    return i;
+}
+
+
+PJ_DECL(pj_ssize_t) pj_strcspn2(const pj_str_t *str, const char *set_char)
+{
+    pj_ssize_t i, j;
+    for (i = 0; i < str->slen; i++) {
+	for (j = 0; set_char[j] != 0; j++) {
+	    if (str->ptr[i] == set_char[j])
+		return i;
+	}
+    }
+    return i;
+}
+
+
+PJ_DEF(pj_ssize_t) pj_strtok(const pj_str_t *str, const pj_str_t *delim,
+			     pj_str_t *tok, pj_size_t start_idx)
+{    
+    pj_ssize_t str_idx;
+
+    tok->slen = 0;
+    if ((str->slen == 0) || ((pj_size_t)str->slen < start_idx)) {
+	return str->slen;
+    }
+    
+    tok->ptr = str->ptr + start_idx;
+    tok->slen = str->slen - start_idx;
+
+    str_idx = pj_strspn(tok, delim);
+    if (start_idx+str_idx == (pj_size_t)str->slen) {
+	return str->slen;
+    }    
+    tok->ptr += str_idx;
+    tok->slen -= str_idx;
+
+    tok->slen = pj_strcspn(tok, delim);
+    return start_idx + str_idx;
+}
+
+
+PJ_DECL(pj_ssize_t) pj_strtok2(const pj_str_t *str, const char *delim,
+			       pj_str_t *tok, pj_size_t start_idx)
+{
+    pj_ssize_t str_idx;
+
+    tok->slen = 0;
+    if ((str->slen == 0) || ((pj_size_t)str->slen < start_idx)) {
+	return str->slen;
+    }
+
+    tok->ptr = str->ptr + start_idx;
+    tok->slen = str->slen - start_idx;
+
+    str_idx = pj_strspn2(tok, delim);
+    if (start_idx + str_idx == (pj_size_t)str->slen) {
+	return str->slen;
+    }
+    tok->ptr += str_idx;
+    tok->slen -= str_idx;
+
+    tok->slen = pj_strcspn2(tok, delim);
+    return start_idx + str_idx;
+}
+
 
 PJ_DEF(char*) pj_strstr(const pj_str_t *str, const pj_str_t *substr)
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 5519)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 5520)
@@ -672,38 +672,36 @@
 			      pj_ice_sess_cand *cand)
 {
-    pj_str_t input;
-    char *token, *host;
-    int af;
-    pj_str_t s;
+    pj_str_t token, delim, host;
+    int af, found_idx;    
     pj_status_t status = PJNATH_EICEINCANDSDP;
 
     pj_bzero(cand, sizeof(*cand));
-    pj_strdup_with_null(pool, &input, orig_input);
 
     PJ_UNUSED_ARG(obj_name);
 
     /* Foundation */
-    token = strtok(input.ptr, " ");
-    if (!token) {
+    delim = pj_str(" ");
+    found_idx = pj_strtok(orig_input, &delim, &token, 0);
+    if (found_idx == orig_input->slen) {
 	TRACE__((obj_name, "Expecting ICE foundation in candidate"));
 	goto on_return;
     }
-    pj_strdup2(pool, &cand->foundation, token);
+    pj_strdup(pool, &cand->foundation, &token);
 
     /* Component ID */
-    token = strtok(NULL, " ");
-    if (!token) {
+    found_idx = pj_strtok(orig_input, &delim, &token, found_idx + token.slen);
+    if (found_idx == orig_input->slen) {
 	TRACE__((obj_name, "Expecting ICE component ID in candidate"));
 	goto on_return;
     }
-    cand->comp_id = (pj_uint8_t) atoi(token);
+    cand->comp_id = (pj_uint8_t)pj_strtoul(&token);
 
     /* Transport */
-    token = strtok(NULL, " ");
-    if (!token) {
+    found_idx = pj_strtok(orig_input, &delim, &token, found_idx + token.slen);
+    if (found_idx == orig_input->slen) {
 	TRACE__((obj_name, "Expecting ICE transport in candidate"));
 	goto on_return;
     }
-    if (pj_ansi_stricmp(token, "UDP") != 0) {
+    if (pj_stricmp2(&token, "UDP") != 0) {
 	TRACE__((obj_name, 
 		 "Expecting ICE UDP transport only in candidate"));
@@ -712,24 +710,24 @@
 
     /* Priority */
-    token = strtok(NULL, " ");
-    if (!token) {
+    found_idx = pj_strtok(orig_input, &delim, &token, found_idx + token.slen);
+    if (found_idx == orig_input->slen) {
 	TRACE__((obj_name, "Expecting ICE priority in candidate"));
 	goto on_return;
     }
-    cand->prio = atoi(token);
+    cand->prio = pj_strtoul(&token);
 
     /* Host */
-    host = strtok(NULL, " ");
-    if (!host) {
+    found_idx = pj_strtok(orig_input, &delim, &host, found_idx + token.slen);
+    if (found_idx == orig_input->slen) {
 	TRACE__((obj_name, "Expecting ICE host in candidate"));
 	goto on_return;
     }
     /* Detect address family */
-    if (pj_ansi_strchr(host, ':'))
+    if (pj_strchr(&host, ':'))
 	af = pj_AF_INET6();
     else
 	af = pj_AF_INET();
     /* Assign address */
-    if (pj_sockaddr_init(af, &cand->addr, pj_cstr(&s, host), 0)) {
+    if (pj_sockaddr_init(af, &cand->addr, &host, 0)) {
 	TRACE__((obj_name, "Invalid ICE candidate address"));
 	goto on_return;
@@ -737,18 +735,18 @@
 
     /* Port */
-    token = strtok(NULL, " ");
-    if (!token) {
+    found_idx = pj_strtok(orig_input, &delim, &token, found_idx + host.slen);
+    if (found_idx == orig_input->slen) {
 	TRACE__((obj_name, "Expecting ICE port number in candidate"));
 	goto on_return;
     }
-    pj_sockaddr_set_port(&cand->addr, (pj_uint16_t)atoi(token));
+    pj_sockaddr_set_port(&cand->addr, (pj_uint16_t)pj_strtoul(&token));
 
     /* typ */
-    token = strtok(NULL, " ");
-    if (!token) {
+    found_idx = pj_strtok(orig_input, &delim, &token, found_idx + token.slen);
+    if (found_idx == orig_input->slen) {
 	TRACE__((obj_name, "Expecting ICE \"typ\" in candidate"));
 	goto on_return;
     }
-    if (pj_ansi_stricmp(token, "typ") != 0) {
+    if (pj_stricmp2(&token, "typ") != 0) {
 	TRACE__((obj_name, "Expecting ICE \"typ\" in candidate"));
 	goto on_return;
@@ -756,25 +754,25 @@
 
     /* candidate type */
-    token = strtok(NULL, " ");
-    if (!token) {
+    found_idx = pj_strtok(orig_input, &delim, &token, found_idx + token.slen);
+    if (found_idx == orig_input->slen) {
 	TRACE__((obj_name, "Expecting ICE candidate type in candidate"));
 	goto on_return;
     }
 
-    if (pj_ansi_stricmp(token, "host") == 0) {
+    if (pj_stricmp2(&token, "host") == 0) {
 	cand->type = PJ_ICE_CAND_TYPE_HOST;
 
-    } else if (pj_ansi_stricmp(token, "srflx") == 0) {
+    } else if (pj_stricmp2(&token, "srflx") == 0) {
 	cand->type = PJ_ICE_CAND_TYPE_SRFLX;
 
-    } else if (pj_ansi_stricmp(token, "relay") == 0) {
+    } else if (pj_stricmp2(&token, "relay") == 0) {
 	cand->type = PJ_ICE_CAND_TYPE_RELAYED;
 
-    } else if (pj_ansi_stricmp(token, "prflx") == 0) {
+    } else if (pj_stricmp2(&token, "prflx") == 0) {
 	cand->type = PJ_ICE_CAND_TYPE_PRFLX;
 
     } else {
-	PJ_LOG(5,(obj_name, "Invalid ICE candidate type %s in candidate", 
-		  token));
+	PJ_LOG(5,(obj_name, "Invalid ICE candidate type %.*s in candidate", 
+		  token.slen, token.ptr));
 	goto on_return;
     }
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 5519)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 5520)
@@ -1217,61 +1217,60 @@
 				     int *tag)
 {
-    pj_str_t input;
-    char *token;
-    pj_str_t tmp;
+    pj_str_t token, delim;
     pj_status_t status;
-    int itmp, token_len;
+    int itmp, found_idx;
 
     pj_bzero(crypto, sizeof(*crypto));
-    pj_strdup_with_null(pool, &input, &attr->value);
 
     /* Tag */
-    token = strtok(input.ptr, " ");
-    if (!token) {
+    delim = pj_str(" ");
+    found_idx = pj_strtok(&attr->value, &delim, &token, 0);
+    if (found_idx == attr->value.slen) {
 	PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting tag"));
 	return PJMEDIA_SDP_EINATTR;
     }
-    token_len = pj_ansi_strlen(token);
 
     /* Tag must not use leading zeroes. */
-    if (token_len > 1 && *token == '0')
+    if (token.slen > 1 && *token.ptr == '0')
 	return PJMEDIA_SDP_EINATTR;
 
     /* Tag must be decimal, i.e: contains only digit '0'-'9'. */
-    for (itmp = 0; itmp < token_len; ++itmp)
-	if (!pj_isdigit(token[itmp]))
+    for (itmp = 0; itmp < token.slen; ++itmp)
+	if (!pj_isdigit(token.ptr[itmp]))
 	    return PJMEDIA_SDP_EINATTR;
 
     /* Get tag value. */
-    *tag = atoi(token);
+    *tag = pj_strtoul(&token);
 
     /* Crypto-suite */
-    token = strtok(NULL, " ");
-    if (!token) {
+    found_idx = pj_strtok(&attr->value, &delim, &token, found_idx+token.slen);
+    if (found_idx == attr->value.slen) {
 	PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting crypto suite"));
 	return PJMEDIA_SDP_EINATTR;
     }
-    crypto->name = pj_str(token);
+    crypto->name = token;
 
     /* Key method */
-    token = strtok(NULL, ":");
-    if (!token) {
+    delim = pj_str(": ");
+    found_idx = pj_strtok(&attr->value, &delim, &token, found_idx+token.slen);
+    if (found_idx == attr->value.slen) {
 	PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key method"));
 	return PJMEDIA_SDP_EINATTR;
     }
-    if (pj_ansi_stricmp(token, "inline")) {
-	PJ_LOG(4,(THIS_FILE, "Attribute crypto key method '%s' not supported!",
-	          token));
+    if (pj_stricmp2(&token, "inline")) {
+	PJ_LOG(4,(THIS_FILE, "Attribute crypto key method '%.*s' "
+	          "not supported!", token.slen, token.ptr));
 	return PJMEDIA_SDP_EINATTR;
     }
 
-    /* Key */
-    token = strtok(NULL, "| ");
-    if (!token) {
+    /* Key */    
+    delim = pj_str("| ");
+    found_idx = pj_strtok(&attr->value, &delim, &token, found_idx+token.slen);
+    if (found_idx == attr->value.slen) {
 	PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key"));
 	return PJMEDIA_SDP_EINATTR;
     }
-    tmp = pj_str(token);
-    if (PJ_BASE64_TO_BASE256_LEN(tmp.slen) > MAX_KEY_LEN) {
+    
+    if (PJ_BASE64_TO_BASE256_LEN(token.slen) > MAX_KEY_LEN) {
 	PJ_LOG(4,(THIS_FILE, "Key too long"));
 	return PJMEDIA_SRTP_EINKEYLEN;
@@ -1281,5 +1280,5 @@
     crypto->key.ptr = (char*) pj_pool_zalloc(pool, MAX_KEY_LEN);
     itmp = MAX_KEY_LEN;
-    status = pj_base64_decode(&tmp, (pj_uint8_t*)crypto->key.ptr,
+    status = pj_base64_decode(&token, (pj_uint8_t*)crypto->key.ptr,
 			      &itmp);
     if (status != PJ_SUCCESS) {
