Qbasicnews.com

Full Version: w00t - our first fb project!!!
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Code:
'------------------------------------------------------------------------------------------
                              ALMIGHTY MULTIPLE FILE LINE COUNTER
                                       Version 11.23
                                         written by

                                    the incredible blitz                            
                                         le marzec
'------------------------------------------------------------------------------------------


A brief history
---------------
it was the time of the big war, with the 10 rings and the dwarfs and all that, when
two little hobits decided to change the destiny of their land. they packed their bags
and went on a journey to seek the ultimate weapon to show off.

and they came back with this: the almighty multiple file line counter version 11.23

"but tell me oh mighty creators, what can it do?" you may ask. and the answer is a lot
it can open files, list directories and PRINT OUT TO THE FUCKING SCREEN! you are right,
to the screen...

yeah and it can count the lines from all the files you specified via search patterns. and
uhm it even has a nifty commandline parser and stuff. blitz wanted that to show off, as
always...

how to use this almighty weapon?
--------------------------------
well first you can specify wheter you want to take all the subdirectories recursively into
account. like with an "-r" or an "-d" whatever you want. next you can specify matching
patters as you are used with the dir command on win32/dos and seperate several of them via
a space.

so if you want to count all the bas and bi files in a directory and want to know how
many god like lines of code you have already coded just do this

wc *.bas *.bi

and bang it tells you how many files of that types are in the current directory and
how many lines and bytes they contain in total

to search through subdirectories too you invoke this like

wc -r *.bas *.bi

for example.

well our quest is over, we now waste all our gold on virgins and grok.

later...

you can find that crap on http://ratatoskr.dragonhill.cc/fbirc/wc.rar
Omg, hobits again, i thought they were all dead, damnit.

Nice, btw, you could have used DIR$(), it supports wildcards too -- but yeah, nothing beats being recursive for free using SHELL "DIR -r" :P
Quote:well our quest is over, we now waste all our gold on virgins and grok.
I'm thinkin' grog, unless I underestimate you guys...
erm, I don't mean to be a wet blanket, but...what useful purpose does this serve, again?
It counts up the total number of lines of code in a project, that may consist of several modules.

As far as I can see, anyway...
Compiles & runs with FreeBASIC 0.14b, probably works with other versions. Only minimally tested. :-)

Code:
Option Explicit

'$Include: 'win/kernel32.bi'

Declare Sub InitTable()
Declare Sub ProcessCommandLine()
Declare Sub ProcessCommandLineItem(item$)
Declare Sub RecursivelyFindFiles(base_path$, spec$)
Declare Sub RecursivelyFindSubdirs(base_path$, subdir_spec$, remaining_spec$)
Declare Sub ProcessFile(path_to_file$)
Declare Sub OutputStatistics(lines As LongInt, words As LongInt, characters As LongInt, label$)
Declare Function MinimumNonZero(a&, b&) As Long

Const FLAG_COUNT_LF_1% = 1
Const FLAG_COUNT_SPACE_1% = 2
Const FLAG_COUNT_CRLF_2% = 4
Const FLAG_COUNT_SPACE_2% = 8
Const FLAG_COUNT_CR_1% = 16
Const FLAG_ENABLE_NEXT_LF_1% = 32
Const FLAG_ENABLE_NEXT_SPACE_1% = 64

Const FLAG_ALWAYS_ON% = 128

Dim Shared table(0 To 65535) As UByte
Dim Shared As LongInt total_lines, total_words, total_characters
Dim Shared show_lines%, show_words%, show_characters%, num_files&

Const FILE_ATTR_DIRECTORY% = 16
Const FILE_ATTR_ARCHIVE% = 32

InitTable
ProcessCommandLine

Sub InitTable()
Dim i&, a$, byte1%, byte2%

For i& = 0 To 65535
  table(i&) = FLAG_ALWAYS_ON% Or FLAG_ENABLE_NEXT_LF_1% Or FLAG_ENABLE_NEXT_SPACE_1%

  a$ = MKI$(i&)

  byte1% = Asc(a$)
  byte2% = Asc(a$, 2)

  Select Case byte1%
   Case 13: table(i&) = table(i&) Or FLAG_COUNT_SPACE_1% Or FLAG_COUNT_CR_1%
   Case 10: table(i&) = table(i&) Or FLAG_COUNT_SPACE_1% Or FLAG_COUNT_LF_1%
   Case 32: table(i&) = table(i&) Or FLAG_COUNT_SPACE_1%
  End Select

  Select Case byte2%
   Case 13:
    table(i&) = table(i&) Or FLAG_COUNT_CRLF_2%
    table(i&) = table(i&) And Not FLAG_ENABLE_NEXT_LF_1%
   Case 10:
    If byte1% <> 13 Then table(i&) = table(i&) Or FLAG_COUNT_CRLF_2%
  End Select

  Select Case byte2%
   Case 13, 10, 32:
    table(i&) = table(i&) And Not FLAG_ENABLE_NEXT_SPACE_1%
    Select Case byte1%
     Case 13, 10, 32: ' do nothing
     Case Else:
      table(i&) = table(i&) Or FLAG_COUNT_SPACE_2%
    End Select
  End Select
