niedziela, 17 kwietnia 2016

Jednolinijkowe generatory melodii

Na blogu countercomplex znalazłem ciekawy artykuł jak generować 8-bitowe oldskulowe (podobne do tych z gier z lat 80-tych) melodie za pomocą jednej linijki kodu w języku C. Poniżej dwa przykładowe programy:

main(t){for(t=0;;t++)putchar((t*5&t>>7)|(t*3&t>>10));}

main(t){for(t=0;;t++)putchar((t>>6|t|t>>(t>>16))*10+((t>>11)&7));}

Powyższe programy kompilujemy następująco:

gcc sound.c -o sound

Aby odtworzyć dźwięk z naszego generatora o nazwie sound, należy przekierować jego standardowe wyjście na standardowe wejście odtwarzacza audio np. aplay (Linux) za pomocą potoku |:

./sound | aplay

W komentarzach do artykułu na blogu countercomplex jest dużo innych przykładów - można poeksperymentować modyfikując funkcję putchar().

Źródła
http://countercomplex.blogspot.com/2011/10/algorithmic-symphonies-from-one-line-of.html 
http://countercomplex.blogspot.com/2011/10/some-deep-analysis-of-one-line-music.html 
 

środa, 9 marca 2016

Kody ASCII

Ostatnio potrzebowałem skorzystać z kodów ASCII w konsoli systemu Windows. Oczywiście można znaleźć gotowe tablice z kodami ASCII w internecie, ale rozszerzone kody ASCII są zależne od systemu operacyjnego oraz strony kodowej. Tak więc stworzyłem prosty programik ascii-codes, który wyświetla symbole (znaki) dla kodów ASCII od 0 do 255.


ASCII (ang. American Standard Code for Information Interchange) – 7-bitowy kod przyporządkowujący liczby z zakresu 0−127: literom alfabetu angielskiego, cyfrom, znakom przestankowym i innym symbolom oraz poleceniom sterującym. Na przykład litera „a” jest kodowana jako liczba 97, a znak spacji jest kodowany jako 32. Znaki ASCII dzielimy na:
- sterujące (kody 0 - 31 oraz 127),
- drukowalne (kody 32 - 126).
Ponieważ kod ASCII jest 7-bitowy, a większość komputerów operuje na 8-bitowych bajtach, dodatkowy bit można wykorzystać na powiększenie zbioru kodowanych znaków do 256 symboli, a więc mamy:
- znaki ASCII rozszerzone (kody 128 - 255) - uzależnione od strony kodowej.

Stronę kodową konsoli Windows sprawdzamy poleceniem:

mode con cp

a ustawiamy poleceniem:

mode con cp=[strona kodowa]

np.

mode con cp=1250

Kod programu ascii-codes.c:
/*
 *  -----------------------------------------
 *  ASCII Codes 1.0
 *  -----------------------------------------
 *  Author: Adam Blaszczyk
 *          http://wyciekpamieci.blogspot.com
 *  Date:   2016-03-08
 *  -----------------------------------------
 *  
 *  Compilation (Linux, Windows):
 *         gcc ascii-codes.c -o ascii-codes -Wall
 *
 *  Usage:
 *         ascii-codes
 *         - ASCII and Extended ASCII *printable* characters between 32 and 255
 *         ascii-codes min
 *         - ASCII and Extended ASCII characters between [min] and 255
 *         ascii-codes min max
 *         - ASCII and Extended ASCII characters between [min] and [max]
 *
 */

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
  
  int ch;
  int min = 32;
  int max = 255;

  if(argc == 2)
    min = atoi(argv[1]);
  if(argc == 3) {
    min = atoi(argv[1]);
    max = atoi(argv[2]);
  }

  printf("\n");
  printf("  ASCII CODES\n");
  printf("  ==============================================\n");
  printf("     0 -  31; 127 --> ASCII control characters\n");
  printf("    32 - 126      --> ASCII printable characters\n");
  printf("   128 - 255      --> Extended ASCII characters\n");

  printf("\n");
  printf("  +-------+------+-----------+\n");
  printf("  |  DEC  |  HEX | Character |\n");
  printf("  +-------+------+-----------+\n");
  
  for(ch = min; ch <= max; ch++) {
    printf("  |  %03d  |  %02X  |     %c     |\n", ch, ch, ch);
  }
  
  printf("\nPress [ENTER] to exit...");
  getchar();

  return 0;
}
https://github.com/adamblaszczyk/ascii-codes 

