Archive for Applications

To, czego oczekuje kompilator

2008-08-19 12:53

Język C++ jest tworem skomplikowanym i jego złożoność daje się we znaki nie tylko programistom. Dość często mają z nią problemy także kompilatory. Obecnie zdecydowana większość narzędzi tego typu spełnia prawie całkowicie wymagania aktualnego standardu. Istnieje jednak sporo miejsca na usprawnienia, chociażby w bodaj najbardziej niedopracowanej dziedzinie: jakości komunikatów o błędach generowanych przez kompilatory.
Jeśli na przykład trafi nam się taka deklaracja zmiennej:

  1. SomeType variable;

a typ SomeType z jakiegoś powodu (niedołączony nagłówek, kwestia zasięgu, itd.) będzie w jej miejscu nieznany, to treść wyprodukowanego przy okazji komunikatu o błędzie może nas trochę zaskoczyć. Zarówno CL (kompilator Microsoftu używany w Visual C++), jak i GCC wyplują bowiem coś w stylu:

error: expected ‘;’ before ‘variable’

To znaczy ni mniej, ni więcej, tylko to, że według tych kompilatorów właściwa jest “deklaracja”:

  1. SomeType;

Dość zaskakujące, nieprawdaż?

Takie zachowanie można częściowo wyjaśnić tym, że kompilator “nie patrzy” na kod tak, jak programista. My widzimy tutaj deklarację zmiennej, natomiast dla kompilatora jest to tylko sekwencja: ‘nieznany identyfikator’, po którym następuje kolejny ‘nieznany identyfikator’. Ponieważ mówi się, że C++ jest językiem kontekstowym (co swoją drogą nie jest do końca ścisłe), taki fragment może sugerować wiele różnych rodzajów pomyłek. To, co sugeruje kompilator, wbrew pozorom też pewnie ma sens, chociaż dość specyficzny. Postawienie średnika w “spodziewanym” miejscu sprawi bowiem, że zamiast dwóch nieznanych nazw w jednej instrukcji będziemy mieli tylko jedną. Cóż za postęp! :)
Na tym prostym przykładzie widać, że interpretacja wyników kompilacji zakończonej niepowodzeniem wymaga niestety pewnego doświadczenia. Dopiero po jakimś czasie nauczymy się trafnie(j) zgadywać, co tak naprawdę oznacza ten czy inny błąd. Najwyraźniej taki już urok C++…

Tags:
Author: Xion, posted under Applications, Programming » 12 comments

Triki z PowerShellem #9 – Potokowanie

2008-08-03 17:33

Jedną z głównych zalet powłok tekstowych w rodzaju PowerShella jest to, że pozwalają one na łączenie ze sobą małych, elementarnych poleceń w jedno duże zadanie. Gdy odbywa się to na zasadzie przekazywania wyników jednego programu na wejście następnego, mówimy o potokowaniu (pipelining). Znawcy basha mogliby rzucić np. takim przykładem:

  1. cat < program.cpp | grep int | wc --lines[/code]
  2. w którym to najpierw odczytywana jest zawartość pliku (<kbd>cat</kbd>), wyszukiwane są wszystkie linijki zawierające ciąg "int" (<kbd>grep</kbd>) i liczona jest ich ilość (<kbd>wc</kbd>). Całkiem oczywiste, prawda? ;-)
  3.  
  4. W PowerShellu przetwarzanie potokowe jest o tyle lepsze niż w innych powłokach, że między poleceniami wymienia się nie tekst, a obiekty .NET-owe. Dobrze byłoby więc wiedzieć, jak należy pisać własne skrypty, aby mogły one działać w potokach. Na szczęście nie jest to specjalnie trudne; prezentuje to ten oto skrypt:
  5. [csharp]# pokemonize.ps1
  6. # Zmienia litery w tekście na losowo duże lub małe
  7.  
  8. begin
  9. {
  10.     # Inicjujemy generator liczb losowych
  11.     $rand = New-Object Random
  12. }
  13.  
  14. process
  15. {
  16.     $str = $_.ToString()
  17.     $result = New-Object Text.StringBuilder
  18.    
  19.     # Zmieniamy znaki
  20.     for ($i = 0; $i -lt $str.Length; ++$i)
  21.     {
  22.         if ($rand.NextDouble() -lt [float]0.5)
  23.             { $newChar = [Char]::ToLower($str[$i]) }
  24.         else
  25.             { $newChar = [Char]::ToUpper($str[$i]) }
  26.            
  27.         $result.Append($newChar) | Out-Null
  28.     }
  29.    
  30.     # Wyświetlamy przetworzony ciąg
  31.     $result.ToString()
  32. }[/csharp]
  33. Tym, co on robi, jest losowa zmiana wielkości liter w ciągu stanowiącym tekstową reprezentację obiektu (lub obiektów), jaki dostaje na wejściu. Jednym słowem, dokonuje jego <em>pokemonizacji</em>... Pewnie dla niektórych byłoby to przydatne, ale powiedzmy, że to tylko taki przykład ;P
  34. Najważniejsze jest to, że podany skrypt działa dobrze na obiektach otrzymanych poprzez potok, czyli np. linijkach tekstu odczytanego z pliku poprzez <kbd>Get-Content</kbd>:
  35. [code]Get-Content ./Plik.txt | . ./pokemonize.ps1 | Out-Host

