1 /* This file pager demo illustrates the screen management and
2  * keyboard routines.
3  */
4 
5 #include <stdio.h>
6 #include <string.h>
7 
8 #include <stdlib.h>
9 
10 #include <signal.h>
11 
12 #ifdef unix
13 # include <unistd.h>
14 #endif
15 
16 #include <slang.h>
17 
18 #include "demolib.c"
19 
usage(char * pgm)20 static void usage (char *pgm)
21 {
22    fprintf (stderr, "Usage: %s [FILENAME]\n", pgm);
23    exit (1);
24 }
25 
26 static int read_file (char *);
27 static void main_loop (void);
28 
29 static char *File_Name;		       /* if NULL, use stdin */
30 
main(int argc,char ** argv)31 int main (int argc, char **argv)
32 {
33    if (argc == 2)
34      {
35 	File_Name = argv[1];
36      }
37    else if ((argc != 1) || (1 == isatty (fileno(stdin))))
38      usage (argv[0]);
39 
40    if (-1 == read_file (File_Name))
41      {
42 	fprintf (stderr, "Unable to read %s\n", File_Name);
43 	return 1;
44      }
45 
46    /* This sets up the terminal, signals, screen management routines, etc... */
47    if (-1 == demolib_init_terminal (1, 1))
48      {
49 	fprintf (stderr, "Unable to initialize terminal.");
50 	return 1;
51      }
52 
53 #define APP_KEY_EOB  0x1001
54 #define APP_KEY_BOB  0x1002
55 
56    /* Add a few application defined keysyms.  0x1000 and above are for
57     * applications.
58     */
59    (void) SLkp_define_keysym ("\033>", APP_KEY_EOB);
60    (void) SLkp_define_keysym ("\033<", APP_KEY_BOB);
61 
62    main_loop ();		       /* should not return */
63    return 1;
64 }
65 
66 /* The SLscroll routines will be used for pageup/down commands.  They assume
67  * a linked list of lines.  The first element of the structure MUST point to
68  * the NEXT line, the second MUST point to the PREVIOUS line.
69  */
70 typedef struct _File_Line_Type
71 {
72    struct _File_Line_Type *next;
73    struct _File_Line_Type *prev;
74    char *data;			       /* pointer to line data */
75 }
76 File_Line_Type;
77 
78 static File_Line_Type *File_Lines;
79 
80 /* The SLscroll routines will use this structure. */
81 static SLscroll_Window_Type Line_Window;
82 
free_lines(void)83 static void free_lines (void)
84 {
85    File_Line_Type *line, *next;
86 
87    line = File_Lines;
88    while (line != NULL)
89      {
90 	next = line->next;
91 	if (line->data != NULL) free (line->data);
92 	free (line);
93 	line = next;
94      }
95    File_Lines = NULL;
96 }
97 
create_line(char * buf)98 static File_Line_Type *create_line (char *buf)
99 {
100    File_Line_Type *line;
101 
102    line = (File_Line_Type *) malloc (sizeof (File_Line_Type));
103    if (line == NULL) return NULL;
104 
105    memset ((char *) line, 0, sizeof (File_Line_Type));
106 
107    line->data = SLmake_string (buf);   /* use a slang routine */
108    if (line->data == NULL)
109      {
110 	free (line);
111 	return NULL;
112      }
113 
114    return line;
115 }
116 
read_file(char * file)117 static int read_file (char *file)
118 {
119    FILE *fp;
120    char buf [1024];
121    File_Line_Type *line, *last_line;
122    unsigned int num_lines;
123 
124    if (file == NULL)
125      fp = stdin;
126    else fp = fopen (file, "r");
127 
128    if (fp == NULL) return -1;
129 
130    last_line = NULL;
131    num_lines = 0;
132 
133    while (NULL != fgets (buf, sizeof(buf), fp))
134      {
135 	num_lines++;
136 
137 	if (NULL == (line = create_line (buf)))
138 	  {
139 	     fprintf (stderr, "Out of memory.");
140 	     free_lines ();
141 	     return -1;
142 	  }
143 
144 	if (last_line == NULL)
145 	  File_Lines = line;
146 	else
147 	  last_line->next = line;
148 
149 	line->prev = last_line;
150 	line->next = NULL;
151 
152 	last_line = line;
153      }
154 
155    memset ((char *)&Line_Window, 0, sizeof (SLscroll_Window_Type));
156 
157    Line_Window.current_line = (SLscroll_Type *) File_Lines;
158    Line_Window.lines = (SLscroll_Type *) File_Lines;
159    Line_Window.line_num = 1;
160    Line_Window.num_lines = num_lines;
161    /* Line_Window.border = 3; */
162 
163    return 0;
164 }
165 
update_display(void)166 static void update_display (void)
167 {
168    unsigned int row, nrows;
169    File_Line_Type *line;
170 
171    /* All well behaved applications should block signals that may affect
172     * the display while performing screen update.
173     */
174    SLsig_block_signals ();
175 
176    Line_Window.nrows = nrows = SLtt_Screen_Rows - 1;
177 
178    /* Always make the current line equal to the top window line. */
179    if (Line_Window.top_window_line != NULL)
180      Line_Window.current_line = Line_Window.top_window_line;
181 
182    SLscroll_find_top (&Line_Window);
183 
184    row = 0;
185    line = (File_Line_Type *) Line_Window.top_window_line;
186 
187    SLsmg_normal_video ();
188 
189    while (row < Line_Window.nrows)
190      {
191 	SLsmg_gotorc (row, 0);
192 
193 	if (line != NULL)
194 	  {
195 	     SLsmg_write_string (line->data);
196 	     line = line->next;
197 	  }
198 	SLsmg_erase_eol ();
199 	row++;
200      }
201 
202    SLsmg_gotorc (row, 0);
203    SLsmg_reverse_video ();
204    SLsmg_printf ("%s | UTF-8 = %d",
205 		 (File_Name == NULL) ? "<stdin>" : File_Name,
206 		 SLutf8_is_utf8_mode ());
207    SLsmg_erase_eol ();
208    SLsmg_refresh ();
209 
210    SLsig_unblock_signals ();
211 }
212 
213 static int Screen_Start;
214 
main_loop(void)215 static void main_loop (void)
216 {
217    int screen_start;
218 
219    while (1)
220      {
221 	update_display ();
222 	switch (SLkp_getkey ())
223 	  {
224 	   case SL_KEY_ERR:
225 	   case 'q':
226 	   case 'Q':
227 	     demolib_exit (0);
228 	     break;
229 
230 	   case SL_KEY_RIGHT:
231 	     Screen_Start += 1;
232 	     screen_start = Screen_Start;
233 	     SLsmg_set_screen_start (NULL, &screen_start);
234 	     break;
235 
236 	   case SL_KEY_LEFT:
237 	     Screen_Start -= 1;
238 	     if (Screen_Start < 0) Screen_Start = 0;
239 	     screen_start = Screen_Start;
240 	     SLsmg_set_screen_start (NULL, &screen_start);
241 	     break;
242 
243 	   case SL_KEY_UP:
244 	     SLscroll_prev_n (&Line_Window, 1);
245 	     Line_Window.top_window_line = Line_Window.current_line;
246 	     break;
247 
248 	   case '\r':
249 	   case SL_KEY_DOWN:
250 	     SLscroll_next_n (&Line_Window, 1);
251 	     Line_Window.top_window_line = Line_Window.current_line;
252 	     break;
253 
254 	   case SL_KEY_NPAGE:
255 	   case ' ': case 4:
256 	     SLscroll_pagedown (&Line_Window);
257 	     break;
258 
259 	   case SL_KEY_PPAGE:
260 	   case 127: case 21:
261 	     SLscroll_pageup (&Line_Window);
262 	     break;
263 
264 	   case APP_KEY_BOB:
265 	     while (-1 != SLscroll_pageup (&Line_Window))
266 	       ;
267 	     break;
268 
269 	   case APP_KEY_EOB:
270 	     while (-1 != SLscroll_pagedown (&Line_Window))
271 	       ;
272 	     break;
273 
274 	   default:
275 	     SLtt_beep ();
276 	  }
277      }
278 }
279