1111 * @copyright
1212 * This file is part of ToaruOS and is released under the terms
1313 * of the NCSA / University of Illinois License - see LICENSE.md
14- * Copyright (C) 2013-2018 K. Lange
14+ * Copyright (C) 2013-2022 K. Lange
1515 */
1616#define _XOPEN_SOURCE 500
17- #define _POSIX_C_SOURCE 200112L
17+ #define _POSIX_C_SOURCE 200809L
1818#include <stdio.h>
1919#include <stdint.h>
2020#include <string.h>
2828#include <errno.h>
2929#include <fcntl.h>
3030#include <ctype.h>
31+ #include <wchar.h>
3132
3233#include <sys/time.h>
3334#include <sys/times.h>
@@ -174,6 +175,63 @@ void gethost() {
174175 memcpy (_hostname , buf .nodename , len + 1 );
175176}
176177
178+ #define UTF8_ACCEPT 0
179+ #define UTF8_REJECT 1
180+ static inline uint32_t decode (uint32_t * state , uint32_t * codep , uint32_t byte ) {
181+ static int state_table [32 ] = {
182+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /* 0xxxxxxx */
183+ 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , /* 10xxxxxx */
184+ 2 ,2 ,2 ,2 , /* 110xxxxx */
185+ 3 ,3 , /* 1110xxxx */
186+ 4 , /* 11110xxx */
187+ 1 /* 11111xxx */
188+ };
189+
190+ static int mask_bytes [32 ] = {
191+ 0x7F ,0x7F ,0x7F ,0x7F ,0x7F ,0x7F ,0x7F ,0x7F ,
192+ 0x7F ,0x7F ,0x7F ,0x7F ,0x7F ,0x7F ,0x7F ,0x7F ,
193+ 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
194+ 0x1F ,0x1F ,0x1F ,0x1F ,
195+ 0x0F ,0x0F ,
196+ 0x07 ,
197+ 0x00
198+ };
199+
200+ static int next [5 ] = {
201+ 0 ,
202+ 1 ,
203+ 0 ,
204+ 2 ,
205+ 3
206+ };
207+
208+ if (* state == UTF8_ACCEPT ) {
209+ * codep = byte & mask_bytes [byte >> 3 ];
210+ * state = state_table [byte >> 3 ];
211+ } else if (* state > 0 ) {
212+ * codep = (byte & 0x3F ) | (* codep << 6 );
213+ * state = next [* state ];
214+ }
215+ return * state ;
216+ }
217+
218+ int display_width_of_string (const char * str ) {
219+ uint8_t * s = (uint8_t * )str ;
220+
221+ int out = 0 ;
222+ uint32_t c , state = 0 ;
223+ while (* s ) {
224+ if (!decode (& state , & c , * s )) {
225+ out += wcwidth (c );
226+ } else if (state == UTF8_REJECT ) {
227+ state = 0 ;
228+ }
229+ s ++ ;
230+ }
231+
232+ return out ;
233+ }
234+
177235void print_extended_ps (char * format , char * buffer , int * display_width ) {
178236 /* Get the time */
179237 struct tm * timeinfo ;
@@ -208,15 +266,16 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
208266
209267 size_t offset = 0 ;
210268 int is_visible = 1 ;
211- * display_width = 0 ;
269+ char dispchars [1024 ] = {0 };
270+ char * dispout = dispchars ;
212271
213272 while (* format ) {
214273 if (* format == '\\' ) {
215274 format ++ ;
216275 switch (* format ) {
217276 case '\\' :
218277 buffer [offset ++ ] = * format ;
219- ( * display_width ) += is_visible ? 1 : 0 ;
278+ if ( is_visible ) * dispout ++ = * format ;
220279 format ++ ;
221280 break ;
222281 case '[' :
@@ -249,57 +308,57 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
249308 }
250309 }
251310 buffer [offset ++ ] = i ;
252- ( * display_width ) += is_visible ? 1 : 0 ;
311+ if ( is_visible ) * dispout ++ = i ;
253312 }
254313 break ;
255314 case 'e' :
256315 buffer [offset ++ ] = '\033' ;
257- ( * display_width ) += is_visible ? 1 : 0 ;
316+ if ( is_visible ) * dispout ++ = '\033' ;
258317 format ++ ;
259318 break ;
260319 case 'd' :
261320 {
262321 int size = sprintf (buffer + offset , "%s" , date_buffer );
263322 offset += size ;
264- ( * display_width ) += is_visible ? size : 0 ;
323+ if ( is_visible ) { dispout += sprintf ( dispout , "%s" , date_buffer ); }
265324 }
266325 format ++ ;
267326 break ;
268327 case 't' :
269328 {
270329 int size = sprintf (buffer + offset , "%s" , time_buffer );
271330 offset += size ;
272- ( * display_width ) += is_visible ? size : 0 ;
331+ if ( is_visible ) { dispout += sprintf ( dispout , "%s" , time_buffer ); }
273332 }
274333 format ++ ;
275334 break ;
276335 case 'h' :
277336 {
278337 int size = sprintf (buffer + offset , "%s" , _hostname );
279338 offset += size ;
280- ( * display_width ) += is_visible ? size : 0 ;
339+ if ( is_visible ) { dispout += sprintf ( dispout , "%s" , _hostname ); }
281340 }
282341 format ++ ;
283342 break ;
284343 case 'u' :
285344 {
286345 int size = sprintf (buffer + offset , "%s" , username );
287346 offset += size ;
288- ( * display_width ) += is_visible ? size : 0 ;
347+ if ( is_visible ) { dispout += sprintf ( dispout , "%s" , username ); }
289348 }
290349 format ++ ;
291350 break ;
292351 case 'w' :
293352 {
294353 int size = sprintf (buffer + offset , "%s" , _cwd );
295354 offset += size ;
296- ( * display_width ) += is_visible ? size : 0 ;
355+ if ( is_visible ) { dispout += sprintf ( dispout , "%s" , _cwd ); }
297356 }
298357 format ++ ;
299358 break ;
300359 case '$' :
301360 buffer [offset ++ ] = (getuid () == 0 ? '#' : '$' );
302- ( * display_width ) += is_visible ? 1 : 0 ;
361+ if ( is_visible ) * dispout ++ = ( getuid () == 0 ? '#' : '$' ) ;
303362 format ++ ;
304363 break ;
305364 case 'U' : /* prompt color string */
@@ -314,39 +373,29 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
314373 {
315374 int size = sprintf (buffer + offset , "%s" , ret );
316375 offset += size ;
317- ( * display_width ) += is_visible ? size : 0 ;
376+ if ( is_visible ) { dispout += sprintf ( dispout , "%s" , ret ); }
318377 }
319378 format ++ ;
320379 break ;
321380 default :
322381 {
323382 int size = sprintf (buffer + offset , "\\%c" , * format );
324383 offset += size ;
325- ( * display_width ) += is_visible ? size : 0 ;
384+ if ( is_visible ) { dispout += sprintf ( dispout , "\\%c" , * format ); }
326385 }
327386 format ++ ;
328387 break ;
329388 }
330389 } else {
331390 buffer [offset ++ ] = * format ;
332- ( * display_width ) += is_visible ? 1 : 0 ;
391+ if ( is_visible ) * dispout ++ = * format ;
333392 format ++ ;
334393 }
335394 }
336395
337- buffer [offset ] = '\0' ;
338- }
339-
340- #define FALLBACK_PS1 "\\u@\\h \\w\\$ "
396+ * display_width = display_width_of_string (dispchars );
341397
342- /* Draw the user prompt */
343- void draw_prompt (void ) {
344- char * ps1 = getenv ("PS1" );
345- char buf [1024 ];
346- int display_width ;
347- print_extended_ps (ps1 ? ps1 : FALLBACK_PS1 , buf , & display_width );
348- fprintf (stdout , "%s" , buf );
349- fflush (stdout );
398+ buffer [offset ] = '\0' ;
350399}
351400
352401volatile int break_while = 0 ;
@@ -712,6 +761,7 @@ void add_environment(list_t * env) {
712761 }
713762}
714763
764+ #define FALLBACK_PS1 "\\u@\\h \\w\\$ "
715765int read_entry (char * buffer ) {
716766 char lprompt [1024 ], rprompt [1024 ];
717767 int lwidth , rwidth ;
0 commit comments