Program da się skompilować pod Windows i Linux za pomocą gcc:

gcc ascii-codes.c -o ascii-codes -Wall

Przykładowe użycie programu:

ascii-codes
Wyświetla drukowalne znaki ASCII o kodach od 32 do 255,

ascii-codes 1
Wyświetla znaki ASCII o kodach od 1 do 255,

ascii-codes 174 181
Wyświetla znaki ASCII o kodach od 174 do 181.
 

piątek, 30 października 2015

valgrind - szukanie wycieków pamięci

Chciałbym zaprezentować pożyteczny program konsolowy valgrind, który bada wycieki pamięci w programach.

Wyciek pamięci (ang. memory leak) – niezamierzone użycie pamięci przez program komputerowy, gdy nie zwalnia on zaalokowanej wcześniej pamięci, która nie jest już mu potrzebna.

Wycieki pamięci są efektem bardzo niepożądanym. Program bowiem zajmuje coraz więcej pamięci, ale nie jest w stanie jej wykorzystać ani zwolnić. Szczególnie w aplikacjach, które działają przez długi czas (w większości serwerowych), efekt wycieku pamięci stopniowo narasta. Sam wyciek prowadzi do spadku wydajności systemu, w skrajnym przypadku zawieszenia się programu lub innych programów, którym system nie może przydzielić wystarczającej ilości pamięci, a nawet zablokowania całego systemu operacyjnego. Kod programu, który powoduje wycieki pamięci, jest kodem błędnym.

Użycie programu valgrind jest bardzo proste:

valgrind nazwa_programu

np.:

valgrind putty
valgrind ./myprog

Wynikiem powyższych poleceń jest uruchomienie danego programu, a po jego zakończeniu wyświetlenie ilości bajtów, które wyciekły.

Program valgrind przydaje się, gdy na komputerze uruchamiamy program, który po pewnym czasie zaczyna "mulić". Można wtedy sprawdzić, czy nie ma dużych wycieków pamięci.

W językach programowania takich jak Java czy C# problem wycieków pamięci został częściowo zniwelowany poprzez zastosowanie odśmiecania pamięci (ang. Garbage Collector). W językach C i C++ programista musi zwalniać pamięć. Poniżej przykład programu w C, który nie zwalnia zaalokowanej wcześniej pamięci na zmienną typu int (4 bajty):

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  int *x = malloc(sizeof(int));
  *x = 16;
  printf("%d\n",*x);
  return 0;
}

Powyższy kod kompilujemy następująco:

gcc memleak.c -o memleak

Sprawdzamy wycieki pamięci:

valgrind ./memleak

Dostajemy informację, że wyciekły 4 bajty.

Poprawnie napisany program powinien zawierać funkcję free(), która zwalnia zarezerwowaną wcześniej pamięć:
 
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  int *x = malloc(sizeof(int));
  *x = 16;
  printf("%d\n",*x);
  free(x);
  return 0;
}

środa, 10 czerwca 2015

Podstawy systemu JunOS

W dzisiejszym poście omówię podstawy konfiguracji urządzeń sieciowych firmy Juniper Networks przy pomocy CLI systemu operacyjnego JunOS. System ten oparty jest na jądrze FreeBSD i zawiera obsługę większości używanych współcześnie protokołów routingu.

Nasz przykładowy router R1 posiada dwa interfejsy sieciowe em0 oraz em1.


Legenda do rysunku:
R1 - router Juniper
SW1 - switch 1
SW2 - switch 2
C1 - host 1
C2 - host 2
C3 - host 3
C4 - host 4
 
W systemie JunOS nie da się ustawić adresu IP bezpośrednio na fizycznym interfejsie sieciowym, tylko na logicznym zwanym unitem. Każdy unit posiada swój identyfikator w postaci liczby całkowitej. W naszym przypadku jest to 0, czyli mamy unit 0 na em0 (em0.0) oraz unit 0 na em1 (em1.0). Identyfikator unitu jest dowolną liczbą całkowitą.

W naszym przypadku będziemy mieć następującą adresację interfejsów:
em0.0 : 192.168.0.1 z maską 255.255.255.0
em1.0 : 10.10.10.1 z maską 255.255.255.0

System JunOS może pracować w dwóch trybach:
- Operational Mode - do odczytywania informacji i monitorowania urządzenia;
- Configuration Mode - do zmiany konfiguracji urządzenia.
Tryby te można rozróżnić po znaku zachęty:
> Operational Mode
# Configuration Mode

