> "Text Mode" & "Graphical Mode" : Bugün kullandığımız ekranlarda temelde iki çalışma modu vardır: Text mod ve grafik mod. >> Text modda karakterler bir kalıp biçiminde ekrana basılır. Bu modda pixel temelinde bir kontrol yoktur. Her karakter için matriste belli bir yer ayrılmıştır. O yere kaarakterler kalıp olarak basılmaktadır. Text mod ekranlara konsol ekranı da denilmektedir. Eskiden yalnızca text modda çalışma söz konusuydu. Sonra zamanla donanım teknolojisi gelişince grafik modda çalışma da yaygınlaşmaya başladı. Eğer biz programı text modda çalışacak biçimde oluşturmuşsak bu tür programlara "konsol tabanlı (console based)" programlar da denilmektedir. Text modda bir imleç (cursor) vardır. stdout dosyasına yazılan şeyler bu imlecin bulunduğu yerden itibaren yazılırlar. Sonra imleç yazılan miktar kadar ilerletilir. Örneğin printf fonksiyonu stdout dosyasına yazar. Bu stdout dosyası default durumda pek çok sistemde terminal aygıt sürücüsüne yönlendirilmiştir. Terminal aygıt sürücüsü de yazılacak şeyleri imlecin bulunduğu yere yazar ve imleci yazılan karakter sayısı kadar ilerletir. Text modda imlecin ilerletilmesi sütun bittiğinde sonraki satırın başından itibaren yapılmaktadır. Text modda son satırdan sonra ekrana bir şeyler yazılmak istendiğinde her satır bir yukarı kaydırılır. Bu işleme "scroll" ya da "scroll up" denilmektedir. Text modda çalışmak çok hızlıdır. Text mod genel olarak basit bir arayüz oluşturmaktadır. Bu nedenle pek çok programalama dili çıktı bağlamında text modda uygun tasarlanmıştır. 25 satırlı 80 sütun eskiden beri en yaygın kullanılan text mod çözünürlüğüydü. Buna standart text mod çözünürlüğü denilmektedir. >> Grafik modda ekrandaki en küçük birim bir pixel'dir. Pixel ("picture element" sözcüklerinden kısaltılmıştır) ekranda görüntülenecek en küçük grafik öğedir. Grafik modda her şey ğixel'lerin uygun biçimde bir araya getirilmesiyle oluşturulmaktadır. Ekran çözünürlükleri pixel matrisinin genişlik ve yükseklik değeri ile belirtilmektedir. Örneğin 1920X1080 çözünürlük demek ekranda toplam "1980 * 1020" tane pixel var demektir. Text modda yalnızca karakter görüntülenebilmektedir. Halbuki grafik modda pixel'lerle her şey görüntülenebilmektedir. Biz bir resmi text modda görüntüleyemeyiz. Ancak grafik modda görüntüleyebiliriz. Bir program çıktısını pixel düzeyinde oluşturuyorsa buı tür programlara "GUI (Graphical User Interface) tabanlı programlar" denilmektedir. Örneğin Excel, Word gibi programlar GUI tabanlı programlardır. Diğer yandan, >> Text mod için program yazmak oldukça kolaydır. Ancak grafik modda program yazmak için ayrı bir bilgi gerekmektedir. C'nin standart fonksiyonlarıyla GUI tabanlı programlar yazılamaz. C'de GUI tabanlı programlar yazabilmek için özel kütüphanelerden faydalanmak gerekir. Bugün GUI tabanlı programlama oldukça yaygın kullanılmaktadır. Ancak GUI çalışma modeli konsole çalışma modeline göre oldukça yavaştır. Bu nedenle pek çok temel araç GUI çalışma modeli yerine konsole çalışma modeline göre tasarlanmış durumdadır. Örneğin derleyiciler GUI arayüzü arayüzü kullanmazlar. Klasik konsole tabanlı bir arayüz kullanırlar. Windows ve macOS sistemleri GUI çalışmanın ön planda olduğu sistemlerdir. Ancak UNIX/Linux dünyasında hala ağırlık konsol tabanlı çalışma modelindedir. Örneğin Linux sistemleri ağırlıklı olarak server sistemlerinde ve gömülü sistemlerde kullanılmaktadır. Burada grafik tabanlı çalışma yavaş olduğu gerekçesiyle ya da güçlü donanım gerektirmesinden dolayı tercih edilmemektedir. Tabii bugün kullanıdğımız Linux dağıtımları genellşkle bir grafik arayüz bulundurmaktadır. Ancak bu grafik arayüz kolaylıkla devre dışı bırakılabilmektedir. >> Bugün kullandığımız grafik kartlarında ekranın bir bölümü text bir bölümü grafik modda olamamaktadır. Ancak konsole tabanlı uygulamalar için GUI arayüzleri konsole ekranını bir pencere içerisinde pixel işlemleriyle emüle edebilmektedir. Örneğin Windows sistemlerinde biz aslında grafik modda çalışmaktayız. Ancak burada "cmd.exe" programını çalıştırdığımızda sanki klasik konsole sisteminde çalışıyormuşuz gibi bir emülasyon yapılmaktadır. Yani burada text mod görüntüsü sahte bir görüntüdür. Yalnızca klasikj konsol programlarının çalışabilmesi için pixel işlemleriyle oluşturulmuştur. Yani bugün grafik arayüze sahip işletim sistemlerinde biz bir konsol terminali açtığımızda sanki o terminal penceresi eski devirdeki text modda çalışan bir konsol penceresini taklit etmektedir. >> Renkli görüntünün bilgisayar ekranlarına oluşturulması 80'li yılların ortalarında başlamıştır. Text modda da grafik modda da bir renk olgusu vardır. Grafik modda her pixel ayrı bir renkle gösterilebilmektedir. Yaygın teknolojide Kırmızı (red), Yeşil (Green) ve Mavi (Blue) olmak üzere üç temel renk vardır. Diğer bütün renkler bu üç temel rengin tonal birleşimleriyle oluşturulmaktadır. Günümüz teknolojisinde bu üç ana renk toplam 256 farklı ([0, 255 arasında]) tonal değere sahiptir. Dolayısıyla grafik ekranlarda her pixel "256 * 256 * 256 ~= 16 milyon" renkten biri ile renklendirilebilmektedir. Ayrıca her pixel için modern grafik kartlarında ismine "alpha channel" denilen yine [0, 255] değer alan bir bilşen daha bulunudurlmaktadır. Bu bileşen pixel'in transparanlığını ayarlamakta kullanılmaktadır. Pekiyi eskiden text modda renk kavramı var mıydı? Evet grafik modun çok seyrek kullanıldığı yıllarda da yavaş yavaş text moda renk olgusu sokulmultur. Text moddaki her bir karakter matrisinin zemini ve şekli yarı ayrı boyanabilmektedir. Ayrıca "bold" ve "reverse" özel durumlar da söz konusu olmaktadır. Tabii bugün grafik arayüzlerdeki terminal ekranları aslında pixel temelinde emüle edildiğinden bu zemin ve şekil renkleri de aslında pixel temelinde oluşturulmaktadır. Pekiyi konsole ekranında renkli bir yazıyı nasıl oluşturabiliriz? Ya da konsol ekranında ekranın istediğimiz yerine bir yazıyı nasıl yazdırabiliriz? Bilindiği gibi C'de bunları yapabilecek standart fonksiyonlar yoktur. İşte C'de text ekranda imleçle ilgili işlemler ya da renkli yazım işlemleri temelde iki yolla yapılmaktadır: -> ANSI terminal komutları ile -> Özel kütüphane fonksiyonları ile Bu yöntemlerden, >> ANSI Terminal Komutları: stdout için aygıt sürücülerini yazanlar standart bazı özel karakter için bazı özel işlemleri yapacak biçimde aygıt sürücülerini yazmaktadır. Bu özel karakterler kullanılarak yazılmış olan komutlara ANSI terminal komutları denilmektedir. ANSI terminal komutları 0x1B karakteri ile başlatılır. ASCII tablosounda 0x1B karakterine "escape karakteri" denilmektedir. Dolayısıyla ANSI terminal komutlarına "ANSI escape komutları" da denilebilmektedir. Tüm ANSI terminal komutları bir escape karakteriyle başlatılır ve bu escape karakterini bazı başka karakterler izler. Örneğin imleci (cursor) belli bir yere taşımak için stdout dosyasına (aygıt sürücüye) gönderilecek escape komutu şöyledir: "\x1B[row;colH" Buradaki \x1B aslında tek bir karakterdir. Buna ASCII tablosunda "escape karakteri" denilmeketedir. Komuttaki row ve col birer sayı olmalıdır. row imlecin taşıanacağı satır numarasını col ise imlecin taşınacağı sütun numarasını belirtmektedir. Örneğin: "\x1B[12;18H" Bu komut imleci 12'inci satır 18'üncü sütuna taşır. Biz imleci taşıyan bir C fonksiyonunu da aşağıdaki gibi yazabiliriz: void move_cursor(int row, int col) { printf("\x1B[%d;%dH", row, col); } İmleci yok etmek şu ANSI terminal komutu kullanılmaktadır: "\x1B[?25l" İmleci yeniden görünür yapmak için ise şu komut kullanılmaktadır: "\x1B[?25h" Tabii bu işlemleri birer fonksiyon haline de getirebiliriz: void hide_cursor(void) { printf("\x1B[?25l"); } void show_cursor(void) { printf("\x1B[?25h"); } İmlecin konumunu aygıt sürücünün saklaması için şu escape komutu kullanılmaktadır: "\x1B\x37" İmlecin son saklanan pozisyona geri yerleştirilmesi için ise şu komut komut kullanılmaktadır: "\x1B\x38" Bu işlemleri fonksiyon olarak da yazabiliriz: void save_cursor(void) { printf("\x1B\x37"); } void restore_cursor(void) { printf("\x1B\x38"); } ANSI escape komutları için Internet'teki çeşitli kaynaklara başvurabilirsiniz. Text modda yazının karakterlerinin zemini ve şekli ayrı ayrı renklendirilebilmektedir. Renklendirme işlemi de ANSI escape kodlarıyla yapılabilmektedir. Örneğin yazıların kırmızı yazılması için (yani yalnızca yazıların şekil renklerini kırmızı yapmak için) şu komut kullanılır: "\x1b[31m" Her renk için buradaki sayı değişmektedir. Şöyle genel bir fonksiyon da yazılabilir: #define BLACK_COLOR 30 #define RED_COLOR 31 #define WHITE_COLOR 37 #define BLUE_COLOR 34 .... void change_color(int color) { printf("\x1b[%dm", color); } Renkelndirme için aşağıdaki dokümana başvurabilirsiniz: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 Aşağıda escape karakterle bazı işlemeler yapan bir program örneği verilmiştir. * Örnek 1, #include #include #include #define BLACK_COLOR 30 #define RED_COLOR 31 #define WHITE_COLOR 37 #define BLUE_COLOR 34 void move_cursor(int row, int col) { printf("\x1B[%d;%dH", row, col); } void hide_cursor(void) { printf("\x1B[?25l"); } void show_cursor(void) { printf("\x1B[?25h"); } void change_color(int color) { printf("\x1b[%dm", color); } int main(void) { time_t t, prev_t; struct tm *pt; int count; change_color(BLUE_COLOR); hide_cursor(); prev_t = 0; count = 0; for (;;) { t = time(NULL); pt = localtime(&t); move_cursor(1, 80); printf("%02d:%02d:%02d", pt->tm_hour, pt->tm_min, pt->tm_sec); if (prev_t != t) { ++count; if (count == 10) break; } prev_t = t; } show_cursor(); change_color(WHITE_COLOR); return 0; } Diğer yandan Windows'un Console API fonksiyonlarını kullanabilmek sırasıyla şu işlemlerin yapılması gerekmektedir: -> İlk olarak terminale ilişkin stdout dosyasının handle değerinin elde edilmesi gerekmektedir. Bu işlem GetStdHandle isimli API fonksiyonuyla yapılır. Fonksiyonun prototipi şöyledir: HANDLE WINAPI GetStdHandle( DWORD nStdHandle ); Fonksiyon parametre olarak handle değeri alınmak istenen standart dosyayı belirten özel değeri alır. Bu değer şunlardan biri olabilir: STD_INPUT_HANDLE STD_OUTPUT_HANDLE STD_ERROR_HANDLE -> WrtiteConsole API fonksiyonu bir adresten itibaren belli miktardaki karakteri imlecin bulunduğu yerden itibaren yazmaktadır. Bu bakımdan puts gibi bir işleve sahiptir. (Tabii imleci aşağı satırın başına geçirmez.) Fonksiyonun prototipi şöyledir: BOOL WINAPI WriteConsole( HANDLE hConsoleOutput, const VOID *lpBuffer, DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved ); Fonksiyonun birinci parametresi stdout dosyasının handle değerini almaktadır. Fonksiyon ikinci parametresiyle belirtilen adresten itibaren üçüncü parametresiyle belirtilen miktarda karakteri imlecin bulunduğu yere yazar. Başarılı bir biçimde yazabildiği karakter sayısını dördüncü parametresiyle girdiğimiz DWORD nesye yerleştirmektedir. Son parametre reserved durumdadır, NULL geçilmelidir. Fonksiyon başarı durumuna geri döner. Ancak genellikle başarınn kontrol edilmesine gerek yoktur. -> İmleci konumlandırmak için SetConsoleCursorPosition isimli API fonksiyonu kulanılmaktadır. Fonksiyonun prototipi şöyledir: BOOL WINAPI SetConsoleCursorPosition( HANDLE hConsoleOutput, COORD dwCursorPosition ); Fonksiyonun birinci parametresi stdout dosyasının handle değerini ikinci parametresi ise konumlandırma yapılacak koordinatı belirtmektedir. COORD yapısı şöyle bildirilmiştir: typedef struct _COORD { SHORT X; SHORT Y; } COORD, *PCOORD; Fonksiyon işlemin başarısı durumuyla geri dönmektedir. Örneğin: COORD coord; ... coord.X = 10; coord.Y = 20; SetConsoleCursorPosition(hConsole, coord); C99 ile birlikte dile eklenen "bileşik sabitler (compound literals)" ile aynı kod şöyle de yazılabilmektedir: SetConsoleCursorPosition(hConsole, (COORD){10, 12}); -> Yazının şekil ve zemin rengini değiştirmek için SetConsoleTextAttribute API fonksiyonu kullanılmaktadır. Fonksiyonun prototipi şöyledir: BOOL WINAPI SetConsoleTextAttribute( HANDLE hConsoleOutput, WORD wAttributes ); Fonsiyonun ikinci parametresi özellik bilgisini belirtmektedir. Özellik bir renk ya da diğer bazı bileşenlerdne oluşmaktadır. Aşağıdaki sembolik sabitler bit düzeyinde OR işlemiyle özellik oluşturmakta kullanılabilir: FOREGROUND_BLUE FOREGROUND_GREEN FOREGROUND_RED FOREGROUND_INTENSITY BACKGROUND_BLUE BACKGROUND_GREEN BACKGROUND_RED BACKGROUND_INTENSITY COMMON_LVB_REVERSE_VIDEO COMMON_LVB_UNDERSCORE Örneğin: SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE); WriteConsole(hConsole, buf, strlen(buf), &dwWritten, NULL); SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); -> İmleci yok etmek için SetConsoleCursorInfo isimli fonksiyon kullanılmaktadır. Fonksiyonun prototipi şöyledir: BOOL WINAPI SetConsoleCursorInfo( HANDLE hConsoleOutput, const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo ); Fonksiyonun ikinci parametresi CONSOLE_CURSOR_INFO isimli bir yapı nesnesinin adresini almaktadır. Bu yapı şöyle bildirilmiştir: typedef struct _CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; } CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO; Yapının dwSize elemanı 1 ile 100 arasında bir değer almaktadır. Bu değer imlecin büyüklüğünü belirtir. Yapının bVisible elemanı TRUE ya da FALSE girilebilir. Eğer bu elemana FALSE girilirse imleç görünmez olur. Aslında GetConsole.CursorInfo isimli bu bilgileri alan da bir fonksiyon vardır. Önce get fonksiyonu kullanılıp sonra set fonksiyonu kullanılırsa yapının diğer elemanı değiştirilmeden işlem yapılabilir. Örneğin: CONSOLE_CURSOR_INFO cci; ... GetConsoleCursorInfo(hConsole, &cci); cci.bVisible = FALSE; SetConsoleCursorInfo(hConsole, &cci); -> Konsole penceresinin karakter genişliğini ve yüksekliğini almak için GetConsoleScreenBufferInfo API fonksiyonu kullakılmaktadır. Fonksiyonun prototipi şöyledir: BOOL WINAPI GetConsoleScreenBufferInfo( HANDLEhConsoleOutput, PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo ); Fonksiyonun ikinci parametresi CONSOLE_SCREEN_BUFFER_INFO isimli bir yapı nesnesinin adresini almaktadır. Bu yapı şöyle bildirilmiştir: typedef struct _CONSOLE_SCREEN_BUFFER_INFO { COORD dwSize; COORD dwCursorPosition; WORD wAttributes; SMALL_RECT srWindow; COORD dwMaximumWindowSize; } CONSOLE_SCREEN_BUFFER_INFO; Bu fonksiyonla imlecin konumuda alınabilmektedir. Konsole ekranın genişlike ve yüksekliği şöyle edilir: CONSOLE_SCREEN_BUFFER_INFO csbi; ... GetConsoleScreenBufferInfo(hConsole, &csbi); width = csbi.srWindow.Right - csbi.srWindow.Left + 1; height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; Aşağıda konsol API fonksiyonlarının kullanımına genel bir verilmiştir. * Örnek 1, #include #include #include #include void ExitSys(LPCSTR lpszMsg); int main(void) { HANDLE hConsole; char buf[1024] = "this is a test"; DWORD dwWritten; CONSOLE_CURSOR_INFO cci; CONSOLE_SCREEN_BUFFER_INFO csbi; int width, height; int len; if ((hConsole = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) ExitSys("GetStdHandle"); GetConsoleCursorInfo(hConsole, &cci); cci.bVisible = FALSE; SetConsoleCursorInfo(hConsole, &cci); SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE); SetConsoleCursorPosition(hConsole, (COORD){ 10, 12 }); WriteConsole(hConsole, buf, strlen(buf), &dwWritten, NULL); GetConsoleScreenBufferInfo(hConsole, &csbi); width = csbi.srWindow.Right - csbi.srWindow.Left + 1; height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; SetConsoleCursorPosition(hConsole, (COORD){ 10, 13 }); len = snprintf(buf, 1024, "Width: %d, Height: %d\n", width, height); WriteConsole(hConsole, buf, len, &dwWritten, NULL); SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); getchar(); return 0; } void ExitSys(LPCSTR lpszMsg) { DWORD dwLastErr = GetLastError(); LPTSTR lpszErr; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpszErr, 0, NULL)) { fprintf(stderr, "%s: %s", lpszMsg, lpszErr); LocalFree(lpszErr); } exit(EXIT_FAILURE); } >> Özel Kütüphane Fonksiyonlarıyla: Text ekranda ayrıntılı işlemler yapmak için özel kütüphaneler de kullanılmaktadır. Örneğin UNIX/Linux dünyasında "curses" ya da bunun daha yeni versiyonu olan "ncurses" kütüphaneleri bu amaçla çokça kullanılmaktadır. Windows dğnyasında zaten text ekranda işlemler yapmak için ismine "Console API Fonksiyonları" denilen bir grup API fonksiyonu bulundurulmuştur. Yukarıda da belirttiğimiz gibi eskiden grafik çalışma yoktu. Yalnızca text modda konsol tabanlı bir çalışma modeli vardı. Text modda karakterlerin kalıp olarak basıldığını pixel temelinde bir kontrolün sağlanamadığını belirtmiştik. Bu nedenle text modda yani konsol ekranında pixel işlemleri gereken "resim gösterme" gibi işlemler yapılamamaktadır. Ancak yine text modda özel karakterlerle çerçeve çizimleri yapılabilmektedir. Bunun için çeşitli karakter kümelerinde ve code page'lerde özel "çerçeve karakterleri (bozing character)" bulundurulmuştur. Bugün bilgisyaralarımızda pek çok karakter kümesi ve code page kullanılabilmektedir. Ancak UNICODE karakter kümesi ve bunun UTF-8 denilen encoding'i en yaygın kullanıma sahip olanlardan biridir. Çerçeve karakterleri biribirini kapatan özel karakterlerdir. Örneğin UNICODE tabloda tipik çerçeve karakterlerinin code point'leri şunlardır: #define BOX_LL "\u2514" #define BOX_V "\u2502" #define BOX_H "\u2500" #define BOX_UL "\u250C" #define BOX_UR "\u2510" #define BOX_LR "\u2518" Bu UNICODE karakterlerin aynılarının çift çizgili biçimleri de vardır. Ayrıca çerçeve ortası için çerçeveye bağlanma için ayrı karakterler de bulunmaktadır. Yukarıdaki sembolik sabitlerde \uxxxx biçimindeki karakterler UNICODE UTF-16 code point'lerini bellirtmektedir. Ancak bu code point'ler derleyicilerin "execution character set" denilen ayarlarına bakılarak derleyiciler tarafından dönüştürülmektedir. Bugün pek çok standart C derleyicisinin default "execution character set" ayarı UNICODE UTF-8 biçimindedir. Eğer terminal de bu encoding'e ayarlanmışsa sorun çıkmayacaktır. Burada kullandığımız kavramlar kursumuzun "karakter kodlamalarının (character encoding)" anlatıldığı bölümde ayrıntılı biçimde ele alınacaktır. >> Visual Studio'da derleyicinin "execution character set"i eğer UTF-8 değilse onu proje seçeneklerinden C/C++ komut satırı "Ek Seçenekler"de "/utf-8" girerek UTF-8 olarak dğeiştirebilirsiniz. Eğer console ekranınızın code page'i UTf-8 değilse aşağıdaki registry ayarından onu "65001" yaparak UTF-9'e geçirebilirsiniz: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage\OEMCP Ayrıca default olarak bir konsol penceresinin UTF-8 encoding'i ile açılmasını sağlamak için aşağıdaki anahtara "@chcp 65001>nul" girmelisiniz: HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\Autorun Aşağıda bir çerçeve çizimine örnek verilmiştir: * Örnek 1, #include #include #include #define BOX_LL "\u2514" #define BOX_V "\u2502" #define BOX_H "\u2500" #define BOX_UL "\u250C" #define BOX_UR "\u2510" #define BOX_LR "\u2518" void save_cursor(void) { printf("\x1B\x37"); } void restore_cursor(void) { printf("\x1B\x38"); } void move_cursor(int row, int col) { printf("\x1B[%d;%dH", row, col); } void hide_cursor(void) { printf("\x1B[?25l"); } void show_cursor(void) { printf("\x1B[?25h"); } int main(int argc, char *argv[]) { save_cursor(); hide_cursor(); move_cursor(10, 10); printf(BOX_LL); move_cursor(9, 10); printf(BOX_V); move_cursor(10, 11); printf(BOX_H); move_cursor(10, 12); printf(BOX_H); move_cursor(8, 10); printf(BOX_UL); move_cursor(8, 11); printf(BOX_H); move_cursor(8, 12); printf(BOX_H); move_cursor(8, 13); printf(BOX_UR); move_cursor(9, 13); printf(BOX_V); move_cursor(10, 13); printf(BOX_LR); restore_cursor(); show_cursor(); return 0; }