public static LineCounts operator+(LineCounts left, LineCounts right) { LineCounts counts = new LineCounts(); counts._files = left._files + right._files; counts._lines = left._lines + right._lines; counts._commentlines = left._commentlines + right._commentlines; counts._blanklines = left._blanklines + right._blanklines; return counts; }
/// <summary> /// Count the lines. /// </summary> /// <param name="sender">Sender.</param> /// <param name="e">Event arguments.</param> private void btnCount_Click(object sender, System.EventArgs e) { if (_files.Count == 0) { MessageBox.Show(this, "At least 1 file must be specified.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } // Give a wait cursor. this.Cursor = Cursors.WaitCursor; // Reset status bar. this.statusBarPanel1.Text = "Counting..."; this.statusBar.ProgressBar.Value = 0; this.statusBar.ProgressBar.Maximum = _files.Count; this.statusBar.ProgressBar.Visible = true; // Disable controls so no one tries any monkey business. this.SetControls(false); // Reset counters. _lineCounts = new LineCounts(); _fileCount = 0; _currentFile = 0; // Store the filter index in case a wise guy decides to change it before the counting // has started. The count threads retrieve this value to determine the commenting style // to use. _winRegistryAccess.LastCommentingStyle = this.cmbbxCommentStyle.SelectedItem.ToString(); // Store the comment style that was used. _winRegistryAccess.CommentMode = _commentMode; // Log file. _log = new StreamWriter(_logFile, false); // Initiate threads. _startedThreadJoin = false; for (int i = 0; i < _nProcessors; i++) { // Create the thread. _threads[i] = new Thread(new ThreadStart(CountLines)); // We use the thread number as the name. That way we can uniquely trigger one of the // reset events once a thread is finished processing. _threads[i].Name = i.ToString(); // A manual reset event is used because it won't set back to the initial state like the auto // reset event. We are waiting for all events to set before continuing. _threadDoneEvents[i] = new ManualResetEvent(false); // Start the thread. _threads[i].Start(); } }
/// <summary> /// Count the lines in a file. /// </summary> /// <param name="filename">Name of the file.</param> /// <returns>The counts in a LineCounts object.</returns> public LineCounts Count(string filename) { // Line counts. LineCounts linecounts = new LineCounts(); linecounts.IncrementFileCount(); // Open the file. System.IO.StreamReader reader = System.IO.File.OpenText(filename); // Loop over the lines in the file. string line; while ((line = reader.ReadLine()) != null) { // Count the total number of lines counted. Should equal comments+blanks+code. linecounts.IncrementLineCount(); // Check for comments. if (IsComment(line)) { linecounts.IncrementCommentLineCount(); continue; } // Check for blank lines. Need to do this after checking for comments so that we can count // blank lines in long comments as comments. if (line.Trim() == "") { linecounts.IncrementBlankLineCount(); } } // Close the file. reader.Close(); return linecounts; }
/// <summary> /// Worker function for line counting threads. /// </summary> private void CountLines() { // Loop through file names. When all of the file names have been processed // a break is called to exit the loop. while (true) { string filename; // Acquire the next file name, insuring we don't miss a name by using a // lock to limit access to one thread at a time. _fileNameLock.AcquireWriterLock(-1); if (_currentFile >= _files.Count) { // No more files, release the lock and break out of while loop. _fileNameLock.ReleaseWriterLock(); // Figure out which thread we are and signal the event that says we are done with // our work. We have to wait here until all threads are done because each thread // updates the GUI with it's results after a file has been processed and the next // step is to int name = System.Convert.ToInt32(Thread.CurrentThread.Name); _threadDoneEvents[name].Set(); WaitHandle.WaitAll(_threadDoneEvents); // We are locking this part with a semaphore to make sure only one gets access at a // time. That way we don't have a race condition to calling the thread joining and // final GUI update. Note, because of this semaphore it might not be strickly necessary // to join the threads (they are done with their work by that time), but it doesn't matter // anyway. _jointhreadsemaphore.WaitOne(); // Make sure we don't try to rejoin threads and reactive the controls once they // have already been joined. if (!_startedThreadJoin) { _startedThreadJoin = true; this.BeginInvoke(new UICallBack(JoinThreads)); } _jointhreadsemaphore.Release(); break; } filename = _files[_currentFile++].ToString(); _fileNameLock.ReleaseWriterLock(); // Use local counters so that we can process an entire file and then update the // master counters and gui. This limits the number of read/write locks required // and the number of gui updates to a reasonable amount so that the counting isn't // done too slowly. LineCounts linecounts = _fileTypes.Count(filename); // Update the line counters and display. _lineCountLock.AcquireWriterLock(-1); _lineCounts += linecounts; // Update the file counter and display. _fileCount++; _lineCountLock.ReleaseWriterLock(); // Do callback to update the user interface. this.Invoke(new UICallBack(UpdateUICounts)); } }