Domyślnie pracujemy w Operational Mode. Aby przejść do Configuration Mode trzeba wydać polecenie:

root> configure

Powrót do Operational Mode:

root# exit

Aby odczytać konfigurację wydajemy polecenie:

root> show configuration

Aby uzyskać pomoc wydajemy polecenie:

root> ?

Co robi dana komenda dowiemy się tak:

root> show?

Listę opcji (dopełnień) danej komendy uzyskamu tak:

root> show ?

Przejdźmy teraz do konfiguracji interfejsów sieciowych. Chcemy wyświetlić bieżącą informację o interfejsach:

root> show interfaces terse


Teraz chcemy ustawić adresację na em0.0:

root> configure

root# set interfaces em0 unit 0 family inet address 192.168.0.1/24

root# commit

Komendy są prawidłowe, ale i tak dostaniemy błąd Missing mandatory statement: 'root-authentication'. Chodzi o to, że domyślnie konto root-a nie ma założonego hasła. Trzeba je założyć:

root# set system root-authentication plain-text-password

root# commit

Polecenie commit zatwierdzi zmianę hasła dla root-a, ale również poprzednią komendę set interfaces, która wygenerowała błąd.

Możemy teraz ustawić IP na em1.0:

root# set interfaces em1 unit 0 family inet address 10.10.10.1/24

root# commit

Przechodzimy do Operational Mode i wyświetlamy interfejsy:

root# exit

root> show interfaces terse

 
Jak widać udało się ustawić adresację na interfejsach sieciowych.

wtorek, 14 kwietnia 2015

ODBC w Linuksie

ODBC (ang. Open DataBase Connectivity - otwarte łącze baz danych) - interfejs pozwalający programom łączyć się z systemami zarządzającymi bazami danych. Jest to API niezależne od języka programowania, systemu operacyjnego i bazy danych. W skład ODBC wchodzą wywołania wbudowane w aplikacje oraz sterowniki ODBC. Pierwsza implementacja ODBC pojawiła się w systemie Windows, lecz obecnie możliwe jest korzystanie z niego na platformach Unix, Linux oraz Macintosh.

W systemie Windows zarządzanie sterownikami ODBC oraz źródłami danych jest bardzo proste i od razu dostępne w systemie - wystarczy wejść w Panel sterowania -> Narzędzia administracyjne -> Źródła danych (ODBC).

Pod linuksem sytuacja jest trochę bardziej skomplikowana:

1. Trzeba zainstalować pakiet unixodbc:

sudo apt-get install unixodbc

Jest to główna biblioteka ODBC dla systemu Linux. Pakiet unixodbc zawiera także narzędzie wiersza poleceń isql, umożliwiające interaktywne wprowadzanie poleceń SQL.

2. Powinniśmy też zainstalować pakiet unixodbc-bin dostarczający graficznych narzędzi do zarządzania sterownikami i źródłami danych:

sudo apt-get install unixodbc-bin

Pakiet ten oferuje dwa pożyteczne graficzne narzędzia:

ODBCManageDataSourcesQ4 - zarządzanie źródłami danych i sterownikami ODBC 



ODBCCreateDataSourceQ4 - kreator źródeł danych




3. Teraz można już instalować sterowniki ODBC do różnych baz danych. Część można znaleźć w Menedżerze Pakietów np. synaptic a część na stronie:


4. Przykład - sterownik SQLite ODBC

sudo apt-get install libsqliteodbc

Efekt jest następujący:


Wystarczy teraz skonfigurować źródło danych (Data Source Names w ODBCManageDataSourcesQ4 lub za pomocą kreatora ODBCCreateDataSourceQ4) i można się do niego podpiąć różnymi programami, które korzystają z ODBC np. LibreOffice Base.

Do testów na wyciągnięcie ręki mamy na przykład dane przechowywane przez Firefoksa w katalogu domowym użytkownika /home/user/.mozilla/firefox. Są to pliki .sqlite np. places.sqlite - baza, która  w swoich tabelach trzyma zakładki i historię przeglądania.

piątek, 20 marca 2015

watch - pożyteczne linuksowe polecenie

Za pomocą polecenia watch możemy cyklicznie wywoływać inne polecenie (proces) w terminalu. Wynik wywoływanego polecenia wyświetla się standardowo co 2 sekundy bez przewijania ekranu konsoli, dzięki czemu odnosimy wrażenie uruchomionego programu przez cały czas. Czas odświeżania procesu możemy zmieniać za pomocą parametru -n.

