gitweb on Svarog
projekti pod git sistemom za održavanje verzija -- projects under the git version control systemdiff --git a/skripta-os2.tex b/skripta-os2.tex
--- a/skripta-os2.tex
+++ b/skripta-os2.tex
% prebreak=\P,
% postbreak=\ding{229}\space,
language=Modula-2,
- xleftmargin=4em
+ xleftmargin=1em
+}
+
+\lstdefinestyle{codeblock-indent}{
+ style=codeblock,
+ xleftmargin=4em
}
\lstdefinestyle{terminal}{
}
\lstnewenvironment{codeblock}[1][]{\lstset{style=codeblock,#1}}{}
+\lstnewenvironment{codeblock-indent}[1][]{\lstset{style=codeblock-indent,#1}}{}
\lstnewenvironment{terminal}{\lstset{style=terminal}}{}
% ----------------==================--------------------------------------
\label{g-prvi-program}
Tradicionalni prvi program ``Hello World'' bi izgledao ovako:
-\begin{codeblock}
+\begin{codeblock-indent}
MODULE hello;
FROM StrIO IMPORT WriteString, WriteLn;
WriteString('hello world');
WriteLn
END hello.
-\end{codeblock}
+\end{codeblock-indent}
Primećuje se razlika u modulu iz koga se uvoze komande u odnosu na
XDS/TopSpeed verzije M2, tamo je sve bilo u \kod{InOut}, dok se ovde
\end{terminal}
odnosno videćemo da je poziv definisan na sledeći način:
-\begin{codeblock}
+\begin{codeblock-indent}
int system(const char *command);
-\end{codeblock}
+\end{codeblock-indent}
što znači da vraća ceo broj, a prima jedan argument koji je pokazivač
(što se označava *) na znak. Ovo je zapravo ceo string, pošto se u C
jeziku oni predstavljaju kao pokazivač na prvi znak, a string se onda
resurse jer je moguće da sistem odbije da otvori novi ako ih
proces već ima previše otvorenih.
-Kada imamo imena stavki iz direktorijuma o njima možemo dobiti više
-informacija \kod{stat}. Ona prima dva argumenta, prvi je \emph{puna}
-putanja do fajla, a drugi je pokazivač na strukturu u koju će komanda
-upisati podatke. Obratiti pažnju da zbog ovoga struktura već mora
-postojati u memoriji, ili kao lokalna promenljiva odgovarajućeg
-slogovnog tipa, ili dinamički alocirana korišćenjem pokazivača na nju.
-
Budući da su u pitanju sistemski pozivi niskog nivoa, veličine tipova
su nažalost promenljive i mogu zavisiti od konkretnog operativnog
sistema, a naročito utiče da li je u pitanju~32--bitni, ili~64--bitni
na Kubuntu 11.10 i 12.10 64bit.
\begin{codeblock}
-DEFINITION MODULE FOR "C" Lib32;
+DEFINITION MODULE FOR "C" libdir;
+
FROM SYSTEM IMPORT
ADDRESS, BYTE;
- EXPORT UNQUALIFIED opendir, readdir, closedir, stat,
- PDir, DirEnt, PDirEnt, Stat, PStat, PInt;
+
+ EXPORT UNQUALIFIED opendir, readdir, closedir, PDir, DirEnt, PDirEnt;
\end{codeblock}
-\begin{minipage}{0.5\textwidth}
+\begin{minipage}{0.45\textwidth}
\begin{codeblock}
(* types for 32 bit *)
TYPE
PDir = ADDRESS;
DirEnt = RECORD
- ino: INTEGER;
- off: INTEGER;
- reclen: SHORTCARD;
- type: BYTE;
- name: ARRAY [0..255] OF CHAR;
+ ino: INTEGER;
+ off: INTEGER;
+ reclen: SHORTCARD;
+ type: BYTE;
+ name: ARRAY [0..255] OF CHAR;
+ END;
+ PDirEnt = POINTER TO DirEnt;
+ \end{codeblock}
+\end{minipage}
+\begin{minipage}{0.45\textwidth}
+\begin{codeblock}[frame=single,frameround=tttt]
+(* types for 64 bit *)
+ TYPE
+ PDir = ADDRESS;
+ DirEnt = RECORD
+ ino: LONGINT;
+ off: LONGINT;
+ reclen: SHORTCARD;
+ type: BYTE;
+ name: ARRAY [0..255] OF CHAR;
END;
PDirEnt = POINTER TO DirEnt;
+\end{codeblock}
+\end{minipage}
+\begin{codeblock}
+ PROCEDURE opendir(name: ARRAY OF CHAR): PDir;
+ PROCEDURE readdir(dirp: PDir): PDirEnt;
+ PROCEDURE closedir(dirp: PDir): [INTEGER];
+
+END libdir.
+\end{codeblock}
+
+\begin{codeblock}
+MODULE Zad3;
+
+FROM StrIO IMPORT
+ WriteString, WriteLn;
+FROM NumberIO IMPORT
+ WriteInt;
+FROM Args IMPORT
+ Narg, GetArg;
+ FROM libdir IMPORT
+ opendir, readdir, closedir, PDir, PDirEnt;
+FROM errno IMPORT
+ geterrno;
+
+TYPE
+ String = ARRAY [0..1023] OF CHAR;
+
+VAR
+ Putanja: String;
+ n, i: INTEGER;
+ ok: BOOLEAN;
+
+PROCEDURE Listaj(Ime: ARRAY OF CHAR);
+VAR
+ dir: PDir;
+ entry: PDirEnt;
+ c: INTEGER;
+BEGIN
+ WriteString("Folder "); WriteString(Ime); WriteLn;
+ dir:= opendir(Ime);
+ IF dir = NIL THEN
+ WriteString(" Greska broj "); WriteInt(geterrno(), 0); WriteString("."); WriteLn();
+ WriteString(" Ne mogu da otvorim direktorijum."); WriteLn();
+ ELSE
+ entry:= readdir(dir);
+ WHILE entry # NIL DO
+ IF entry^.name[0] # "." THEN
+ WriteString(" "); WriteString(entry^.name); WriteLn;
+ END;
+ entry:= readdir(dir);
+ END;
+ c:= closedir(dir);
+ IF c = -1 THEN
+ WriteString(" Greska broj "); WriteInt(geterrno(), 0); WriteString("."); WriteLn();
+ WriteString(" Ne mogu da zatvorim direktorijum."); WriteLn();
+ END;
+ END;
+END Listaj;
+
+BEGIN
+ n:= Narg();
+ FOR i:= 1 TO n - 1 DO
+ ok:= GetArg(Putanja, i);
+ WriteLn;
+ Listaj(Putanja);
+ END;
+ WriteLn;
+END Zad3.
+\end{codeblock}
+
+\subsubsection{Primer: Ispis osobina pojedinih fajlova}
+
+O pojedinim fajlovima možemo dobiti više informacija koristeći
+sistemski poziv \kod{stat}. On prima dva argumenta, prvi je
+\emph{puna} putanja do fajla, a drugi je pokazivač na strukturu u koju
+će komanda upisati podatke. Obratiti pažnju da zbog ovoga struktura
+već mora postojati u memoriji, ili kao lokalna promenljiva
+odgovarajućeg slogovnog tipa, ili dinamički alocirana korišćenjem
+pokazivača na nju.
+
+Linux i mnogi drugi srodni sistemi za internu prezentaciju vremena
+koriste broj sekundi od početka ``epohe'', odnosno od prvog januara
+1970 godine. Za konverziju u klasičnije mere vremena se može koristiti
+poziv \kod{localtime}.
+
+Kao i u prethodnom primeru date su dve verzije definicija nekih
+tipova.
+
+\begin{codeblock}
+DEFINITION MODULE FOR "C" LibStat32;
+ FROM SYSTEM IMPORT
+ ADDRESS, BYTE;
+ EXPORT UNQUALIFIED stat, localtime,
+ Stat, PStat, Tm, PTm, PInt,
+ fifo, character, directory, block, regular, network, link, socket;
+
+ CONST
+ fifo = 1;
+ character = 2;
+ directory = 4;
+ block = 6;
+ regular = 8;
+ network = 9;
+ link = 10;
+ socket = 12;
+\end{codeblock}
+\begin{minipage}{0.45\textwidth}
+\begin{codeblock}
+(* types for 32 bit *)
+ TYPE
Stat = RECORD
dev: LONGINT;
ino: LONGINT;
\begin{codeblock}[frame=single,frameround=tttt]
(* types for 64 bit *)
TYPE
- PDir = ADDRESS;
- DirEnt = RECORD
- ino: LONGINT;
- off: LONGINT;
- reclen: SHORTCARD;
- type: BYTE;
- name: ARRAY [0..255] OF CHAR;
- END;
- PDirEnt = POINTER TO DirEnt;
Stat = RECORD
dev: LONGINT;
ino: LONGINT;
\end{codeblock}
\end{minipage}
\begin{codeblock}
- PStat = POINTER TO Stat;
+ Tm = RECORD
+ sec, min, hour,
+ mday, mon, year,
+ wday, yday, isdst: INTEGER;
+ END;
+ PTm = POINTER TO Tm;
PInt = POINTER TO INTEGER;
- PROCEDURE opendir(name: ARRAY OF CHAR): PDir;
- PROCEDURE readdir(dirp: PDir): PDirEnt;
- PROCEDURE closedir(dirp: PDir): [INTEGER];
PROCEDURE stat(path: ARRAY OF CHAR; buf: PStat): [INTEGER];
-END Lib32.
+ PROCEDURE localtime(time: PInt): PTm;
+
+END LibStat32.
\end{codeblock}
\begin{codeblock}
-MODULE Zad3;
+MODULE Zad4;
+FROM SYSTEM IMPORT
+ ADR;
FROM StrIO IMPORT
WriteString, WriteLn;
FROM NumberIO IMPORT
WriteInt;
+FROM StrLib IMPORT
+ StrLen, StrConCat;
FROM Args IMPORT
Narg, GetArg;
- FROM Lib32 IMPORT
- opendir, readdir, closedir, PDir, PDirEnt;
+FROM LibStat32 IMPORT
+ stat, localtime, Stat, PTm;
+IMPORT LibStat32;
FROM errno IMPORT
geterrno;
n, i: INTEGER;
ok: BOOLEAN;
-PROCEDURE Listaj(Ime: ARRAY OF CHAR);
+PROCEDURE WriteMode(mode: INTEGER);
+
+ PROCEDURE WriteType(type: INTEGER);
+ BEGIN
+ IF type = lib32.fifo THEN
+ WriteString("f");
+ ELSIF type = lib32.character THEN
+ WriteString("c");
+ ELSIF type = lib32.directory THEN
+ WriteString("d");
+ ELSIF type = lib32.block THEN
+ WriteString("b");
+ ELSIF type = lib32.regular THEN
+ WriteString("-");
+ ELSIF type = lib32.network THEN
+ WriteString("n");
+ ELSIF type = lib32.link THEN
+ WriteString("l");
+ ELSIF type = lib32.socket THEN
+ WriteString("s");
+ ELSE
+ WriteString("?");
+ END;
+ END WriteType;
+
+ PROCEDURE WriteRWX(triplet: INTEGER);
+ BEGIN
+ IF ((triplet DIV 4) MOD 2) # 0 THEN
+ WriteString("r");
+ ELSE
+ WriteString("-");
+ END;
+ IF ((triplet DIV 2) MOD 2) # 0 THEN
+ WriteString("w");
+ ELSE
+ WriteString("-");
+ END;
+ IF (triplet MOD 2) # 0 THEN
+ WriteString("x");
+ ELSE
+ WriteString("-");
+ END;
+ END WriteRWX;
+
+BEGIN
+ WriteType((mode DIV 4096) MOD 16);
+ WriteRWX(mode DIV 64);
+ WriteRWX(mode DIV 8);
+ WriteRWX(mode);
+END WriteMode;
+
+PROCEDURE WriteTime(time: LONGINT);
VAR
- dir: PDir;
- entry: PDirEnt;
- c: INTEGER;
+ tm: PTm;
BEGIN
- WriteString("Folder "); WriteString(Ime); WriteLn;
- dir:= opendir(Ime);
- IF dir = NIL THEN
- WriteString(" Greska broj "); WriteInt(geterrno(), 0); WriteString("."); WriteLn();
- WriteString(" Ne mogu da otvorim direktorijum."); WriteLn();
- ELSE
- entry:= readdir(dir);
- WHILE entry # NIL DO
- IF entry^.name[0] # "." THEN
- WriteString(" "); WriteString(entry^.name); WriteLn;
- END;
- entry:= readdir(dir);
+ tm:= localtime(ADR(time));
+ IF tm # NIL THEN
+ WriteInt(tm^.year + 1900, 0);
+ WriteString("-");
+ IF tm^.mon < 9 THEN
+ WriteString("0");
END;
- c:= closedir(dir);
- IF c = -1 THEN
- WriteString(" Greska broj "); WriteInt(geterrno(), 0); WriteString("."); WriteLn();
- WriteString(" Ne mogu da zatvorim direktorijum."); WriteLn();
+ WriteInt(tm^.mon + 1, 0);
+ WriteString("-");
+ IF tm^.mday < 10 THEN
+ WriteString("0");
+ END;
+ WriteInt(tm^.mday, 0);
+ WriteString(" ");
+ IF tm^.hour < 10 THEN
+ WriteString("0");
+ END;
+ WriteInt(tm^.hour, 0);
+ WriteString(":");
+ IF tm^.hour < 10 THEN
+ WriteString("0");
END;
+ WriteInt(tm^.min, 0);
+ ELSE
+ WriteString("??:??");
+ END;
+END WriteTime;
+
+PROCEDURE Listaj(Putanja: ARRAY OF CHAR);
+VAR
+ info: Stat;
+ c: INTEGER;
+BEGIN
+ c:= stat(Putanja, ADR(info));
+ IF c = -1 THEN
+ WriteString("?????????? ? ? KB ????-??-?? ??:??");
+ ELSE
+ WriteMode(info.mode);
+ WriteInt(info.nlink, 3);
+ WriteInt((info.size + 512) DIV 1024, 5); WriteString(" KB ");
+ WriteTime(info.atime);
END;
+ WriteString(" "); WriteString(Putanja); WriteLn;
END Listaj;
BEGIN
Listaj(Putanja);
END;
WriteLn;
-END Zad3.
+END Zad4.
\end{codeblock}
\subsection{Stvaranje novih procesa}
Korišćenjem sistemske komande \kod{fork} trenutni proces se duplira
(``račva''). Novi proces je identičan sa originalnim, osim u svom
identifikacionom broj. Komanda ne prima parametre i vraća jedan integer, pa se može mapirati na sledeći način:
-\begin{codeblock}
+\begin{codeblock-indent}
PROCEDURE fork(): INTEGER;
-\end{codeblock}
+\end{codeblock-indent}
Oba procesa se nakon račvanja nastavljaju odvijati u sledećem redu
koda. Jedino po čemu se razlikuju je vrednost koju je vratio
procesu je ova vrednost jednaka nuli. Budući da je najčešće potrebno
da dete i roditelj rade različite stvari, to se obično rešava kodom
sledećeg oblika:
-\begin{codeblock}
+\begin{codeblock-indent}
pid := fork();
IF pid = 0 THEN
(* "detetove" operacije *)
ELSE
(* "roditeljske" operacije *)
END;
-\end{codeblock}
+\end{codeblock-indent}
Komanda \kod{wait} (uvezena kao sistemska) se može pozvati u
originalnom procesu sa efektom da se proces uspava dokle god neki od
Prvi korak za instalaciju dodatnog kompajlera GNU Modula 2 je
dodavanje repozitorijuma softvera u sistem. Ovo se može uraditi ručnim
menjanjem fajla \kod{/etc/apt/sources.list} i dodavanjem
-\begin{codeblock}
+\begin{codeblock-indent}
#
# GNU Modula-2 repo
#
deb http://floppsie.comp.glam.ac.uk/debian/ squeeze main
deb-src http://floppsie.comp.glam.ac.uk/debian/ squeeze main
-\end{codeblock}
+\end{codeblock-indent}
Alternativno se mogu koristiti sledeće komande:
Videti Glavu~\ref{g-prvi-program} za primer kompajliranja programa.
+\paragraph{Napomena:} Prilikom unapredjivanja Linux distribucije na
+sledeću verziju (npr. 13.10 na 14.04) se standardno onemogućavaju
+dodati izvori softvera i potrebno ih je ručno ponovo upaliti. Ovo se
+može uraditi otvoranjem \kod{/etc/apt/sources.list} i uklonjanjem
+``\#'' sa početka redova koje želimo da koristimo ponovo ili
+korišćenjem adekvatnih vizuelnih alata.
+
\subsection{Problem: nedostaje ``ctli.o'' i/ili još neki fajlovi}
Pri pokušaju kompajliranja se na nekim sistemima može desiti da