Usermode - Starting on a text editor
[tpg/acess2.git] / Usermode / Applications / edit_src / main.c
1 /*\r
2  * Acess2 Text Editor\r
3  */\r
4 #if !USE_LOCAL\r
5 # include <acess/sys.h> // Needed for IOCtl\r
6 #endif\r
7 #include <stdlib.h>\r
8 #include <stdio.h>\r
9 #include <stdint.h>\r
10 #include <string.h>\r
11 #include <signal.h>\r
12 #include <unistd.h>\r
13 #if USE_LOCAL\r
14 # include <sys/ioctl.h>\r
15 # include <termios.h>\r
16 #else\r
17 # include <acess/devices/terminal.h>\r
18 #endif\r
19 \r
20 #define MAX_FILES_OPEN  1\r
21 \r
22 // === TYPES ===\r
23 typedef struct\r
24 {\r
25         const char      *Filename;\r
26         char    **LineBuffer;\r
27          int    FileSize;\r
28          int    LineCount;\r
29          \r
30          int    FirstLine;\r
31          int    CurrentLine;    //!< Currently selected line\r
32          int    CurrentPos;     //!< Position in that line\r
33 }       tFile;\r
34 \r
35 // === PROTOTYPES ===\r
36 void    SigINT_Handler(int Signum);\r
37 void    ExitHandler(void);\r
38  int    main(int argc, char *argv[]);\r
39  int    OpenFile(tFile *Dest, const char *Path);\r
40 void    UpdateDisplayFull(void);\r
41 void    UpdateDisplayLine(int LineNum);\r
42 void    UpdateDisplayStatus(void);\r
43 \r
44 void    CursorUp(tFile *File);\r
45 void    CursorDown(tFile *File);\r
46 void    CursorRight(tFile *File);\r
47 void    CursorLeft(tFile *File);\r
48 \r
49 void    Term_SetPos(int Row, int Col);\r
50 \r
51 // === GLOBALS ===\r
52  int    giProgramState = 0;\r
53 tFile   gaFiles[MAX_FILES_OPEN];\r
54 tFile   *gpCurrentFile;\r
55 #if USE_LOCAL\r
56 struct termios  gOldTermios;\r
57 #endif\r
58  int    giTerminal_Width = 80;\r
59  int    giTerminal_Height = 25;\r
60 \r
61 // === CODE ===\r
62 void SigINT_Handler(int Signum)\r
63 {\r
64         exit(55);\r
65 }\r
66 \r
67 void ExitHandler(void)\r
68 {\r
69         #if USE_LOCAL\r
70         tcsetattr(0, TCSANOW, &gOldTermios);\r
71         #endif\r
72         printf("\x1B[?1047l");\r
73 }\r
74 \r
75 /**\r
76  * \fn int main(int argc, char *argv[])\r
77  * \brief Entrypoint\r
78  */\r
79 int main(int argc, char *argv[])\r
80 {\r
81         \r
82         if(argc < 2) {\r
83                 printf("Usage: edit <file>\n");\r
84                 return -1;\r
85         }\r
86 \r
87         if( OpenFile(&gaFiles[0], argv[1]) ) {\r
88                 return -1;\r
89         }\r
90         \r
91         signal(SIGINT, SigINT_Handler);\r
92         atexit(ExitHandler);\r
93 \r
94         // Disable input buffering\r
95         #if USE_LOCAL\r
96         {\r
97                 struct termios  term;\r
98                 tcgetattr(0, &gOldTermios);\r
99                 term = gOldTermios;\r
100                 term.c_lflag &= ~(ICANON|ECHO);\r
101                 tcsetattr(0, TCSANOW, &term);\r
102                 //setbuf(stdin, NULL);\r
103         }\r
104         #endif\r
105         \r
106         // Go to alternte screen buffer\r
107         printf("\x1B[?1047h");\r
108         \r
109         gpCurrentFile = &gaFiles[0];\r
110         \r
111         UpdateDisplayFull();\r
112         \r
113         giProgramState = 1;\r
114         \r
115         while(giProgramState)\r
116         {\r
117                 char    ch = 0;\r
118                 \r
119                 read(0, &ch, 1);\r
120                 \r
121                 if(ch == '\x1B')\r
122                 {\r
123                         read(0, &ch, 1);\r
124                         switch(ch)\r
125                         {\r
126                         case 'A':       CursorUp(gpCurrentFile);        break;\r
127                         case 'B':       CursorDown(gpCurrentFile);      break;\r
128                         case 'C':       CursorRight(gpCurrentFile);     break;\r
129                         case 'D':       CursorLeft(gpCurrentFile);      break;\r
130                         \r
131                         case '[':\r
132                                 read(0, &ch, 1);\r
133                                 switch(ch)\r
134                                 {\r
135                                 case 'A':       CursorUp(gpCurrentFile);        break;\r
136                                 case 'B':       CursorDown(gpCurrentFile);      break;\r
137                                 case 'C':       CursorRight(gpCurrentFile);     break;\r
138                                 case 'D':       CursorLeft(gpCurrentFile);      break;\r
139                                 default:\r
140                                         printf("ch (\\x1B[) = %x\r", ch);\r
141                                         fflush(stdout);\r
142                                         break;\r
143                                 }\r
144                                 break;\r
145                         \r
146                         default:\r
147                                 printf("ch (\\x1B) = %x\r", ch);\r
148                                 fflush(stdout);\r
149                                 break;\r
150                         }\r
151                         // TODO: Move\r
152                 }\r
153                 \r
154                 switch(ch)\r
155                 {\r
156                 case 'q':\r
157                         giProgramState = 0;\r
158                         break;\r
159                 }\r
160         }\r
161 \r
162         return 0;\r
163 }\r
164 \r
165 int OpenFile(tFile *Dest, const char *Path)\r
166 {\r
167         FILE    *fp;\r
168         char    *buffer;\r
169          int    i, j;\r
170          int    start;\r
171         \r
172         fp = fopen(Path, "r");\r
173         if(!fp) {\r
174                 fprintf(stderr, "Unable to open %s\n", Path);\r
175                 return -1;\r
176         }\r
177         \r
178         Dest->Filename = Path;\r
179         \r
180         fseek(fp, 0, SEEK_END);\r
181         Dest->FileSize = ftell(fp);\r
182         fseek(fp, 0, SEEK_SET);\r
183         \r
184         buffer = malloc(Dest->FileSize+1);\r
185         fread(buffer, Dest->FileSize, 1, fp);\r
186         fclose(fp);\r
187         buffer[Dest->FileSize] = '\0';\r
188         \r
189         Dest->LineCount = 1;\r
190         for( i = 0; i < Dest->FileSize; i ++ )\r
191         {\r
192                 if( buffer[i] == '\n' )\r
193                         Dest->LineCount ++;\r
194         }\r
195         \r
196         Dest->LineBuffer = malloc( Dest->LineCount * sizeof(char*) );\r
197         start = 0;\r
198         j = 0;\r
199         for( i = 0; i < Dest->FileSize; i ++ )\r
200         {\r
201                 if( buffer[i] == '\n' )\r
202                 {\r
203                         buffer[i] = '\0';\r
204                         Dest->LineBuffer[j] = strdup( &buffer[start] );\r
205                         start = i+1;\r
206                         j ++;\r
207                 }\r
208         }\r
209         Dest->LineBuffer[j] = strdup( &buffer[start] );\r
210         \r
211         free(buffer);\r
212         \r
213         Dest->FirstLine = 0;\r
214         Dest->CurrentLine = 0;\r
215         Dest->CurrentPos = 0;\r
216         \r
217         return 0;\r
218 }\r
219 \r
220 void ShowLine(tFile *File, int LineNum, int X, int Y, int W)\r
221 {\r
222          int    j, k;\r
223         char    *line;\r
224         \r
225         line = File->LineBuffer[LineNum];\r
226         printf("%6i  ", LineNum+1);\r
227         j = 8;\r
228         for( k = 0; j < W-1 && line[k]; j++, k++ )\r
229         {\r
230                 switch( line[k] )\r
231                 {\r
232                 case '\t':\r
233                         printf("\t");\r
234                         j += 8;\r
235                         j &= ~7;\r
236                         break;\r
237                 default:\r
238                         if( line[k] < ' ' || line[k] >= 0x7F )  continue;\r
239                         printf("%c", line[k]);\r
240                         break;\r
241                 }\r
242         }\r
243         \r
244         for( ; j < W-1; j++ )\r
245                 printf(" ");\r
246         printf("\n");\r
247 }\r
248 \r
249 void ShowFile(tFile *File, int X, int Y, int W, int H)\r
250 {\r
251          int    i;\r
252         Term_SetPos(Y, X);\r
253         \r
254         for( i = 0; i < H; i ++ )\r
255         {\r
256                 if( File->FirstLine + i >= File->LineCount )    break;\r
257                 ShowLine( File, File->FirstLine + i, X, Y + i, W );\r
258         }\r
259         for( ; i < H; i++ )\r
260                 printf("\n");\r
261 }\r
262 \r
263 void UpdateDisplayFull(void)\r
264 {\r
265         #if USE_LOCAL\r
266         {\r
267                 struct winsize ws;\r
268                 ioctl(0, TIOCGWINSZ, &ws);\r
269                 giTerminal_Width = ws.ws_col;\r
270                 giTerminal_Height = ws.ws_row;\r
271         }\r
272         #else\r
273         giTerminal_Width = ioctl(1, TERM_IOCTL_WIDTH, NULL);\r
274         giTerminal_Height = ioctl(1, TERM_IOCTL_HEIGHT, NULL);\r
275         #endif\r
276         \r
277         printf("\x1B[2J");\r
278         \r
279         ShowFile(gpCurrentFile, 0, 0, giTerminal_Width, giTerminal_Height - 1);\r
280         \r
281         \r
282         // Status Line\r
283         UpdateDisplayStatus();\r
284         \r
285         Term_SetPos(\r
286                 gpCurrentFile->CurrentLine-gpCurrentFile->FirstLine,\r
287                 8 + gpCurrentFile->CurrentPos\r
288                 );\r
289         fflush(stdout);\r
290 }\r
291 \r
292 void UpdateDisplayLine(int Line)\r
293 {\r
294         ShowLine(\r
295                 gpCurrentFile, Line,\r
296                 0, Line - gpCurrentFile->FirstLine,\r
297                 giTerminal_Width );\r
298 }\r
299 \r
300 void UpdateDisplayStatus(void)\r
301 {\r
302         int lastLine = gpCurrentFile->FirstLine + giTerminal_Height - 1;\r
303         \r
304         if( lastLine > gpCurrentFile->LineCount )\r
305                 lastLine = gpCurrentFile->LineCount;\r
306         \r
307         printf("--- Line %i/%i (showing %i to %i)",\r
308                 gpCurrentFile->CurrentLine + 1, gpCurrentFile->LineCount,\r
309                 gpCurrentFile->FirstLine, lastLine);\r
310 }\r
311 \r
312 void CursorUp(tFile *File)\r
313 {\r
314         if( File->CurrentLine > 0 )\r
315         {\r
316                 File->CurrentLine --;\r
317                 if( File->FirstLine > File->CurrentLine )\r
318                 {\r
319                         File->FirstLine = File->CurrentLine;\r
320                         UpdateDisplayFull();\r
321                 }\r
322                 else\r
323                 {\r
324                         UpdateDisplayLine(File->CurrentLine + 1);\r
325                         UpdateDisplayLine(File->CurrentLine);\r
326                         UpdateDisplayStatus();\r
327                 }\r
328         }\r
329 }\r
330 \r
331 void CursorDown(tFile *File)\r
332 {\r
333         if( File->CurrentLine+1 < File->LineCount )\r
334         {\r
335                 File->CurrentLine ++;\r
336                 if( File->FirstLine < File->CurrentLine - (giTerminal_Height-2) )\r
337                 {\r
338                         File->FirstLine = File->CurrentLine - (giTerminal_Height-2);\r
339                         UpdateDisplayFull();\r
340                 }\r
341                 else\r
342                 {\r
343                         UpdateDisplayLine(File->CurrentLine - 1);\r
344                         UpdateDisplayLine(File->CurrentLine);\r
345                         UpdateDisplayStatus();\r
346                 }\r
347         }\r
348 }\r
349 \r
350 void CursorRight(tFile *File)\r
351 {\r
352         if( File->CurrentPos > 0 )\r
353         {\r
354                 File->CurrentPos --;\r
355                 UpdateDisplayLine(File->CurrentLine);\r
356                 UpdateDisplayStatus();\r
357         }\r
358 }\r
359 \r
360 void CursorLeft(tFile *File)\r
361 {\r
362         if( File->LineBuffer[File->CurrentLine][File->CurrentPos+1] )\r
363         {\r
364                 File->CurrentPos --;\r
365                 UpdateDisplayLine(File->CurrentLine);\r
366                 UpdateDisplayStatus();\r
367         }\r
368 }\r
369 \r
370 void Term_SetPos(int Row, int Col)\r
371 {\r
372         printf("\x1B[%i;%iH", Row+1, Col+1);    // Set cursor\r
373         fflush(stdout);\r
374 }\r

UCC git Repository :: git.ucc.asn.au