tags.c revision 161475
11553Srgrimes/* 21553Srgrimes * Copyright (C) 1984-2004 Mark Nudelman 31553Srgrimes * 41553Srgrimes * You may distribute under the terms of either the GNU General Public 51553Srgrimes * License or the Less License, as specified in the README file. 61553Srgrimes * 752653Smarcel * For more information about less, or for information on how to 81553Srgrimes * contact the author, see the README file. 946855Speter */ 101553Srgrimes 11152018Sru 121553Srgrimes#include "less.h" 13111582Sru 1482393Speter#define WHITESP(c) ((c)==' ' || (c)=='\t') 151553Srgrimes 16185186Sthompsa#if TAGS 1761640Speter 181553Srgrimespublic char *tags = "tags"; 191553Srgrimes 2067109Sphkstatic int total; 211553Srgrimesstatic int curseq; 22111582Sru 231553Srgrimesextern int linenums; 24111582Sruextern int sigs; 251553Srgrimes 2679607Sddenum tag_result { 27129073Scognet TAG_FOUND, 281553Srgrimes TAG_NOFILE, 291553Srgrimes TAG_NOTAG, 301553Srgrimes TAG_NOTYPE, 311553Srgrimes TAG_INTR 321553Srgrimes}; 3346104Sluoqi 341553Srgrimes/* 35180922Sobrien * Tag type 361553Srgrimes */ 371553Srgrimesenum { 381553Srgrimes T_CTAGS, /* 'tags': standard and extended format (ctags) */ 391553Srgrimes T_CTAGS_X, /* stdin: cross reference format (ctags) */ 401553Srgrimes T_GTAGS, /* 'GTAGS': function defenition (global) */ 411553Srgrimes T_GRTAGS, /* 'GRTAGS': function reference (global) */ 421553Srgrimes T_GSYMS, /* 'GSYMS': other symbols (global) */ 431553Srgrimes T_GPATH /* 'GPATH': path name (global) */ 441553Srgrimes}; 451553Srgrimes 461553Srgrimesstatic enum tag_result findctag(); 471553Srgrimesstatic enum tag_result findgtag(); 481553Srgrimesstatic char *nextgtag(); 491553Srgrimesstatic char *prevgtag(); 501553Srgrimesstatic POSITION ctagsearch(); 511553Srgrimesstatic POSITION gtagsearch(); 521553Srgrimesstatic int getentry(); 531553Srgrimes 541553Srgrimes/* 551553Srgrimes * The list of tags generated by the last findgtag() call. 561553Srgrimes * 571553Srgrimes * Use either pattern or line number. 581553Srgrimes * findgtag() always uses line number, so pattern is always NULL. 591553Srgrimes * findctag() usually either pattern (in which case line number is 0), 601553Srgrimes * or line number (in which case pattern is NULL). 611553Srgrimes */ 621553Srgrimesstruct taglist { 631553Srgrimes struct tag *tl_first; 641553Srgrimes struct tag *tl_last; 651553Srgrimes}; 661553Srgrimes#define TAG_END ((struct tag *) &taglist) 671553Srgrimesstatic struct taglist taglist = { TAG_END, TAG_END }; 6852007Speterstruct tag { 691553Srgrimes struct tag *next, *prev; /* List links */ 701553Srgrimes char *tag_file; /* Source file containing the tag */ 71169507Swkoszek LINENUM tag_linenum; /* Appropriate line number in source file */ 721553Srgrimes char *tag_pattern; /* Pattern used to find the tag */ 7329451Scharnier char tag_endline; /* True if the pattern includes '$' */ 741553Srgrimes}; 7512772Speterstatic struct tag *curtag; 761553Srgrimes 7745775Speter#define TAG_INS(tp) \ 7845775Speter (tp)->next = taglist.tl_first; \ 79169647Simp (tp)->prev = TAG_END; \ 8045744Speter taglist.tl_first->prev = (tp); \ 8182393Speter taglist.tl_first = (tp); 8282393Speter 8365091Speter#define TAG_RM(tp) \ 8445744Speter (tp)->next->prev = (tp)->prev; \ 8579607Sdd (tp)->prev->next = (tp)->next; 86110895Sru 87129073Scognet/* 8845744Speter * Delete tag structures. 8945744Speter */ 9045744Speter public void 9120458Sjoergcleantags() 9279607Sdd{ 9379607Sdd register struct tag *tp; 94151744Sjhb 9520458Sjoerg /* 96174892Simp * Delete any existing tag list. 97174892Simp * {{ Ideally, we wouldn't do this until after we know that we 98174892Simp * can load some other tag information. }} 99185186Sthompsa */ 100174892Simp while ((tp = taglist.tl_first) != TAG_END) 101174892Simp { 10271251Speter TAG_RM(tp); 10371251Speter free(tp); 10471251Speter } 10571251Speter curtag = NULL; 10671251Speter total = curseq = 0; 10771251Speter} 10871251Speter 10971251Speter/* 11071251Speter * Create a new tag entry. 11145775Speter */ 1121553Srgrimes static struct tag * 1131553Srgrimesmaketagent(name, file, linenum, pattern, endline) 1141553Srgrimes char *name; 1151553Srgrimes char *file; 1161553Srgrimes LINENUM linenum; 1171553Srgrimes char *pattern; 1181553Srgrimes int endline; 1191553Srgrimes{ 1201553Srgrimes register struct tag *tp; 1211553Srgrimes 1221553Srgrimes tp = (struct tag *) ecalloc(sizeof(struct tag), 1); 1231553Srgrimes tp->tag_file = (char *) ecalloc(strlen(file) + 1, sizeof(char)); 1241553Srgrimes strcpy(tp->tag_file, file); 1251553Srgrimes tp->tag_linenum = linenum; 12672841Speter tp->tag_endline = endline; 1271553Srgrimes if (pattern == NULL) 1281553Srgrimes tp->tag_pattern = NULL; 129180922Sobrien else 130180922Sobrien { 131180922Sobrien tp->tag_pattern = (char *) ecalloc(strlen(pattern) + 1, sizeof(char)); 132180922Sobrien strcpy(tp->tag_pattern, pattern); 133180922Sobrien } 134174892Simp return (tp); 135169507Swkoszek} 136169507Swkoszek 137169507Swkoszek/* 138122656Sbde * Get tag mode. 139174892Simp */ 140129073Scognet public int 1411553Srgrimesgettagtype() 1421553Srgrimes{ 1431553Srgrimes int f; 1441553Srgrimes 1451553Srgrimes if (strcmp(tags, "GTAGS") == 0) 1461553Srgrimes return T_GTAGS; 147174892Simp if (strcmp(tags, "GRTAGS") == 0) 148152865Sru return T_GRTAGS; 149117269Sjkoshy if (strcmp(tags, "GSYMS") == 0) 150117269Sjkoshy return T_GSYMS; 15172000Speter if (strcmp(tags, "GPATH") == 0) 152144509Simp return T_GPATH; 1531553Srgrimes if (strcmp(tags, "-") == 0) 154174892Simp return T_CTAGS_X; 155152865Sru f = open(tags, OPEN_READ); 156152865Sru if (f >= 0) 157144509Simp { 158144509Simp close(f); 159144509Simp return T_CTAGS; 160144509Simp } 161144509Simp return T_GTAGS; 162174892Simp} 1631553Srgrimes 164159362Sdelphij/* 165205880Sru * Find tags in tag file. 166205880Sru * Find a tag in the "tags" file. 16720458Sjoerg * Sets "tag_file" to the name of the file containing the tag, 168110895Sru * and "tagpattern" to the search pattern which should be used 1691553Srgrimes * to find the tag. 170174892Simp */ 171152018Sru public void 172152018Srufindtag(tag) 173152024Sru register char *tag; 174152024Sru{ 175152024Sru int type = gettagtype(); 176152024Sru enum tag_result result; 177152018Sru 178152018Sru if (type == T_CTAGS) 1791553Srgrimes result = findctag(tag); 1801553Srgrimes else 181174892Simp result = findgtag(tag, type); 1821553Srgrimes switch (result) 1831553Srgrimes { 184174892Simp case TAG_FOUND: 185174892Simp case TAG_INTR: 18646855Speter break; 18746855Speter case TAG_NOFILE: 188174892Simp error("No tags file", NULL_PARG); 189174892Simp break; 190174892Simp case TAG_NOTAG: 191163637Simp error("No such tag in tags file", NULL_PARG); 192163637Simp break; 19382393Speter case TAG_NOTYPE: 194174892Simp error("unknown tag type", NULL_PARG); 195163638Simp break; 196163638Simp } 197163638Simp} 198205880Sru 199205880Sru/* 200163638Simp * Search for a tag. 201163638Simp */ 202163637Simp public POSITION 203122656Sbdetagsearch() 2041553Srgrimes{ 20546855Speter if (curtag == NULL) 206174892Simp return (NULL_POSITION); /* No gtags loaded! */ 207174892Simp if (curtag->tag_linenum != 0) 208174892Simp return gtagsearch(); 209174892Simp else 21046855Speter return ctagsearch(); 21146855Speter} 21246855Speter 21346855Speter/* 21446855Speter * Go to the next tag. 215185186Sthompsa */ 21646855Speter public char * 21746855Speternexttag(n) 21846855Speter int n; 21946855Speter{ 22046855Speter char *tagfile = (char *) NULL; 22146855Speter 2221553Srgrimes while (n-- > 0) 2231553Srgrimes tagfile = nextgtag(); 2241553Srgrimes return tagfile; 2251553Srgrimes} 2261553Srgrimes 2271553Srgrimes/* 2281553Srgrimes * Go to the previous tag. 229174892Simp */ 230185186Sthompsa public char * 231160522Sstefanfprevtag(n) 23279607Sdd int n; 23379607Sdd{ 2341553Srgrimes char *tagfile = (char *) NULL; 235174892Simp 236185186Sthompsa while (n-- > 0) 2371553Srgrimes tagfile = prevgtag(); 2381553Srgrimes return tagfile; 23946104Sluoqi} 240174892Simp 241174892Simp/* 24246021Speter * Return the total number of tags. 2431553Srgrimes */ 24446021Speter public int 24546021Speterntags() 24646021Speter{ 2471553Srgrimes return total; 2481553Srgrimes} 249174892Simp 2501553Srgrimes/* 2511553Srgrimes * Return the sequence number of current tag. 2521553Srgrimes */ 2531553Srgrimes public int 2541553Srgrimescurr_tag() 2551553Srgrimes{ 2561553Srgrimes return curseq; 2571553Srgrimes} 2581553Srgrimes 259185186Sthompsa/***************************************************************************** 260212570Semaste * ctags 261185186Sthompsa */ 262185186Sthompsa 2631553Srgrimes/* 2641553Srgrimes * Find tags in the "tags" file. 265174892Simp * Sets curtag to the first tag entry. 2661553Srgrimes */ 2671553Srgrimes static enum tag_result 2681553Srgrimesfindctag(tag) 269136880Sdes register char *tag; 270136880Sdes{ 271136880Sdes char *p; 272136880Sdes register FILE *f; 273136880Sdes register int taglen; 274136880Sdes LINENUM taglinenum; 275136880Sdes char *tagfile; 276136880Sdes char *tagpattern; 277136880Sdes int tagendline; 278136880Sdes int search_char; 279136880Sdes int err; 280136880Sdes char tline[TAGLINE_SIZE]; 281136880Sdes struct tag *tp; 282136880Sdes 283136880Sdes p = shell_unquote(tags); 284136880Sdes f = fopen(p, "r"); 285136880Sdes free(p); 286136880Sdes if (f == NULL) 287174892Simp return TAG_NOFILE; 288185186Sthompsa 28971251Speter cleantags(); 290136880Sdes total = 0; 291136880Sdes taglen = strlen(tag); 292136880Sdes 293136880Sdes /* 294174892Simp * Search the tags file for the desired tag. 295136880Sdes */ 296111582Sru while (fgets(tline, sizeof(tline), f) != NULL) 297169647Simp { 298111582Sru if (tline[0] == '!') 299110897Sru /* Skip header of extended format. */ 300169647Simp continue; 30146021Speter if (strncmp(tag, tline, taglen) != 0 || !WHITESP(tline[taglen])) 3021553Srgrimes continue; 3031553Srgrimes 3041553Srgrimes /* 30579607Sdd * Found it. 30672684Speter * The line contains the tag, the filename and the 3071553Srgrimes * location in the file, separated by white space. 30829493Scharnier * The location is either a decimal line number, 30979607Sdd * or a search pattern surrounded by a pair of delimiters. 3101553Srgrimes * Parse the line and extract these parts. 3111553Srgrimes */ 312151744Sjhb tagpattern = NULL; 313151744Sjhb 314151744Sjhb /* 315169647Simp * Skip over the whitespace after the tag name. 316169647Simp */ 317169647Simp p = skipsp(tline+taglen); 318169647Simp if (*p == '\0') 319151744Sjhb /* File name is missing! */ 320169647Simp continue; 321151744Sjhb 322151744Sjhb /* 323151744Sjhb * Save the file name. 324151744Sjhb * Skip over the whitespace after the file name. 325151744Sjhb */ 3261553Srgrimes tagfile = p; 327129073Scognet while (!WHITESP(*p) && *p != '\0') 328129073Scognet p++; 329129073Scognet *p++ = '\0'; 330129073Scognet p = skipsp(p); 331129073Scognet if (*p == '\0') 332129073Scognet /* Pattern is missing! */ 333129073Scognet continue; 334159362Sdelphij 335205880Sru /* 336205880Sru * First see if it is a line number. 337129073Scognet */ 338129073Scognet tagendline = 0; 339129073Scognet taglinenum = getnum(&p, 0, &err); 340129073Scognet if (err) 341129073Scognet { 342153889Sru /* 3431553Srgrimes * No, it must be a pattern. 344153889Sru * Delete the initial "^" (if present) and 345169507Swkoszek * the final "$" from the pattern. 346153889Sru * Delete any backslash in the pattern. 347153889Sru */ 348153889Sru taglinenum = 0; 349169507Swkoszek search_char = *p++; 350153889Sru if (*p == '^') 351153889Sru p++; 352153889Sru tagpattern = p; 353153889Sru while (*p != search_char && *p != '\0') 354153889Sru { 355153889Sru if (*p == '\\') 356153889Sru p++; 357153889Sru p++; 358153889Sru } 35945744Speter tagendline = (p[-1] == '$'); 360134542Speter if (tagendline) 3611553Srgrimes p--; 36261640Speter *p = '\0'; 3631553Srgrimes } 364169507Swkoszek tp = maketagent(tag, tagfile, taglinenum, tagpattern, tagendline); 365210144Simp TAG_INS(tp); 366210144Simp total++; 367153889Sru } 368153889Sru fclose(f); 369153889Sru if (total == 0) 370159362Sdelphij return TAG_NOTAG; 371205880Sru curtag = taglist.tl_first; 372205880Sru curseq = 1; 37372841Speter return TAG_FOUND; 374110895Sru} 3751553Srgrimes 37672841Speter/* 377110897Sru * Edit current tagged file. 378169507Swkoszek */ 379110897Sru public int 38072841Speteredit_tagfile() 381169507Swkoszek{ 382110897Sru if (curtag == NULL) 383153889Sru return (1); 384110897Sru return (edit(curtag->tag_file)); 385169647Simp} 386169647Simp 387169647Simp/* 388169647Simp * Search for a tag. 389153889Sru * This is a stripped-down version of search(). 390110897Sru * We don't use search() for several reasons: 391110897Sru * - We don't want to blow away any search string we may have saved. 392110897Sru * - The various regular-expression functions (from different systems: 393153889Sru * regcmp vs. re_comp) behave differently in the presence of 394153889Sru * parentheses (which are almost always found in a tag). 395153889Sru */ 396153889Sru static POSITION 397153889Sructagsearch() 398153889Sru{ 399153889Sru POSITION pos, linepos; 400153889Sru LINENUM linenum; 401153889Sru int len; 402153889Sru char *line; 403153889Sru 404153889Sru pos = ch_zero(); 405153889Sru linenum = find_linenum(pos); 406153889Sru 407153889Sru for (;;) 408153889Sru { 409153889Sru /* 410153889Sru * Get lines until we find a matching one or 411110897Sru * until we hit end-of-file. 412185186Sthompsa */ 41372841Speter if (ABORT_SIGS()) 414185186Sthompsa return (NULL_POSITION); 41572841Speter 416169507Swkoszek /* 417169507Swkoszek * Read the next line, and save the 418169507Swkoszek * starting position of that line in linepos. 419169507Swkoszek */ 420169507Swkoszek linepos = pos; 421169507Swkoszek pos = forw_raw_line(pos, &line); 422169507Swkoszek if (linenum != 0) 423169507Swkoszek linenum++; 424185186Sthompsa 425185186Sthompsa if (pos == NULL_POSITION) 426210144Simp { 427210144Simp /* 428153889Sru * We hit EOF without a match. 429153889Sru */ 430153889Sru error("Tag not found", NULL_PARG); 431159362Sdelphij return (NULL_POSITION); 432205880Sru } 433205880Sru 43472841Speter /* 43572841Speter * If we're using line numbers, we might as well 43672841Speter * remember the information we have now (the position 437185186Sthompsa * and line number of the current line). 438185186Sthompsa */ 439185186Sthompsa if (linenums) 440185186Sthompsa add_lnum(linenum, pos); 441185186Sthompsa 442185186Sthompsa /* 44372841Speter * Test the line to see if we have a match. 444110897Sru * Use strncmp because the pattern may be 445153889Sru * truncated (in the tags file) if it is too long. 446153889Sru * If tagendline is set, make sure we match all 447153889Sru * the way to end of line (no extra chars after the match). 448110897Sru */ 449169507Swkoszek len = strlen(curtag->tag_pattern); 450110897Sru if (strncmp(curtag->tag_pattern, line, len) == 0 && 451153889Sru (!curtag->tag_endline || line[len] == '\0' || line[len] == '\r')) 452110897Sru { 453169647Simp curtag->tag_linenum = find_linenum(linepos); 454169647Simp break; 455169647Simp } 456169647Simp } 457153889Sru 458110897Sru return (linepos); 459110897Sru} 460 461/******************************************************************************* 462 * gtags 463 */ 464 465/* 466 * Find tags in the GLOBAL's tag file. 467 * The findgtag() will try and load information about the requested tag. 468 * It does this by calling "global -x tag" and storing the parsed output 469 * for future use by gtagsearch(). 470 * Sets curtag to the first tag entry. 471 */ 472 static enum tag_result 473findgtag(tag, type) 474 char *tag; /* tag to load */ 475 int type; /* tags type */ 476{ 477 char buf[256]; 478 FILE *fp; 479 struct tag *tp; 480 481 if (type != T_CTAGS_X && tag == NULL) 482 return TAG_NOFILE; 483 484 cleantags(); 485 total = 0; 486 487 /* 488 * If type == T_CTAGS_X then read ctags's -x format from stdin 489 * else execute global(1) and read from it. 490 */ 491 if (type == T_CTAGS_X) 492 { 493 fp = stdin; 494 /* Set tag default because we cannot read stdin again. */ 495 tags = "tags"; 496 } else 497 { 498#if !HAVE_POPEN 499 return TAG_NOFILE; 500#else 501 char *command; 502 char *flag; 503 char *qtag; 504 char *cmd = lgetenv("LESSGLOBALTAGS"); 505 506 if (cmd == NULL || *cmd == '\0') 507 return TAG_NOFILE; 508 /* Get suitable flag value for global(1). */ 509 switch (type) 510 { 511 case T_GTAGS: 512 flag = "" ; 513 break; 514 case T_GRTAGS: 515 flag = "r"; 516 break; 517 case T_GSYMS: 518 flag = "s"; 519 break; 520 case T_GPATH: 521 flag = "P"; 522 break; 523 default: 524 return TAG_NOTYPE; 525 } 526 527 /* Get our data from global(1). */ 528 qtag = shell_quote(tag); 529 if (qtag == NULL) 530 qtag = tag; 531 command = (char *) ecalloc(strlen(cmd) + strlen(flag) + 532 strlen(qtag) + 5, sizeof(char)); 533 sprintf(command, "%s -x%s %s", cmd, flag, qtag); 534 if (qtag != tag) 535 free(qtag); 536 fp = popen(command, "r"); 537 free(command); 538#endif 539 } 540 if (fp != NULL) 541 { 542 while (fgets(buf, sizeof(buf), fp)) 543 { 544 char *name, *file, *line; 545 int len; 546 547 if (sigs) 548 { 549#if HAVE_POPEN 550 if (fp != stdin) 551 pclose(fp); 552#endif 553 return TAG_INTR; 554 } 555 len = strlen(buf); 556 if (len > 0 && buf[len-1] == '\n') 557 buf[len-1] = '\0'; 558 else 559 { 560 int c; 561 do { 562 c = fgetc(fp); 563 } while (c != '\n' && c != EOF); 564 } 565 566 if (getentry(buf, &name, &file, &line)) 567 { 568 /* 569 * Couldn't parse this line for some reason. 570 * We'll just pretend it never happened. 571 */ 572 break; 573 } 574 575 /* Make new entry and add to list. */ 576 tp = maketagent(name, file, (LINENUM) atoi(line), NULL, 0); 577 TAG_INS(tp); 578 total++; 579 } 580 if (fp != stdin) 581 { 582 if (pclose(fp)) 583 { 584 curtag = NULL; 585 total = curseq = 0; 586 return TAG_NOFILE; 587 } 588 } 589 } 590 591 /* Check to see if we found anything. */ 592 tp = taglist.tl_first; 593 if (tp == TAG_END) 594 return TAG_NOTAG; 595 curtag = tp; 596 curseq = 1; 597 return TAG_FOUND; 598} 599 600static int circular = 0; /* 1: circular tag structure */ 601 602/* 603 * Return the filename required for the next gtag in the queue that was setup 604 * by findgtag(). The next call to gtagsearch() will try to position at the 605 * appropriate tag. 606 */ 607 static char * 608nextgtag() 609{ 610 struct tag *tp; 611 612 if (curtag == NULL) 613 /* No tag loaded */ 614 return NULL; 615 616 tp = curtag->next; 617 if (tp == TAG_END) 618 { 619 if (!circular) 620 return NULL; 621 /* Wrapped around to the head of the queue */ 622 curtag = taglist.tl_first; 623 curseq = 1; 624 } else 625 { 626 curtag = tp; 627 curseq++; 628 } 629 return (curtag->tag_file); 630} 631 632/* 633 * Return the filename required for the previous gtag in the queue that was 634 * setup by findgtat(). The next call to gtagsearch() will try to position 635 * at the appropriate tag. 636 */ 637 static char * 638prevgtag() 639{ 640 struct tag *tp; 641 642 if (curtag == NULL) 643 /* No tag loaded */ 644 return NULL; 645 646 tp = curtag->prev; 647 if (tp == TAG_END) 648 { 649 if (!circular) 650 return NULL; 651 /* Wrapped around to the tail of the queue */ 652 curtag = taglist.tl_last; 653 curseq = total; 654 } else 655 { 656 curtag = tp; 657 curseq--; 658 } 659 return (curtag->tag_file); 660} 661 662/* 663 * Position the current file at at what is hopefully the tag that was chosen 664 * using either findtag() or one of nextgtag() and prevgtag(). Returns -1 665 * if it was unable to position at the tag, 0 if succesful. 666 */ 667 static POSITION 668gtagsearch() 669{ 670 if (curtag == NULL) 671 return (NULL_POSITION); /* No gtags loaded! */ 672 return (find_pos(curtag->tag_linenum)); 673} 674 675/* 676 * The getentry() parses both standard and extended ctags -x format. 677 * 678 * [standard format] 679 * <tag> <lineno> <file> <image> 680 * +------------------------------------------------ 681 * |main 30 main.c main(argc, argv) 682 * |func 21 subr.c func(arg) 683 * 684 * The following commands write this format. 685 * o Traditinal Ctags with -x option 686 * o Global with -x option 687 * See <http://www.gnu.org/software/global/global.html> 688 * 689 * [extended format] 690 * <tag> <type> <lineno> <file> <image> 691 * +---------------------------------------------------------- 692 * |main function 30 main.c main(argc, argv) 693 * |func function 21 subr.c func(arg) 694 * 695 * The following commands write this format. 696 * o Exuberant Ctags with -x option 697 * See <http://ctags.sourceforge.net> 698 * 699 * Returns 0 on success, -1 on error. 700 * The tag, file, and line will each be NUL-terminated pointers 701 * into buf. 702 */ 703 static int 704getentry(buf, tag, file, line) 705 char *buf; /* standard or extended ctags -x format data */ 706 char **tag; /* name of the tag we actually found */ 707 char **file; /* file in which to find this tag */ 708 char **line; /* line number of file where this tag is found */ 709{ 710 char *p = buf; 711 712 for (*tag = p; *p && !IS_SPACE(*p); p++) /* tag name */ 713 ; 714 if (*p == 0) 715 return (-1); 716 *p++ = 0; 717 for ( ; *p && IS_SPACE(*p); p++) /* (skip blanks) */ 718 ; 719 if (*p == 0) 720 return (-1); 721 /* 722 * If the second part begin with other than digit, 723 * it is assumed tag type. Skip it. 724 */ 725 if (!IS_DIGIT(*p)) 726 { 727 for ( ; *p && !IS_SPACE(*p); p++) /* (skip tag type) */ 728 ; 729 for (; *p && IS_SPACE(*p); p++) /* (skip blanks) */ 730 ; 731 } 732 if (!IS_DIGIT(*p)) 733 return (-1); 734 *line = p; /* line number */ 735 for (*line = p; *p && !IS_SPACE(*p); p++) 736 ; 737 if (*p == 0) 738 return (-1); 739 *p++ = 0; 740 for ( ; *p && IS_SPACE(*p); p++) /* (skip blanks) */ 741 ; 742 if (*p == 0) 743 return (-1); 744 *file = p; /* file name */ 745 for (*file = p; *p && !IS_SPACE(*p); p++) 746 ; 747 if (*p == 0) 748 return (-1); 749 *p = 0; 750 751 /* value check */ 752 if (strlen(*tag) && strlen(*line) && strlen(*file) && atoi(*line) > 0) 753 return (0); 754 return (-1); 755} 756 757#endif 758