aboutsummaryrefslogtreecommitdiff
path: root/src/fs/fs_uri.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2014-05-11 12:23:02 +0000
committerChristian Grothoff <christian@grothoff.org>2014-05-11 12:23:02 +0000
commitf5c3a149407e22d066600f8b63ca7733ac0092fd (patch)
tree5eafe5794bcfbb9560b58b5b37ad95a8007d1c82 /src/fs/fs_uri.c
parentf217c9a3b51cf38c2d58f1afe712df86356523a4 (diff)
downloadgnunet-f5c3a149407e22d066600f8b63ca7733ac0092fd.tar.gz
gnunet-f5c3a149407e22d066600f8b63ca7733ac0092fd.zip
improve error reporting for malformed URIs in search results to help diagnose #3395
Diffstat (limited to 'src/fs/fs_uri.c')
-rw-r--r--src/fs/fs_uri.c93
1 files changed, 55 insertions, 38 deletions
diff --git a/src/fs/fs_uri.c b/src/fs/fs_uri.c
index d90fa42a5..eda1710db 100644
--- a/src/fs/fs_uri.c
+++ b/src/fs/fs_uri.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2003--2013 Christian Grothoff (and other contributing authors) 3 (C) 2003--2014 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -200,7 +200,8 @@ GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri)
200 * @return decodded string with leading space (or preserved plus) 200 * @return decodded string with leading space (or preserved plus)
201 */ 201 */
202static char * 202static char *
203percent_decode_keyword (const char *in, char **emsg) 203percent_decode_keyword (const char *in,
204 char **emsg)
204{ 205{
205 char *out; 206 char *out;
206 char *ret; 207 char *ret;
@@ -219,7 +220,7 @@ percent_decode_keyword (const char *in, char **emsg)
219 { 220 {
220 GNUNET_free (out); 221 GNUNET_free (out);
221 *emsg = GNUNET_strdup (_(/* xgettext:no-c-format */ 222 *emsg = GNUNET_strdup (_(/* xgettext:no-c-format */
222 "`%' must be followed by HEX number")); 223 "Malformed KSK URI (`%' must be followed by HEX number)"));
223 return NULL; 224 return NULL;
224 } 225 }
225 rpos += 3; 226 rpos += 3;
@@ -258,7 +259,8 @@ percent_decode_keyword (const char *in, char **emsg)
258 * @return NULL on error, otherwise the KSK URI 259 * @return NULL on error, otherwise the KSK URI
259 */ 260 */
260static struct GNUNET_FS_Uri * 261static struct GNUNET_FS_Uri *
261uri_ksk_parse (const char *s, char **emsg) 262uri_ksk_parse (const char *s,
263 char **emsg)
262{ 264{
263 struct GNUNET_FS_Uri *ret; 265 struct GNUNET_FS_Uri *ret;
264 char **keywords; 266 char **keywords;
@@ -296,14 +298,14 @@ uri_ksk_parse (const char *s, char **emsg)
296 max++; 298 max++;
297 if (s[i - 1] == '+') 299 if (s[i - 1] == '+')
298 { 300 {
299 *emsg = GNUNET_strdup (_("`++' not allowed in KSK URI")); 301 *emsg = GNUNET_strdup (_("Malformed KSK URI (`++' not allowed)"));
300 return NULL; 302 return NULL;
301 } 303 }
302 } 304 }
303 } 305 }
304 if (saw_quote == 1) 306 if (saw_quote == 1)
305 { 307 {
306 *emsg = GNUNET_strdup (_("Quotes not balanced in KSK URI")); 308 *emsg = GNUNET_strdup (_("Malformed KSK URI (quotes not balanced)"));
307 return NULL; 309 return NULL;
308 } 310 }
309 iret = max; 311 iret = max;
@@ -328,7 +330,7 @@ uri_ksk_parse (const char *s, char **emsg)
328 keywords[--max] = percent_decode_keyword (&dup[pos], emsg); 330 keywords[--max] = percent_decode_keyword (&dup[pos], emsg);
329 if (NULL == keywords[max]) 331 if (NULL == keywords[max])
330 goto CLEANUP; 332 goto CLEANUP;
331 GNUNET_assert (max == 0); 333 GNUNET_assert (0 == max);
332 GNUNET_free (dup); 334 GNUNET_free (dup);
333 ret = GNUNET_new (struct GNUNET_FS_Uri); 335 ret = GNUNET_new (struct GNUNET_FS_Uri);
334 ret->type = GNUNET_FS_URI_KSK; 336 ret->type = GNUNET_FS_URI_KSK;
@@ -354,7 +356,8 @@ CLEANUP:
354 * @return NULL on error, SKS URI otherwise 356 * @return NULL on error, SKS URI otherwise
355 */ 357 */
356static struct GNUNET_FS_Uri * 358static struct GNUNET_FS_Uri *
357uri_sks_parse (const char *s, char **emsg) 359uri_sks_parse (const char *s,
360 char **emsg)
358{ 361{
359 struct GNUNET_FS_Uri *ret; 362 struct GNUNET_FS_Uri *ret;
360 struct GNUNET_CRYPTO_EcdsaPublicKey ns; 363 struct GNUNET_CRYPTO_EcdsaPublicKey ns;
@@ -373,7 +376,7 @@ uri_sks_parse (const char *s, char **emsg)
373 &ns, 376 &ns,
374 sizeof (ns))) ) 377 sizeof (ns))) )
375 { 378 {
376 *emsg = GNUNET_strdup (_("Malformed SKS URI")); 379 *emsg = GNUNET_strdup (_("Malformed SKS URI (wrong syntax)"));
377 return NULL; /* malformed */ 380 return NULL; /* malformed */
378 } 381 }
379 end++; /* skip over '/' */ 382 end++; /* skip over '/' */
@@ -395,7 +398,8 @@ uri_sks_parse (const char *s, char **emsg)
395 * @return NULL on error, CHK URI otherwise 398 * @return NULL on error, CHK URI otherwise
396 */ 399 */
397static struct GNUNET_FS_Uri * 400static struct GNUNET_FS_Uri *
398uri_chk_parse (const char *s, char **emsg) 401uri_chk_parse (const char *s,
402 char **emsg)
399{ 403{
400 struct GNUNET_FS_Uri *ret; 404 struct GNUNET_FS_Uri *ret;
401 struct FileIdentifier fi; 405 struct FileIdentifier fi;
@@ -416,7 +420,7 @@ uri_chk_parse (const char *s, char **emsg)
416 if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') || 420 if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
417 (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.')) 421 (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.'))
418 { 422 {
419 *emsg = GNUNET_strdup (_("Malformed CHK URI")); 423 *emsg = GNUNET_strdup (_("Malformed CHK URI (wrong syntax)"));
420 return NULL; 424 return NULL;
421 } 425 }
422 memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); 426 memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
@@ -431,7 +435,7 @@ uri_chk_parse (const char *s, char **emsg)
431 SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2], 435 SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2],
432 "%llu", &flen))) 436 "%llu", &flen)))
433 { 437 {
434 *emsg = GNUNET_strdup (_("Malformed CHK URI")); 438 *emsg = GNUNET_strdup (_("Malformed CHK URI (failed to decode CHK)"));
435 return NULL; 439 return NULL;
436 } 440 }
437 fi.file_length = GNUNET_htonll (flen); 441 fi.file_length = GNUNET_htonll (flen);
@@ -487,7 +491,8 @@ GNUNET_NETWORK_STRUCT_END
487 * @return NULL on error, valid LOC URI otherwise 491 * @return NULL on error, valid LOC URI otherwise
488 */ 492 */
489static struct GNUNET_FS_Uri * 493static struct GNUNET_FS_Uri *
490uri_loc_parse (const char *s, char **emsg) 494uri_loc_parse (const char *s,
495 char **emsg)
491{ 496{
492 struct GNUNET_FS_Uri *uri; 497 struct GNUNET_FS_Uri *uri;
493 char h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; 498 char h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)];
@@ -505,11 +510,11 @@ uri_loc_parse (const char *s, char **emsg)
505 pos = strlen (GNUNET_FS_URI_LOC_PREFIX); 510 pos = strlen (GNUNET_FS_URI_LOC_PREFIX);
506 if ((slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) || 511 if ((slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
507 (0 != strncmp (s, GNUNET_FS_URI_LOC_PREFIX, pos))) 512 (0 != strncmp (s, GNUNET_FS_URI_LOC_PREFIX, pos)))
508 return NULL; /* not an SKS URI */ 513 return NULL; /* not a LOC URI */
509 if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') || 514 if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
510 (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.')) 515 (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.'))
511 { 516 {
512 *emsg = GNUNET_strdup (_("SKS URI malformed")); 517 *emsg = GNUNET_strdup (_("LOC URI malformed (wrong syntax)"));
513 return NULL; 518 return NULL;
514 } 519 }
515 memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); 520 memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
@@ -524,7 +529,7 @@ uri_loc_parse (const char *s, char **emsg)
524 SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2], 529 SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2],
525 "%llu", &flen))) 530 "%llu", &flen)))
526 { 531 {
527 *emsg = GNUNET_strdup (_("LOC URI malformed")); 532 *emsg = GNUNET_strdup (_("LOC URI malformed (no CHK)"));
528 return NULL; 533 return NULL;
529 } 534 }
530 ass.fi.file_length = GNUNET_htonll (flen); 535 ass.fi.file_length = GNUNET_htonll (flen);
@@ -534,7 +539,7 @@ uri_loc_parse (const char *s, char **emsg)
534 npos++; 539 npos++;
535 if (s[npos] == '\0') 540 if (s[npos] == '\0')
536 { 541 {
537 *emsg = GNUNET_strdup (_("LOC URI malformed")); 542 *emsg = GNUNET_strdup (_("LOC URI malformed (missing LOC)"));
538 goto ERR; 543 goto ERR;
539 } 544 }
540 npos++; 545 npos++;
@@ -542,7 +547,7 @@ uri_loc_parse (const char *s, char **emsg)
542 ('.' != s[npos+GNUNET_CRYPTO_PKEY_ASCII_LENGTH]) ) 547 ('.' != s[npos+GNUNET_CRYPTO_PKEY_ASCII_LENGTH]) )
543 { 548 {
544 *emsg = 549 *emsg =
545 GNUNET_strdup (_("LOC URI malformed (could not decode public key)")); 550 GNUNET_strdup (_("LOC URI malformed (wrong syntax for public key)"));
546 } 551 }
547 if (GNUNET_OK != 552 if (GNUNET_OK !=
548 GNUNET_CRYPTO_eddsa_public_key_from_string (&s[npos], 553 GNUNET_CRYPTO_eddsa_public_key_from_string (&s[npos],
@@ -556,13 +561,13 @@ uri_loc_parse (const char *s, char **emsg)
556 npos += GNUNET_CRYPTO_PKEY_ASCII_LENGTH; 561 npos += GNUNET_CRYPTO_PKEY_ASCII_LENGTH;
557 if (s[npos++] != '.') 562 if (s[npos++] != '.')
558 { 563 {
559 *emsg = GNUNET_strdup (_("SKS URI malformed (could not find signature)")); 564 *emsg = GNUNET_strdup (_("LOC URI malformed (could not find signature)"));
560 goto ERR; 565 goto ERR;
561 } 566 }
562 if ( (strlen (&s[npos]) <= SIGNATURE_ASCII_LENGTH + 1) || 567 if ( (strlen (&s[npos]) <= SIGNATURE_ASCII_LENGTH + 1) ||
563 ('.' != s[npos + SIGNATURE_ASCII_LENGTH]) ) 568 ('.' != s[npos + SIGNATURE_ASCII_LENGTH]) )
564 { 569 {
565 *emsg = GNUNET_strdup (_("SKS URI malformed (could not decode signature)")); 570 *emsg = GNUNET_strdup (_("LOC URI malformed (wrong syntax for signature)"));
566 goto ERR; 571 goto ERR;
567 } 572 }
568 if (GNUNET_OK != 573 if (GNUNET_OK !=
@@ -571,19 +576,19 @@ uri_loc_parse (const char *s, char **emsg)
571 &sig, 576 &sig,
572 sizeof (struct GNUNET_CRYPTO_EddsaSignature))) 577 sizeof (struct GNUNET_CRYPTO_EddsaSignature)))
573 { 578 {
574 *emsg = GNUNET_strdup (_("SKS URI malformed (could not decode signature)")); 579 *emsg = GNUNET_strdup (_("LOC URI malformed (could not decode signature)"));
575 goto ERR; 580 goto ERR;
576 } 581 }
577 npos += SIGNATURE_ASCII_LENGTH; 582 npos += SIGNATURE_ASCII_LENGTH;
578 if (s[npos++] != '.') 583 if (s[npos++] != '.')
579 { 584 {
580 *emsg = GNUNET_strdup (_("SKS URI malformed")); 585 *emsg = GNUNET_strdup (_("SKS URI malformed (wrong syntax for expiration time)"));
581 goto ERR; 586 goto ERR;
582 } 587 }
583 if (1 != SSCANF (&s[npos], "%llu", &exptime)) 588 if (1 != SSCANF (&s[npos], "%llu", &exptime))
584 { 589 {
585 *emsg = 590 *emsg =
586 GNUNET_strdup (_("SKS URI malformed (could not parse expiration time)")); 591 GNUNET_strdup (_("LOC URI malformed (could not parse expiration time)"));
587 goto ERR; 592 goto ERR;
588 } 593 }
589 ass.purpose.size = htonl (sizeof (struct LocUriAssembly)); 594 ass.purpose.size = htonl (sizeof (struct LocUriAssembly));
@@ -595,7 +600,7 @@ uri_loc_parse (const char *s, char **emsg)
595 &ass.purpose, &sig, &ass.peer.public_key)) 600 &ass.purpose, &sig, &ass.peer.public_key))
596 { 601 {
597 *emsg = 602 *emsg =
598 GNUNET_strdup (_("SKS URI malformed (signature failed validation)")); 603 GNUNET_strdup (_("LOC URI malformed (signature failed validation)"));
599 goto ERR; 604 goto ERR;
600 } 605 }
601 uri = GNUNET_new (struct GNUNET_FS_Uri); 606 uri = GNUNET_new (struct GNUNET_FS_Uri);
@@ -619,7 +624,8 @@ ERR:
619 * @return NULL on error 624 * @return NULL on error
620 */ 625 */
621struct GNUNET_FS_Uri * 626struct GNUNET_FS_Uri *
622GNUNET_FS_uri_parse (const char *uri, char **emsg) 627GNUNET_FS_uri_parse (const char *uri,
628 char **emsg)
623{ 629{
624 struct GNUNET_FS_Uri *ret; 630 struct GNUNET_FS_Uri *ret;
625 char *msg; 631 char *msg;
@@ -1035,7 +1041,8 @@ GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri)
1035 * if keywords is not legal (i.e. empty). 1041 * if keywords is not legal (i.e. empty).
1036 */ 1042 */
1037struct GNUNET_FS_Uri * 1043struct GNUNET_FS_Uri *
1038GNUNET_FS_uri_ksk_create (const char *keywords, char **emsg) 1044GNUNET_FS_uri_ksk_create (const char *keywords,
1045 char **emsg)
1039{ 1046{
1040 char **keywordarr; 1047 char **keywordarr;
1041 unsigned int num_Words; 1048 unsigned int num_Words;
@@ -1131,7 +1138,8 @@ GNUNET_FS_uri_ksk_create (const char *keywords, char **emsg)
1131 * if keywords is not legal (i.e. empty). 1138 * if keywords is not legal (i.e. empty).
1132 */ 1139 */
1133struct GNUNET_FS_Uri * 1140struct GNUNET_FS_Uri *
1134GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, const char **argv) 1141GNUNET_FS_uri_ksk_create_from_args (unsigned int argc,
1142 const char **argv)
1135{ 1143{
1136 unsigned int i; 1144 unsigned int i;
1137 struct GNUNET_FS_Uri *uri; 1145 struct GNUNET_FS_Uri *uri;
@@ -1184,7 +1192,7 @@ GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, const char **argv)
1184 * 1192 *
1185 * @param u1 one of the URIs 1193 * @param u1 one of the URIs
1186 * @param u2 the other URI 1194 * @param u2 the other URI
1187 * @return GNUNET_YES if the URIs are equal 1195 * @return #GNUNET_YES if the URIs are equal
1188 */ 1196 */
1189int 1197int
1190GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1, 1198GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1,
@@ -1250,7 +1258,7 @@ GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1,
1250 * Is this a namespace URI? 1258 * Is this a namespace URI?
1251 * 1259 *
1252 * @param uri the uri to check 1260 * @param uri the uri to check
1253 * @return GNUNET_YES if this is an SKS uri 1261 * @return #GNUNET_YES if this is an SKS uri
1254 */ 1262 */
1255int 1263int
1256GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri) 1264GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri)
@@ -1265,7 +1273,7 @@ GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri)
1265 * 1273 *
1266 * @param uri the uri to get the namespace ID from 1274 * @param uri the uri to get the namespace ID from
1267 * @param pseudonym where to store the ID of the namespace 1275 * @param pseudonym where to store the ID of the namespace
1268 * @return GNUNET_OK on success 1276 * @return #GNUNET_OK on success
1269 */ 1277 */
1270int 1278int
1271GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri, 1279GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri,
@@ -1325,7 +1333,7 @@ GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri)
1325 * Is this a file (or directory) URI? 1333 * Is this a file (or directory) URI?
1326 * 1334 *
1327 * @param uri the uri to check 1335 * @param uri the uri to check
1328 * @return GNUNET_YES if this is a CHK uri 1336 * @return #GNUNET_YES if this is a CHK uri
1329 */ 1337 */
1330int 1338int
1331GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri) 1339GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri)
@@ -1361,7 +1369,7 @@ GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri * uri)
1361 * Is this a location URI? 1369 * Is this a location URI?
1362 * 1370 *
1363 * @param uri the uri to check 1371 * @param uri the uri to check
1364 * @return GNUNET_YES if this is a LOC uri 1372 * @return #GNUNET_YES if this is a LOC uri
1365 */ 1373 */
1366int 1374int
1367GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri) 1375GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri)
@@ -1380,7 +1388,9 @@ GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri)
1380 * @param index offset where to add the keyword 1388 * @param index offset where to add the keyword
1381 */ 1389 */
1382static void 1390static void
1383insert_non_mandatory_keyword (const char *s, char **array, int index) 1391insert_non_mandatory_keyword (const char *s,
1392 char **array,
1393 int index)
1384{ 1394{
1385 char *nkword; 1395 char *nkword;
1386 1396
@@ -1401,7 +1411,9 @@ insert_non_mandatory_keyword (const char *s, char **array, int index)
1401 * @return #GNUNET_YES if the keyword exists, #GNUNET_NO if not 1411 * @return #GNUNET_YES if the keyword exists, #GNUNET_NO if not
1402 */ 1412 */
1403static int 1413static int
1404find_duplicate (const char *s, const char **array, int array_length) 1414find_duplicate (const char *s,
1415 const char **array,
1416 int array_length)
1405{ 1417{
1406 int j; 1418 int j;
1407 1419
@@ -1458,6 +1470,7 @@ normalize_metadata (enum EXTRACTOR_MetaFormat format,
1458 return (char *) normalized; 1470 return (char *) normalized;
1459} 1471}
1460 1472
1473
1461/** 1474/**
1462 * Counts the number of UTF-8 characters (not bytes) in the string, 1475 * Counts the number of UTF-8 characters (not bytes) in the string,
1463 * returns that count. 1476 * returns that count.
@@ -1486,14 +1499,16 @@ u8_strcount (const uint8_t *s)
1486 * @param array array to fill with enclosed tokens. If NULL, then tokens 1499 * @param array array to fill with enclosed tokens. If NULL, then tokens
1487 * are only counted. 1500 * are only counted.
1488 * @param index index at which to start filling the array (entries prior 1501 * @param index index at which to start filling the array (entries prior
1489 * to it are used to check for duplicates). ignored if array == NULL. 1502 * to it are used to check for duplicates). ignored if @a array == NULL.
1490 * @return number of tokens counted (including duplicates), or number of 1503 * @return number of tokens counted (including duplicates), or number of
1491 * tokens extracted (excluding duplicates). 0 if there are no 1504 * tokens extracted (excluding duplicates). 0 if there are no
1492 * matching parens in the string (when counting), or when all tokens 1505 * matching parens in the string (when counting), or when all tokens
1493 * were duplicates (when extracting). 1506 * were duplicates (when extracting).
1494 */ 1507 */
1495static int 1508static int
1496get_keywords_from_parens (const char *s, char **array, int index) 1509get_keywords_from_parens (const char *s,
1510 char **array,
1511 int index)
1497{ 1512{
1498 int count = 0; 1513 int count = 0;
1499 char *open_paren; 1514 char *open_paren;
@@ -1586,14 +1601,16 @@ get_keywords_from_parens (const char *s, char **array, int index)
1586 * @param array array to fill with tokens. If NULL, then tokens are only 1601 * @param array array to fill with tokens. If NULL, then tokens are only
1587 * counted. 1602 * counted.
1588 * @param index index at which to start filling the array (entries prior 1603 * @param index index at which to start filling the array (entries prior
1589 * to it are used to check for duplicates). ignored if array == NULL. 1604 * to it are used to check for duplicates). ignored if @a array == NULL.
1590 * @return number of tokens (>1) counted (including duplicates), or number of 1605 * @return number of tokens (>1) counted (including duplicates), or number of
1591 * tokens extracted (excluding duplicates). 0 if there are no 1606 * tokens extracted (excluding duplicates). 0 if there are no
1592 * separators in the string (when counting), or when all tokens were 1607 * separators in the string (when counting), or when all tokens were
1593 * duplicates (when extracting). 1608 * duplicates (when extracting).
1594 */ 1609 */
1595static int 1610static int
1596get_keywords_from_tokens (const char *s, char **array, int index) 1611get_keywords_from_tokens (const char *s,
1612 char **array,
1613 int index)
1597{ 1614{
1598 char *p; 1615 char *p;
1599 char *ss; 1616 char *ss;