Dla każdego takiego obiektu (tutaj: wiersza z pliku) wykonywany jest blok process, w którym to ów obiekt jest reprezentowany jako zmienna $_. Można to sobie wyobrazić jako wnętrze pętli foreach, przelatującej po wszystkich obiektach z wejścia skrypt. Dodatkowo możemy jeszcze określić bloki: begin (uruchamiany na samym początku) i end (na końcu). W nich powinniśmy umieścić ewentualny kod inicjalizujący i/lub kończący pracę skryptu.

Tags: ,
Author: Xion, posted under Applications » Comments Off on Triki z PowerShellem #9 – Potokowanie

Triki z PowerShellem #8 – Profil i prompt

2008-07-22 16:44

Jeśli posługujemy się PowerShellem, to pewnie po jakimś czasie zechcemy dodać do niego jakiś nowy alias lub zupełnie nową komendę ogólnego przeznaczenia. W takim przypadku warto wiedzieć o istnieniu tak zwanego profilu, czyli skryptu ładowanego automatycznie przy starcie każdej sesji PS. Ścieżka do niego jest zawarta w zmiennej $profile i domyślnie ma formę:

  1. <Moje dokumenty>\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

Początkowo plik ten (ani nawet katalog, w którym się znajduje) nie istnieje, więc musimy go utworzyć. Gdy to zrobimy, będzie on pełnił funkcję powershellowego Autostartu.

Następnie możemy zechcieć coś w nim umieścić. Na początek można na przykład zmienić domyślny prompt (zwany czasem po “polskiemu” znakiem zachęty) powłoki na coś bardziej gustownego i przydatnego. W tym celu należy napisać funkcję prompt, która jako rezultat zwracać będzie odpowiedni ciąg.
Fani linuksowych shelli mogą na przykład sprawić, aby PS wyglądał trochę jak bash przy pomocy następującej funkcji:

  1. function prompt {
  2.     $Env:USERNAME + "@" + $(hostname) + " " + $(Get-Location) + "$ "
  3. }

Wynik prezentuje się mniej więcej tak:

Można naturalnie poeksperymentować z dodaniem innych informacji niż nazwa komputera i na nim zalogowanego użytkownika. Możliwości są bowiem nieporównywalnie większe niż to, co oferuje chociażby stary cmd.exe.

Tags:
Author: Xion, posted under Applications » 2 comments

Odblokowywanie plików

2008-07-18 11:07

