// -*- ASCII:EDT -*- // checklinks.edt // checks all HREF-links, // following them // and generates a log file // (schlicht 20010327) ///////////////////////////// // Options: // //----------// // Only check files with either of these extensions: //-------------------------------------------------- Assign("checkFiles","HTML|HTM|PHP"); // The macro can open all checked files, only the // ones which include errors, or none: //------------------------------------ //Assign("openFiles","All"); Assign("openFiles","onError"); //Assign("openFiles","None"); // Build a list of files (for the Tree window) //-------------------------------------------- Assign("buildTree","yes"); //Assign("buildTree","no"); //------------------------------------------------------------------------------- GetDate(0,"dd.mm.yy 'at' hh:nn:ss"); Assign("Date0","%!0"); Assign("currentPath","%p\"); Assign("TotalFiles","0"); Assign("Links","0"); Assign("Errors","0"); Assign("BaseFile","%p\%n%t"); Assign("Files","°%$('BaseFile');°"); Release("Checked"); Release("Tree"); IfStr("%$('buildTree');","yes","=",> "DeleteTree;SetMainFile('%$(|BaseFile|);')"); SaveFind; SetFindCenterLine(0); SetFindTextSelect(1); SetSearchCurrentDoc; SetSearchCyclic(0); SetSearchEntire(0); SetSearchForward(1); SetRegEx(0); SetSearchCaseSensitive(0); SetSearchRelaxed(1); SetNotFoundNotify(0); OpenOutput("%p\%n.log"); WrL("This file has been generated by checklinks.edt"); WrL("on %!0 (Summary at end of file)"); WrL("------------------------------------------------"); WrL("Base File: %$('BaseFile')"); StartWorking("checklinks (%n%t)"); LetRegNum(8,-1); Loop(!|> Loop(!:> SetOK(1);> // Get the next file from the list of files: FindInString("%$('Files');","°*°",1,8,1001,%!8+1);> IfOK(!||> ExtractByIndex(0,"%$('Files');",%!1+1,%!8-1);> GetLength(3,"%!0");> GetFilePath("%!0",9);> // Have I already checked that file? SetOK(1);> FindInString("%$('Checked');","°%!0°",1,2,0);> IfOK("",> !"GetFileName('%!0',3);> GetFileType('%!0',4);> Assign('currentFile','%!3%!4');> SetOK(1);> // Am I supposed to check it? FindInString('%!4','\.%$(*checkFiles*);',5,5,1);> IfOK(> !'IfStr(''%$(*openFiles*);'',''All'',''='',!''Open(*%!0*,0,0,-1,0);'');> ReadFile(''%!0'',5);> Assign(''absFile'',''%!0'');> Assign(''File'',''%!5'');> // Get the path of the checked file relative to the base file (we need it for the log file and the tree): LetReg(4,''%$(*currentPath*);'');> LetReg(5,''%!9\'');> LetRegNum(6,0);> LetRegNum(7,0);> Loop(!''> SetOK(1);> FindInString(""%!4"",""*\\"",3,6,1001,%!6);> IfOK(!""> ExtractByIndex(1,`%!4`,%!3,%!6);> SetOK(1);> FindInString(`%!5`,`*\\`,2,7,1001,%!7);> IfOK(!`ExtractByIndex(2,``%!5``,%!2,%!7);`);> IfStr(`%!1`,`%!2`,`=`,> !`ReplaceInString(``%!4``,````,%!3,%!6,0,4);> ReplaceInString(``%!5``,````,%!3,%!6,0,5);> LetRegNum(6,0);LetRegNum(7,0);`,> !`GetLength(1,``%!1``);> ReplaceInString(``%!4``,``..\``,%!3,%!6,0,4);> LetRegNum(6,%!6+4-%!1);`> );"",> ""Stop;"");''> );> Assign(''currentFile'',''%!4%!5%$(""currentFile"");'');> Assign(''Tree'',''%$(*Tree*);%$(""currentFile"");%\'');> StartWorking(''checklinks (%$(""currentFile"");)'');> WrL(''%\ Checking links in file ""%!0""::'');> LetRegNum(3,''%$(*TotalFiles*);+1'');> Assign(''TotalFiles'',''%!3'');> Stop;',> !'WrL(''%\ Skipping ""%!0"". '');'> );"> );> ||,> // We've checked all files: !||WrL("%\%\*** Summary ***%\");> GetDate(0,"'Finished::' hh::nn::ss");> WrL("Started::%\%$('Date0');%\%!0%\");> WrL("Checked %$('Links'); links");> WrL("in %$('TotalFiles'); files.");> WrL("Errors:: %$('Errors');");> CloseOutput;> RestoreFind;> StopWorking;> Open("%$('BaseFile');");> IfStr("%$('buildTree');","yes","=","SetTree('%$(*Tree*);',0);");> SetTracking(1);> Refresh;> ErrorLogUpdate(1);> IfLogErrors(> "ShowErrorLog(1);Prompt('I found some errors',0,1);",> "Prompt('All links are OK!',0,1);",0);> Exit;||> );> :);> // index: LetRegNum(6,0);> // number of links: LetRegNum(4,0);> // number of errors: LetRegNum(7,0);> // Here we actually start checking: Loop(!`> Release("Error");> SetOK(1);> FindInString("%$('File');","{HREF||SRC}=[""']*['""]",1,6,1001,%!6);> IfOK(!``> ExtractByIndex(0,"%$(*File*);",%!1,%!6);> Assign("Link","%!0");> FindInString("%!0","[""']*['""]",1,3,1,0);> ExtractByIndex(0,"%!0",%!1+1,%!3-1);> GetLength(3,'%!0');> LetRegNum(4,%!4+1);> WrS(" ""%!0"":");> // browser-like file description? FindInString("%!0","file:///?||",1,2,0,0);> IfOK(> !"ExtractByIndex(0,'%!0',%!2,%!3); > ReplaceInString('%!0',':/',1,2,0,0); > LetReg(9,'');");> // something beginning with "http://" or "ftp://"? FindInString("%!0","://",1,2,0,0);> IfOK("WrL(' ... cannot follow this link.');> LetReg(0,'<>');");> // mail address? FindInString("%!0","mailto:",1,2,0,0);> IfOK("WrL(' ... is a mail address.');> LetReg(0,'<>');");> // news group? FindInString("%!0","news:",1,2,0,0);> IfOK("WrL(' ... is a news group.');> LetReg(0,'<>');");> // reference to an anchor? FindInString("%!0","#",1,2,0,0);> IfOK(> !"ExtractByIndex(3,'%!0',%!1+1,%!3);> SetOK(1);> IfNum(%!1,0,'=',> // anchor in the same file: !'FindInString(''%$(*File*);'',''name=""%!3""'',1,2,0,0);> IfOK(> ''WrL(|| ... Anchor ... OK||);'',> ''Assign(||Error||,||??? Anchor not found.||);''> );',> // it's an external anchor: !'ExtractByIndex(2,''%!0'',0,%!1-1);> LetReg(2,''%!9\%!2'');> IfFileExists(''%!2'',> !''WrS(|| ... File exists||);> ReadFile(||%!2||,5);> FindInString(||%!5||,||name=""%!3""||,1,2,0,0);> IfOK(> ||WrL(* ... Anchor ... OK*);||,> ||Assign(*Error*,*??? Anchor not found.*);||> );> '',> !''Assign(||Error||,||??? File does not exist (%!0)||);''> );'> );> ",> !"IfStr('%!0','<>','=','',!'> // convert UNIX-style and relative paths into absolute and DOS-like: LetReg(0,''%!9\%!0'');> UnixToDos(''%!0'');> Loop(!''SetOK(1);> FindInString(""%!0"",""{\\\\}||{\\+{{$Alpha$}||{$Numeric$}}\\\.\.\\}"",1,2,1,0);> IfOK(!""ReplaceInString(*%!0*,**,%!1+1,%!2,0);"",""Stop;"");'');> // does the referenced file exist? IfFileExists(''%!0'',> !''WrL("" ... OK."");> SetOK(1);> FindInString(""%$(*Files*);"",""°%!0°"",1,2,0);> IfOK("""",!""Assign(||Files||,||%$(*Files*);%\°%!0°||);"");'',> !''Assign(""Error"",""??? File does not exist (%!0)"");''> );'> );"> );> // link broken? IfStr("%$('Error');","","=","",!"> IfNum(%!7,0,'=',!'> Open(''%$(:currentPath:);%$(:currentFile:);'',0,0,-1,0);> StartWorking(''broken links in %$(:currentFile:);'');> SetTracking(0);> CMD(''Go To Beginning Of File'');'> );> SetFindStr('%$(||Link||);');> IfFound(!'> WrL(''%\%$(:currentFile:);(%l):%\%$(:Error:);'');',> !'WrL(''%\%$(:currentFile:);(1):%\%$(:Error:);'');');> LetRegNum(7,%!7+1);"> );> ``,> // We've checked every link in the current file: !``Assign("Checked","%$('Checked');%\°%$('absFile');°");> WrL(" --- %!7 errors --- %!4 links ---");> LetRegNum(4,"%!4+%$('Links');");> LetRegNum(7,"%!7+%$('Errors');");> Assign("Links","%!4");> Assign("Errors","%!7");> IfStr("%$('absFile');","%$('BaseFile');","=","",> !"IfStr('%$(""openFiles"");','None','=',> !'CloseFile(""%$(*absFile*);"");');> IfStr('%$(""openFiles"");','onError','=',> !'IfNum(%!7,0,""="",> !""CloseFile(''%$(*absFile*);'');"");'> );"> );> Stop;> ``> );`> );|> ); End; /////////////////////////////////// // This macro checks all links in a HTML project. // // You can start from any file you want. The macro will not only check the // links in that file, but follow the links until it has checked all linked // files. It won't get stuck in a loop because it tests if a file has already // been checked. // Because it is independent from WinEdt's Tree feature, you don't have to // have the Tree built nor a Main File set. // // The macro understands and checks the following links: // - relative paths (like "../../up.html") // - file with browser-like path specification ("file:///C|/Programs...") // - internal or external references ("#annote" or "foo.html#mark") // - folders ("folder/") // It does not follow links beginning with "http://" or "ftp://", "news:" or // "mailto:" // The macro will only check links in files of the types specified in the // variable %$('checkFiles'); (see first line). // // The log file is parsable by WinEdt, i.e. you can browse through the // (hopefully not existing) errors using WinEdt's Error Search. To achieve // this, the macro has to open the defective file. // // The macro will by default also build a tree (for WinEdt's Project | Tree // window), which isn't really a tree, but a list of all checked files. // // Note that while Windows' filesystem, on which this macro relies, is case- // insensitive, Unix servers are usually case-sensitive! // // Finally: Be patient. Checking a big project can take a while. F.i. checking // with 728 links in 60 files took about 1:00 min. // // R Schlicht w.m.l@gmx.net /////////////////////////////////// $Id: checklinks.edt,v 1.5 2001-12-09 05:53:43+01 standard Exp standard $