從main.c
開始。git
extern int main (int __unused__ argc, char **argv) { cookedArgs *args; #ifdef VMS extern int getredirection (int *ac, char ***av); /* do wildcard expansion and I/O redirection */ getredirection (&argc, &argv); #endif #ifdef AMIGA /* This program doesn't work when started from the Workbench */ if (argc == 0) exit (1); #endif #ifdef __EMX__ _wildcard (&argc, &argv); /* expand wildcards in argument list */ #endif #if defined (macintosh) && BUILD_MPW_TOOL == 0 argc = ccommand (&argv); #endif setCurrentDirectory (); setExecutableName (*argv++); checkRegex (); args = cArgNewFromArgv (argv); previewFirstOption (args); testEtagsInvocation (); initializeParsing (); initOptions (); readOptionConfiguration (); verbose ("Reading initial options from command line "); parseOptions (args); checkOptions (); makeTags (args); /* Clean up. */ cArgDelete (args); freeKeywordTable (); freeRoutineResources (); freeSourceFileResources (); freeTagFileResources (); freeOptionResources (); freeParserResources (); freeRegexResources (); exit (0); return 0; }
一開始cTags維護了一個本身的cookedArgs
類型的參數列表,args
。以後根據不一樣系統的狀況,從新定義了argc
與argv
。數組
第一個函數setCurrentDirectory()
定義在routines.c
中,根據系統不一樣,定義了CurrentDirectory
一個全局變量(使用getcwd()
),並在最後增長了OUTPUT_PATH_SEPARATOR
。函數
第二個函數setExecutableName (*argv++)
定義了ExecutableProgram
(主文件路徑)和ExecutableName
(主文件名)兩個全局變量。ui
第三個函數checkRegex()
是regex
庫的內部函數,檢查regex
可否正常工做.this
以後,args = cArgNewFromArgv (argv)
將默認的選項格式加以處理轉換到args
中.指針
previewFirstOption (args)
處理-v
和沒有選項的狀況(直接退出)。code
testEtagsInvocation ()
檢測是否有-e
選項,如有,則初始化etags
。內存
initializeParsing()
是重要的一步,它檢查每個內建的語言,它們的名稱是否合法,它們的regex
是否存在,若是是,則將它們插入LanguageTable[]
數組中。這個數組的成員類型是parserDefinition*
,而parserDefinition
的定義以下:ci
typedef struct { /* defined by parser */ char* name; /* name of language */ kindOption* kinds; /* tag kinds handled by parser */ unsigned int kindCount; /* size of `kinds' list */ const char *const *extensions; /* list of default extensions */ const char *const *patterns; /* list of default file name patterns */ parserInitialize initialize; /* initialization routine, if needed (初始化的函數指針) */ simpleParser parser; /* simple parser (common case) */ rescanParser parser2; /* rescanning parser (unusual case) */ boolean regex; /* is this a regex parser? */ /* used internally */ unsigned int id; /* id assigned to language */ boolean enabled; /* currently enabled? */ stringList* currentPatterns; /* current list of file name patterns */ stringList* currentExtensions; /* current list of extensions */ } parserDefinition;
以後initializeParsing
調用initializeParsers ()
,即循環調用每一個LanguageTable[]
中語言的LanguageTable[i]->initialize()
,進行語言初始化工做(創建hash表等)。get
接下來的一大步是initOptions()
,設置默認選項,創建默認語言映射,自動添加.git
等控制文件到--exclude
選項中。
readOptionConfiguration ()
讀取目錄下的.ctags
配置文件與環境變量。
parseOptions (args)
把以前簡單分拆的選項細分紅longOptions
和shortOptions
,並設置Options
結構的相應位。
checkOptions()
是對選項的靜態檢查。
makeTags(args)
,是最重要的部分,代碼以下:
static void makeTags (cookedArgs *args) { clock_t timeStamps [3]; boolean resize = FALSE; boolean files = (boolean)(! cArgOff (args) || Option.fileList != NULL || Option.filter); if (! files) { if (filesRequired ()) error (FATAL, "No files specified. Try "%s --help".", getExecutableName ()); else if (! Option.recurse && ! etagsInclude ()) return; } #define timeStamp(n) timeStamps[(n)]=(Option.printTotals ? clock():(clock_t)0) if (! Option.filter) openTagFile (); timeStamp (0); if (! cArgOff (args)) { verbose ("Reading command line arguments "); resize = createTagsForArgs (args); } if (Option.fileList != NULL) { verbose ("Reading list file "); resize = (boolean) (createTagsFromListFile (Option.fileList) || resize); } if (Option.filter) { verbose ("Reading filter input "); resize = (boolean) (createTagsFromFileInput (stdin, TRUE) || resize); } if (! files && Option.recurse) resize = recurseIntoDirectory ("."); timeStamp (1); if (! Option.filter) closeTagFile (resize); timeStamp (2); if (Option.printTotals) printTotals (timeStamps); #undef timeStamp }
簡而言之,就是如下幾步:
openTagFile (resize)
打開Tag文件;
根據選項不一樣,分別調用createTagsForArgs (args)
、createTagsFromListFile (Option.fileList)
、createTagsFromFileInput (stdin, TRUE)
、recurseIntoDirectory (".")
,而它們都調用了createTagsForEntry(filename)
,通過檢查後,最終調用了parse.c
中的parseFile(filename)
;
closeTagFile (resize)
關閉Tag文件。
最終,經過以下幾步,free
掉前幾步申請的動態內存,防止內存泄漏:
cArgDelete (args); //釋放args[] freeKeywordTable (); //釋放KeywordTable[] freeRoutineResources (); //釋放CurrentDirectory freeSourceFileResources (); //釋放File(一個用於讀取文件的變量) freeTagFileResources (); //釋放TagFile變量 freeOptionResources (); //釋放Options變量 freeParserResources (); //釋放LanguageTable[] freeRegexResources (); //釋放Regex庫內存