Wynik działania komendy watch free:



Parametry programu watch:

-n - zmiana czasu (w sekundach) wywoływania procesu, np.:
      -n 0  - 0.1 sekundy
      -n 1  - 1 sekunda
      -n 3  - 3 sekundy
-d - podświetla zmiany
-t - nie wyświetla nagłówka

Przykłady użycia:

watch -n 0 free - monitoruje wykorzystanie pamięci,

watch sensors - monitorowanie temperatur np. temperatury procesora,

watch "dmesg | tail -20" - monitorowanie stanu urządzeń i innych zdarzeń systemowych, np. gdy coś podłączymy do USB, to zobaczymy informacje o tym urządzeniu.

czwartek, 12 marca 2015

Kurs Bash cz.2

1. Arytmetyka

W bashu mamy następujące operatory arytmetyczne:

+ dodawanie
- odejmowanie
* mnożenie
/ dzielenie
% reszta z dzielenia (modulo)
** potęgowanie

Przykład wykorzystania tych operatorów:

#!/bin/bash

X=9
Y=4

# dodawanie
let Z=X+Y
echo "$X + $Y = $Z"

# odejmowanie
let Z=X-Y
echo "$X - $Y = $Z"

# mnozenie
let Z=X*Y
echo "$X * $Y = $Z"

# dzielenie
let Z=X/Y
echo "$X / $Y = $Z"

# reszta z dzielenia (modulo)
let Z=X%Y
echo "$X modulo $Y = $Z"

# potegowanie
let Z=X**Y
echo "$X^$Y = $Z"


Uruchamiając powyższy skrypt widać, że bash operuje tylko na liczbach całkowitych tzn. 9/4 =2. Resztę z dzielenia otrzymujemy po wykonaniu operacji modulo.

Mamy też operatory arytmetyczne bitowe:

>> przesunięcie bitowe w prawo
<< przesunięcie bitowe w lewo
~ bitowa negacja
& AND bitowe
| OR bitowe
^ XOR bitowe

#!/bin/bash

X=8
Y=1

# przesuniecie bitowe w prawo
let "Z=X>>2"
echo "$Z"

# przesuniecie bitowe w lewo
let "Z=X<<2"
echo "$Z"

# bitowa negacja
let "Z=~X"
echo "$Z"

# AND bitowe
let "Z=X&Y"
echo "$Z"

# OR bitowe
let "Z=X|Y"
echo "$Z"

# XOR bitowe
let "Z=X^Y"
echo "$Z"

W bashu można też przeliczać systemy liczbowe:

#!/bin/bash

declare -i a #deklaracja zmiennej calkowitej

#BIN->DEC
a=2#1001
echo $a

#HEX->DEC
a=16#EF
echo $a

2. Pętle

Pętla for - wykonuje polecenia zawarte wewnątrz pętli, na każdym składniku listy (iteracja).

for zmienna in lista
do
  polecenia
done


Na poniższym przykładzie mamy dwie pętle for. Pierwsza wyświetla elementy listy a druga wszystkie pliki o rozszerzeniu .sh:

#!/bin/bash

for x in apple pear strawberry
do
  echo "This is $x"
done

for plik_sh in *.sh
do
  echo $plik_sh
done

I tu przychodzi następujące pytanie - jak odliczać kolejne wartości liczbowe w pętli for. Jest kilka sposobów. Oto  jeden z nich:

#!/bin/bash

for i in {1..10}
do
  echo $i
done

Pętla while - sprawdza warunek czy jest prawdziwy, jeśli tak to wykonane zostaną polecenia wewnątrz pętli, gdy warunek stanie się fałszywy pętla zostanie zakończona.

while warunek
do
polecenia
done


Przykład:

#!/bin/bash

x=1

while [ $x -le 10 ] #-le mniejsze badz rowne
do
echo $x
x=$[x+1]
done

Pętla until - działa odwrotnie niż while; polecenia w pętli wykonywane są, gdy warunek jest fałszywy - aż stanie się prawdziwy.

until warunek
do
polecenia
done


Przykład:

#!/bin/bash

x=1

until [ $x -ge 10 ] #-le wieksze badz rowne
do
echo $x
x=$[x+1]
done

Koniec części drugiej, cdn.