Next i&
End Sub

Sub ProcessCommandLine()
Dim show_all%
Dim cmd$, in_string%, i&, c%, word$, word_length%

show_all% = -1
show_lines% = 0
show_words% = 0
show_characters% = 0
in_string% = 0
cmd$ = Trim$(Command$)
While Asc(cmd$) = 45 ' the '-' character
  show_all% = 0
  For i& = 2 To Len(cmd$)
   c% = Asc(cmd$, i&)
   Select Case c%
    Case 32:
     cmd$ = LTrim$(Mid$(cmd$, i& + 1))
     Exit For
    Case 108: ' the 'l' character, for lines
     show_lines% = -1
    Case 119: ' the 'w' character, for words
     show_words% = -1
    Case 99: ' the 'c' character, for characters
     show_characters% = -1
    Case Else:
     Print "Usage: wc [-lwc] [filename ...]"
     End
   End Select
  Next i&
WEnd
If show_all% Then
  show_lines% = -1
  show_words% = -1
  show_characters% = -1
End If
word$ = Space$(10)
word_length% = 0
For i& = 1 To Len(cmd$)
  c% = Asc(cmd$, i&)
  If in_string% Then
   If c% = 34 Then
    in_string% = 0
   Else
    word_length% = word_length% + 1
    If word_length% > Len(word$) Then word$ = word$ + Space$(10)
    Mid$(word$, word_length%, 1) = Chr$(c%)
   End If
  Else
   If c% = 34 Then
    in_string% = 0
   ElseIf c% = 32 Then
    If word_length% Then ProcessCommandLineItem Left$(word$, word_length%)
    word_length% = 0
   Else
    word_length% = word_length% + 1
    If word_length% > Len(word$) Then word$ = word$ + Space$(10)
    Mid$(word$, word_length%, 1) = Chr$(c%)
   End If
  End If
Next i&
If word_length% Then ProcessCommandLineItem Left$(word$, word_length%)

If num_files& > 1 Then OutputStatistics total_lines, total_words, total_characters, "total"
End Sub

Sub ProcessCommandLineItem(item$)
Dim i&, c%

If Abs(Asc(item$, Len(item$)) * 2 - 139) = 45 Then ' fancy way of saying "is either '/' or '\'"
  Exit Sub ' if the spec ends in a divider, then no files are named
End If

If Len(item$) > 3 Then
  If (Asc(item$, 2) = 58) And Abs(Asc(item$, 3) * 2 - 139) = 45 Then
   For i& = 4 To Len(item$)
    c% = Asc(item$, i&)
    If (c% <> 47) And (c% <> 92) Then
     RecursivelyFindFiles Left$(item$, 2) + "\", Mid$(item$, i&)
     Exit For
    End If
   Next i&
  End If
Else
  Select Case Asc(item$, 1)
   Case 47, 92: ' the '/' and '\' characters, respectively
    For i& = 2 To Len(item$)
     c% = Asc(item$, i&)
     If (c% <> 47) And (c% <> 92) Then
      RecursivelyFindFiles "\", Mid$(item$, i&)
      Exit For
     End If
    Next i&
   Case Else:
    RecursivelyFindFiles "", item$
  End Select
End If
End Sub

Function MinimumNonZero(a&, b&) As Long
If a& = 0 Then
  MinimumNonZero = b&
ElseIf b& = 0 Then
  MinimumNonZero = a&
ElseIf a& < b& Then
  MinimumNonZero = a&
Else
  MinimumNonZero = b&
End If
End Function

Sub RecursivelyFindFiles(base_path$, spec$)
Dim divider&, this_spec$, next_spec$

