1 #include <errno.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <notcurses/notcurses.h>
5 #include "lib/internal.h" // internal headers
6 
7 static inline wchar_t
capboolbool(unsigned utf8,bool cap)8 capboolbool(unsigned utf8, bool cap){
9   // FIXME these fancy glyphs aren't reliable enough yet (they're not
10   // usually present on the linux console, for instance) for such an
11   // essential, must-work-everywhere tool.
12   /*if(utf8){
13     return cap ? L'✓' : L'✖';
14   }else{
15     return cap ? '+' : '-';
16   }*/
17   (void)utf8;
18   return cap ? '+' : '-';
19 }
20 
21 static void
tinfo_debug_cap(struct ncplane * n,const char * name,bool yn)22 tinfo_debug_cap(struct ncplane* n, const char* name, bool yn){
23   if(!yn){
24     ncplane_set_styles(n, NCSTYLE_ITALIC);
25   }
26   ncplane_putstr(n, name);
27   ncplane_set_styles(n, NCSTYLE_BOLD);
28   ncplane_putwc(n, capboolbool(notcurses_canutf8(ncplane_notcurses(n)), yn));
29   ncplane_set_styles(n, NCSTYLE_NONE);
30   ncplane_putchar(n, ' ');
31 }
32 
33 static void
tinfo_debug_style(struct ncplane * n,const char * name,int style,char ch)34 tinfo_debug_style(struct ncplane* n, const char* name, int style, char ch){
35   unsigned support = notcurses_supported_styles(ncplane_notcurses(n)) & style;
36   if(!support){
37     ncplane_set_styles(n, NCSTYLE_ITALIC);
38   }
39   ncplane_set_styles(n, style);
40   ncplane_putstr(n, name);
41   ncplane_set_styles(n, NCSTYLE_BOLD);
42   ncplane_putwc(n, capboolbool(notcurses_canutf8(ncplane_notcurses(n)), support));
43   ncplane_set_styles(n, NCSTYLE_NONE);
44   ncplane_putchar(n, ch);
45 }
46 
47 static void
wviz(struct ncplane * n,const wchar_t * wp)48 wviz(struct ncplane* n, const wchar_t* wp){
49   unsigned wchars;
50   for(const wchar_t* w = wp ; *w ; w += wchars){
51     if(ncplane_putwc_utf32(n, w, &wchars) <= 0){
52       ncplane_putchar(n, ' ');
53     }
54   }
55 }
56 
57 static void
wvizn(struct ncplane * n,const wchar_t * wp,int nnn)58 wvizn(struct ncplane* n, const wchar_t* wp, int nnn){
59   for(int nn = 0 ; nn < nnn ; ++nn){
60     if(ncplane_putwc(n, wp[nn]) <= 0){
61       ncplane_putchar(n, ' ');
62     }
63   }
64 }
65 
66 static int
braille_viz(struct ncplane * n,wchar_t l,const wchar_t * egcs,wchar_t r,const char * indent,const wchar_t * bounds,wchar_t r8,wchar_t l8,const wchar_t * trailer)67 braille_viz(struct ncplane* n, wchar_t l, const wchar_t* egcs, wchar_t r,
68             const char* indent, const wchar_t* bounds, wchar_t r8, wchar_t l8,
69             const wchar_t* trailer){
70   ncplane_printf(n, "%s%lc", indent, l);
71   for(int i = 0 ; i < 64 ; ++i){
72     if(ncplane_putwc(n, egcs[i]) <= 0){
73       ncplane_putchar(n, ' ');
74     }
75   }
76   ncplane_putwc(n, r);
77   ncplane_putwc(n, bounds[0]);
78   if(ncplane_putwc(n, r8) <= 0){
79     ncplane_putchar(n, ' ');
80   }
81   if(ncplane_putwc(n, l8) <= 0){
82     ncplane_putchar(n, ' ');
83   }
84   ncplane_putwc(n, bounds[1]);
85   if(trailer){
86     wviz(n, trailer);
87   }
88   if(ncplane_dim_x(n) > 80){
89     ncplane_putchar(n, '\n');
90   }
91   return 0;
92 }
93 
94 static void
finish_line(struct ncplane * n)95 finish_line(struct ncplane* n){
96   unsigned x;
97   ncplane_cursor_yx(n, NULL, &x);
98   while(x++ < 80){
99     ncplane_putchar(n, ' ');
100   }
101   if(ncplane_dim_x(n) > 80){
102     ncplane_putchar(n, '\n');
103   }
104 }
105 
106 static int
emoji_viz(struct ncplane * n)107 emoji_viz(struct ncplane* n){
108   static const char emoji[] = "\U0001f47e" // alien monster
109                               "\U0001f3f4" // waving black flag
110                               "\U0001f918" // sign of the horns
111                               "\U0001f6ac" // cigarette, delicious
112                               "\U0001f30d" // globe europe/africa
113                               "\U0001f30e" // globe americas
114                               "\U0001f30f" // globe asia/australia
115                               "\U0001F946" // rifle
116                               "\U0001f4a3" // bomb
117                               "\U0001f5e1" // dagger
118                               "\U0001F52B" // pistol
119                               "\u2697\ufe0f" // alembic
120                               "\u269b\ufe0f" // atom
121                               "\u2622\ufe0f" // radiation sign
122                               "\u2623\ufe0f" // biohazard
123                               "\U0001F33F" // herb
124                               "\U0001F3B1" // billiards
125                               "\U0001F3E7" // automated teller machine
126                               "\U0001F489" // syringe
127                               "\U0001F48A" // pill
128                               "\U0001f574\ufe0f" // man in suit levitating
129                               "\U0001F4E1" // satellite antenna
130                               "\U0001F93B" // modern pentathlon
131                               "\U0001F991" // squid
132                               "\U0001f1e6\U0001f1f6" // regional indicators AQ (antarctica)
133                               "\U0001f469\u200d\U0001f52c" // woman scientist
134                               "\U0001faa4" // mouse trap
135                               "\U0001f6b1" // non-potable water
136                               "\u270a\U0001f3ff" // type-6 raised fist
137                               "\U0001f52c" // microscope
138                               "\U0001f9ec" // dna double helix
139                               "\U0001f3f4\u200d\u2620\ufe0f" // pirate flag
140                               "\U0001f93d\U0001f3fc\u200d\u2640\ufe0f" // type-3 woman playing water polo
141                               ;
142   ncplane_set_bg_rgb(n, 0);
143   size_t bytes;
144   for(const char* e = emoji ; *e ; e += bytes){
145     if(ncplane_putegc(n, e, &bytes) < 0){
146       if(ncplane_putchar(n, ' ') < 0){
147         break;
148       }
149     }
150   }
151   unsigned x;
152   ncplane_cursor_yx(n, NULL, &x);
153   while(x++ < 80){
154     ncplane_putchar(n, ' ');
155   }
156   if(ncplane_dim_x(n) > 80){
157     ncplane_putchar(n, '\n');
158   }
159   return 0;
160 }
161 
162 // symbols for legacy computing
163 static int
legacy_viz(struct ncplane * n,const char * indent,const wchar_t * eighths,const wchar_t * anglesr,const wchar_t * anglesl)164 legacy_viz(struct ncplane* n, const char* indent, const wchar_t* eighths,
165            const wchar_t* anglesr, const wchar_t* anglesl){
166   ncplane_printf(n, "%s ", indent);
167   unsigned wchars;
168   for(const wchar_t* e = eighths ; *e ; e += wchars){
169     if(ncplane_putwc_utf32(n, e, &wchars) <= 0){
170       ncplane_putchar(n, ' ');
171     }
172   }
173   ncplane_putchar(n, ' ');
174   const wchar_t* r = anglesr;
175   const wchar_t* l = anglesl;
176   while(*r){
177     if(ncplane_putwc_utf32(n, r, &wchars) <= 0){
178       ncplane_putchar(n, ' ');
179     }
180     r += wchars;
181     if(ncplane_putwc_utf32(n, l, &wchars) <= 0){
182       ncplane_putchar(n, ' ');
183     }
184     l += wchars;
185     ncplane_putchar(n, ' ');
186   }
187   return 0;
188 }
189 
190 static int
sex_viz(struct ncplane * n,const wchar_t * sex,wchar_t r,const wchar_t * post)191 sex_viz(struct ncplane* n, const wchar_t* sex, wchar_t r, const wchar_t* post){
192   for(int i = 0 ; i < 31 ; ++i){
193     if(ncplane_putwc(n, sex[i]) <= 0){
194       ncplane_putchar(n, ' ');
195     }
196   }
197   if(ncplane_putwc(n, r) <= 0){
198     ncplane_putchar(n, ' ');
199   }
200   unsigned wchars = 0;
201   for(const wchar_t* p = post ; *p ; p += wchars){
202     if(ncplane_putwc_utf32(n, p, &wchars) <= 0){
203       ncplane_putchar(n, ' ');
204     }
205   }
206   return 0;
207 }
208 
209 static void
triviz(struct ncplane * n,const wchar_t * w1,const wchar_t * w2,const wchar_t * w3,const wchar_t * w4,const wchar_t * w5,const wchar_t * w6,const wchar_t * w7,const wchar_t * w8,const wchar_t * w9,const wchar_t * wa,const wchar_t * wb,const wchar_t * wc,const wchar_t * wd,const wchar_t * we,const wchar_t * wf,const wchar_t * w10,const wchar_t * w11,const wchar_t * w12,const wchar_t * w13,const wchar_t * w14,const wchar_t * w15)210 triviz(struct ncplane* n, const wchar_t* w1, const wchar_t* w2, const wchar_t* w3,
211        const wchar_t* w4, const wchar_t* w5, const wchar_t* w6,
212        const wchar_t* w7, const wchar_t* w8, const wchar_t* w9,
213        const wchar_t* wa, const wchar_t* wb, const wchar_t* wc,
214        const wchar_t* wd, const wchar_t* we, const wchar_t* wf,
215        const wchar_t* w10, const wchar_t* w11, const wchar_t* w12,
216        const wchar_t* w13, const wchar_t* w14, const wchar_t* w15){
217   wvizn(n, w1, 2);
218   ncplane_putchar(n, ' ');
219   wvizn(n, w2, 2);
220   ncplane_putchar(n, ' ');
221   wvizn(n, w3, 2);
222   ncplane_putchar(n, ' ');
223   wvizn(n, w4, 2);
224   wvizn(n, w5, 2);
225   ncplane_putchar(n, ' ');
226   wvizn(n, w6, 2);
227   ncplane_putchar(n, ' ');
228   wvizn(n, w7, 2);
229   ncplane_putchar(n, ' ');
230   wvizn(n, w8, 2);
231   ncplane_putchar(n, ' ');
232   wvizn(n, w9, 2);
233   wvizn(n, wa, 1);
234   ncplane_putchar(n, ' ');
235   wvizn(n, wb, 2);
236   wvizn(n, wc, 1);
237   ncplane_putchar(n, ' ');
238   wvizn(n, wd, 2);
239   wvizn(n, we, 1);
240   ncplane_putchar(n, ' ');
241   wvizn(n, wf, 2);
242   wvizn(n, w10, 1);
243   ncplane_putchar(n, ' ');
244   wvizn(n, w11, 2);
245   wvizn(n, w12, 1);
246   wvizn(n, w13, 3); // chess
247   wviz(n, w14);
248   wviz(n, w15);
249 }
250 
251 static void
vertviz(struct ncplane * n,wchar_t l,wchar_t li,wchar_t ri,wchar_t r,const wchar_t * trail)252 vertviz(struct ncplane* n, wchar_t l, wchar_t li, wchar_t ri, wchar_t r,
253         const wchar_t* trail){
254   if(ncplane_putwc(n, l) <= 0){
255     ncplane_putchar(n, ' ');
256   }
257   if(ncplane_putwc(n, li) <= 0){
258     ncplane_putchar(n, ' ');
259   }
260   if(ncplane_putwc(n, ri) <= 0){
261     ncplane_putchar(n, ' ');
262   }
263   if(ncplane_putwc(n, r) <= 0){
264     ncplane_putchar(n, ' ');
265   }
266   wviz(n, trail);
267   if(ncplane_dim_x(n) > 80){
268     ncplane_putchar(n, '\n');
269   }
270 }
271 
272 static int
unicodedumper(struct ncplane * n,const char * indent)273 unicodedumper(struct ncplane* n, const char* indent){
274   if(notcurses_canutf8(ncplane_notcurses_const(n))){
275     // all NCHALFBLOCKS are contained within NCQUADBLOCKS
276     ncplane_printf(n, "%s%ls⎧", indent, NCQUADBLOCKS);
277     // �������������������� (on Windows, these will be encoded as UTF-16 surrogate
278     // pairs due to a 16-bit wchar_t.
279     sex_viz(n, NCSEXBLOCKS, L'⎫', L"♠♥" NCSEGDIGITS L"\u2157\u2158\u2159\u215a\u215b");
280     vertviz(n, L'⎧', NCEIGHTHSR[0], NCEIGHTHSL[0], L'⎫', L"┌╥─╥─╥┐��⎛⎞");
281     ncplane_printf(n, "%s╲╿╱ ◨◧ ◪◩ ◖◗ ⫷⫸ ⎩", indent);
282     sex_viz(n, &NCSEXBLOCKS[32], L'⎭', L"♦♣\u00bc\u00bd\u00be\u2150\u2151\u2152\u2153\u2154\u2155\u2156\u215c\u215d\u215e\u215f\u2189");
283     vertviz(n, L'⎪', NCEIGHTHSR[1], NCEIGHTHSL[1], L'⎪', L"├╜╓╫╖╙┤��⎜⎟");
284     ncplane_printf(n, "%s╾╳╼ ", indent);
285     triviz(n, NCWHITESQUARESW, NCWHITECIRCLESW, NCDIAGONALSW, &NCDIAGONALSW[4],
286            NCCIRCULARARCSW, NCWHITETRIANGLESW, NCSHADETRIANGLESW, NCBLACKTRIANGLESW,
287            NCBOXLIGHTW, &NCBOXLIGHTW[4], NCBOXHEAVYW, &NCBOXHEAVYW[4], NCBOXROUNDW,
288            &NCBOXROUNDW[4], NCBOXDOUBLEW, &NCBOXDOUBLEW[4], NCBOXOUTERW, &NCBOXOUTERW[4],
289            NCCHESSBLACK, L"⩘▵△▹▷▿▽◃◁", NCARROWW);
290     vertviz(n, L'⎪', NCEIGHTHSR[2], NCEIGHTHSL[2], L'⎪', L"├─╨╫╨─┤┇⎜⎟");
291     ncplane_printf(n, "%s╱╽╲ ", indent);
292     triviz(n, &NCWHITESQUARESW[2], &NCWHITECIRCLESW[2], &NCDIAGONALSW[2], &NCDIAGONALSW[6],
293            &NCCIRCULARARCSW[2], &NCWHITETRIANGLESW[2], &NCSHADETRIANGLESW[2], &NCBLACKTRIANGLESW[2],
294            &NCBOXLIGHTW[2], &NCBOXLIGHTW[5], &NCBOXHEAVYW[2], &NCBOXHEAVYW[5], &NCBOXROUNDW[2],
295            &NCBOXROUNDW[5], &NCBOXDOUBLEW[2], &NCBOXDOUBLEW[5], &NCBOXOUTERW[2], &NCBOXOUTERW[5],
296            &NCCHESSBLACK[3], L"⩗▴⏶⯅▲▸⏵⯈▶", L"▾⏷⯆▼◂⏴⯇◀");
297     vertviz(n, L'⎪', NCEIGHTHSR[3], NCEIGHTHSL[3], L'⎪', L"╞═╤╬╤═╡┋⎜⎟");
298     braille_viz(n, L'⎡', NCBRAILLEEGCS, L'⎤', indent, L"⎨⎬", NCEIGHTHSR[4], NCEIGHTHSL[4],
299                 L"╞╕╘╬╛╒╡┊⎜⎟");
300     braille_viz(n, L'⎢', &NCBRAILLEEGCS[64], L'⎥', indent, L"⎪⎪", NCEIGHTHSR[5], NCEIGHTHSL[5],
301                 L"└┴─╨─┴┘╏⎝⎠");
302     braille_viz(n, L'⎢', &NCBRAILLEEGCS[128], L'⎥', indent, L"⎪⎪", NCEIGHTHSR[6], NCEIGHTHSL[6],
303                 L"╭──╮⟬⟭╔╗≶≷");
304     braille_viz(n, L'⎣', &NCBRAILLEEGCS[192], L'⎦', indent, L"⎪⎪", NCEIGHTHSR[7], NCEIGHTHSL[7],
305                 L"│╭╮│╔═╝║⊆⊇");
306     legacy_viz(n, indent, L"▔������������▁", NCANGLESBR, NCANGLESBL);
307     wviz(n, NCDIGITSSUBW);
308     wviz(n, L" ⎛");
309     wviz(n, NCEIGHTHSB);
310     // ��⎞⎪����⎪╰╯││║╔═╝⊴⊵
311     wviz(n, L"\U0001FB6B\u239e⎪����⎪╰╯││║╔═╝⊴⊵");
312     if(ncplane_dim_x(n) > 80){
313       ncplane_putchar(n, '\n');
314     }
315     legacy_viz(n, indent, L"▏������������▕", NCANGLESTR, NCANGLESTL);
316     wviz(n, NCDIGITSSUPERW);
317     wviz(n, L" ⎝");
318     wviz(n, NCEIGHTHST);
319     // ��⎠⎩����⎭⧒⧑╰╯╚╝❨❩⟃⟄
320     wviz(n, L"\U0001FB69\u23a0⎩����⎭⧒⧑╰╯╚╝❨❩⟃⟄");
321     if(ncplane_dim_x(n) > 80){
322       ncplane_putchar(n, '\n');
323     }
324     emoji_viz(n);
325     unsigned y, x;
326     ncplane_cursor_yx(n, &y, &x);
327     uint64_t ur = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x1B, 0xd8, 0x8E);
328     uint64_t lr = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0xdB, 0x18, 0x8E);
329     uint64_t ul = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x19, 0x19, 0x70);
330     uint64_t ll = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x19, 0x19, 0x70);
331     ncplane_stain(n, y - 16, 0, 16, 80, ul, ur, ll, lr);
332     ncplane_set_styles(n, NCSTYLE_BOLD | NCSTYLE_ITALIC);
333     ncplane_cursor_move_yx(n, y - 12, 54);
334     wviz(n, L"������https://notcurses.com");
335     ncplane_set_styles(n, NCSTYLE_NONE);
336   }
337   return 0;
338 }
339 
340 static int
display_logo(struct ncplane * n,const char * path)341 display_logo(struct ncplane* n, const char* path){
342   unsigned cpixy, cpixx;
343   ncplane_pixel_geom(n, NULL, NULL, &cpixy, &cpixx, NULL, NULL);
344   struct ncvisual* ncv = ncvisual_from_file(path);
345   if(ncv == NULL){
346     return -1;
347   }
348   if(ncvisual_resize(ncv, 3 * cpixy, 24 * cpixx)){
349     ncvisual_destroy(ncv);
350     return -1;
351   }
352   unsigned y;
353   ncplane_cursor_yx(n, &y, NULL);
354   struct ncvisual_options vopts = {
355     .n = n,
356     .y = y - 3,
357     .x = 54,
358     .blitter = NCBLIT_PIXEL,
359     .flags = NCVISUAL_OPTION_CHILDPLANE | NCVISUAL_OPTION_NODEGRADE,
360   };
361   struct ncplane* bitm = ncvisual_blit(ncplane_notcurses(n), ncv, &vopts);
362   if(bitm == NULL){
363     ncvisual_destroy(ncv);
364     return -1;
365   }
366   ncvisual_destroy(ncv);
367   return 0;
368 }
369 
370 static void
tinfo_debug_bitmaps(struct ncplane * n,const tinfo * ti,const char * indent)371 tinfo_debug_bitmaps(struct ncplane* n, const tinfo* ti, const char* indent){
372   uint32_t fg = 0;
373   int r = notcurses_default_foreground(ncplane_notcurses(n), &fg);
374   if(r){
375     ncplane_printf(n, "%sno known default fg ", indent);
376   }else{
377     ncplane_printf(n, "%sdefault fg 0x%06x ", indent, fg);
378   }
379   uint32_t bg = 0;
380   r = notcurses_default_background(ncplane_notcurses(n), &bg);
381   if(r){
382     ncplane_printf(n, "no known default bg");
383   }else{
384     ncplane_printf(n, "default bg 0x%06x", bg);
385   }
386   finish_line(n);
387   ncpixelimpl_e blit = notcurses_check_pixel_support(ncplane_notcurses(n));
388   switch(blit){
389     case NCPIXEL_NONE:
390       ncplane_printf(n, "%sno bitmap graphics detected", indent);
391       break;
392     case NCPIXEL_SIXEL:
393       if(ti->sixel_maxy){
394         ncplane_printf(n, "%smax sixel size: %dx%d colorregs: %u",
395                       indent, ti->sixel_maxy, ti->sixel_maxx, ti->color_registers);
396       }else{
397         ncplane_printf(n, "%ssixel colorregs: %u", indent, ti->color_registers);
398       }
399       break;
400     case NCPIXEL_LINUXFB:
401       ncplane_printf(n, "%sframebuffer graphics supported", indent);
402       break;
403     case NCPIXEL_ITERM2:
404       ncplane_printf(n, "%siTerm2 graphics supported", indent);
405       break;
406     case NCPIXEL_KITTY_STATIC:
407       ncplane_printf(n, "%srgba pixel graphics support", indent);
408       break;
409     case NCPIXEL_KITTY_ANIMATED:
410       ncplane_printf(n, "%s1st gen rgba pixel animation support", indent);
411       break;
412     case NCPIXEL_KITTY_SELFREF:
413       ncplane_printf(n, "%s2nd gen rgba pixel animation support", indent);
414       break;
415   }
416   finish_line(n);
417 }
418 
419 static void
tinfo_debug_caps(struct ncplane * n,const tinfo * ti,const char * indent)420 tinfo_debug_caps(struct ncplane* n, const tinfo* ti, const char* indent){
421   ncplane_printf(n, "%s", indent);
422   tinfo_debug_cap(n, "af", get_escape(ti, ESCAPE_SETAF));
423   tinfo_debug_cap(n, "ab", get_escape(ti, ESCAPE_SETAB));
424   tinfo_debug_cap(n, "sum", get_escape(ti, ESCAPE_BSUM));
425   tinfo_debug_cap(n, "cup", get_escape(ti, ESCAPE_CUP));
426   tinfo_debug_cap(n, "vpa", get_escape(ti, ESCAPE_VPA));
427   tinfo_debug_cap(n, "hpa", get_escape(ti, ESCAPE_HPA));
428   tinfo_debug_cap(n, "sgr0", get_escape(ti, ESCAPE_SGR0));
429   tinfo_debug_cap(n, "op", get_escape(ti, ESCAPE_OP));
430   tinfo_debug_cap(n, "fgop", get_escape(ti, ESCAPE_FGOP));
431   tinfo_debug_cap(n, "bgop", get_escape(ti, ESCAPE_BGOP));
432   tinfo_debug_cap(n, "bce", ti->bce);
433   finish_line(n);
434 }
435 
436 static void
tinfo_debug_styles(const notcurses * nc,struct ncplane * n,const char * indent)437 tinfo_debug_styles(const notcurses* nc, struct ncplane* n, const char* indent){
438   const tinfo* ti = &nc->tcache;
439   ncplane_putstr(n, indent);
440   tinfo_debug_style(n, "bold", NCSTYLE_BOLD, ' ');
441   tinfo_debug_style(n, "ital", NCSTYLE_ITALIC, ' ');
442   tinfo_debug_style(n, "struck", NCSTYLE_STRUCK, ' ');
443   tinfo_debug_style(n, "ucurl", NCSTYLE_UNDERCURL, ' ');
444   tinfo_debug_style(n, "uline", NCSTYLE_UNDERLINE, ' ');
445   tinfo_debug_cap(n, "u7", get_escape(ti, ESCAPE_U7));
446   tinfo_debug_cap(n, "ccc", ti->caps.can_change_colors);
447   tinfo_debug_cap(n, "rgb", ti->caps.rgb);
448   tinfo_debug_cap(n, "el", get_escape(ti, ESCAPE_EL));
449   finish_line(n);
450   ncplane_putstr(n, indent);
451   tinfo_debug_cap(n, "utf8", notcurses_canutf8(nc));
452   tinfo_debug_cap(n, "2x1", notcurses_canhalfblock(nc));
453   tinfo_debug_cap(n, "2x2", notcurses_canquadrant(nc));
454   tinfo_debug_cap(n, "3x2", notcurses_cansextant(nc));
455   tinfo_debug_cap(n, "4x2", notcurses_canbraille(nc));
456   tinfo_debug_cap(n, "img", notcurses_canopen_images(nc));
457   tinfo_debug_cap(n, "vid", notcurses_canopen_videos(nc));
458   tinfo_debug_cap(n, "indn", get_escape(ti, ESCAPE_INDN));
459   tinfo_debug_cap(n, "gpm", ti->gpmfd >= 0);
460   tinfo_debug_cap(n, "kbd", ti->kittykbdsupport);
461   finish_line(n);
462 }
463 
464 static int
usage(const char * base,FILE * fp,int ret)465 usage(const char* base, FILE* fp, int ret){
466   fprintf(fp, "usage: %s [ -v ]\n", base);
467   exit(ret);
468 }
469 
470 // we should probably change this up to use regular good ol'
471 // notcurses_render() without the alternate screen, no?
main(int argc,const char ** argv)472 int main(int argc, const char** argv){
473   notcurses_options nopts = {
474     .flags = NCOPTION_NO_ALTERNATE_SCREEN
475              | NCOPTION_PRESERVE_CURSOR
476              | NCOPTION_NO_CLEAR_BITMAPS
477              | NCOPTION_DRAIN_INPUT,
478   };
479   if(argc > 2){
480     usage(*argv, stderr, EXIT_FAILURE);
481   }
482   if(argc == 2){
483     if(strcmp(argv[1], "-v")){
484       usage(*argv, stderr, EXIT_FAILURE);
485     }
486     nopts.loglevel = NCLOGLEVEL_TRACE;
487   }
488   struct notcurses* nc = notcurses_init(&nopts, NULL);
489   if(nc == NULL){
490     return EXIT_FAILURE;
491   }
492   // so that we know whether we're talking to gpm
493   notcurses_mice_enable(nc, NCMICE_ALL_EVENTS);
494   const char indent[] = "";
495   unsigned dimx;
496   struct ncplane* stdn = notcurses_stddim_yx(nc, NULL, &dimx);
497   if(dimx < 80){
498     ncplane_set_fg_rgb(stdn, 0xff5349);
499     ncplane_set_styles(stdn, NCSTYLE_BOLD);
500     ncplane_putstr(stdn, "This program requires at least 80 columns.\n");
501     notcurses_render(nc);
502     notcurses_stop(nc);
503     return EXIT_FAILURE;
504   }
505   ncplane_set_scrolling(stdn, true);
506   tinfo_debug_caps(stdn, &nc->tcache, indent);
507   tinfo_debug_styles(nc, stdn, indent);
508   tinfo_debug_bitmaps(stdn, &nc->tcache, indent);
509   unicodedumper(stdn, indent);
510   char* path = prefix_data("notcurses.png");
511   if(path){
512     display_logo(stdn, path); // let it fail
513     free(path);
514   }
515   if(notcurses_render(nc)){
516     notcurses_stop(nc);
517     return EXIT_FAILURE;
518   }
519   return notcurses_stop(nc) ? EXIT_FAILURE : EXIT_SUCCESS;
520 }
521