Szépen akarok írni

Mostanság vágtam bele a C/C++ nyelv komolyabb megismerésére, és afféle tanulmányként írtam egy kis osztott könyvtárat, melynek segítéségével a Gentoo Linuxon látható kiírási stílust lehet elérni C programból. Szeretném ha valaki átnézné a kódot, és esetleg tanácsokkal tudna nekem szolgálni, hogy ez alapján is fejlődhessek.

A stuff GPLv2 alá tartozik, jelenleg stabil, csak a kód csúnya egy kicsit.

A kátránylabda innen szedegethető.

A jelenleg megvalósított függvények és funkcióik:

  • etitle: A terminálablak címének módosítását teszi lehetővé az azt támogató terminálokon (xterm, gnome-terminal, screen, rxvt, stb.) Ez elég vacak, beégetett listával dolgozik...
  • einfo, ewarn, eerror: printf szerű szintaxissal rendelkező függvények, az üzenet típusától függő színű csillagot tesz a neki átadott szöveg elejére, így emelvén azt ki a szürke sorokból. Ide kellene egy behúzás-támogató rész is, csak nem tudom ,hogyan lehetne permanensen eltárolni két hívás közt az aktuális behúzás mértékét. Bash-ban ez egyszerűbb, de itt tanácstalan vagyok...
  • ebegin, eend, ewend: Egy hosszabb folyamat számára biztosít kijelzési lehetőséget. Az ebegin a kezdő üzenetért felel, az eend-ewend páros a befejezésért felelős. A két ikerfüggvény közt csak annyi az eltérés, hogy az eend hívható üzenet nélkül is, csak visszatérési értékkel, az ewend viszont csak üzenettel együtt hívható. Az eend az üzenettel az eerror-t, az ewend az ewarn-t hívja meg az üzenet kiírásához.
  • esyslog: Nevéből yól látszik, egy syslog wrapper, aminek meg lehet adni a program nevét, a prioritást szövegesen (pl. daemon.warn), valamint az üzenetet printf szintaxissal.
  • ebeep: Egy pittyenést hallat a PC speakeren ha ez lehetséges (egy BELL jelet ír a standard outputra). Az EBEEP_IGNORE környezeti változó beállításával letiltható a működése.
  • epause: Adott ideig vár (az idő mp.-ekben értendő). Az ő működése az EPAUSE_IGNORE környezeti változóval tiltható.

Minden szines kiírást végző függvény kimenete fekete-fehér lesz, ha az EF_NOCOLOR környezeti változó be van állítva.

Hozzászólások

Making all in src
make[1]: Entering directory `/home/turul/Desktop/libefuncs-1.0/src'
make all-am
make[2]: Entering directory `/home/turul/Desktop/libefuncs-1.0/src'
/bin/sh ../libtool --tag=CXX --mode=compile g++ -DHAVE_CONFIG_H -I. -g -O2 -MT colors.lo -MD -MP -MF .deps/colors.Tpo -c -o colors.lo colors.cpp


mkdir .libs
 g++ -DHAVE_CONFIG_H -I. -g -O2 -MT colors.lo -MD -MP -MF .deps/colors.Tpo -c colors.cpp  -fPIC -DPIC -o .libs/colors.o
colors.cpp:1:20: error: colors.h: No such file or directory
colors.cpp:8: error: expected constructor, destructor, or type conversion before '<' token
colors.cpp: In function 'void initcoldb()':
colors.cpp:11: error: 'colors' was not declared in this scope
colors.cpp:14: error: 'colors' was not declared in this scope
colors.cpp: At global scope:
colors.cpp:55: error: 'string' does not name a type
make[2]: *** [colors.lo] Error 1
make[2]: Leaving directory `/home/turul/Desktop/libefuncs-1.0/src'
make[1]: *** [all] Error 2
make[1]: Leaving directory `/home/turul/Desktop/libefuncs-1.0/src'
make: *** [all-recursive] Error 1
turul@gluon8 ~/Desktop/libefuncs-1.0 $ find -name colors.h
turul@gluon8 ~/Desktop/libefuncs-1.0 $  

Valami hianyzik.