Czasami zdarza się, że chcemy usunąć plik, który okazuje się być używany przez inny proces lub system operacyjny. Często nie mamy pojęcia, dlaczego tak jest i kto ma jakiś interes w trzymaniu blokady na tym właśnie pliku. Zwłaszcza Vista, będąca paranoicznie przewrażliwiona na punkcie zachowania integralności systemu plików, jest bardzo restrykcyjna pod względem swobody kasowania zbiorów będących w użyciu.
Oczywiście w takiej sytuacji można zawsze zrestartować system, ale trudno uznać to za wygodne rozwiązanie :) Dobrze byłoby więc mieć sposób na dowiedzenie się, jaki proces używa danego pliku, aby ewentualnie go zakończyć lub w skrajnym przypadku po prostu ubić.

I tu jest problem, bowiem w Windows nie ma na to prostego sposobu. Dotyczy to między innymi istnienia jakiegoś API, które by na to pozwalało; w najlepszym przypadku należy posłużyć się narzędziami z DDK, czyli pakietu służącego do… pisania sterowników działających w trybie jądra (kernel mode). Podobnie rzecz ma się z istnieniem wbudowanych w system programów, służących do tego celu (a więc czegoś podobnego do uniksowej komendy lsof). Odpowiednie narzędzia są jedynie częścią pakietów dodatkowych, jak Windows Server 2003 Resource Kit (niekompatybilny z Vistą) czy Windows Sysinternals. Mogą być one jednak dość kłopotliwe w obsłudze.

Dlatego podzielę się moim niedawnym odkryciem, którym jest mały i niezwykle przydatny programik o nazwie Unlocker. Potrafi on dokładnie to, o czym jest tu mowa: wylistować procesy, które używają danego pliku. Działa on przy tym na każdej sensownej wersji Windows, integruje się z menu kontekstowym plików dla większej wygody, no i jest do tego aplikacją freeware.
Rzadko robię czemuś aż taką “reklamę”, ale w tym przypadku uznałem, że tak dobrym i użytecznym narzędziem należy się niezwłocznie podzielić ze światem :)

Tags: ,
Author: Xion, posted under Applications » 5 comments

Triki z PowerShellem #7 – Zliczanie wierszy

2008-07-12 10:10

Gdy zawzięcie i wytrwale tworzymy jakiś koderski projekt, chciałoby się od czasu do czasu zmierzyć, ile to już pracy zdołaliśmy w nim wykonać. Pewnym sposobem na to jest policzenie ilości wszystkich linii kodu, które udało nam się już napisać.
Istnieją do tego nawet oddzielne aplikacje, niekiedy z rozbudowanym interfejsem graficznym. Jednak takie proste zadanie można by przecież zrealizować przy pomocy równie prostego narzędzia. Jakiego? Oczywiście – niewielkiego skryptu PowerShella :) Chociażby takiego jak ten:

  1. # lines.ps1
  2. # Skrypt liczący wiersze kodu w plikach podanego katalogu
  3.  
  4. # Parametr: ścieżka do katalogu z plikami
  5. param ([string]$path = ".")
  6.  
  7. # Stałe
  8. $EXTENSIONS = @("cpp", "h", "hpp")  # Rozszerzenia interesujących plików
  9.  
  10. # Zmienne
  11. $filesCount = 0
  12. $totalLinesCount = 0
  13. $emptyLinesCount = 0
  14.  
  15. # Przeszukujemy podany katalog rekurencyjnie (wszerz)
  16. $dirQueue = New-Object Collections.Queue
  17. $dirQueue.Enqueue($path)
  18. while ($dirQueue.Count -gt 0)
  19. {
  20.     # Dodajemy podkatalogi do przeszukania
  21.     $dir = [string]$dirQueue.Dequeue()
  22.     foreach ($subDir in [IO.Directory]::GetDirectories($dir))
  23.         { $dirQueue.Enqueue($subDir) }
  24.        
  25.     # Pobieramy wszystkie pliki w aktualnym katalogu pasujące do filtra
  26.     $files = New-Object Collections.ArrayList
  27.     foreach ($ext in $EXTENSIONS)
  28.         { $files.AddRange([IO.Directory]::GetFiles($dir, "*." + $ext)) }
  29.    
  30.     # Liczymy w nich wiersze
  31.     foreach ($file in $files)
  32.     {
  33.         ++$filesCount
  34.         foreach ($line in [IO.File]::ReadAllLines($file))
  35.         {
  36.             ++$totalLinesCount
  37.             if ($line.Trim().Length -eq 0) { ++$emptyLinesCount }
  38.         }
  39.     }
  40. }
  41.  
  42. # Wyświetlamy statystyki
  43. "Files: " + $filesCount | Out-Host
  44. "Total lines: " + $totalLinesCount | Out-Host
  45. "Non-empty lines: " + ($totalLinesCount - $emptyLinesCount) | Out-Host

