Introduction
XLineCounter is a open source C# program to analyze source code files and count the number of source code lines. It can count number of source lines, comment lines and blank lines.
Background
Millions of programmers work hard year after year, and write many source codes in C++, C#, VB or Delphi. Sometimes, they want know how many lines are there of that source code. Of course, they cannot count line by line, so they need a tool to count the source lines.
XLineCounter
Today, source code files are not alone, many source code files construct a project, and the compiler handles the project and generates a program file.
For example, in VS.NET 2005, people create a C# project whose file name’s extension is csproj, and add many C# source files to the C# project.
XLineCounter needs to analyze develop project file and get a list of source code file, also equip source code analyzer which can analyze source code like VB , C# or Pascal. So I design XLineCounter structure as the following shape:
There are two stresses in XLineCounter: first, analyze project file and get file list; second, analyze source file use specify syntax.
For example, a C# .NET2005 project file in XML format. There is a sample.
<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AssemblyName>CellViewLib</AssemblyName>
</PropertyGroup>
<ItemGroup>
<Reference Include="System">
<Name>System</Name>
</Reference>
</ItemGroup>
<ItemGroup>
<Content Include="App.ico" />
<Compile Include="frmTestCellView.cs">
<SubType>Form</SubType>
</Compile>
<EmbeddedResource Include="frmTestCellView.resx">
<DependentUpon>frmTestCellView.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
</Project>
To this XML document, I can execute XPath “Project/ItemGroup/Compile” and get a list of C# source file names. So I write the following C# code:
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(txt);
if (doc.DocumentElement.Name == "Project"
&& doc.DocumentElement.GetAttribute("xmlns") ==
"http://schemas.microsoft.com/developer/msbuild/2003")
{
project.ProjectFileName = strFileName;
project.RootPath = System.IO.Path.GetDirectoryName(strFileName);
ProjectFile ProjFile = new ProjectFile();
ProjFile.FileName = System.IO.Path.GetFileName(strFileName);
ProjFile.FullFileName = strFileName;
ProjFile.Style = FileStyle.None;
project.Files.Add(ProjFile);
System.Xml.XmlNamespaceManager ns =
new System.Xml.XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("a", "http://schemas.microsoft.com/developer/msbuild/2003");
System.Xml.XmlNode NameNode = doc.SelectSingleNode
("a:Project/a:PropertyGroup/a:AssemblyName", ns);
if (NameNode != null)
{
project.Name = NameNode.InnerText;
}
foreach (System.Xml.XmlElement element in doc.SelectNodes
("a:Project/a:ItemGroup/*[name()='Compile' or name()='None' or
name()='EmbeddedResource' or name()='Content']", ns))
{
string file = element.GetAttribute("Include");
ProjectFile NewFile = new ProjectFile();
NewFile.FileName = project.FixFileName(file);
if (System.IO.Path.IsPathRooted(file))
{
NewFile.FullFileName = file;
}
else
{
NewFile.FullFileName = System.IO.Path.Combine(project.RootPath, file);
}
if (element.Name == "Compile")
{
NewFile.Style = FileStyle.SourceCode;
}
else if (element.Name == "EmbeddedResource")
{
NewFile.Style = FileStyle.Resource;
}
else
{
NewFile.Style = FileStyle.None;
}
project.Files.Add(NewFile);
}}
Using this code, XLineCounter can get a file list from C#2005 project file. In the same way, XLineCounter can analyze VB.NET 2005, VB6.0, Delphi project file and get source code file list.
Next, XLineCounter needs to analyze source code with some kind of syntax. For example, there are some C# source code as follows:
string str = "abc";
string str2 = @"abc
efg";
In C# syntax, there are 5 characters:
- Single line comment starts with
// .
- Multi-line comment starts with
/* and end with */ .
String data starts with double quotes and ends with double quotes.
- In
string data , \” define a double quotes characters.
- Multi-line
string data starts with @” .
So I write the following C# code to analyze C# source code text:
int DefineString = 0;
bool DefineComment = false ;
foreach( LineInfo info in myLines )
{
info.CodeFlag = false;
if( info.LineText.Length == 0 && DefineString == 2)
info.BlankLine = false;
for(int iCount = 0 ; iCount < info.LineText.Length ; iCount ++)
{
char c = info.LineText[iCount] ;
char c2 = (char)0;
if( iCount < info.LineText.Length - 1 )
c2 = info.LineText[ iCount + 1 ];
if(! char.IsWhiteSpace( c ))
info.BlankLine = false;
if( DefineComment )
{
info.BlankLine = false;
info.CommentFlag = true;
if( c == '*' && c2 == '/' )
{
DefineComment = false;
iCount ++ ;
}
continue ;
}
if( DefineString == 0 )
{
if( c == '/' && c2 != 0 )
{
if( c2 == '/' )
{
info.CommentFlag = true;
DefineComment = false;
goto NextLine ;
}
if( c2 == '*' )
{
if( iCount > 0 )
info.CodeFlag = true;
info.CommentFlag = true;
DefineComment = true;
iCount ++ ;
continue;
}
}
if( c == '\"')
{
if( iCount < 0 && info.LineText[iCount-1] == '@')
DefineString = 2 ;
else
DefineString = 1 ;
}
}
else
{
info.BlankLine = false;
if( c == '\"' )
{
if( iCount < 0 && info.LineText[iCount-1] !='\\' )
DefineString = 0 ;
}
}
if( ! char.IsWhiteSpace( c ))
info.CodeFlag = true;
}NextLine:;
}
LineInfo type is a class which contains information of a source code line. It is defined as follows:
public class LineInfo
{
public string LineText = null;
public bool CommentFlag = false;
public bool BlankLine = true;
public bool CodeFlag = false;
}
By using upper code, XLineCounter can analyze C#.NET 2005 project file and C# source code, count number of C# source code. In the same way, XLineCounter can count number of source code of VB.NET, Delphi and C++.
Points of Interest
None.
History
- 2010-11-26 Added line count result report