Ja es string a satan muve foleg, ha van #define vagy enum helyette. (A templatek (map) is gonoszak, foleg, ha nem szugsegesek. es akkor mar irhatod Isten nyelven)

Lehet g_print hez is jol jonne valakinek.

Miert nem LGPL ?

Menjünk sorban:
Feltettem ugyanoda egy friss kátránylabdát, ez a kimenet kérdéses része (gcc 4.1.2):
make[1]: Entering directory `/home/hron/develop/c/plusplus/libefuncs/trunk/src'
make all-am
make[2]: Entering directory `/home/hron/develop/c/plusplus/libefuncs/trunk/src'
/bin/sh ../libtool --tag=CXX --mode=compile g++ -DHAVE_CONFIG_H -I. -g -O2 -MT colors.lo -MD -MP -MF .deps/colors.Tpo -c -o colors.lo colors.cpp
mkdir .libs
g++ -DHAVE_CONFIG_H -I. -g -O2 -MT colors.lo -MD -MP -MF .deps/colors.Tpo -c colors.cpp -fPIC -DPIC -o .libs/colors.o
g++ -DHAVE_CONFIG_H -I. -g -O2 -MT colors.lo -MD -MP -MF .deps/colors.Tpo -c colors.cpp -o colors.o >/dev/null 2>&1
mv -f .deps/colors.Tpo .deps/colors.Plo
[/code]
A hiba oka az volt, hogy a csomagból nem fordítottam, csak a svn fából, így nem vettem észre, hogy a Makefile.am nem tudodd a header fájlokról. FIXED.

String, map: Először #define sorokra akartam megírni, de elvetettem, mert a color() függvény így bármilyen olyan attributum kiírására is képes lesz, ami jelenleg még nem ismert (nem fújom kívülről a termcap adatbázist, és a netről csak ennyi jött össze). Enum-ba asszem csak integereket lehet tenni, ha megnézed, ezek sztringek. A map azért tünt jó ötletnek, mert a lehető legkevesebbet akartam szopni a lehívással. Ugyanezokból vetettem el a végén a #define-t is: a 534586 darab if elágazás helyett (ugye a switch csak int-et tud) egyszerűen megvizsgálopm, hogy létezik-e az adott dolog. Tudtommal az if-eknek az egyik legnagyobb a kiértékelési költsége.

g_print: az meg mi a fene?

LGPL: Mi a difi a GPL és az LGPL között? Nekem édesmindegy, használja aki akarja, csak ha van jó ötlete/hibamegoldása azt küldje vissza hozzám, és ne tartsa meg magának.

"Tudtommal az if-eknek az egyik legnagyobb a kiértékelési költsége."
Ja foleg, ha az else aggal fojtatodik a program. Map Piros-Fekete fat hasznal AFIK, ott is van par if. (Map azert egesz jol ossze lehet rakva :) )

String feldolgozas koltseges, amikor csak lehet el kell kerulni. (ha jobban tetszik enumokat tegy lancolt listba, vagy igyesmi)

De a láncolt listából nem tudok lista["kulcs"] móddal lehívni, ez nekem annyira tetszik :). Mondjuk listában folyamatosan végig kellene iterálnom, hogy mind a 3féle attributumot feldolgozhassam. Ezt mondjuk le tudom úgy egyszerűsíteni, hogy 3 listára bontom az eredeti 1-et, de akkor is ilyen szerkezetek lesznek:


string retval;
list<char *> colors;
list<char *>::iterator it;
(...)
for(it=colors.begin(); it != colors.end(); it++){
    if(strcmp(*it, fg) == 0) {
        retval += *it;
        break;
    }
}

És ezeket nem szeretem. Különösen rühellem a strcmp-t, a string-nél olyan yó kihasználni azt, hogy az "if(*it != fg);" szerkezet is működőképes, és nem kell még segédfügvényekkel hülyéskedni. Miért kell egy egyszerű összehasonlítás miatt függvényt hívjak, mikor azért tartom a mögöttes rendszert, hogy ilyeneket elrejtsen előlem? Tudom, most nagyon szemét vagyok...
Ennél már csak az lenne horribilisebb, hogy ha a retval is char * lenne... nem tudom mekkora legyen, és csak a baj van onnantól, mert az ANSI C-beli tömbök ugye nem dinamikus memóriafoglalásúak, azaz ha tök véletlen túllépném a keretet, akkor ugyebár olló. az meg nagyon nem yó.