Podajemy mu tylko ścieżkę do katalogu z naszym kodem, a on przeglądnie wszystkie pliki z ustalonymi rozszerzeniami i wyświetli statystykę z liczbą linii: wszystkich oraz niepustych. Cała ta czynność ta nie zajmuje w kodzie specjalnie dużo miejsca, gdyż najważniejsze jej elementy: pobranie podkatalogów, plików w katalogu i wierszy tekstu w pliku dają się zrobić pojedynczymi wywołaniami funkcji (odpowiednio: GetDirectories i GetFiles z System.IO.Directory oraz System.IO.File.ReadAllLines). To aczkolwiek zasługa nie samego PowerShella, tylko niezawodnej platformy .NET ;)

Skrypt ten można rzecz jasna znacznie usprawnić, pozwalając chociażby na definiowanie filtra nazw plików z kodem w jego wywołaniu czy też umożliwiając wykluczanie niektórych katalogów (np. bin, Debug, Release) w celu przyspieszenia zliczania. Jeśli ktoś miałby na to ochotę, może się dodawaniem takich feature‘ów pobawić :)

Tags:
Author: Xion, posted under Applications, Programming » Comments Off on Triki z PowerShellem #7 – Zliczanie wierszy

Kolorowanie semantyczne

2008-07-07 19:04

W dzisiejszych czasach niemal każdy edytor plików tekstowych nieco bardziej zaawansowany od windowsowego Notatnika oferuje funkcję kolorowania składni (syntax highlighting) przynajmniej kilku najpopularniejszych języków programowania. W przypadku całych IDE jest to oczywiście funkcjonalność absolutnie oczywista i niezbędna, jednak coraz więcej środowisk oferuje też coś więcej. Coś, co dla odróżnienia nazywam kolorowaniem semantycznym; nie jestem bowiem pewien, czy ten mechanizm ma jakąś ogólnie przyjętą nazwę.


Kodowanie semantyczne w Visual Studio z pluginem AssistX

O co w nim chodzi? Standardowe kolorowanie potrafi między innymi odróżnić słowa kluczowe od identyfikatorów, wyróżniając zwykle te pierwsze innym stylem czcionki, zaś te drugie pozostawiając bez zmian. Wszystkie identyfikatory: nazwy zmiennych, funkcji, typów, stałych, szablonów, itp., są więc formatowane tak samo i wyglądają identycznie.
Trik kolorowania semantycznego polega właśnie na rozróżnieniu tych wszystkich kategorii identyfikatorów. Oczywiście jest to możliwe tylko wtedy, gdy IDE dysponuje bazą danych o całej strukturze projektu. Ale taka baza jest przecież coraz częściej tworzona, tyle że w innym celu: zapewnienia automatycznego uzupełniania poprzez mechanizmy w rodzaju IntelliSense w Visual Studio. Na szczęście ktoś kreatywny wpadł na pomysł, że można ją wykorzystać także w inny sposób – i chwała mu za to :)

