8. Standart kütüphane turu
Modüller modul.fonksiyon() biçiminde çağrılır. Çoğu için kullan
yazmanız gerekmez; yazmak okunurluğu artırır ve hangi yeteneği kullandığınızı
belgeler.
kullan kaba.sistem # sistem, zaman, dosya, matematik... birlikte gelir
kullan kaba.web # HTTP sunucusu (yalnız gerektiğinde)
kullan kaba.arayuz # pencereli uygulamalar
yazdir("modüller hazır")| Modül | Ne için | Durum |
|---|---|---|
sistem |
makine adı, çekirdek, CPU, komut çalıştırma | çalışıyor |
dosya |
okuma/yazma/listeleme/kopyalama | çalışıyor |
zaman |
saat, tarih, biçimlendirme, süre ölçümü | çalışıyor |
matematik |
karekök, üs, yuvarlama, trigonometri | çalışıyor |
konsol |
girdi okuma, etkileşim algılama | çalışıyor (belki/sonuc döner) |
gunluk |
sistem günlüğüne düzeyli kayıt | çalışıyor |
cevre |
ortam değişkenleri | çalışıyor |
rastgele |
rastgele sayı/seçim/UUID | çalışıyor |
json |
JSON üretme/çözme/doğrulama | çalışıyor |
kripto |
sha256/sha512/md5/hmac/base64 | çalışıyor |
web |
HTTP sunucusu (12. sayfa) | çalışıyor, ek kütüphane gerektirmez |
servis |
daemon yaşam döngüsü (11. sayfa) | çalışıyor |
arayuz |
pencereli uygulama (10. sayfa) | çalışıyor |
ag |
HTTP istemcisi, indirme | yalnız istemci; hata bildirimi sessiz |
paket |
KabaOS paket işlemleri | KabaOS'a özgü |
veritabani |
SQLite sorgusu + parametre bağlama (libsqlite3) | çalışıyor; SurrealDB tarafı deneysel |
ses · ai |
bip/çalma, model sorgusu | kısmi/deneysel |
⚠️ "Sessiz hata bildirimi" ne demek: bu modüllerin bir kısmı başarısızlığı
sonuc ile bildirmez, boş değer döndürür. Dönüşü elle denetleyin.
sistem
kullan kaba.sistem
yazdir("makine : " + sistem.makine_adi())
yazdir("çekirdek: " + sistem.cekirdek())
yazdir("işlemci : " + sistem.cpu_model())
yazdir("kullanıcı: " + sistem.kullanici())
# Komut çalıştırıp ÇIKTISINI almak:
cikti = sistem.komut("echo merhaba").kirp()
dogrula(cikti == "merhaba", "sistem.komut çıktıyı verir")
# Yalnız çıkış kodu gerekiyorsa:
dogrula(sistem.calistir("true") == 0, "sistem.calistir çıkış kodu verir")
# ⚠️ DIŞARIDAN GELEN VERİ VARSA KABUKSUZ ÇAĞIR.
# `sistem.komut("rm " + girdi)` bir KABUK satırı kurar: girdi ";" içeriyorsa
# ikinci bir komut çalışır. Argümanları ayrı ayrı vermek bunu imkânsız kılar.
# ⚠️ YENİ AD: `cikti` yukarıda kullanıldı. Çoklu atama yeni adlar
# bildirir; var olan bir adı YENİDEN BİLDİREMEZ.
argv_cikti, argv_kod = sistem.komut_argv(["echo", "; bu komut DEĞİL argüman"])
dogrula(argv_kod == 0, "komut_argv çıkış kodunu da verir")
dogrula(argv_cikti == "; bu komut DEĞİL argüman", "argüman kabuktan geçmez")
# Çıktı gerekmiyorsa:
dogrula(sistem.calistir_argv(["true"]) == 0, "calistir_argv")
# ⚠️ Çıkış kodu anlamları: 0.. programın kendi kodu · -1 sinyal ·
# -2 program BULUNAMADI · -3 zaman aşımı. "Boş çıktı" ile "komut yok"
# ayrı şeylerdir; `komut()` bu ayrımı veremez.
_, yokkod = sistem.komut_argv(["bulunmayan_ikili_xyz"])
dogrula(yokkod == -2, "bulunamayan program -2 döner")
# Programın kendi argümanları (ilki programın yoludur):
a = sistem.argumanlar()
dogrula(a.uzunluk() >= 1, "argümanlar")
yazdir("sistem tamam")dosya
kullan kaba.sistem
dosya.klasor_olustur("deneme")
dosya.yaz("deneme/not.txt", "birinci satır\n")
dosya.ekle("deneme/not.txt", "ikinci satır\n")
dogrula(dosya.var_mi("deneme/not.txt"), "var_mi")
dogrula(dosya.dosya_mi("deneme/not.txt"), "dosya_mi")
dogrula(dosya.dizin_mi("deneme"), "dizin_mi")
dogrula(dosya.oku("deneme/not.txt").icerir("ikinci"), "oku")
dogrula(dosya.listele("deneme").uzunluk() == 1, "listele")
dogrula(dosya.boyut("deneme/not.txt") > 0, "boyut")
dosya.kopyala("deneme/not.txt", "deneme/kopya.txt")
dogrula(dosya.var_mi("deneme/kopya.txt"), "kopyala")
dosya.sil("deneme/not.txt")
dosya.sil("deneme/kopya.txt")
dosya.klasor_sil("deneme")
dogrula(degil dosya.var_mi("deneme"), "klasor_sil")
yazdir("dosya tamam")zaman
kullan kaba.sistem
yazdir("saat : " + zaman.saat()) # 14:05:09
yazdir("tarih: " + zaman.tarih()) # 2026-09-18
yazdir("tam : " + zaman.simdi()) # 2026-09-18 14:05:09
yazdir("yıl : " + zaman.bicimlendir("%Y"))
dogrula(zaman.milisaniye() > 0, "milisaniye — dönemden beri")
dogrula(zaman.saniye() > 0, "saniye")
yazdir("zaman tamam")matematik
kullan kaba.sistem
dogrula(matematik.karekok(9.0) == 3.0, "karekok")
dogrula(matematik.mutlak(-3) == 3, "mutlak")
dogrula(matematik.taban(3.7) == 3.0, "taban")
dogrula(matematik.tavan(3.2) == 4.0, "tavan")
dogrula(matematik.yuvarla(3.5) == 4.0, "yuvarla")
dogrula(sayi(matematik.tavan(3.2)) == 4, "tam sayıya çevirme")
dogrula(matematik.us(2.0, 10.0) == 1024.0, "us")
dogrula(matematik.pi > 3.14 ve matematik.pi < 3.15, "pi sabiti")
yazdir("matematik tamam")taban, tavan ve yuvarla sonucu ondalik verir (matematik.taban(3.7)
→ 3.0; iki arka uçta aynı). Tam sayı gerekiyorsa sayi(...) ile çevirin.
rastgele
kullan kaba.sistem
z = rastgele.sayi(1, 6)
dogrula(z >= 1 ve z <= 6, "aralıkta rastgele sayı")
yazdir(f"zar: {z}")
yazdir("uuid: " + rastgele.uuid())cevre — ortam değişkenleri
kullan kaba.sistem
kip = cevre.al("KABA_KIP")
eger kip == "": # tanımsızsa boş metin döner
kip = "gelistirme"
yazdir(f"çalışma kipi: {kip}")⚠️ Tanımsız değişken boş metin verir, hata vermez. "Tanımlı mı" ayrımı
gerekiyorsa cevre.var_mi("AD") kullanın.
json
kullan kaba.sistem
metni = json.uret({"ad": "Deniz", "yas": 30})
yazdir(metni)
dogrula(json.gecerli_mi(metni), "gecerli_mi")
dogrula(json.al(metni, "ad") == "Deniz", "al — tek anahtar oku")
s = json.coz(metni)
dogrula(s["yas"] == 30, "coz — sözlüğe çevir")
yazdir(json.bicimlendir(metni)) # girintili
dogrula(degil json.gecerli_mi("{bozuk"), "bozuk JSON yakalanır")
yazdir("json tamam")kripto
kullan kaba.sistem
ozet = kripto.sha256("merhaba")
dogrula(ozet.uzunluk() == 64, "sha256 onaltılık 64 karakter")
yazdir("sha256: " + ozet)
k = kripto.base64_kodla("merhaba")
dogrula(kripto.base64_coz(k) == "merhaba", "base64 gidiş-dönüş")
yazdir("kripto tamam")gunluk — sistem günlüğü
yazdir kullanıcıya konuşur, gunluk işletim sistemine. Servisler için
doğru olan budur: çıktı systemd günlüğüne düzeyiyle birlikte düşer.
kullan kaba.sistem
gunluk.bilgi("işlem başladı")
gunluk.uyari("disk %85 dolu")
gunluk.hata("bağlantı kurulamadı")
yazdir("günlük tamam")| Çağrı | Düzey |
|---|---|
gunluk.ayikla(m) |
hata ayıklama |
gunluk.bilgi(m) |
bilgi |
gunluk.dikkat(m) |
dikkat |
gunluk.uyari(m) |
uyarı |
gunluk.hata(m) |
hata |
gunluk.kritik(m) |
kritik |
desen — düzenli ifade (regex)
kullan kaba.desen
# Var mı? (metnin HERHANGİ BİR yerinde arar — baştan sona değil)
dogrula(desen.esler_mi("^ka.a", "kabalang"), "esler_mi")
dogrula(desen.esler_mi("^zz", "kabalang") == yanlis, "eşleşmeyince yanlış")
# İlk eşleşme
dogrula(desen.bul("[0-9]+", "sürüm 42 ve 7") == "42", "bul")
# Hepsi
dogrula(desen.tum_bul("[0-9]+", "1 ve 22 ve 333").uzunluk() == 3, "tum_bul")
# Yakalama grupları (grup 0 = tüm eşleşme LİSTEYE KONMAZ, onu bul() verir)
g = desen.gruplar("([a-z]+)@([a-z.]+)", "posta: ali@kaba.os")
dogrula(g[0] == "ali", "grup 1")
dogrula(g[1] == "kaba.os", "grup 2")
# Değiştirme — $1, $2 geri başvurudur
dogrula(desen.degistir("\\s+", "a b c", "-") == "a-b-c", "degistir")
dogrula(desen.degistir_ilk("a", "aaa", "X") == "Xaa", "yalnız ilki")
# Bölme — baştaki VE sondaki boş parça KORUNUR (Python re.split gibi)
dogrula(desen.bol(",\\s*", "a, b,c").uzunluk() == 3, "bol")
uclu = desen.bol(",", ",a,")
dogrula(uclu.uzunluk() == 3, "başta ve sonda boş parça korunur")
dogrula(uclu[0] == "" ve uclu[2] == "", "iki uçtaki boşluk atılmaz")
yazdir("desen tamam")⚠️ Ters eğik çizgi İKİLENİR. Metin sabitinde "\\s+" yazılır; "\s+"
yazan kişi s+ deseni elde eder ve desen sessizce yanlış çalışır. En sık
düşülen tuzak budur.
⚠️ [a-z] Türkçe harfleri İÇERMEZ. ç ğ ı ö ş ü o aralığın dışındadır;
"küçük harf" demek isteyen [a-zçğıöşü] yazmalıdır. Aynısı [A-Z] için de
geçerlidir. Buna karşılık . bir KOD NOKTASI eşler, bayt değil:
kullan kaba.desen
# Tek bir `.` bütün bir Türkçe harfi alır — yarım karakter ÇIKMAZ.
dogrula(desen.bul("^.", "şeker") == "ş", "nokta kod noktası eşler")
dogrula(desen.bul("^..", "şeker") == "şe", "iki nokta iki harf")
yazdir("türkçe tamam")⚠️ Kullanıcı verisini desene gömüyorsan kacir() kullan. Ham veri
desene girerse en hafifi yanlış sonuç, en ağırı (a+)+$ gibi bir desenle
üstel geri izlemedir (ReDoS).
kullan kaba.desen
aranan = "a.c" # kullanıcıdan geldi varsayalım
dogrula(desen.esler_mi(desen.kacir(aranan), "abc") == yanlis, "nokta artık joker değil")
dogrula(desen.esler_mi(desen.kacir(aranan), "a.c"), "gerçek metin eşleşir")
yazdir("kaçırma tamam")ag — HTTP istemcisi
Ağ örneği bu belgede derlenir ama çalıştırılmaz (test makinesi internete çıkmak zorunda olmasın diye):
kullan kaba.ag
eger ag.baglanti_var_mi():
icerik = ag.get("https://example.com")
yazdir("gelen bayt: " + metin(icerik.uzunluk()))
degilse:
yazdir("bağlantı yok")Ulaşılamayan adres ya da HTTP hatası hata fırlatır (içerik gibi bir
metin dönmez); dene/yakala ile yakalayın. Ağa gerçekten gidip gelen
sınama, internete çıkmadan yerel bir sunucuyla cekirdek/test_ag_ai.py
içinde koşar.
⚠️ kaba.ag bugün yalnız istemcidir. Sunucu yazmak için kaba.web
kullanın (12. sayfa).
arsiv — tar · gzip · zstd
.kaba paketleri gzip'li tar'dır; üst-akım paketleri zstd. İkisi de aynı
çağrılardan geçer — biçim içerikten algılanır, uzantıdan değil.
kullan kaba.arsiv
fonksiyon ana():
# Oluşturma — biçim: "gzip" · "zstd" · "yok"
dosyalar = ["KABAINFO", "usr/bin/program"]
arsiv.olustur("paket.kaba", dosyalar, "gzip")
# Üyeleri listele
yazdir(metin(arsiv.listele("paket.kaba")))
# Tek üyeyi OKU (metin üyeler için: KABAINFO, .PKGINFO …)
bilgi = arsiv.uye_oku("paket.kaba", "KABAINFO")
yazdir(bilgi)
# "boş üye" ile "üye yok" ayrımı
eger arsiv.uye_var_mi("paket.kaba", "KABAINFO"):
yazdir("üstveri var")
# Diske aç
arsiv.ac("paket.kaba", "/tmp/hedef")
ana()⚠️ ac() yol geçişine karşı kapalıdır. İçinde ../../etc/passwd taşıyan
bir arşiv hedef dizinin dışına yazamaz; böyle bir arşiv reddedilir
(yanlis döner). Paket açan bir araçta bu koruma olmadan zararlı bir paket
doğrudan kök ele geçirir.
⚠️ uye_oku METİN döner. İkili üye içeriği için ac() kullanılır — dosya
diske açılır. Dilde bayt türü yoktur; müşterisi yokken icat etmemek için.
⚠️ olustur DOSYA LİSTESİ alır, dizin değil. Dizin yürümek ayrı bir
karardır (gizli dosyalar? bağlar? dışlamalar?) ve dosya.listele zaten var.
⚠️ libarchive yalnız bu modülü kullanan programa bağlanır. kullan
kaba.arsiv yazmayan bir ikili ona hiç bağlanmaz (ölçülüyor).
toml — yapılandırma dosyası okuma
TOML, KabaOS'un yapılandırma yazımıdır: tasarım jetonları, paket üstverisi.
kaba.toml onun belgelenmiş bir alt kümesini okur.
kullan kaba.toml
kullan kaba.dosya
fonksiyon ana():
k = dosya.oku("kabaos-tasarim.toml")
# Değer — yol NOKTALIDIR, `json.al` ile aynı düşünce
yazdir(toml.al(k, "renk.vurgu.deger"))
# "boş değer" ile "anahtar yok" AYRI ŞEYLER
eger toml.var_mi(k, "renk.marka.deger"):
yazdir("marka rengi tanımlı")
# Dizi
dongu b icinde toml.liste(k, "yukseklik.boylar"):
yazdir(b)
# Bir tablonun doğrudan alt anahtarları
dongu ad icinde toml.anahtarlar(k, "renk"):
yazdir(ad + " = " + toml.al(k, "renk." + ad + ".deger"))
ana()⚠️ Tırnak içindeki # yorum değildir. renk = "#FF7A3D" satırını
renk = " yapan bir ayrıştırıcı, hex renklerle dolu bir tasarım dosyasında
her değeri bozar. Burada yorum ayıklama tırnağı bilir.
⚠️ Tırnaklı tablo başlığının tırnağı adın parçası değildir.
[sema.plasma."Colors:Button"] başlığının yolu sema.plasma.Colors:Button
olur. Tırnağı saklayan bir uygulamada o anahtar hiçbir zaman bulunamaz —
hata da vermez, sadece yok görünür.
⚠️ Aynı adlı tablo dizisi ([[ad]]) ezilmez. Düz bir ad→değer
haritasında ikinci [[ayrisma]] birinciyi silerdi. Yola sıra numarası
eklenir: ayrisma.0.ad, ayrisma.1.ad … Tek [tablo] numara almaz.
⚠️ Desteklenmeyen sözdizimi SESSİZCE ATLANMAZ, satır numarasıyla hata
verir ve dene/yakala ile yakalanabilir. Alt kümenin dışında kalanlar:
satır içi tablo ({ }), üç tırnaklı ham metin ('''), tarih/saat türleri.
Atlayan bir ayrıştırıcı, eksik jetonlu bir temayı "başarıyla derlendi" diye
geçirirdi.
kullan kaba.toml
fonksiyon ana():
dene:
toml.al("a = { x = 1 }", "a")
yakala h:
yazdir(metin(h)) # toml: satır 1: satır içi tablo ...
ana()⚠️ Değerler metin döner, sayıya çevrilmez. 0.90 kaynakta nasılsa öyle
gelir; sayi() ile çevirirsiniz. Ayrıştırıcının kendi başına float'a çevirip
geri basması, jeton üreten bir araçta 0.90ı 0.9 yapardı.
dbus — masaüstü ve sistem servisleriyle konuşma
KabaOS'un parçaları birbirine D-Bus'la konuşur: KWin, Plasma, systemd.
kaba.dbus bunu dış süreç çağırmadan yapar.
kullan kaba.dbus
fonksiyon ana():
# Argümansız çağrı
dbus.cagir("org.kde.KWin", "/KWin", "org.kde.KWin", "reconfigure")
# Argümanlı çağrı — imza AÇIKÇA verilir ("u" = uint32)
dbus.cagir("org.kde.KWin", "/KWin", "org.kde.KWin",
"setCurrentDesktop", "u", ["2"])
# Dizi dönen çağrı
dongu ad icinde dbus.cagir_liste("org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"ListNames", "", []):
yazdir(ad)
# Servis otobüste var mı?
eger dbus.hizmet_var_mi("org.kde.KWin"):
yazdir("KWin çalışıyor")
# Özellik oku / yaz
yazdir(dbus.ozellik_al("org.kde.KWin", "/KWin", "org.kde.KWin", "id"))
ana()⚠️ İmza tahmin edilmez, sizden istenir. D-Bus güçlü tiplidir:
setCurrentDesktop u (uint32) bekler, i göndermek hata verir. qdbus
bunu her çağrıda introspection ile tahmin eder; biz etmiyoruz — tahmin
yanlış tipi sessizce seçebilir ve her çağrıya bir gidiş-dönüş + XML
ayrıştırma ekler. Harfler: y n q i u x t d b s o g.
⚠️ Sayıya çevrilemeyen argüman sessizce 0 olmaz. "iki" yazarsanız
hata alırsınız. atoi sessizce 0 döndürseydi çağrı masaüstü 0'a giderdi ve
kimse fark etmezdi.
⚠️ Hata sessiz değildir. D-Bus hatası fırlar ve dene/yakala ile
yakalanır; iletide hatanın D-Bus adı geçer. Yerine geçtiği kabuk deseni
(qdbus6 … 2>/dev/null) tam tersini yapıyordu: hata kaybolur, betik
başarılı sanılırdı.
⚠️ Sinyal aboneliği YOKTUR. Ölçüm: KabaOS'ta yöntem çağrısı 49,
Properties.Set 7, Properties.Get 1, sinyal aboneliği 0. Sinyal bir
olay döngüsü ister ve dilin eşzamanlılık sözlüğü birlikte/kanaltır.
⚠️ Oturum otobüsü varsayılan, sistem otobüsü için dbus.sistem_cagir.
⚠️ libsystemd yalnız bu modülü kullanan programa bağlanır (ölçülüyor —
ldd ile değil objdump -p DT_NEEDED ile: Qt6Core libsystemd'yi zaten
dolaylı çekiyor).
sinama — sınama iddiaları
kullan kaba.sinama
fonksiyon ana():
sinama.esit(2 + 2, 4, "toplama")
sinama.esit_degil("a", "b", "farklı")
sinama.dogru(1 < 2, "küçüktür")
sinama.yanlis(1 > 2, "büyük değil")
sinama.yaklasik(0.1 + 0.2, 0.3, 0.000001, "ondalık")
sinama.icerir("merhaba dünya", "dünya", "içerme")
sinama.ozet()
ana()⚠️ Kusurlar birikir, ilk kusurda durmaz. Eski dogrula başarısızlıkta
exit(1) çağırıyordu: 50 iddialı bir dosyada 1. iddia düşerse 2–50 arası
hiç koşmuyor, kaç şeyin bozuk olduğunu öğrenmek için 50 kez
derle-çalıştır turu gerekiyordu.
⚠️ Beklenen ve bulunan yazılır. dogrula(a == b, "esit") düştüğünde
ekranda yalnız "esit" vardı; a ile b görünmüyordu.
⚠️ Sessizce geçmek imkânsızdır — iki kapı birden. ozet() çağrılmadan
biten kusurlu bir koşu yine de 1 ile çıkar; ve hiç iddia koşmayan bir
dosya da kusurludur. kullan kaba.sinama yazıp hiçbir şey sınamamak,
koşucuya yalan söylemektir.
⚠️ Ondalık sayıda esit değil yaklasik. 0.1 + 0.2 == 0.3 yanlıştır.
Tolerans zorunludur: varsayılan bir tolerans vermek, hassasiyeti hiç
düşünmemeye yol açardı.
⚠️ dogrula kaldırılmadı. 230 kullanımı var ve "ilk kusurda dur"
davranışı bazı yerlerde bilinçli. sinama.* onun yanına gelir.
belge — docx · xlsx · pdf üretimi
Rapor, teklif, sertifika. Office eklentisi değil, belge ÜRETİCİSİ: program belgeyi kendi yazar, Word/Excel/LibreOffice okur.
kullan kaba.belge
fonksiyon ana():
b = belge.yeni("Bilirkişi Raporu") # yalnız ÜSTVERİ (dc:title)
belge.altbilgi(b, "ForensicAI · GİZLİ") # + "Sayfa X / Y" kendiliğinden
belge.baslik(b, "ADLİ BİLİMLER RAPORU", 1)
belge.paragraf(b, "Dava No: 2026/1487")
belge.vurgu(b, "GİZLİ — yalnızca yetkili kişiler")
belge.baslik(b, "DELİL LİSTESİ", 2)
belge.tablo_basligi(b, ["No", "Tür", "Açıklama"])
belge.tablo_satiri(b, ["D-1", "Biyolojik", "Kan lekesi"])
belge.tablo_satiri(b, ["D-2", "Dijital", "Disk imajı"])
belge.sayfa_sonu(b)
belge.baslik(b, "İMZA VE ONAY", 2)
belge.paragraf(b, "Hazırlayan: ForensicAI")
belge.docx_yaz(b, "rapor.docx") # Word belgesi
belge.xlsx_yaz(b, "rapor.xlsx") # tablolar → çalışma sayfaları
belge.kapat(b)
ana()pdf_yaz — aynı belge, kendi dizgisiyle
Aynı belgeden PDF de çıkar. Ek bir çağrı yeter:
kullan kaba.belge
fonksiyon ana():
b = belge.yeni("Bilirkişi Raporu")
belge.altbilgi(b, "ForensicAI · GİZLİ")
belge.baslik(b, "DELİL LİSTESİ", 2)
belge.tablo_basligi(b, ["No", "Tür", "Açıklama"])
belge.tablo_satiri(b, ["D-1", "Biyolojik", "Kan lekesi"])
belge.paragraf(b, "DELİL LİSTESİ ğüşıöçĞÜŞİÖÇ")
eger belge.pdf_yaz(b, "rapor.pdf"):
yazdir("PDF yazıldı")
degilse:
yazdir("PDF yazılamadı: yazı tipi yok ya da gömülemeyen karakter")
belge.kapat(b)
ana()PDF çıktısı hakkında bilmeniz gerekenler:
| Konu | Davranış |
|---|---|
| Bağımlılık | PDF üretmek ek kütüphane gerektirmez; PDF üreten programın bağımlılıkları, yalnız docx üretenle aynıdır (ölçüldü). |
| Türkçe karakterler | PDF'in standart yazı tipleri Türkçe taşımaz (DELİL LİSTESİ → DEL?L L?STES?). Bu yüzden yazı tipi belgeye gömülür; metin pdftotext gibi araçlarla birebir geri okunur (ölçüldü). |
| Dizgi | Satır sarma · sayfa sonu · sayfa numarası · sütun genişliği · tablo başlığının her sayfada tekrarı kendiliğinden yapılır. |
⚠️ Yazı tipi DejaVu Sans, ve seçim ölçüldü. Türkçe harflerin tamamını
ve ₺yi taşıyor, statik glyf tabanlı (değişken yazı tipinin alt
kümesi için örnekleme gerekirdi), fsType = 0 yani gömme kısıtsız, lisansı
gömmeye açık. Adaylardan Liberation Sans ve Carlito'da ₺ yok; Noto Sans ve
Carlito ISO paket listesinde yok; Adwaita Sans değişken yazı tipi.
Paketi (ttf-dejavu) KABASPEC'in depends= satırında yazılıdır —
"zaten kurulu" bir varsayımdır, bağımlılık bir sözleşmedir.
⚠️ Yalnız kullanılan glifler gömülür. Ölçüldü: örnek raporda iki yazı tipi toplam ~21 KB; tam gömme 1,4 MB olurdu. Belgede hiç kalın metin yoksa ikinci yazı tipi hiç gömülmez.
⚠️ pdf_yaz gömülemeyen bir karakter görürse yanlis döner ve dosya
YAZMAZ. Ölçülen örnek: ₼ (U+20BC) DejaVu'da yok. Sessizce atlamak
"1.500 ₼" tutarını "1.500 " yapardı; bilirkişi raporunda bu, yanlış
çıktıdır. Aynı şey yazı tipi paketi kurulu değilse de olur — yarım dosya
kalmaz, çünkü dosya ancak baytlar hazır olduktan sonra açılır.
⚠️ Sayfa düzeni docx ile AYNI sayılardır: A4, 2 cm kenar, gövde 11 pt, başlık 16/14/12 pt. İki çıktının aynı kaynaktan farklı sayfalanması bir kusur olurdu. Fark şurada: docx'te sayfa numarası bir alan kodudur (okuyucu hesaplar), PDF'te biz hesaplayıp basarız.
⚠️ Satırlar sola dayalıdır; iki yana yayma ve heceleme yok
(müşterisi ölçülmedi). Akış sıkıştırma da yok: zlib yeni bir sözleşme
olurdu ve ölçülen kazanç bunu karşılamıyor — yukarıdaki örnek rapor
27 KB, 21,5 KB'ı gömülü yazı tipi alt kümeleri.
⚠️ Tablo DÜZ LİSTE alır, iç içe liste değil. tablo_basligi tabloyu
açar ve sütun sayısını belirler; tablo_satiri ona satır ekler.
Tablo dışı ilk öğe tabloyu örtük olarak kapatır. (Bu API iç içe liste
dilde yokken tasarlandı; iç içe liste artık destekleniyor — bkz.
4. sayfa — ama tablo API'si satır satır kalır.)
⚠️ Başlıksız satır belgeye GİRMEZ (yanlis döner): sütun sayısı
bilinmeden yazılan satır tabloyu sessizce bozardı. Eksik hücreli satır ise
doldurulur, fazlası kırpılır.
⚠️ Tablosuz belgede xlsx_yaz yanlis döner ve dosya yazmaz. Sıfır
sayfalı bir çalışma kitabı Excel'in açamadığı bir dosyadır; çağıran
"yazdım" sanırdı.
⚠️ xlsx sayfa adı tablodan önceki BAŞLIKTAN gelir, 31 karakterde
kırpılır (bayttan değil — 31. bayttan kesmek Öyü ikiye böler ve dosya
hiç açılmaz) ve çakışırsa numaralanır.
⚠️ Sayı tanıma DAR tutuldu. 12.5 sayı, 007 metin kalır:
baştaki sıfırı yutan bir dışa aktarma fatura numarasını bozar.
1.234,56 da metindir — ondalık ayracını tahmin etmek tutarı 1000 katına
çıkarabilir.
⚠️ Aynı girdi → aynı bayt. Paketin zaman damgası sabittir; aynı delilden üretilen rapor, üretim saatine göre farklı özet vermez (imzalanan rapor için şart).
⚠️ libarchive yalnız bu modülü (ya da kaba.arsivi) kullanan programa
bağlanır — docx/xlsx birer ZIP'tir ve ZIP tabanı kaba.arsivindir;
ikinci bir ZIP yazıcısı yazılmadı.
UYGULANMADI: görsel gömme (üç tüketicide de sıfır kullanım) · satır içi renk · üstbilgi · içindekiler · dipnot · hücre birleştirme · xlsx formülü · PDF'te eğik yazı, iki yana yayma ve akış sıkıştırma.
veritabani — SQLite
Sorgu libsqlite3'e gider; kabuk yoktur, sqlite3 ikilisi çağrılmaz.
Dönüş biçimi: sütunlar |, satırlar satır sonu ile ayrılır, NULL boş
dizedir, sonu kırpılmıştır.
kullan kaba.veritabani
db = "ornek.db"
dosya.sil(db)
# Şema ve veri — çoklu deyim tek çağrıda verilebilir
veritabani.sqlite(db, "CREATE TABLE kisi(id INTEGER, ad TEXT);")
veritabani.sqlite(db, "INSERT INTO kisi VALUES (1,'Ayşe'),(2,'Ali'),(3,'O''Brien');")
hepsi = veritabani.sqlite(db, "SELECT id, ad FROM kisi ORDER BY id")
yazdir(hepsi)
dogrula(hepsi == "1|Ayşe\n2|Ali\n3|O'Brien", "sütun | ile, satır \\n ile")
# ⚠️ KULLANICI VERİSİ VARSA PARAMETRE BAĞLA — üçüncü argüman bir listedir
ad = "O'Brien"
bulunan = veritabani.sqlite(db, "SELECT id FROM kisi WHERE ad = ?", [ad])
dogrula(bulunan == "3", "tek tırnaklı değer kaçış yazmadan bağlanır")
# Enjeksiyon denemesi parametre olarak geçtiğinde yalnız VERİdir
kotu = veritabani.sqlite(db, "SELECT ad FROM kisi WHERE ad = ?",
["Ali'; DROP TABLE kisi; --"])
dogrula(kotu == "", "eşleşen kayıt yok — dize bir deyim değil")
dogrula(veritabani.sqlite(db, "SELECT count(*) FROM kisi") == "3",
"tablo duruyor, DROP çalışmadı")
dosya.sil(db)⚠️ Metin birleştirerek sorgu kurmayın. İki yüzey arasındaki fark güvenliktir, üslup değil — ve fark aşağıda ÖLÇÜLÜYOR, anlatılmıyor:
kullan kaba.veritabani
db = "enjeksiyon.db"
dosya.sil(db)
veritabani.sqlite(db, "CREATE TABLE kisi(ad TEXT);")
veritabani.sqlite(db, "INSERT INTO kisi VALUES ('Ayşe'),('Ali'),('Veli');")
girdi = "yok' OR '1'='1"
# ⛔ BİRLEŞTİRME: girdi sorgunun ANLAMINI değiştirir — 3 kayıt döner
acik = veritabani.sqlite(db, "SELECT ad FROM kisi WHERE ad = '" + girdi + "'")
dogrula(acik.bol("\n").uzunluk() == 3, "birleştirme tüm tabloyu sızdırdı")
# ✓ PARAMETRE: aynı girdi yalnız bir DEĞERdir — eşleşen kayıt yok
kapali = veritabani.sqlite(db, "SELECT ad FROM kisi WHERE ad = ?", [girdi])
dogrula(kapali == "", "parametre bağlanınca girdi kod değil veri")
dosya.sil(db)
yazdir("ölçüldü: birleştirme sızdırıyor, parametre sızdırmıyor")⚠️ Parametreli çağrı TEK deyim kabul eder. "SELECT 1; DROP TABLE x;"
reddedilir — yığılmış sorgu (stacked query) yolu kapalıdır. Parametre sayısı
da denetlenir: eksik bağlanan bir ? SQLite'ta sessizce NULL olur ve
sorgu "kayıt yok" dönerdi.
⚠️ Hata dönüş değerinde DEĞİL, stderr'dedir. Başarısız sorgu boş dize
döner ve sebebi ✗ sqlite: ... satırıyla yazılır. Dönüşü elle
denetleyin.
⚠️ Yol alanı URI olamaz. "file:veri.db?mode=ro" reddedilir: yol
alanının bir sorgu dizesi ayrıştırıcısını beslemesi, kapatılan açığın
küçük bir kopyası olurdu. ":memory:" çalışır.
⚠️ Sorgunun 10 saniyelik bir sınırı var. Aşılırsa sorgu kesilir, o ana kadar biriken satırlar döner ve stderr'e zaman aşımı yazılır.
⚠️ libsqlite3 yalnız bu modülü kullanan programa bağlanır (ölçülüyor).
Sonraki adım
Uygulama türleri: 9. Konsol · 10. Arayüz · 11. Servis · 12. Web