De a folyamatos iterálás is zavar.. map esetén minderre nincs gondom, mert a operator []() megoldja az egészet sokkal optimálisabban, mint amire én egyáltalán képes lehetek - a jelenlegi tudásommal.

Amúgy nem válaszoltál a LGPL-re vonatkozó kérdésre... Nekem télleg mindegy, de azért érdekel, miért mondod...

Ha erre a g_print-re gondoltál, akkor annyit tehetek, hogy csinálok egy-egy f kezdetű függvényt, ami a neki átadott descriptorra írja ki a kiírandót. Csak vissza kell ellenőrizzem, mert ha ezek a descriptorok nem a stdout/stderr valamelyike, akkor nem írhatok ki színesen, csak fekete-fehérben.

Ja, és még valami: kellenének ötletek, hogyan lehetne a sorvége karakterek mentén a sztringet. Jó lenne azt megoldani, hogy ha egy többsoros üzenetet kell kiírni, akkor minden sor az üzenet típusának megfelelő csillaggal kezdődjön.


sorok_containerT<char*> sorok_container;//lista vagy amit akarsz

int i=0;
sorok_container.push_back(buf);
while (buf[i]!=0)
{
if (buf[i]=='\n') { 
                    buf[i]='\0';
                    if (buf[i+1]!='\0') sorok_container.push_back(buf+i+1);
                  }
i++;
}

Valami ilyesmi.

pusholdis helyett akkar fel is dolgozhatod a sorokat.

Várj, az elején miért teszed bele a teljes puffert?
Illetve részleteiben hogyan működik ez? Valahogy nem tiszta, mi hajtja...

Elmondom mi az amit megértettem:

létrehozok egy listát (sorok_containterT).
egy ciklusban addig keresek, míg az akutális karakter '\0' (ez itt gondolom typo) nem lesz.
Ha '\n'-t találtam, azt lecserélem '\0'-ra. Ha az utána következő karakter is '\0' akkor megint a teljes puffert beleteszem a listába, kipörgetve belőle a már elhagyott elemeket.

Ez a kezdetnél azért nem tűnik jónak, mert a komplett puffert is bepakolja, és utána szerintem folyamatosan a \n-nel teli puffereket pakolássza a listába. Valószínű, inkább hátulról kellene az i-t csökkentenem (kezdetben mondjuk strlen(buf) az értéke, és akkor már elméletben jól működne.

Yól látom, vagy teljesen rosszul gondolom?

null terminated string-rol beszelunk ugye ?


          // 000000000011 11111111 222222222233333
          // 012345678901 23456789 012345678901234
char cucc[]="hello world\n ujsor \n meg egy sor";

char *stingek[3]; //tartalma legyen ez most a lista
cucc
cucc+12
cucc+20

kiiratva:
printf(stringek[0]); //"hello world" megall 11 helyen levo nulanal
printf(stringek[1]); //" ujsor " megal 19 helyel levo nullanal
printf(stringek[2]); //"meg egy sor" megal 32 helyen levo 0 nal.


     string string string
mut1-^      ^      ^
mut2--------       |
mut3----------------

"egy ciklusban addig keresek, míg az akutális karakter '\0' (ez itt gondolom typo) nem lesz."
vegig megyek a karakter lancon (null vegu).

"Várj, az elején miért teszed bele a teljes puffert?"
Csak egy mutatot teszek bele az elejerol. A veget majd nulla hatarozza meg.

man strtok

Kezdem kapisgálni, bár érteni annyira továbbra sem értem a dolgot. Mindenesetre köszönöm a kódokat.

Apropó, esetleg van MSN címed, ahol az ilyen alap dolgokat megbeszélhetnénk? Elég keveset tudok, és a google nem mindig ad kielégítő válaszokat, viszont nem akarok kérdezni programozós fórumokon, mert a láma kérdésért tuti lehülyéznek. De van amikor az ember nem érti, hogy mi hajtja...