divider& = MinimumNonZero(InStr(spec$, "/"), InStr(spec$, "\"))
If divider& > 0 Then
  this_spec$ = Left$(spec$, divider& - 1)
  While Abs(Asc(spec$, divider&) * 2 - 139) = 45 ' fancy way of saying "is either '/' or '\'"
   divider& = divider& + 1 ' we know the spec doesn't end in a divider because ProcessCommandLineItem checks that
  WEnd
  next_spec$ = Mid$(spec$, divider&)
  RecursivelyFindSubdirs base_path$, this_spec$, next_spec$
Else
  Dim filename$, full_filename$

  filename$ = Dir$(base_path$ + spec$, -1)
  While Len(filename$) <> 0
   full_filename$ = base_path$ + filename$
   If (GetFileAttributes(full_filename$) And FILE_ATTR_DIRECTORY%) = 0 Then ProcessFile full_filename$
   filename$ = Dir$("", -1)
  WEnd
End If
End Sub

Sub RecursivelyFindSubdirs(base_path$, subdir_spec$, remaining_spec$)
Dim num_subdirs%, subdirname$, i&
ReDim subdirs$(10)
num_subdirs% = 0
subdirname$ = Dir$(base_path$ + subdir_spec$, -1)
While Len(subdirname$) <> 0
  If (GetFileAttributes(base_path$ + subdirname$) And FILE_ATTR_DIRECTORY%) <> 0 Then
   If (subdirname$ <> ".") And (subdirname$ <> "..") Then
    num_subdirs% = num_subdirs% + 1
    If num_subdirs% > UBound(subdirs$) Then ReDim Preserve subdirs$(num_subdirs% + 10)
    subdirs$(num_subdirs%) = base_path$ + subdirname$ + "\"
   End If
  End If
  subdirname$ = Dir$("", -1)
WEnd
For i& = 1 To num_subdirs%
  RecursivelyFindFiles subdirs$(i&), remaining_spec$
Next i&
End Sub

Sub ProcessFile(path_to_file$)
Dim ff%, state%, remaining&, i&
Dim As LongInt file_lines, file_words, file_characters
Dim buffer As String * 32768
Dim buf_ptr As UShort Ptr
buf_ptr = VarPtr(buffer)
num_files& = num_files& + 1
ff% = FreeFile
state% = FLAG_ALWAYS_ON% Or FLAG_ENABLE_NEXT_LF_1% Or FLAG_ENABLE_NEXT_SPACE_1%
Open path_to_file$ For Binary As #ff%
remaining& = LOF(ff%)
file_characters = remaining&
total_characters = total_characters + file_characters
While remaining& > 32768
  Get #ff%, , buffer
  remaining& = remaining& - 32768
  For i& = 0 To 16383
   state% = ((state% SHR 5) Or &HF8) And table(buf_ptr[i&])
   If state% And FLAG_COUNT_CR_1% Then
    file_lines = file_lines + 1
    total_lines = total_lines + 1
   End If
   If state% And FLAG_COUNT_LF_1% Then
    file_lines = file_lines + 1
    total_lines = total_lines + 1
   End If
   If state% And FLAG_COUNT_CRLF_2% Then
    file_lines = file_lines + 1
    total_lines = total_lines + 1
   End If
   If state% And FLAG_COUNT_SPACE_1% Then
    file_words = file_words + 1
    total_words = total_words + 1
   End If
   If state% And FLAG_COUNT_SPACE_2% Then
    file_words = file_words + 1
    total_words = total_words + 1
   End If
  Next i&
WEnd
Get #ff%, , buffer
If (remaining& And 1) <> 0 Then
  buf_ptr[remaining& SHR 1] = buf_ptr[remaining& SHR 1] And &HFF
End If
For i& = 0 To (remaining& + 1) SHR 1
  state% = ((state% SHR 5) Or &HF8) And table(buf_ptr[i&])
  If (state% And FLAG_COUNT_CR_1%) <> 0 Then
   file_lines = file_lines + 1
   total_lines = total_lines + 1
  End If
  If (state% And FLAG_COUNT_LF_1%) <> 0 Then
   file_lines = file_lines + 1
   total_lines = total_lines + 1
  End If
  If (state% And FLAG_COUNT_CRLF_2%) <> 0 Then
   file_lines = file_lines + 1
   total_lines = total_lines + 1
  End If
  If (state% And FLAG_COUNT_SPACE_1%) <> 0 Then
   file_words = file_words + 1
   total_words = total_words + 1
  End If
  If (state% And FLAG_COUNT_SPACE_2%) <> 0 Then
   file_words = file_words + 1
   total_words = total_words + 1
  End If
Next i&
If (state% And FLAG_ENABLE_NEXT_SPACE_1%) <> 0 Then
  file_words = file_words + 1
  total_words = total_words + 1
End If
Close #ff%

OutputStatistics file_lines, file_words, file_characters, path_to_file$
End Sub

Sub OutputStatistics(lines As LongInt, words As LongInt, characters As LongInt, label$)
If show_lines% Then Print Using "#######  "; lines;
If show_words% Then Print Using "########  "; words;
If show_characters% Then Print Using "#########  "; characters;
Print label$
End Sub