home *** CD-ROM | disk | FTP | other *** search
Text File | 1986-07-11 | 72.5 KB | 2,915 lines |
- /*
-
- Date: Thu 10 Jul 86 03:07:25-EDT
- From: Joseph M. Newcomer <Joe.Newcomer@C.CS.CMU.EDU>
- Subject: TAGS.C Added to Library
-
-
- I now have a working TAGS system for C and Epsilon. For those of you
- who don't know what TAGS is, it allows you to find the file which
- contains a definition if you know the name of the object being defined.
- For example, you are looking at a call on procedure xYzzY, and want to
- see what it does. Fine. Invoke TAGS by typing Alt-., give it the
- name xYzzY, and suddenly before your very orbs is the definition point
- for the function! If the cursor is sitting somewhere before a word,
- that word is the default name to look up and so A-. CR usually suffices.
-
- This requires running a program over your source file that locates all
- the tags and puts them in a tag dictionary, then having an editor command
- that looks things up in the tag dictionary. I am submitting the source
- for both of these. TAGS.C is the name of the file, and it contains
- its makefile and the editor support for Epsilon, TAGS.E and TAGS1.E.
- Tags is non-resident and loaded by a library load operation; included is
- the procedure to do the library load, which you can install in your
- Epsilon environment somewhere (I put mine in FILES.E).
-
- There are some caveats. I didn't write this, it was written by Richard
- M. Stallman of EMACS and GNU fame. It comes with his copyright, which
- I believe I have honored in providing full support source with it (namely
- Epsilon code). Please continue to honor this copyright. I added
- Scribe and TeX modes, but have only tested them minimally. I have not
- tested the Fortran or Lisp modes at all. .C and .E files seem to work.
- Feel free to enhance it. It seems to have various obscure switch options
- which I don't understand; I've inserted documentation showing the result
- of the various switches. I've also added a mode that allows it to
- interact reasonably with makefiles; this is documented in the comments.
-
- I have found it immensley useful after I went back to my 84-file 700,000 byte
- source after 6 months' absence; I can now find things. I offer it,
- unsupported and 'as is'. If it is broken, please feel free to make
- improvments and resubmit it.
- joe
- -------
-
- Received: from PREP.AI.MIT.EDU by A.SEI.CMU.EDU; 29 May 86 19:02:21 EDT
- Received: by PREP.AI.MIT.EDU; Thu, 29 May 86 19:02:12 EDT
- Date: Thu, 29 May 86 19:02:12 EDT
- From: rms@PREP.AI.MIT.EDU (Richard M. Stallman)
- Message-Id: <8605292302.AA01542@prep.ai.mit.edu>
- To: Joe.Newcomer
- In-Reply-To: Joe.Newcomer's message of Wednesday, 28 May 1986 18:42:06 EDT
- Subject: tags
- */
-
- /* Tags file maker to go with GNUmacs
- Copyright (C) 1984 Richard M. Stallman and Ken Arnold
-
- This program is distributed in the hope that it will be useful,
- but without any warranty. No author or distributor
- accepts responsibility to anyone for the consequences of using it
- or for whether it serves any particular purpose or works at all,
- unless he says so in writing.
-
- Permission is granted to anyone to distribute verbatim copies
- of this program's source code as received, in any medium, provided that
- the copyright notice, the nonwarraty notice above
- and this permission notice are preserved,
- and that the distributor grants the recipient all rights
- for further redistribution as permitted by this notice,
- and informs him of these rights.
-
- Permission is granted to distribute modified versions of this
- program's source code, or of portions of it, under the above
- conditions, plus the conditions that all changed files carry
- prominent notices stating who last changed them and that the
- derived material, including anything packaged together with it and
- conceptually functioning as a modification of it rather than an
- application of it, is in its entirety subject to a permission
- notice identical to this one.
-
- Permission is granted to distribute this program (verbatim or
- as modified) in compiled or executable form, provided verbatim
- redistribution is permitted as stated above for source code, and
- A. it is accompanied by the corresponding machine-readable
- source code, under the above conditions, or
- B. it is accompanied by a written offer, with no time limit,
- to distribute the corresponding machine-readable source code,
- under the above conditions, to any one, in return for reimbursement
- of the cost of distribution. Verbatim redistribution of the
- written offer must be permitted. Or,
- C. it is distributed by someone who received only the
- compiled or executable form, and is accompanied by a copy of the
- written offer of source code which he received along with it.
-
- Permission is granted to distribute this program (verbatim or as modified)
- in executable form as part of a larger system provided that the source
- code for this program, including any modifications used,
- is also distributed or offered as stated in the preceding paragraph.
-
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding! */
-
- /*
-
- Converted to Lattice C 3.0 for MS/PC DOS by Joseph M. Newcomer
- June, 1986.
-
- Copyright 1986, Joseph M. Newcomer.
-
- Subject to the same copyright and distribution agreement as stated above.
- Non-hoardable software.
-
- Change notes:
-
- Several changes were required to convert this to Lattice C and MS/PC DOS.
- In particular, the 'system' command and case sensitivity in files do
- not exist and had to be replaced. Filename expansion is not implicitly
- done on the DOS command line and had to be explicitly installed.
-
- */
-
- /*****************************************************************************
- User documentation
-
- invoke as
- tags [options] filename filename ...
-
- where each filename may be a DOS wildcard pattern filename.
-
- The options are:
-
- -e Produces mapping of name --> line,char
- -v Produces mapping of name --> file ((line+63) / 64)
- -x Produces human-readable xref name -> line file declaration
- none of the above
- Produces format suitable for Epsilon 'tags' mode
-
- -t include typedef symbols;
-
- -a appends current input result to 'tags' file
-
- -u updates existing 'tags' file (removes previous entry and
- appends new result on end)
-
- -B sets search delimiter to '?'
-
- -F sets search delimiter to '/' (default)
-
- -w suppresses warnings
-
- -m Writes .tag file (empty file to be used by makefile
- to regenerate tags that have changed)
-
-
- Normal use is one of the following forms
-
- tags file file file ...
- Creates 'tags' from the files listed, suitable for Epsilon
- tags-mode
-
- tags -u file1 file2 ...
- Replaces the entries for file1, file2, etc. in 'tags' (or adds
- them if they are not present)
-
- tags -m -u file1
- Replaces the entries for file1 in 'tags' and
- updates the .tag file. This line would typically appear
- in the makefile as
-
- .tag.c :
- tags -m -u $<
-
-
- Included at the end of this listing is the makefile for tags itself.
-
-
- *****************************************************************************/
-
- /*
- Documentation of output file format:
-
- -e flag
-
- ^L
- file_name,number_of_entries
- name\0177line,char
- name\0177line,char
- ...
- -----------------------------------------------------------------------------
- -v
- name file (line+63)/64
-
- D:\TAGS>tags -v junk.c
- C_entries junk.c 2
- L_getit junk.c 3
- PF_funcs junk.c 3
- add_node junk.c 2
- begtoken junk.c 1
- concat junk.c 3
- consider_token junk.c 2
- endtoken junk.c 1
- error junk.c 3
- fatal junk.c 3
- find_entries junk.c 2
- free_tree junk.c 2
- getit junk.c 3
- getline junk.c 3
- init junk.c 2
- initbuffer junk.c 3
- intoken junk.c 1
- isgood junk.c 1
- iswhite junk.c 1
- main junk.c 2
- max junk.c 1
- pfnote junk.c 2
- put_entries junk.c 2
- readline junk.c 3
- rindex junk.c 3
- savestr junk.c 3
- tail junk.c 3
- takeprec junk.c 3
- total_size_of_entries junk.c 2
- xmalloc junk.c 3
- xrealloc junk.c 3
-
- D:\TAGS>
- -----------------------------------------------------------------------------
- -x
- name line file definition
-
- D:\TAGS>tags -x junk.c
- C_entries 124 junk.c C_entries ()
- L_getit 143 junk.c L_getit()
- PF_funcs 133 junk.c PF_funcs(fi)
- add_node 103 junk.c add_node(node, cur_node)
- begtoken 16 junk.c #define begtoken(arg) (_btk[arg])
- concat 169 junk.c concat (s1, s2, s3)
- consider_token 126 junk.c consider_token (lpp, token, f)
- endtoken 18 junk.c #define endtoken(arg) (_etk[arg])
- error 165 junk.c void error (s1, s2)
- fatal 162 junk.c fatal (s1, s2)
- find_entries 89 junk.c void find_entries (file)
- free_tree 100 junk.c void free_tree(node)
- getit 141 junk.c getit()
- getline 130 junk.c void getline (atchar)
- init 87 junk.c init()
- initbuffer 146 junk.c initbuffer (linebuffer)
- intoken 17 junk.c #define intoken(arg) (_itk[arg])
- isgood 19 junk.c #define isgood(arg) (_gd[arg])
- iswhite 15 junk.c #define iswhite(arg) (_wht[arg])
- main 83 junk.c main(ac,av)
- max 20 junk.c #define max(I1,I2) (I1 > I2 ? I1 : I2)
- pfnote 92 junk.c pfnote (name, f, linestart, linelen, lno, cno)
- put_entries 106 junk.c put_entries(node)
- readline 150 junk.c readline (linebuffer, stream)
- rindex 159 junk.c rindex(sp, c)
- savestr 155 junk.c savestr(cp)
- tail 136 junk.c tail(cp)
- takeprec 139 junk.c takeprec()
- total_size_of_entries 109 junk.c int total_size_of_entries(node)
- xmalloc 173 junk.c xmalloc (size)
- xrealloc 177 junk.c xrealloc (ptr, size)
-
- If the -e flag is given, it dominates everything
- If the -e flag is not given and the -x flag is not given, we
- get search patterns
-
- If the -e flag is not given and the -v flag is not given,
-
- D:\TAGS>tags junk.c
-
- produces no output but writes the file 'tags':
-
- ^L
- junk.c,604
- C_entries124,3669
- L_getit143,3902
- PF_funcs133,3809
- add_node103,3310
- #define begtoken16,428
- concat169,4282
- consider_token126,3687
- #define endtoken18,561
- void error165,4228
- fatal162,4187
- void find_entries89,3026
- void free_tree100,3266
- getit141,3889
- void getline130,3763
- init87,3014
- initbuffer146,3923
- #define intoken17,495
- #define isgood19,624
- #define iswhite15,368
- main83,2965
- #define max20,689
- pfnote92,3074
- put_entries106,3368
- readline150,3995
- rindex159,4140
- savestr155,4099
- tail136,3843
- takeprec139,3873
- int total_size_of_entries109,3413
- xmalloc173,4341
- xrealloc177,4390
-
- -----------------------------------------------------------------------------
- tags -t
-
- produces no output but writes file 'tags':
- C_entries junk.c /^C_entries ()$/
- L_getit junk.c /^L_getit()$/
- Mjunk junk.c /^main(ac,av)$/
- NODE junk.c 32
- PF_funcs junk.c /^PF_funcs(fi)$/
- TYST junk.c 36
- add_node junk.c /^add_node(node, cur_node)$/
- begtoken junk.c /^#define begtoken(arg) (_btk[arg]) \
- concat junk.c /^concat (s1, s2, s3)$/
- consider_token junk.c /^consider_token (lpp, token, f)$/
- endtoken junk.c /^#define endtoken(arg) (_etk[arg]) \
- error junk.c /^void error (s1, s2)$/
- fatal junk.c /^fatal (s1, s2)$/
- find_entries junk.c /^void find_entries (file)$/
- free_tree junk.c /^void free_tree(node)$/
- getit junk.c /^getit()$/
- getline junk.c /^void getline (atchar)$/
- init junk.c /^init()$/
- initbuffer junk.c /^initbuffer (linebuffer)$/
- intoken junk.c /^#define intoken(arg) (_itk[arg]) \
- isgood junk.c /^#define isgood(arg) (_gd[arg]) \
- iswhite junk.c /^#define iswhite(arg) (_wht[arg]) \
- max junk.c /^#define max(I1,I2) (I1 > I2 ? I1 : I2)$/
- pfnote junk.c /^pfnote (name, f, linestart, linelen, lno, cno)$/
- put_entries junk.c /^put_entries(node)$/
- readline junk.c /^readline (linebuffer, stream)$/
- rindex junk.c /^rindex(sp, c)$/
- savestr junk.c /^savestr(cp)$/
- tail junk.c /^tail(cp)$/
- takeprec junk.c /^takeprec()$/
- total_size_of_entries junk.c /^int total_size_of_entries(node)$/
- xmalloc junk.c /^xmalloc (size)$/
- xrealloc junk.c /^xrealloc (ptr, size)$/
-
- -----------------------------------------------------------------------------
- */
-
- /*****************************************************************************
- * Change Log
- * Date | Change
- *-----------+-----------------------------------------------------------------
- * 2-Jun-86 | Created
- * 2-Jun-86 | reg => (nothing) since register variables don't buy all that
- * | much on an 80286, and most compilers have bugs with them
- * 2-Jun-86 | logical is now unsigned char
- * 2-Jun-86 | Added void to valueless procedures
- * 2-Jun-86 | replaced several 'register' declarations with 'reg'
- * 2-Jun-86 | xmalloc changed from int to char* so it works properly on
- * | 80286 and friends in all memory models
- * 2-Jun-86 | xmalloc takes unsigned arg, like malloc
- * 2-Jun-86 | xrealloc also changed consistent with xmalloc. Only problem
- * | is, I can't find out what realloc does...
- * 2-Jun-86 | include <> => include ""
- * 2-Jun-86 | Wrote a realloc routine which is sort of what is supposed
- * | to be done, I think
- * 2-Jun-86 | 'entry' => 'entry_name', reserved word in Lattice C
- * 2-Jun-86 | Added some forward (extern) declarations
- * 2-Jun-86 | Added explict case to return of readline
- * 2-Jun-86 | Looks like Lattice C has undocumented realloc function.
- * | Comment out my implementation
- * 2-Jun-86 | Added debug ctce and do some debug output
- * 3-Jun-86 | readline now returns the file position, not the number of chars
- * | read. Appropriate changes have been made at all sites that
- * | call readline. This is because of CRLF -> LF translation by
- * | C runtime. Note that Lattice C 3.0 provides correct file
- * | position even when translation is done; earlier Lattice C
- * | versions did not.
- * 3-Jun-86 | In C functions, pfnote adjusts endpos-1 (probably caused by
- * | above change)
- * 3-Jun-86 | Remove code for -u, did Unix system call; will need to rewrite
- * | later.
- * | Do wildcard expansions inline, since we can't assume that the
- * | commands are expanded; create new processing routine each_file
- * | which takes the filename as input and is the body of the loop
- * | formerly in 'main'
- * 3-Jun-86 | Quote patterns for Epsilon re_search
- * 3-Jun-86 | Changed pattern size from 50 to 40 due to apparent Epsilon
- * | limitation on pattern size for re-s
- * 3-Jun-86 | Expand wildcards by using Lattice C 3.0 functions dfind, dnext
- * | and strsfn (parses file names)
- * 4-Jun-86 | Always expand filename to full d:\path\file
- * 4-Jun-86 | Added code to support -u option
- * 4-Jun-86 | In changing name of 'main', search for \\, not /
- * 4-Jun-86 | Added Scribe/FinalWord mode
- * 4-Jun-86 | Annouce files and modes
- * 4-Jun-86 | Made duplicate tag message same format as standard error message
- * | so find-next-error in editor will find it
- * 4-Jul-86 | Added -m flag for makefile processing
- * 4-Jul-86 | Removed realloc code, no longer needed
- * 4-Jul-86 | Added TeX mode, not tested since I have no TeX files today
- * 4-Jul-86 | Added 'void' to various void procedures to a-void compiler
- * | warnings
- * 4-Jul-86 | Flush stderr when logging filenames
- *****************************************************************************/
-
-
- #include "stdio.h"
- #include "ctype.h"
- #include "string.h"
- #include "dos.h"
-
- /* Define the symbol ETAGS to make the program "etags",
- which makes emacs-style tag tables by default.
- Define CTAGS to make the program "ctags" compatible with the usual one.
-
- Default is CTAGS = ETAGS = 0, which creates Epsilon tags. */
-
- /* #define ETAGS 1 */
-
- #define reg
- #define logical unsigned char
-
- #define debug FALSE
-
- #define TRUE (1)
- #define FALSE (0)
-
- #define iswhite(arg) (_wht[arg]) /* T if char is white */
- #define begtoken(arg) (_btk[arg]) /* T if char can start token */
- #define intoken(arg) (_itk[arg]) /* T if char can be in token */
- #define endtoken(arg) (_etk[arg]) /* T if char ends tokens */
- #define isgood(arg) (_gd[arg]) /* T if char can be after ')' */
-
- #define max(I1,I2) (I1 > I2 ? I1 : I2)
-
- struct nd_st { /* sorting structure */
- char *entry_name; /* function or type name */
- char *file; /* file name */
- logical f; /* use pattern or line no */
- int lno; /* line number tag is on */
- long cno; /* character number line starts on */
- char *pat; /* search pattern */
- logical been_warned; /* set if noticed dup */
- struct nd_st *left,*right; /* left and right sons */
- };
-
- long ftell();
- typedef struct nd_st NODE;
-
- int number; /* tokens found so far on line starting with # (including #) */
- logical gotone, /* found a func already on line */
- /* boolean "func" (see init) */
- _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177];
-
- /* typedefs are recognized using a simple finite automata,
- * tydef is its state variable.
- */
- typedef enum {none, begin, middle, end } TYST;
-
- TYST tydef = none;
-
- char searchar = '/'; /* use /.../ searches */
-
- int lineno; /* line number of current line */
- long charno; /* current character number */
- long linecharno; /* character number of start of line */
-
- char *curfile, /* current input file name */
- *outfile= "tags", /* output file */
- *white = " \f\t\n", /* white chars */
- *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",
- /* token ending chars */
- *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz",
- /* token starting chars */
- *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789",
- /* valid in-token chars */
- *notgd = ",;"; /* non-valid after-function chars */
-
- int file_num; /* current file number */
- int aflag; /* -a: append to tags */
- int tflag; /* -t: create tags for typedefs */
- int mflag; /* -m: create .tag file for makefile */
- int uflag; /* -u: update tags */
- int wflag; /* -w: suppress warnings */
- int vflag; /* -v: create vgrind style index output */
- int xflag; /* -x: create cxref style output */
- int eflag; /* -e: emacs style output */
-
- FILE *inf, /* ioptr for current input file */
- *outf; /* ioptr for tags file */
-
- NODE *head; /* the head of the sorted binary tree */
-
- char *savestr();
- char *rindex();
- char *concat ();
- void initbuffer ();
- long readline ();
-
- /* A `struct linebuffer' is a structure which holds a line of text.
- `readline' reads a line from a stream into a linebuffer
- and works regardless of the length of the line. */
-
- struct linebuffer
- {
- long size;
- char *buffer;
- };
-
- struct linebuffer lb, lb1;
-
- int needCRLF = FALSE;
-
- #define forward extern
-
- forward void add_node();
- forward void C_entries();
- forward void checkCRLF();
- forward void each_file();
- forward void error();
- forward void find_entries();
- forward void free_tree();
- forward void getit();
- forward void getline();
- forward void init();
- forward void L_funcs();
- forward void L_getit();
- forward void put_entries();
- forward void S_labels();
- forward void tagit();
- forward void takeprec();
- forward void T_labels();
- forward void usage();
- forward char * xmalloc();
- forward char * xrealloc();
- forward char * realloc();
- extern char * malloc();
- extern char * stpchr();
-
- /****************************************************************************
- * main
- * Inputs:
- * int ac: count of arguments
- * char * av[]: vector of pointers to arguments
- * Result: void
- * Implicit value is returned via exit() call
- * Effect:
- * Executes the tags program
- ****************************************************************************/
-
- void main(ac,av)
- int ac;
- char *av[];
- {
- int i;
-
- #ifdef ETAGS
- eflag = 1;
- #endif
-
-
- while (ac > 1 && av[1][0] == '-')
- {
- eflag = 0;
- for (i=1; av[1][i]; i++)
- {
- switch(av[1][i])
- {
- case 'B':
- searchar='?';
- break;
- case 'F':
- searchar='/';
- break;
- case 'a':
- aflag++;
- break;
- case 'e':
- eflag++;
- break;
- case 'm':
- mflag++;
- break;
- case 't':
- tflag++;
- break;
- case 'u':
- uflag++;
- break;
- case 'w':
- wflag++;
- break;
- case 'v':
- vflag++;
- xflag++;
- break;
- case 'x':
- xflag++;
- break;
- default:
- usage(av[0]);
- exit(1);
- }
- }
- ac--; av++;
- }
-
- if (ac <= 1)
- {
- usage(av[0]);
- exit(1);
- }
-
- if (eflag)
- outfile = "TAGS";
-
- init(); /* set up boolean "functions" */
-
- initbuffer (&lb);
- initbuffer (&lb1);
- /*
- * loop through files finding functions
- */
- if (eflag)
- {
- outf = fopen (outfile, aflag ? "a" : "w");
- if (!outf)
- {
- perror (outfile);
- exit (1);
- }
- }
-
- for (file_num = 1; file_num < ac; file_num++)
- {
- /* Unix would expand the file names; in MS-DOS if we have wildcards
- we have to expand them here. This requires doing the expansion
- and calling a per-file processing routine
- */
-
- struct FILEINFO info;
-
- char fname[80];
- char dev[3];
- char path[FMSIZE];
- char name[FNSIZE];
- char ext[4];
- int drive;
-
-
- if(dfind(&info,av[file_num],0))
- { /* no files match */
- fprintf(stderr,"%s 0 Error: Could not find file\n",av[file_num]);
- continue;
- } /* no files match */
-
- /* Parse the filename into its device, path, filename and extension
- components
- */
- strsfn(av[file_num],dev,path,name,ext);
-
- /* If no explicit path is given, get the current path */
-
- if(strlen(dev) == 0)
- { /* default drive */
- drive = getdsk() + 1; /* current default drive's path */
- /* Note that A=0, B=1, etc., but
- we want it encoded as
- A=1, B=2, etc.
- */
- dev[0] = drive + 'A' - 1;
- dev[1] = ':';
- dev[2] = '\0';
- } /* default drive */
- else
- drive = dev[0] - 'A' + 1;
-
- if(strlen(path) == 0)
- getcd(drive,path);
-
- do
- { /* scan file name */
-
- /* Expand the filename by getting the device and path from the
- input string and appending the filename from the info block
- */
-
- strcpy(fname,dev);
- if(strlen(path) > 0 && path[0] != '\\')
- strcat(fname,"\\");
- strcat(fname,path);
- if(fname[strlen(fname)-1] != '\\')
- strcat(fname,"\\");
-
- strcat(fname,info.name);
- strlwr(fname); /* make all lower case for readability */
-
- if(!xflag && !vflag)
- { /* announce */
- fprintf(stderr,"%s",fname);
- fflush(stderr);
- needCRLF = TRUE;
- } /* announce */
-
- each_file(fname);
-
- checkCRLF();
-
- } /* scan file name */
- while (!dnext(&info));
- }
-
- if (uflag)
- {
- /* This sequence can be omitted because we sort the listing
- when we are in Epsilon
- */
- /****************************************************************
- sprintf(cmd, "sort %s -o %s", outfile, outfile);
- system(cmd);
- ****************************************************************/
- }
-
-
- exit(0);
- }
-
- /****************************************************************************
- * usage
- * Inputs:
- * char * name: Program name from argv[0]
- * Result: void
- *
- * Effect:
- * Issues the 'usage' message
- * Notes:
- * This depends upon the fact that DOS 3.x returns the program name as
- * the first argument. If it does not, you will have to change this
- * routine
- ****************************************************************************/
-
- void usage(name)
- char * name;
- {
- char node[20];
- char drive[4];
- char path[80];
- char ext[5];
- strsfn(name,drive,path,node,ext);
- fprintf(stderr,"Usage: %s [-BFaemtuwvx] file ...\n",node);
- }
-
- /****************************************************************************
- * checkCRLF
- * Effect:
- * If a CRLF is needed on the output stream, puts one out. Sets
- * needCRLF to false
- ****************************************************************************/
-
- void checkCRLF()
- {
- if(needCRLF) fprintf(stderr,"\n");
- needCRLF = FALSE;
- }
-
- /****************************************************************************
- * strip_out
- * Inputs:
- * char * file: file name to strip out (note that it must be in the
- * same form as the one in the file)
- *
- * Result: boolean
- * true if operation was successful
- * false if it failed for some reason
- * Effect:
- * renames "tags" to "otags", copies it back to "tags" stripping out
- * entries for the current file
- ****************************************************************************/
-
- int strip_out(file)
- char * file;
- {
- FILE * old;
- FILE * new;
-
- fprintf(stderr,"stripping out old entries...");
- fflush(stderr);
- needCRLF = TRUE;
-
- remove("otags");
- if(rename("tags","otags"))
- { /* failed */
- fprintf(stderr,"Unable to rename 'tags' to 'otags', update cannot be done\n");
- return FALSE;
- } /* failed */
-
- old = fopen("otags","r");
- if(old==NULL)
- { /* failed */
- fprintf(stderr,"failed to open 'otags' for copy, update cannot be done\n");
- return FALSE;
- } /* failed */
-
- new = fopen(outfile,"w");
-
- if(new==NULL)
- { /* failed again */
- fprintf(stderr,"failed to open '%s' for copy, update cannot be done\n",
- outfile);
- close(old);
- return FALSE;
- } /* failed again */
-
- while(TRUE)
- { /* copy lines */
- char line[256];
- char * p1;
- char * p2;
-
- fgets(line,256,old);
-
- if(feof(old)) break;
-
- p1 = stpchr(line,'\t'); /* find initial tab char */
-
- if(p1 != NULL)
- { /* ok */
- p1++;
- p2 = stpchr(p1,'\t'); /* find next tab char */
-
- if(p2 != NULL)
- { /* found it! */
- if(strncmp(p1,file,p2-p1) == 0)
- { /* strip it! */
- continue;
- } /* strip it! */
- } /* found it! */
- } /* ok */
- fputs(line,new);
- } /* copy lines */
-
- fclose(old);
- fclose(new);
-
- printf("\n");
-
- return TRUE;
- }
-
- /****************************************************************************
- * each_file
- * Inputs:
- * char * file: File name to process
- * Result: void
- *
- * Effect:
- * Processes the file.
- ****************************************************************************/
-
- void each_file(file)
- char * file;
- {
- find_entries(file);
- if (eflag)
- {
- fprintf (outf, "\f\n%s,%d\n",
- file, total_size_of_entries (head));
- put_entries (head);
- free_tree (head);
- head = NULL;
- }
-
- if (eflag)
- {
- fclose (outf);
- }
-
- if (xflag)
- {
- put_entries(head);
- }
-
- if (uflag)
- {
- /*
- The purpose of the following sequence is to copy everything
- from the original output file to a file of the same name,
- eliminating all of the information of the current file
- under consideration.
-
- In Unix, this is done by using fgrep to remove all but the
- strings of the current file name.
-
- In MS-DOS, we have to be much, much sneakier, but I'm not
- going to write that code right now.
- */
- /*****************************************************************
- sprintf(cmd,
- "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
- outfile, file, outfile);
- system(cmd);
- ****************************************************************/
- if(strip_out(file))
- aflag++;
- else
- return;
- }
-
- /* If we are in update mode, we open for append access (having just
- eliminated the data for our current file in the section above
- if necessary); otherwise we overwrite the output file
- If we have already processed one file, we also have incremented aflag,
- so we will be in update mode also.
- */
-
- outf = fopen(outfile, aflag ? "a" : "w");
- if (outf == NULL)
- { /* output open failed */
- perror(outfile);
- exit(1);
- } /* output open failed */
-
- put_entries(head);
- fclose(outf);
-
- }
-
- /****************************************************************************
- * init
- * Effect:
- * This routine sets up the boolean psuedo-functions which work
- * by seting boolean flags dependent upon the corresponding character
- * Every char which is NOT in that string is not a white char.
- * Therefore, all of the array "_wht" is set to FALSE, and then the
- * elements subscripted by the chars in "white" are set to TRUE. Thus
- * "_wht" of a char is TRUE if it is the string "white", else FALSE.
- ****************************************************************************/
-
- void init()
- {
-
- reg char *sp;
- reg int i;
-
- for (i = 0; i < 0177; i++)
- {
- _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
- _gd[i] = TRUE;
- }
- for (sp = white; *sp; sp++)
- _wht[*sp] = TRUE;
- for (sp = endtk; *sp; sp++)
- _etk[*sp] = TRUE;
- for (sp = intk; *sp; sp++)
- _itk[*sp] = TRUE;
- for (sp = begtk; *sp; sp++)
- _btk[*sp] = TRUE;
- for (sp = notgd; *sp; sp++)
- _gd[*sp] = FALSE;
- _wht[0] = _wht['\n'];
- _etk[0] = _etk['\n'];
- _btk[0] = _btk['\n'];
- _itk[0] = _itk['\n'];
- _gd[0] = _gd['\n'];
- }
-
- /****************************************************************************
- * tagit
- * Inputs:
- * char * file: Name of file
- * Result: void
- *
- * Effect:
- * Writes a .tag file of the same name as the input file; this is
- * for use with makefiles so that tags can be automatically updated
- * (note that recompilation should not affect tag regeneration, since
- * it may be that the source is unchanged but a dependent file is
- * changed)
- ****************************************************************************/
-
- void tagit(file)
- char * file;
- {
- char tagname[80];
- char * p;
- FILE * tagfile;
-
- strcpy(tagname,file);
-
- p = rindex(tagname,'.');
- if(p!=NULL) *p = '\0';
- strcat(tagname,".tag");
- tagfile = fopen(tagname,"w");
- if(tagfile == NULL)
- { /* failed */
- fprintf(stderr,"Failed to create \"%s\", auto-retagging may file in your makefile\n",tagfile);
- return;
- } /* failed */
- fclose(tagfile);
- return;
-
- }
-
- /****************************************************************************
- * find_entries
- * Inputs:
- * char * file
- * Result: void
- *
- * Effect:
- * This routine opens the specified file and calls the function
- * which finds the function and type definitions.
- ****************************************************************************/
-
- void find_entries (file)
- char *file;
- {
- char *cp;
-
- if ((inf=fopen(file,"r")) == NULL)
- {
- perror(file);
- return;
- }
- curfile = savestr(file);
- cp = rindex(file, '.');
-
- /* .l or .el or .lisp implies lisp source code */
- /* LISP MODE FILE */
-
- if (cp && (!strcmp (cp + 1, "l") || !strcmp (cp + 1, "el")
- || !strcmp (cp + 1, "lisp")))
- {
- L_funcs(inf);
- fclose(inf);
- if(mflag) tagit(file);
- return;
- }
-
- /* If a .MSS file, try Scribe mode */
-
- if (cp && (strcmp(cp+1,"mss") == 0))
- { /* scribe */
- S_labels(inf);
- fclose(inf);
- if(mflag) tagit(file);
- return;
- } /* scribe */
-
- /* If a .TEX file, try TeX mode */
-
- if (cp && (strcmp(cp+1,"tex") == 0))
- { /* TeX */
- T_labels(inf);
- fclose(inf);
- if(mflag) tagit(file);
- return;
- } /* TeX */
-
-
- /* if not a .c or .h or .y file, try fortran */
- if (cp && (cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y')
- && cp[2] == '\0')
- {
- if (PF_funcs(inf) != 0)
- {
- fclose(inf);
- if(mflag) tagit(file);
- return;
- }
- rewind(inf); /* no fortran tags found, try C */
- }
- C_entries();
- fclose(inf);
- if(mflag) tagit(file);
- }
-
- /****************************************************************************
- * pfnote
- * Inputs:
- * char * name:
- * logical f:
- * char * linestart: pointer to start of line
- * int linelen: length of line in characters
- * int lno: Number of line in input file
- * long cno: Character number in input file
- * Result: void
- *
- * Effect:
- * Record a tag on the current line.
- * 'name' is the tag name,
- * 'f' is nonzero to use a pattern, zero to use line number instead.
- ****************************************************************************/
-
- void pfnote (name, f, linestart, linelen, lno, cno)
- char *name;
- logical f; /* f == TRUE when function */
- char *linestart;
- int linelen;
- int lno;
- long cno;
- {
- reg char *fp;
- reg NODE *np;
- char *altname;
- char tem[51];
-
- #if debug
- printf("pfnote(\"%s\",%d,\"%s\",%d,%d,%ld)\n",
- name,f,linestart,linelen,lno,cno);
- #endif
- if ((np = (NODE *) malloc(sizeof (NODE))) == NULL)
- {
- fprintf(stderr, "ctags: too many entries to sort\n");
- put_entries(head);
- free_tree(head);
- head = NULL;
- np = (NODE *) xmalloc(sizeof (NODE));
- }
- /* Change name "main" to M<thisfilename>. */
- if (!eflag && !xflag && !strcmp(name, "main"))
- {
- fp = rindex(curfile, '\\');
- if (fp == 0)
- fp = curfile;
- else
- fp++;
- altname = concat ("M", fp, "");
- fp = rindex(altname, '.');
- if (fp && fp[2] == 0)
- *fp = 0;
- name = altname;
- }
- np->entry_name = savestr(name);
- np->file = curfile;
- np->f = f;
- np->lno = lno;
- np->cno = cno;
- np->left = np->right = 0;
- if (eflag)
- {
- linestart[linelen] = 0;
- }
- else if (xflag == 0)
- {
- sprintf (tem, strlen (linestart) < 40 ? "%s$" : "%.40s", linestart);
- linestart = tem;
- }
- np->pat = savestr (linestart);
- if (head == NULL)
- head = np;
- else
- add_node(np, head);
- }
-
- /****************************************************************************
- * free_tree
- * Inputs:
- * NODE * node: Root of tree to free
- * Result: void
- *
- * Effect:
- * Releases all the storage in the tree
- ****************************************************************************/
-
- void free_tree(node)
- NODE *node;
- {
- while (node)
- {
- free_tree(node->right);
- free(node);
- node = node->left;
- }
- }
-
- /****************************************************************************
- * add_node
- * Inputs:
- * NODE * node: Node to add
- * NODE * cur_node: Node at which we are currently sitting
- * Result: void
- *
- * Effect:
- * Adds the node into the tree as a descendent of cur_node
- ****************************************************************************/
-
- void add_node(node, cur_node)
- NODE *node,*cur_node;
- {
- register int dif;
-
- dif = strcmp(node->entry_name, cur_node->entry_name);
-
- /* If this tag name matches an existing one, then
- unless -e was given, do not add the node, but maybe print a warning */
- if (!eflag && !dif)
- {
- if (node->file == cur_node->file)
- {
- if (!wflag)
- {
- checkCRLF();
- fprintf(stderr,"%s %d Warning: Duplicate entry \"%s\"\n",
- node->file,lineno,node->entry_name);
- fprintf(stderr,"Second entry ignored\n");
- }
- return;
- }
- if (!cur_node->been_warned)
- if (!wflag)
- { /* print warning */
- checkCRLF();
-
- fprintf(stderr,"Duplicate entry in files %s and %s: %s (Warning only)\n",
- node->file, cur_node->file, node->entry_name);
- } /* print warning */
-
- cur_node->been_warned = TRUE;
- return;
- }
-
- /* Actually add the node */
- if (dif < 0)
- {
- if (cur_node->left != NULL)
- add_node(node,cur_node->left);
- else
- cur_node->left = node;
- return;
- }
- if (cur_node->right != NULL)
- add_node(node,cur_node->right);
- else
- cur_node->right = node;
- }
-
- /****************************************************************************
- * put_entries
- * Inputs:
- * NODE * node:
- * Result: void
- *
- * Effect:
- * 2
- ****************************************************************************/
-
- void put_entries(node)
- reg NODE *node;
- {
- reg char *sp;
-
- if (node == NULL)
- return;
-
- /* Output subentries that precede this one */
- put_entries (node->left);
-
- /* Output this entry */
-
- if (eflag)
- {
- fprintf (outf, "%s%c%d,%d\n",
- node->pat, 0177, node->lno, node->cno);
- }
- else if (!xflag)
- {
- fprintf (outf, "%s\t%s\t",
- node->entry_name, node->file);
-
- if (node->f)
- { /* a function */
- putc (searchar, outf);
- putc ('^', outf);
-
- for (sp = node->pat; *sp; sp++)
- {
- if ( /* Epsilon re_search chars quoted */
- *sp == searchar
- || *sp == '*'
- || *sp == '%'
- || *sp == '^'
- || *sp == '.'
- || *sp == '['
- || *sp == ']'
- || *sp == '('
- || *sp == ')'
- || *sp == '+'
- || *sp == '|'
- || *sp == '!')
- putc ('%', outf); /* put out quoting char */
- putc (*sp, outf);
- }
- putc (searchar, outf);
- }
- else
- { /* a typedef; text pattern inadequate */
- fprintf (outf, "%d", node->lno);
- }
- putc ('\n', outf);
- }
- else if (vflag)
- fprintf (stdout, "%s %s %d\n",
- node->entry_name, node->file, (node->lno+63)/64);
- else
- fprintf (stdout, "%-16s%4d %-16s %s\n",
- node->entry_name, node->lno, node->file, node->pat);
-
- /* Output subentries that follow this one */
- put_entries (node->right);
- }
-
-
- /****************************************************************************
- * total_size_of_entries
- * Inputs:
- * NODE * node: root of subtree
- * Result: int
- * Return total number of characters that put_entries will output for
- * the nodes in the subtree of the specified node.
- * Works only if eflag is set, but called only in that case.
- ****************************************************************************/
-
-
- int total_size_of_entries(node)
- reg NODE *node;
- {
- reg int total = 0;
- reg long num;
-
- if (node == NULL)
- return 0;
-
- /* Count subentries that precede this one */
- total = total_size_of_entries (node->left);
-
- /* Count subentries that follow this one */
- total += total_size_of_entries (node->right);
-
- /* Count this entry */
-
- total += strlen (node->pat) + 3;
-
- num = node->lno;
- while (num)
- {
- total++;
- num /= 10;
- }
-
- num = node->cno;
- if (!num) total++;
- while (num)
- {
- total++;
- num /= 10;
- }
- return total;
- }
-
- /****************************************************************************
- * CNL_SAVE_NUMBER
- * Effect:
- * 2
- ****************************************************************************/
-
- #define CNL_SAVE_NUMBER \
- { \
- linecharno = charno; lineno++; \
- charno = readline (&lb, inf); \
- lp = lb.buffer; \
- }
-
- /****************************************************************************
- * CNL
- * Effect:
- * 2
- ****************************************************************************/
-
-
- #define CNL \
- { \
- CNL_SAVE_NUMBER; \
- number = 0; \
- }
-
- /****************************************************************************
- * C_entries
- * Result: 2
- * 2
- * Effect:
- * This routine finds functions and typedefs in C syntax and adds them
- * to the list.
- ****************************************************************************/
-
- void C_entries ()
- {
- reg int c;
- reg char *token, *tp, *lp;
- logical incomm, inquote, inchar, midtoken;
- int level;
- char tok[BUFSIZ];
-
- token = NULL; /* avoid uninitialized var errors, even though
- flow of control makes it impossible*/
- tp = NULL; /* likewise */
-
- fprintf(stderr," C mode ");
- fflush(stderr);
- needCRLF = TRUE;
-
- lineno = 0;
- charno = 0;
- lp = lb.buffer;
- *lp = 0;
-
- number = 0;
- gotone = midtoken = inquote = inchar = incomm = FALSE;
- level = 0;
-
- while (!feof (inf))
- {
- c = *lp++;
- if (c == 0)
- {
- CNL;
- gotone = FALSE;
- }
- if (c == '\\')
- {
- c = *lp++;
- if (c == 0)
- CNL_SAVE_NUMBER;
- c = ' ';
- }
- else if (incomm)
- {
- if (c == '*')
- {
- while ((c = *lp++) == '*')
- continue;
- if (c == 0)
- CNL;
- if (c == '/')
- incomm = FALSE;
- }
- }
- else if (inquote)
- {
- /*
- * Too dumb to know about \" not being magic, but
- * they usually occur in pairs anyway.
- */
- if (c == '"')
- inquote = FALSE;
- continue;
- }
- else if (inchar)
- {
- if (c == '\'')
- inchar = FALSE;
- continue;
- }
- else switch (c)
- { /* decode char */
- case '"':
- inquote = TRUE;
- continue;
- case '\'':
- inchar = TRUE;
- continue;
- case '/':
- if (*lp == '*')
- {
- lp++;
- incomm = TRUE;
- }
- continue;
- case '#':
- if (lp == lb.buffer + 1)
- number = 1;
- continue;
- case '{':
- if (tydef == begin)
- {
- tydef=middle;
- }
- level++;
- continue;
- case '}':
- if (lp == lb.buffer + 1)
- level = 0; /* reset */
- else
- level--;
- if (!level && tydef==middle)
- {
- tydef=end;
- }
- continue;
- } /* decode char */
-
- if (!level && !inquote && !incomm && gotone == FALSE)
- {
- if (midtoken)
- {
- if (endtoken(c))
- {
- int f;
- char *buf = lb.buffer;
- int endpos = lp - lb.buffer;
- char *lp1 = lp;
- int line = lineno;
- long linestart = linecharno;
- int tem = consider_token (&lp1, token, &f);
-
- lp = lp1;
- if (tem)
- {
- if (linestart != linecharno)
- {
- getline (linestart);
- strncpy (tok, token + (lb1.buffer - buf),
- tp-token+1);
- tok[tp-token+1] = 0;
- pfnote(tok, f, lb1.buffer, endpos - 1, line, linestart);
- }
- else
- {
- strncpy (tok, token, tp-token+1);
- tok[tp-token+1] = 0;
- pfnote(tok, f, lb.buffer, endpos - 1, line, linestart);
- }
- gotone = f; /* function */
- }
- midtoken = FALSE;
- token = lp - 1;
- }
- else if (intoken(c))
- tp++;
- }
- else if (begtoken(c))
- {
- token = tp = lp - 1;
- midtoken = TRUE;
- }
- }
- if (c == ';' && tydef==end) /* clean with typedefs */
- tydef=none;
- }
- }
-
- /****************************************************************************
- * consider_token
- * Inputs:
- * char ** lpp: Pointer to line position pointer
- * char * token: Pointer to token buffer
- * int * f:
- * Result: boolean
- * 2
- * Effect:
- * This routine checks to see if the current token is
- * at the start of a function, or corresponds to a typedef
- * It updates the input line * 'lpp' so that the '(' will be
- * in it when it returns.
- ****************************************************************************/
-
- consider_token (lpp, token, f)
- char **lpp, *token;
- int *f;
- {
- reg char *lp = *lpp;
- reg char c;
- static logical next_token_is_func;
- logical firsttok; /* T if have seen first token in ()'s */
- int bad, win;
-
- #if debug
- printf("consider_token(0x%x:\"%s\",0x%x,0x%x)\n",lpp,*lpp,token,f);
- #endif
- *f = 1; /* a function */
- c = lp[-1];
- bad = FALSE;
- if (!number)
- { /* space is not allowed in macro defs */
- while (iswhite(c))
- {
- c = *lp++;
- if (c == 0)
- {
- if (feof (inf))
- break;
- CNL;
- }
- }
- /* the following tries to make it so that a #define a b(c) */
- /* doesn't count as a define of b. */
- }
- else
- {
- number++;
- if (number >= 4 || (number==2 && strncmp (token, "define", 6)))
- {
- gotone = TRUE;
- badone:
- bad = TRUE;
- goto ret;
- }
- }
- /* check for the typedef cases */
- if (tflag && !strncmp(token, "typedef", 7))
- {
- tydef=begin;
- goto badone;
- }
- if (tydef==begin && (!strncmp(token, "struct", 6) ||
- !strncmp(token, "union", 5) || !strncmp(token, "enum", 4)))
- {
- goto badone;
- }
- if (tydef==begin)
- {
- tydef=end;
- goto badone;
- }
- if (tydef==end)
- {
- *f = 0;
- win = 1;
- goto ret;
- }
- /* Detect GNUmacs's function-defining macros. */
- if (!number && !strncmp (token, "DEF", 3))
-
- {
- next_token_is_func = 1;
- goto badone;
- }
- if (next_token_is_func)
- {
- next_token_is_func = 0;
- win = 1;
- goto ret;
- }
- if (c != '(')
- goto badone;
- firsttok = FALSE;
- while ((c = *lp++) != ')')
- {
- if (c == 0)
- {
- if (feof (inf))
- break;
- CNL;
- }
- /*
- * This line used to confuse ctags:
- * int (*oldhup)();
- * This fixes it. A nonwhite char before the first
- * token, other than a / (in case of a comment in there)
- * makes this not a declaration.
- */
- if (begtoken(c) || c=='/') firsttok++;
- else if (!iswhite(c) && !firsttok) goto badone;
- }
- while (iswhite (c = *lp++))
- {
- if (!c)
- CNL;
- }
- win = isgood (c);
- ret:
- *lpp = lp - 1;
- return !bad && win;
- }
-
- /****************************************************************************
- * getline
- * Inputs:
- * long atchar: character at which to start scan
- * Result: void
- *
- * Effect:
- * Reads an input line starting at 'atchar' and proceeding thru the
- * next linefeed character
- ****************************************************************************/
-
- void getline (atchar)
- long atchar;
- {
- long saveftell = ftell (inf);
-
- #if debug
- printf("getline(%ld): saveftell = %ld",atchar,saveftell);
- #endif
- fseek (inf, atchar, 0);
- readline (&lb1, inf);
- #if debug
- printf(" => \"%s\"\n",lb.buffer);
- #endif
- fseek (inf, saveftell, 0);
- }
-
- /* Fortran parsing */
-
- char *dbp;
- int pfcnt;
-
- PF_funcs(fi)
- FILE *fi;
- {
- lineno = 0;
- charno = 0;
- pfcnt = 0;
-
- while (!feof (fi))
- {
- lineno++;
- linecharno = charno;
- charno = readline (&lb, fi);
- dbp = lb.buffer;
- if (*dbp == '%') dbp++ ; /* Ratfor escape to fortran */
- while (isspace(*dbp))
- dbp++;
- if (*dbp == 0)
- continue;
- switch (*dbp |' ')
- {
- case 'i':
- if (tail("integer"))
- takeprec();
- break;
- case 'r':
- if (tail("real"))
- takeprec();
- break;
- case 'l':
- if (tail("logical"))
- takeprec();
- break;
- case 'c':
- if (tail("complex") || tail("character"))
- takeprec();
- break;
- case 'd':
- if (tail("double"))
- {
- while (isspace(*dbp))
- dbp++;
- if (*dbp == 0)
- continue;
- if (tail("precision"))
- break;
- continue;
- }
- break;
- }
- while (isspace(*dbp))
- dbp++;
- if (*dbp == 0)
- continue;
- switch (*dbp|' ')
- {
- case 'f':
- if (tail("function"))
- getit();
- continue;
- case 's':
- if (tail("subroutine"))
- getit();
- continue;
- case 'p':
- if (tail("program"))
- {
- getit();
- continue;
- }
- if (tail("procedure"))
- getit();
- continue;
- }
- }
- return (pfcnt);
- }
-
- int tail(cp)
- char *cp;
- {
- register int len = 0;
-
- while (*cp && (*cp&~' ') == ((*(dbp+len))&~' '))
- cp++, len++;
- if (*cp == 0)
- {
- dbp += len;
- return (1);
- }
- return (0);
- }
-
- void takeprec()
- {
- while (isspace(*dbp))
- dbp++;
- if (*dbp != '*')
- return;
- dbp++;
- while (isspace(*dbp))
- dbp++;
- if (!isdigit(*dbp))
- {
- --dbp; /* force failure */
- return;
- }
- do
- dbp++;
- while (isdigit(*dbp));
- }
-
- /****************************************************************************
- * getit
- * Result: void
- *
- * Effect:
- * 2
- ****************************************************************************/
-
- void getit()
- {
- register char *cp;
- char c;
- char nambuf[BUFSIZ];
-
- while (isspace(*dbp))
- dbp++;
- if (*dbp == 0 || !isalpha(*dbp))
- return;
- for (cp = dbp+1; *cp && (isalpha(*cp) || isdigit(*cp)); cp++)
- continue;
- c = cp[0];
- cp[0] = 0;
- strcpy(nambuf, dbp);
- cp[0] = c;
- pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
- pfcnt++;
- }
-
- /****************************************************************************
- * get_bkt
- * Inputs:
- * char * bp: Bracket pointer to start of bracketed string (may have
- * leading whitespace)
- * Result: char *
- * Bracket pointer to ending bracket
- ****************************************************************************/
-
- char * get_bkt(bp)
- char * bp;
- {
- char * ebp;
- char ebkt;
-
- /* skip initial whitespace */
-
- while(*bp == ' ') bp++;
-
- switch(*bp)
- { /* find match */
- #define mbkt(l,r) case l: ebkt = r; break
- mbkt('[',']');
- mbkt('(',')');
- mbkt('<','>');
- mbkt('{','}');
- mbkt('\"','\"');
- default: ebkt = NULL;
- } /* find match */
-
- if(!ebkt) return NULL;
-
- ebp = stpchr(++bp,ebkt);
-
- return ebp;
-
- }
-
- /****************************************************************************
- * S_labels
- * Inputs:
- * FILE * fi: Input file
- * Effect:
- * Scans for @tag and @label directives
- ****************************************************************************/
-
- void S_labels(fi)
- FILE * fi;
- {
- char nambuf[BUFSIZ];
- char * ebp;
- char * dbp;
- char * obp;
- char * cp;
-
- fprintf(stderr," Scribe mode ");
- fflush(stderr);
- needCRLF = TRUE;
-
- lineno = 0;
- charno = 0;
- pfcnt = 0;
-
- while (!feof(fi))
- { /* read lines */
-
- lineno++;
- linecharno = charno;
- charno = readline(&lb,fi);
- dbp = lb.buffer;
- while( dbp = stpchr(dbp,'@'))
- { /* some Scribe command... */
- ebp = NULL;
- if(strncmp(dbp,"@label",6) == 0)
- { /* @label */
- obp = &dbp[6];
- while(*obp == ' ') obp++;
- ebp = get_bkt(obp);
- if(ebp != NULL)
- { /* parse label */
- char c;
- /* @label < name >
- * ^dbp ^ebp
- * ^obp
- */
-
- while (*++obp == ' ') ;
-
- c = *ebp;
- *ebp = '\0';
- strcpy(nambuf,obp);
- *ebp = c;
-
- /* trim trailing whitespace */
-
- while(cp = rindex(nambuf,' ')) *cp = '\0';
-
- pfnote(nambuf, TRUE, dbp, ebp - dbp + 1, lineno, linecharno);
- pfcnt++;
- } /* parse label */
- } /* @label */
- else
- if(strncmp(dbp,"@tag",4) == 0)
- { /* @tag */
- obp = &dbp[4];
- /* @tag < name >
- * ^dbp
- * ^obp
- */
-
- while(*obp == ' ') obp++;
- /* @tag < name >
- * ^dbp
- * ^obp
- */
-
- ebp = get_bkt(obp);
- if(ebp != NULL)
- { /* parse tag */
- char c;
- /* @tag < name >
- * ^dbp ^ebp
- * ^obp
- */
-
- while( *++obp == ' ') ;
-
- /* @tag < name >
- * ^dbp ^ebp
- * ^obp
- */
-
- c = *ebp;
- *ebp = '\0';
- strcpy(nambuf,obp);
- *ebp = c;
-
- /* It may be of the form
- @tag < name = value >
- so nambuf contains
- name = value
- */
-
- if(cp = stpchr(nambuf,'='))
- { /* equality */
- *cp = '\0';
- } /* equality */
-
- /* trim trailing whitespace */
-
- while(cp = rindex(nambuf,' ')) *cp = '\0';
-
- pfnote(nambuf, TRUE, dbp, ebp - dbp + 1, lineno, linecharno);
- pfcnt++;
- } /* parse tag */
- } /* @tag */
-
- dbp++;
- } /* some Scribe command... */
- } /* read lines */
- }
-
- /****************************************************************************
- * T_labels
- * Inputs:
- * FILE * fi: Input file
- * Effect:
- * Scans for \label directives
- ****************************************************************************/
-
- void T_labels(fi)
- FILE * fi;
- {
- char nambuf[BUFSIZ];
- char * ebp;
- char * dbp;
- char * obp;
- char * cp;
-
- fprintf(stderr," TeX mode ");
- fflush(stderr);
- needCRLF = TRUE;
- lineno = 0;
- charno = 0;
- pfcnt = 0;
-
- while (!feof(fi))
- { /* read lines */
-
- lineno++;
- linecharno = charno;
- charno = readline(&lb,fi);
- dbp = lb.buffer;
- while( dbp = stpchr(dbp,'\\'))
- { /* some TeX command... */
- ebp = NULL;
- if(strncmp(dbp,"\\label",6) == 0)
- { /* \label */
- obp = &dbp[6];
- while(*obp == ' ') obp++;
-
- ebp = obp;
- while(*ebp != '\n' && *ebp != ' ') ebp++;
-
- if(ebp != NULL)
- { /* parse label */
- char c;
- /* \label name
- * ^dbp ^ebp
- * ^obp
- */
- c = *ebp;
- *ebp = '\0';
- strcpy(nambuf,obp);
- *ebp = c;
-
- /* trim trailing whitespace */
-
- while(cp = rindex(nambuf,' ')) *cp = '\0';
-
- pfnote(nambuf, TRUE, dbp, ebp - dbp + 1, lineno, linecharno);
- pfcnt++;
- } /* parse label */
- } /* \label */
- dbp++;
- } /* some TeX command... */
- } /* read lines */
- }
-
- /*
- * lisp tag functions
- * just look for (def or (DEF
- */
-
- void L_funcs (fi)
- FILE *fi;
- {
- lineno = 0;
- charno = 0;
- pfcnt = 0;
-
- while (!feof (fi))
- {
- lineno++;
- linecharno = charno;
- charno = readline (&lb, fi);
- dbp = lb.buffer;
- if (dbp[0] == '(' &&
- (dbp[1] == 'D' || dbp[1] == 'd') &&
- (dbp[2] == 'E' || dbp[2] == 'e') &&
- (dbp[3] == 'F' || dbp[3] == 'f'))
- {
- while (!isspace(*dbp)) dbp++;
- while (isspace(*dbp)) dbp++;
- L_getit();
- }
- }
- }
-
- void L_getit()
- {
- register char *cp;
- char c;
- char nambuf[BUFSIZ];
-
- if (*dbp == 0) return;
- for (cp = dbp+1; *cp && *cp != '(' && *cp != ' '; cp++)
- continue;
- c = cp[0];
- cp[0] = 0;
- strcpy(nambuf, dbp);
- cp[0] = c;
- pfnote(nambuf, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
- pfcnt++;
- }
-
- /****************************************************************************
- * initbuffer
- * Inputs:
- * struct linebuffer * linebuffer: Line buffer structure to be
- * initialized
- * Result: void
- *
- * Effect:
- * initializes a line buffer for use
- ****************************************************************************/
-
- void
- initbuffer (linebuffer)
- struct linebuffer *linebuffer;
- {
- linebuffer->size = 200;
- linebuffer->buffer = (char *) xmalloc (200);
- }
-
-
- /****************************************************************************
- * readline
- * Inputs:
- * struct linebuffer * linebuffer: Line buffer to hold input line
- * FILE * stream: file from which to read
- * Result: long
- * file position of end of read operation
- * Effect:
- * Read a line of text from `stream' into `linebuffer'.
- * Return the length of the line.
- ****************************************************************************/
-
- long
- readline (linebuffer, stream)
- struct linebuffer *linebuffer;
- reg FILE *stream;
- {
- char *buffer = linebuffer->buffer;
- reg char *p = linebuffer->buffer;
- reg char *pend = p + linebuffer->size;
-
- while (1)
- {
- int c = getc (stream);
- if (p == pend)
- {
- buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);
- p += buffer - linebuffer->buffer;
- pend += buffer - linebuffer->buffer;
- linebuffer->buffer = buffer;
- }
-
- /* If we have a NUL or LF, store a NUL at the end of the buffer
- and exit the loop
- */
-
- if (c < 0 || c == '\n')
- {
- *p = 0;
- break;
- }
-
- /* Otherwise, store the character and update the pointer */
-
- *p++ = c;
- }
-
- #if debug
- printf("readline: |%s| => %ld\n", buffer, (long) (p-buffer));
- #endif
- return ftell( stream);
- }
-
- /****************************************************************************
- * savestr
- * Inputs:
- * char * cp: Pointer to string
- * Result: char *
- * pointer to copy of the string originally pointed to by cp
- * Effect:
- * Creates a copy of the string pointed to by 'cp'
- ****************************************************************************/
-
- char *
- savestr(cp)
- char *cp;
- {
- register int len;
- register char *dp;
-
- len = strlen(cp);
- dp = (char *)xmalloc(len+1);
- strcpy(dp, cp);
- return (dp);
- }
-
-
- /****************************************************************************
- * rindex
- * Inputs:
- * char * sp: Pointer to string
- * char c: Character of interest
- * Result: char *
- * Pointer to last instance of c in sp, or NULL if no occurrence
- *
- * Identical to v7 rindex, included for portability.
- ****************************************************************************/
-
-
- char *
- rindex(sp, c)
- register char *sp, c;
- {
- register char *r;
-
- r = NULL;
- do
- {
- if (*sp == c)
- r = sp;
- } while (*sp++);
- return(r);
- }
-
- /****************************************************************************
- * fatal
- * Inputs:
- * char * s1: Printf control string with one %-arg
- * char * s2: Argument for printf control string
- * Result: never returns
- *
- * Effect:
- * Issues error message and exits with halt code 1
- ****************************************************************************/
-
- void fatal (s1, s2)
- char *s1, *s2;
- {
- error (s1, s2);
- exit (1);
- }
-
- /****************************************************************************
- * error
- * Inputs:
- * char * s1: Printf control string with one %-arg
- * char * s2: Argument for printf control string
- * Result: void
- *
- * Effect:
- * Issues error message followed by newline
- ****************************************************************************/
-
- void error (s1, s2)
- char *s1, *s2;
- {
- #ifdef CTAGS
- printf ("ctags: ");
- #else
- printf ("etags: ");
- #endif
- printf (s1, s2);
- printf ("\n");
- }
-
- /****************************************************************************
- * concat
- * Inputs:
- * char * s1, *s2, *s3: Three string pointers
- * Result: char *
- * New string which is concatenation of s1, s2, s3
- * Effect:
- * Allocates new string and copies s1, s2, s3 into it
- ****************************************************************************/
-
- char *
- concat (s1, s2, s3)
- char *s1, *s2, *s3;
- {
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
-
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
-
- return result;
- }
-
-
- /****************************************************************************
- * xmalloc
- * Inputs:
- * unsigned size: Size of storage to allocate
- * Result: char *
- * Newly allocated storage.
- * Effect:
- * Like malloc, except takes fatal error and exits if memory exhausted
- ****************************************************************************/
-
- char *
- xmalloc (size)
- unsigned size;
- {
- char * result = malloc (size);
- if (!result)
- fatal ("virtual memory exhausted", 0);
- return result;
- }
-
- /****************************************************************************
- * xrealloc
- * Inputs:
- * char * ptr: Pointer to space containing information
- * unsigned size: Size we really want
- * Result: 2
- * 2
- * Effect:
- * like realloc but gives fatal error and exits if memory exhausted
- *
- * jmn: I can't find this anywhere in my Unix manuals or Lattice C
- * manual, but judging from its use it is supposed to allocate
- * a chunk of storage of size 'size' and return a pointer to it.
- * The presumption is that if it can tail-allocate or otherwise
- * avoid copying it will do so. I have written a realloc for
- * MS-DOS which has to copy
- ****************************************************************************/
-
- char *
- xrealloc (ptr, size)
- char *ptr;
- unsigned size;
- {
- char * result = realloc (ptr, size);
- if (!result)
- fatal ("virtual memory exhausted");
- return result;
- }
-
-
- /* The text which follows is the Epsilon Tags.e file. Extract it and
- use it with Epsilon
- */
- #if 0
-
- /*****************************************************************************
- * Change Log
- * Date | Change
- *-----------+-----------------------------------------------------------------
- * 3-Jun-86 | Created
- * 4-Jun-86 | Use absolute for tagname in load_tags
- * 4-Jun-86 | [313.43] Made non-resident; copied goodies to tags1
- *****************************************************************************/
-
- #include "eel.h"
- #include "boolean.h"
-
- boolean tags_loaded = false;
-
- /****************************************************************************
- * tags
- * Effect:
- * Loads and executes the tags library
- ****************************************************************************/
-
- command tags() on reg_tab[ALT('.')]
- {
- if(!tags_loaded)
- { /* load it */
- load_library("tags1");
- tags_loaded = true;
- tags_1();
- } /* load it */
- else
- tags_1();
- }
- /* End of TAGS.E */
- #endif
-
- /* The following file is the Epsilon code for TAGS1.E. Extract it and use
- it with Epsilon
- */
- #if 0
-
- /*****************************************************************************
- * Change Log
- * Date | Change
- *-----------+-----------------------------------------------------------------
- * 3-Jun-86 | Created
- * 4-Jun-86 | Use absolute for tagname in load_tags
- * 4-Jun-86 | [313.43] Made nonresident; entry point is tags_1
- * 10-Jul-86 | [313.46] Restore point after grab of search string
- * 10-Jul-86 | [313.46] Make sure all 'error' calls after reading in tags
- * | properly restore oldbuf and point
- *****************************************************************************/
-
- /* Parse the tags file looking for the input name; position the user in that
- file looking at the name.
-
- Limitations: If the filename in the tags file is not a full path, it
- is interpreted relative to the current connected directory.
-
- */
-
- #include "eel.h"
- #include "boolean.h"
-
- #define debug_tags false
-
- /****************************************************************************
- * debug_tags_msg
- * Inputs:
- * char * msg: Message to print
- * Effect:
- * Puts it in the debug buffer
- ****************************************************************************/
-
- #if debug_tags
- debug_tags_msg(msg)
- char * msg;
- {
- char * oldbuf = bufname;
- if(!exist("debug"))
- { /* make debug buffer */
- zap("debug");
- } /* make debug buffer */
-
- bufname = "debug";
- point = size();
- stuff(msg);
- bufname = oldbuf;
- }
- #endif
-
- /****************************************************************************
- * load_tags
- * Result: boolean
- * true if tags file found
- * false if tags file not found
- * Effect:
- * loads the tags file
- ****************************************************************************/
-
- boolean load_tags()
- {
- char * s;
- char tagname[80];
-
- s = buffer_list(1);
-
- do
- { /* see if buffer exists */
- bufname = s;
- if(strcmp(filename,"tags")==0)
- { /* found it */
- /* What we do here is see if the file timestamp is the same;
- if not, we reload the tags file
- */
- struct file_info f_disk;
-
- struct time_info tf, tb;
-
- if(check_file("tags",&f_disk))
- { /* lost tags */
- /* This is probably because we have shifted to another
- directory, or tags failed after partially erasing the
- old file, so what we do here is assume the 'tags' buffer
- we are in is valid
- */
- #if debug_tags
- debug_tags_msg("load_tags: lost tags file, use existing one\n");
- #endif
-
- return true;
- } /* lost tags */
-
- if(f_disk.year == f_info.year &&
- f_disk.month == f_info.month &&
- f_disk.day == f_info.day &&
- f_disk.hour == f_info.hour &&
- f_disk.minute == f_info.minute &&
- f_disk.second == f_info.second)
- { /* same file */
- #if debug_tags
- debug_tags_msg("load_tags: tags file is the same\n");
- #endif
- return true;
- } /* same file */
-
- /* At this point, the timestamp of 'tags' on disk and the
- timestamp of 'tags' in the buffer are different
- */
-
- #if debug_tags
- { /* reverting */
- char msg[80];
- sprintf(msg,
- "load_tags: reverted 'tags' file. bufname = %s\n",
- bufname);
- debug_tags_msg(msg);
- } /* reverting */
- #endif
- read_file("tags");
- point = 0;
- return true;
- } /* found it */
- } /* see if buffer exists */
- while (s = buffer_list(0));
-
- /* We didn't find a tags buffer; create one and try to read in a
- file called 'tags'
- */
-
- zap("tags");
- bufname = "tags";
- strcpy(tagname,"tags");
- absolute(tagname);
- read_file(tagname);
-
- #if debug_tags
- debug_tags_msg("load_tags: created 'tags' buffer and loaded it\n");
- #endif
- return true;
- }
-
- /****************************************************************************
- * locate_pattern
- * Inputs:
- * char * fname: File name in which to locate pattern
- * char * pattern: Pattern to find
- * Result: boolean
- * true if pattern found
- * false if pattern not found
- * Effect:
- * true:
- * Reads the file into a buffer if required.
- * Leaves the buffer positioned at the line containing the pattern
- * false:
- * Reads the file into a buffer if required.
- * Leaves the buffer unchanged (at start if just read in)
- ****************************************************************************/
-
- locate_pattern(fname,pattern)
- char * fname;
- char * pattern;
- {
- int oldpoint;
- char * oldbuf = bufname;
- int orig_num = window_number;
-
- window_number = 0;
- /* We search to see if the file is displayed in any window; in that
- case we want to go to the window to find it
- */
-
- do
- { /* search for currently on screen */
- if(strcmp(filename,fname) == 0)
- orig_num = window_number;
- window_number++;
- } /* search for currently on screen */
- while (window_number);
-
- window_number = orig_num;
-
- #if debug_tags
- { /* log it */
- char msg[120];
- sprintf(msg,"locate_pattern(\"%s\",\"%s\")\n",fname,pattern);
- debug_tags_msg(msg);
- } /* log it */
- #endif
-
- find_it(fname);
-
- oldpoint = point;
-
- point = 0;
-
- if(!re_search(FORWARD,pattern))
- { /* failed */
- point = oldpoint;
- sayput("Couldn't find tag for \"%s\"",pattern);
- return false;
- } /* failed */
-
- to_begin_line();
-
- return true;
- }
-
- /****************************************************************************
- * tags_1
- * Effect:
- * Loads the 'tags' file, searches it for the tag; if the tag is
- * found, go open the file in the current window and use the pattern
- * to locate the function. If not, complain.
- ****************************************************************************/
-
- command tags_1() on reg_tab[ALT('.')]
- {
- int oldpoint = point;
- int start;
- char search_string[80];
- char search_word[80];
- char search_msg[120];
- char * oldbuf = bufname;
- char fname[80];
- int filestart;
- #define pattern search_msg
- int pattern_start;
-
- if(!parse_string(1, word_pattern, search_word)) strcpy(search_word,"");
-
- strcpy(search_msg,"Tag [");
- strcat(search_msg,search_word);
- strcat(search_msg,"] :");
- point = oldpoint;
- get_string(&search_string[1],search_msg);
- check_abort();
- iter = 0;
- if(search_string[1] == '\0') strcpy(&search_string[1],search_word);
-
- /* Now see if we have a tag at all */
-
- if(search_string[1] == '\0') return;
-
- /* Now make up an re_search string of the form
- ^word<space>
- to find the search string in the tags file
- */
-
- search_string[0] = '^';
- strcat(search_string,"\t");
-
- if(!load_tags()) return; /* couldn't find tags file */
-
- /* If we loaded tags sucessfully, we are now in the tags buffer */
-
- point = 0;
-
- if(!re_search(FORWARD,search_string))
- { /* no such tag */
- bufname = oldbuf;
- point = oldpoint;
- error("No tag \"%s\" found",search_string);
- } /* no such tag */
-
- /* If we get here, the search was successful */
-
- /* We have searched for a line of the form
- C_entries\tjunk.c\t/^C_entries ()$/
- ^we are here
- */
- filestart = point;
-
- if(!search(FORWARD,"\t"))
- { /* bad format */
- bufname = oldbuf;
- point = oldpoint;
- error("internal error: bad format in tags file, no tab after filename");
- } /* bad format */
-
- /* We are now after the filename
- C_entries\tjunk.c\t/^C_entries ()$/
- ^we are here
- */
-
- /* Grab the file name */
-
- grab(filestart,point - 1, fname);
-
- absolute(fname); /* make it absolute */
-
- search(FORWARD,"/");
- pattern_start = point;
- to_end_line();
- search(BACKWARD,"/");
-
- grab(pattern_start,point, pattern);
-
- point = oldpoint; /* restore point */
-
- if(!locate_pattern(fname,pattern))
- { /* no match */
- bufname = oldbuf;
- point = oldpoint;
- error("Couldn't find \"%s\" in \"%s\"",pattern, fname);
- } /* no match */
-
- /* bufname is now the buffer in which the tag was found */
-
- to_buffer(bufname);
-
- }
- /* End of TAGS1.E */
- #endif
-
- /* The following code is the code for Epsilon load_library. Extract it and
- use it with Epsilon*/
- #if 0
-
- /****************************************************************************
- * load_library (jmn)
- * Inputs:
- * char * name: Library file name
- * Result: boolean
- * true if library loaded sucessfully
- * false if it failed for some reason
- * Effect:
- * Loads the bytes from the library file. Uses the library path
- * as first choice.
- *
- * Library path is based upon the variable ELIB
- ****************************************************************************/
-
- boolean load_library(name)
- char * name;
- {
- char filename[80];
- char * elib;
-
- elib = getenv("ELIB");
-
- #if debug_load
- say("ELIB=%s",elib);
- #endif
-
- if(elib != NULL && strlen(elib) > 0)
- { /* try library path */
- #if debug_load
- char * oldbuf = bufname;
- zap("debug");
- to_buffer("debug");
- bprintf("elib = %s.",elib);
- to_buffer(oldbuf);
- #endif
- strcpy(filename,elib);
- strcat(filename,name);
- strcat(filename,".b");
- if(!check_file(filename, (struct file_info *) 0))
- { /* file exists */
- load_commands(filename); /* may abort to top-level */
- return true; /* all done */
- } /* file exists */
- #if debug_load
- else
- { /* failed */
- to_buffer("debug");
- bprintf("Cannot find %s.",filename);
- to_buffer(oldbuf);
- } /* failed */
- #endif
- } /* try library path */
-
- /* The file does not exist on the elib path, or there is no
- elib path
- */
-
- /* Try the default search path */
-
- elib = lookpath(name);
-
- if(elib != NULL)
- { /* found on path */
- load_commands(elib);
- } /* found on path */
- else
- { /* use default */
- load_commands(name); /* default path; may abort to top-level */
- } /* use default */
-
- return true;
- }
- /* End of load_library */
- #endif
-
- /* This file is the 'makefile' which can be used to build 'tags'. Be sure
- to read it over carefully since it is tuned to my development environment.
- I use UniPress 'psmake'. The file 'go.bat' is included later
-
- IMPORTANT: Replace all instances of "%#" with "#" because the presence
- of the # in column 1 produces a very sick Lattice C compiler (it runs
- out of memory with 594K available).
- */
-
- #if 0
- %#*****************************************************************************
- %# makefile for TAGS
- %#*****************************************************************************
- %# Change Log
- %# Date | Change
- %#-----------+----------------------------------------------------------------
- %# 4-Jul-86 | Created
- %#*****************************************************************************
-
- %# Standard prolog
-
- %# This declaration defines the location of the C compiler
-
- COMPILER = c:\lc\
-
- %# This declaration defines the device on which the intermediate files
- %# (.Q files) are written. If a RAMdisk (e.g., E:) is selected, the
- %# compilation will run much faster
-
- VDISK=e:
-
- %# This declaration defines the device on which the output file is written.
-
- LDISK=d:
-
- %# The source extensions
-
- SRCEXT = .c .asm
-
- %#############################################################################
- %# Compilation rules.
- %#############################################################################
-
- %# Rules for compiling .c source files
- %# Note the use of the virtual disk 'm' for the memory model
- %# The association must be made in the 'go.bat' file
-
- .c.obj :
- del $*.obj
- $(COMPILER)lc1 -o$(VDISK) -ms -d -n -ic:\lc\ -cstu -im: $<
- $(COMPILER)lc2 -o$(LDISK) $(VDISK)$*
- if exist $*.obj goto $*
- echo * * * Compilation of '$*' failed >> nolink
- :$*
-
- .c.tag :
- tags -m -u $<
-
- .asm.obj :
- del $*.obj
- masm $*,$*,$*;
- if exist $*.obj goto $*
- echo * * * Assembly of $* failed >> nolink
- :$*
-
-
-
- %##############################################################################
- %# Object file specifications
- %##############################################################################
-
- TAGS =m:c.obj tags.obj
-
- %# The name of the linker files
-
- T=tags.lnk
-
-
- %##############################################################################
- %# The files
- %##############################################################################
- %#
- %# Note the use of the dummy name (xxxxx) which never exists, but captures
- %# the dependency of the two result files, tags and tags.exe.
-
- xxxxx: tags. tags.exe
-
- tags.: tags.tag
-
- TAGS.EXE: $(TAGS) $T makefile
- if not exist nolink goto oklink
- echo ***** Compilation errors exist *****
- type nolink
- goto nolink
- :oklink
- version version.c version.ver
- link @$(T),tags,tags,m:ctools+m:ctools2+m:lcm+m:lc/map/line/segments:256
- :nolink
-
-
- %# The linker file. Note that it depends on 'makefile' so that it is
- %# always updated. If you add more OBFILESn, all but the last must
- %# include the + symbol at the end of line
-
- $T : makefile
- echo $(TAGS) > $T
-
- tags.obj : l:stdio.h l:ctype.h l:string.h l:dos.h
-
- tags.tag : tags.c
-
-
- #endif
-