Kolorowanie semantyczne ma przynajmniej dwie zalety. Ułatwia ono zorientowanie się w przeglądanym kodzie, zwłaszcza takim który widzimy po raz pierwszy. Ponadto zaś pozwala ono na wczesne wykrycie prostych acz uciążliwych błędów w rodzaju literówek. Sprawiają one bowiem, że dany identyfikator – jako nieznany – jest kolorowany inaczej, co pozwala na łatwiejsze dostrzeżenie pomyłki.
A wady? Jak każdy mechanizm działający w tle, kolorowanie semantyczne zjada trochę zasobów systemowych – m.in. dla niego opłaca się mieć w procesorze więcej niż jeden rdzeń. A poza tym można zwyczajnie nie lubić pstrokatego kodu i preferować bardziej jednolitą kolorystykę… O gustach się przecież nie dyskutuje, a teoretycznie kodować można i w Notatniku :)

Tags:
Author: Xion, posted under Applications, Programming » 8 comments

Triki z PowerShellem #6 – Mail z załącznikami

2008-07-03 20:05

Kiedy mamy komuś przesłać plik, możemy niekiedy użyć do tego zwykłej poczty e-mail. Nie jest to oczywiście możliwe zawsze: plik nie powinien być zbyt duży i zwykle nie może też należeć do żadnego z “niebezpiecznych” typów (np. aplikacji EXE), by serwery pocztowe mogły go przepchnąć bez narażania lub zatykania sieci.
Jeśli w naszym przypadku tak jest, to możemy wykonać całą operację na przykład przy pomocy poniższego skryptu PowerShella:

  1. # MailFile.ps1 - Wysyła podany plik e-mailem na podany adres
  2. # Parametr: nazwa pliku lokalnego
  3. param([string]$file = $(throw "File not specified"))
  4.  
  5. # Stałe
  6. $SERVER = "moj.server.pl"
  7. $LOGIN = "loginSmtp"
  8. $PASSWORD = "hasłoSmtp"
  9. $FROM_ADDRESS = "ja@server.pl"
  10.  
  11. # Odczytanie adresu docelowego
  12. $recipentAddress = Read-Host -Prompt "Recipent e-mail address"
  13. $recipent = New-Object Net.Mail.MailAddress @($recipentAddress)
  14.  
  15. # Złożenie maila
  16. $mail = New-Object Net.Mail.MailMessage
  17. $mail.From = New-Object Net.Mail.MailAddress @($FROM_ADDRESS)
  18. $mail.To.Add($recipent)
  19. $mail.Subject = (New-Object IO.FileInfo @($file)).Name
  20.  
  21. # Dodanie załącznika
  22. $attachment = New-Object Net.Mail.Attachment @($file,
  23.     [Net.Mime.MediaTypeNames+Application]::Octet)
  24. $cd = $attachment.ContentDisposition
  25. $cd.CreationDate = [IO.File]::GetCreationTime($file)
  26. $cd.ModificationDate = [IO.File]::GetLastWriteTime($file)
  27. $cd.ReadDate = [IO.File]::GetLastAccessTime($file)
  28. $mail.Attachments.Add($attachment)
  29.  
  30. # Łączenie z serwerem SMTP i wysłanie maila
  31. $smtp = New-Object Net.Mail.SmtpClient @($SERVER)
  32. $smtp.Credentials = New-Object Net.NetworkCredential @($LOGIN, $PASSWORD)
  33. # $smtp.EnableSsl = $true # Odkomentowujemy, jeśli serwer wymaga SSL
  34. $smtp.Send($mail)

Jak widać, nie jest to nic skomplikowanego. A jak wykorzystać go w praktyce?… Podobnie jak prezentowany wcześniej skrypt do uploadu na serwer FTP, można go wywołać komendą w rodzaju:

  1. powershell -Command . 'C:\Sciezka\Do\Skryptu\MailFile.ps1' '%1'

którą podpinamy do menu kontekstowego plików lub podmenu Wyślij do.
W ten prosty sposób możemy oszczędzić sobie uruchamiania całego klienta poczty, względnie przeglądarki z webmailem. Naturalnie sporo rzeczy – jak chociażby temat wysyłanej wiadomości czy jej treść – możemy w zaprezentowanym kawałku kodu zmienić lub uzupełnić.

Tags: , ,
Author: Xion, posted under Applications, Internet » 1 comment
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.