Rev 643 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
616 | bw | 1 | {} |
2 | |||
3 | procedure OpenStdout(var f: TextRec); forward; |
||
4 | procedure WriteStdout(var f: TextRec); forward; |
||
666 | bw | 5 | procedure FlushStdout(var f: TextRec); forward; |
616 | bw | 6 | procedure CloseStdout(var f: TextRec); forward; |
7 | |||
8 | procedure OpenStdin(var f: TextRec); forward; |
||
9 | procedure ReadStdin(var f: TextRec); forward; |
||
10 | procedure CloseStdin(var f: TextRec); forward; |
||
11 | |||
12 | |||
13 | |||
14 | procedure AssignStdout(var f: Text); |
||
15 | begin |
||
16 | Assign(f, ''); |
||
17 | TextRec(f).OpenFunc := @OpenStdout; |
||
18 | Rewrite(f); |
||
19 | end; |
||
20 | |||
21 | procedure OpenStdout(var f: TextRec); |
||
22 | begin |
||
23 | TextRec(f).InOutFunc := @WriteStdout; |
||
666 | bw | 24 | TextRec(f).FlushFunc := @FlushStdout; |
616 | bw | 25 | TextRec(f).CloseFunc := @CloseStdout; |
26 | end; |
||
27 | |||
28 | procedure WriteStdout(var f: TextRec); |
||
29 | var |
||
30 | msg: String; |
||
31 | begin |
||
32 | msg := StrPas(PChar(f.bufptr)); |
||
33 | SetLength(msg, f.bufpos); |
||
34 | f.bufpos := 0; |
||
35 | Konsole.Write(msg); |
||
36 | end; |
||
37 | |||
666 | bw | 38 | procedure FlushStdout(var f: TextRec); |
39 | begin |
||
40 | WriteStdout(f); |
||
41 | Konsole.Flush; |
||
42 | end; |
||
43 | |||
616 | bw | 44 | procedure CloseStdout(var f: TextRec); |
45 | begin |
||
46 | end; |
||
47 | |||
48 | |||
49 | |||
50 | procedure AssignStdin(var f: Text); |
||
51 | begin |
||
52 | Assign(f, ''); |
||
53 | TextRec(f).OpenFunc := @OpenStdin; |
||
54 | Reset(f); |
||
55 | end; |
||
56 | |||
57 | procedure OpenStdin(var f: TextRec); |
||
58 | begin |
||
59 | TextRec(f).InOutFunc := @ReadStdin; |
||
60 | TextRec(f).FlushFunc := nil; |
||
61 | TextRec(f).CloseFunc := @CloseStdin; |
||
62 | end; |
||
63 | |||
64 | procedure ReadStdin(var f: TextRec); |
||
65 | var |
||
66 | max, curpos: Longint; |
||
67 | c: Longint; |
||
68 | begin |
||
69 | max := f.bufsize - Length(LineEnding); |
||
70 | curpos := 0; |
||
71 | repeat |
||
72 | c := 13{l4_getc()}; |
||
73 | case c of |
||
74 | 13: |
||
75 | begin |
||
76 | {f.bufptr^[curpos] := LineEnding;} |
||
77 | Inc(curpos); |
||
78 | f.bufpos := 0; |
||
79 | f.bufend := curpos; |
||
80 | {l4_putc(Longint(LineEnding));} |
||
81 | break; |
||
82 | end; |
||
83 | 32..126: if curpos < max then |
||
84 | begin |
||
85 | f.bufptr^[curpos] := Char(c); |
||
86 | Inc(curpos); |
||
87 | {l4_putc(c);} |
||
88 | end; |
||
89 | end; |
||
90 | until False; |
||
91 | end; |
||
92 | |||
93 | procedure CloseStdin(var f: TextRec); |
||
94 | begin |
||
95 | end; |
||
96 | |||
97 | |||
98 | { TKonsole } |
||
99 | |||
100 | procedure KonsoleThreadMain(Console: PKonsole); |
||
101 | {Рабочий цикл консоли} |
||
102 | var |
||
103 | ThreadInfo: TKosThreadInfo; |
||
104 | Message: ShortString; |
||
105 | Event: DWord; |
||
106 | begin |
||
107 | kos_maskevents(ME_PAINT or ME_KEYBOARD or ME_IPC); |
||
108 | kos_threadinfo(@ThreadInfo); |
||
109 | Console^.FThreadSlot := kos_getthreadslot(ThreadInfo.ThreadID); |
||
110 | |||
111 | kos_initipc(Console^.FIPCBuffer, Console^.FIPCBufferSize); |
||
112 | |||
113 | {сразу отобразить и активировать окно} |
||
114 | Console^.Paint(); |
||
115 | {$ifndef EMULATOR} |
||
116 | kos_setactivewindow(Console^.FThreadSlot); |
||
117 | {$endif} |
||
118 | |||
119 | {готов к обработке событий} |
||
120 | Console^.FOpened := True; |
||
121 | while not Console^.FTerminate do |
||
122 | begin |
||
123 | Event := kos_getevent(); |
||
666 | bw | 124 | Console^.FOnAir := True; |
619 | bw | 125 | if not Console^.FTerminate then |
616 | bw | 126 | case Event of |
127 | SE_PAINT: Console^.Paint(); |
||
128 | SE_KEYBOARD: Console^.ProcessKeyboard(kos_getkey()); |
||
129 | SE_IPC: while Console^.ReceiveMessage(Message) do Console^.ProcessMessage(Message); |
||
130 | end; |
||
666 | bw | 131 | Console^.FOnAir := False; |
616 | bw | 132 | end; |
133 | Console^.FOpened := False; |
||
134 | end; |
||
135 | |||
136 | constructor TKonsole.Init(ACaption: String); |
||
137 | const |
||
138 | IPC_SIZE = 4096; |
||
139 | var |
||
140 | ThreadInfo: TKosThreadInfo; |
||
141 | begin |
||
142 | if ACaption <> '' then |
||
143 | FCaption := ACaption else |
||
144 | begin |
||
145 | kos_threadinfo(@ThreadInfo); |
||
146 | FCaption := StrPas(ThreadInfo.AppName); |
||
147 | end; |
||
148 | SetLength(FLines, 1); |
||
666 | bw | 149 | FLines[0] := ''; |
616 | bw | 150 | FCursor.X := 1; |
151 | FCursor.Y := 0; |
||
152 | FMaxLines := 150; |
||
153 | FTerminate := False; |
||
154 | FOpened := False; |
||
666 | bw | 155 | FOnAir := False; |
616 | bw | 156 | FIPCBufferSize := SizeOf(TKosIPC) + IPC_SIZE; |
157 | FIPCBuffer := GetMem(FIPCBufferSize); |
||
158 | FIPCBuffer^.Lock := False; |
||
159 | FIPCBuffer^.Size := 0; |
||
160 | FThreadSlot := -1; |
||
161 | FThreadID := BeginThread(TThreadFunc(@KonsoleThreadMain), @Self); |
||
162 | if FThreadID <> 0 then |
||
619 | bw | 163 | {XXX: может зависнуть} |
164 | while not FOpened do ThreadSwitch; |
||
616 | bw | 165 | end; |
166 | |||
167 | destructor TKonsole.Done(); |
||
168 | begin |
||
169 | FTerminate := True; |
||
619 | bw | 170 | if FOpened then begin Self.Write(#0); kos_delay(01); end; |
171 | if FOpened then begin Self.Write(#0); kos_delay(10); end; |
||
172 | if FOpened then begin Self.Write(#0); kos_delay(20); end; |
||
616 | bw | 173 | if FOpened then |
174 | begin |
||
175 | FOpened := False; |
||
666 | bw | 176 | FOnAir := False; |
616 | bw | 177 | KillThread(FThreadID); |
178 | end; |
||
666 | bw | 179 | {FreeMem(FIPCBuffer); |
180 | SetLength(FLines, 0);} |
||
616 | bw | 181 | end; |
182 | |||
183 | function TKonsole.ReceiveMessage(var Message: ShortString): Boolean; |
||
184 | {Извлечь первое сообщение из буфера} |
||
185 | var |
||
186 | PMsg: PKosMessage; |
||
187 | Size: Longword; |
||
188 | begin |
||
666 | bw | 189 | FIPCBuffer^.Lock := True; |
190 | |||
616 | bw | 191 | if FIPCBuffer^.Size > 0 then |
192 | begin |
||
193 | PMsg := Pointer(Longword(FIPCBuffer) + SizeOf(TKosIPC)); |
||
194 | {TODO: проверка PMsg^.SenderID} |
||
195 | {Size := PMsg^.Size; |
||
196 | Dec(FIPCBuffer^.Size, Size + SizeOf(TKosMessage)); |
||
197 | if Size > 255 then Size := 255; |
||
198 | SetLength(Message, Size); |
||
199 | Move(Pointer(Longword(PMsg) + SizeOf(TKosMessage))^, Message[1], Size); |
||
200 | if FIPCBuffer^.Size > 0 then |
||
201 | Move(Pointer(Longword(PMsg) + SizeOf(TKosMessage) + PMsg^.Size)^, PMsg^, FIPCBuffer^.Size);} |
||
202 | |||
203 | {XXX} |
||
204 | Size := FIPCBuffer^.Size; |
||
205 | Dec(FIPCBuffer^.Size, Size); |
||
206 | if Size > 255 then Size := 255; |
||
207 | SetLength(Message, Size); |
||
208 | Move(PMsg^, Message[1], Size); |
||
209 | |||
210 | Result := True; |
||
211 | end else |
||
212 | begin |
||
213 | Message := ''; |
||
214 | Result := False; |
||
215 | end; |
||
216 | |||
217 | {FIXME: если FIPCBuffer^.Size = 0, то FIPCBuffer^.Lock все равно > 0} |
||
218 | FIPCBuffer^.Lock := False; |
||
219 | end; |
||
220 | |||
221 | procedure TKonsole.ProcessMessage(Message: ShortString); |
||
666 | bw | 222 | { Вывести сообщение на консоль } |
616 | bw | 223 | var |
666 | bw | 224 | OnlyBottomLine: Boolean = True; |
616 | bw | 225 | |
666 | bw | 226 | procedure PutChar(C: Char); |
227 | var |
||
228 | LinesCount: Longint; |
||
229 | PLine: PShortString; |
||
230 | I: Longint; |
||
231 | begin |
||
232 | { перевод коретки на позицию влево } |
||
233 | if C = #8 then |
||
616 | bw | 234 | begin |
666 | bw | 235 | if FCursor.X > 1 then |
236 | Dec(FCursor.X); |
||
237 | end else |
||
238 | |||
239 | { перевод коретки на следующую строку } |
||
240 | if C = #10 then |
||
241 | begin |
||
242 | OnlyBottomLine := False; |
||
243 | Inc(FCursor.Y); |
||
244 | LinesCount := Length(FLines); |
||
245 | while FCursor.Y >= FMaxLines do Dec(FCursor.Y, FMaxLines); |
||
246 | if FCursor.Y < LinesCount then FLines[FCursor.Y] := ''; |
||
247 | while FCursor.Y >= LinesCount do |
||
616 | bw | 248 | begin |
666 | bw | 249 | SetLength(FLines, LinesCount + 1); |
250 | FLines[LinesCount] := ''; |
||
251 | Inc(LinesCount); |
||
616 | bw | 252 | end; |
666 | bw | 253 | end else |
254 | |||
255 | { перевод коретки в начало строки } |
||
256 | if C = #13 then |
||
257 | FCursor.X := 1 else |
||
258 | |||
259 | { помещение символа в строку } |
||
260 | begin |
||
261 | if FCursor.X > 200 then |
||
616 | bw | 262 | begin |
666 | bw | 263 | PutChar(#13); |
264 | PutChar(#10); |
||
265 | end; |
||
266 | |||
267 | { FIXME: Если в PascalMain только один Write/Ln, то зависон. |
||
268 | см. FPC_DO_EXIT, InternalExit } |
||
269 | PLine := @FLines[FCursor.Y]; |
||
270 | I := Length(PLine^); |
||
271 | if FCursor.X > I then |
||
272 | begin |
||
273 | SetLength(PLine^, FCursor.X); |
||
274 | Inc(I); |
||
275 | while I < FCursor.X do |
||
616 | bw | 276 | begin |
666 | bw | 277 | PLine^[I] := ' '; |
278 | Inc(I); |
||
616 | bw | 279 | end; |
280 | end; |
||
666 | bw | 281 | FLines[FCursor.Y][FCursor.X] := C; |
282 | |||
283 | Inc(FCursor.X); |
||
616 | bw | 284 | end; |
666 | bw | 285 | end; |
616 | bw | 286 | |
666 | bw | 287 | var |
288 | I: Longint; |
||
289 | begin |
||
290 | for I := 1 to Length(Message) do |
||
291 | PutChar(Message[I]); |
||
292 | Paint(OnlyBottomLine); |
||
616 | bw | 293 | end; |
294 | |||
295 | procedure TKonsole.ProcessKeyboard(Key: Word); |
||
296 | begin |
||
297 | FKeyPressed := Key; |
||
298 | end; |
||
299 | |||
300 | function TKonsole.GetRect(): TKosRect; |
||
301 | var |
||
302 | ThreadInfo: TKosThreadInfo; |
||
303 | begin |
||
304 | kos_threadinfo(@ThreadInfo, FThreadSlot); |
||
305 | Result := ThreadInfo.WindowRect; |
||
306 | end; |
||
307 | |||
308 | function TKonsole.GetKeyPressed(): Word; |
||
309 | begin |
||
310 | Result := FKeyPressed; |
||
311 | FKeyPressed := 0; |
||
312 | end; |
||
313 | |||
314 | procedure TKonsole.Paint(BottomRow: Boolean); |
||
315 | var |
||
316 | Buffer: array[Byte] of Char; |
||
317 | Rect: TKosRect; |
||
318 | J: Longint; |
||
319 | Width, Height, Row: Longint; |
||
320 | CaptionHeight, BorderWidth, FontWidth, FontHeight: Longint; |
||
321 | begin |
||
322 | CaptionHeight := 16; |
||
323 | BorderWidth := 5; |
||
324 | FontWidth := 6; |
||
325 | FontHeight := 9; |
||
326 | |||
327 | kos_begindraw(); |
||
328 | |||
329 | if not BottomRow then |
||
330 | begin |
||
331 | {отрисовка окна} |
||
332 | kos_definewindow(60, 60, 400, 400, $63000000); |
||
333 | {вывод заголовка} |
||
334 | Move(FCaption[1], Buffer, Length(FCaption)); |
||
335 | Buffer[Length(FCaption)] := #0; |
||
336 | kos_setcaption(Buffer); |
||
337 | end; |
||
338 | |||
339 | {подготовка к выводу строк} |
||
340 | Rect := GetRect(); |
||
341 | Dec(Rect.Width, BorderWidth * 2); |
||
342 | Dec(Rect.Height, CaptionHeight + BorderWidth * 2); |
||
343 | Width := Rect.Width div FontWidth; |
||
344 | Height := Rect.Height - FontHeight; |
||
345 | Row := FCursor.Y; |
||
346 | |||
347 | while Height > 0 do |
||
348 | begin |
||
349 | {вывод одной строки} |
||
350 | J := Length(FLines[Row]); |
||
351 | if J > Width then J := Width; |
||
352 | kos_drawtext(0, Height, Copy(FLines[Row], 1, J), $00DD00, $FF000000); |
||
353 | {заливка оставшегося пространства в строке} |
||
354 | J := J * FontWidth; |
||
355 | kos_drawrect(J, Height, Rect.Width - J + 1, FontHeight, $000000); |
||
356 | {подготовка к выводу следующей строки} |
||
357 | Dec(Height, FontHeight); |
||
358 | Dec(Row); |
||
359 | if BottomRow or ((Row < 0) and (Length(FLines) < FMaxLines)) then Break; |
||
360 | while Row < 0 do Inc(Row, FMaxLines); |
||
361 | end; |
||
362 | if FCursor.X <= Width then |
||
363 | {отрисовка курсора} |
||
364 | kos_drawrect((FCursor.X - 1) * FontWidth, Rect.Height - 2, FontWidth, 2, $FFFFFF); |
||
365 | if not BottomRow then |
||
366 | {заливка оставшейся части окна} |
||
367 | kos_drawrect(0, 0, Rect.Width + 1, Height + FontHeight, $000000); |
||
368 | |||
369 | kos_enddraw(); |
||
370 | end; |
||
371 | |||
372 | procedure TKonsole.Write(Message: ShortString); |
||
373 | var |
||
374 | I: Integer; |
||
375 | begin |
||
376 | {XXX: возможна ситуация при которой сообщение не будет отправлено} |
||
377 | if FOpened then |
||
378 | begin |
||
619 | bw | 379 | I := 100; |
616 | bw | 380 | while (kos_sendmsg(FThreadID, @Message[1], Length(Message)) = 2) and (I > 0) do |
381 | begin |
||
382 | Dec(I); |
||
383 | ThreadSwitch; |
||
384 | end; |
||
385 | end; |
||
386 | end; |
||
666 | bw | 387 | |
388 | procedure TKonsole.Flush(); |
||
389 | begin |
||
390 | while FOnAir do ThreadSwitch; |
||
391 | end;=>>>>>>>>> |