/*
scifi_terminal.c
Simple inventory & text storage terminal in C.
- Command-driven (type commands like "inventory", "add", "save file.txt", "load file.txt")
- File-based storage (plain text CSV)
- Minimal dependencies; intended for old Windows machines
- 80s sci-fi terminal style (ASCII)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define INITIAL_CAP 64
#define LINE_BUF 512
#define NAME_LEN 128
typedef struct {
char name[ NAME_LEN] ;
long qty;
char note[ LINE_BUF] ;
} Item;
typedef struct {
Item * items;
size_t len;
size_t cap;
} Inventory;
void init_inventory( Inventory * inv) {
inv-> len = 0 ;
inv-> cap = INITIAL_CAP;
inv
-> items
= ( Item
* ) malloc ( sizeof ( Item
) * inv
-> cap
) ; if ( ! inv
-> items
) { fprintf ( stderr
, "Memory allocation failed\n " ) ; exit ( 1 ) ; } }
void free_inventory( Inventory * inv) {
if ( inv
-> items
) free ( inv
-> items
) ; inv-> items = NULL;
inv-> len = inv-> cap = 0 ;
}
void grow_if_needed( Inventory * inv) {
if ( inv-> len >= inv-> cap) {
inv-> cap *= 2 ;
Item
* n
= ( Item
* ) realloc ( inv
-> items
, sizeof ( Item
) * inv
-> cap
) ; if ( ! n
) { fprintf ( stderr
, "Reallocation failed\n " ) ; exit ( 1 ) ; } inv-> items = n;
}
}
void add_item( Inventory * inv, const char * name, long qty, const char * note) {
grow_if_needed( inv) ;
strncpy ( inv
-> items
[ inv
-> len
] .
name , name
, NAME_LEN
- 1 ) ; inv-> items[ inv-> len] .name [ NAME_LEN- 1 ] = '\0 ' ;
inv-> items[ inv-> len] .qty = qty;
if ( note) {
strncpy ( inv
-> items
[ inv
-> len
] .
note , note
, LINE_BUF
- 1 ) ; inv-> items[ inv-> len] .note [ LINE_BUF- 1 ] = '\0 ' ;
} else {
inv-> items[ inv-> len] .note [ 0 ] = '\0 ' ;
}
inv-> len++;
}
int find_item_index( Inventory * inv, const char * name) {
for ( size_t i= 0 ; i< inv-> len; i++ ) {
if ( strcmp ( inv
-> items
[ i
] .
name , name
) == 0 ) return ( int ) i
; }
return - 1 ;
}
void remove_item( Inventory * inv, const char * name) {
int idx = find_item_index( inv, name) ;
if ( idx
< 0 ) { printf ( "No item named '%s' found.\n " , name
) ; return ; } for ( size_t i = idx; i+ 1 < inv-> len; ++ i) inv-> items[ i] = inv-> items[ i+ 1 ] ;
inv-> len--;
printf ( "Removed '%s'.\n " , name
) ; }
void list_inventory( Inventory * inv) {
puts ( "┌────────────────────────────────────────────────────────────┐" ) ; puts ( "│ S Y S T E M I N V E N T O R Y │" ) ; puts ( "└────────────────────────────────────────────────────────────┘" ) ; if ( inv-> len == 0 ) {
return ;
}
printf ( "%-3s %-30s %-8s %s\n " , "No" , "Name" , "Quantity" , "Note" ) ; puts ( "------------------------------------------------------------------" ) ; for ( size_t i= 0 ; i< inv-> len; i++ ) {
printf ( "%-3zu %-30s %-8ld %s\n " , i
+ 1 , inv
-> items
[ i
] .
name , inv
-> items
[ i
] .
qty , inv
-> items
[ i
] .
note ) ; }
}
int save_inventory( Inventory * inv, const char * filename) {
FILE
* f
= fopen ( filename
, "w" ) ; if ( ! f) return 0 ;
// simple CSV: name,qty,note
for ( size_t i= 0 ; i< inv-> len; i++ ) {
// escape commas by replacing with semicolon to keep simple
char name_safe[ NAME_LEN] ; char note_safe[ LINE_BUF] ;
strncpy ( name_safe
, inv
-> items
[ i
] .
name , NAME_LEN
) ; name_safe
[ NAME_LEN
- 1 ] = '\0 ' ; strncpy ( note_safe
, inv
-> items
[ i
] .
note , LINE_BUF
) ; note_safe
[ LINE_BUF
- 1 ] = '\0 ' ; for ( char * p= name_safe; * p; ++ p) if ( * p== ',' ) * p= ';' ;
for ( char * p= note_safe; * p; ++ p) if ( * p== ',' ) * p= ';' ;
fprintf ( f
, "%s,%ld,%s\n " , name_safe
, inv
-> items
[ i
] .
qty , note_safe
) ; }
return 1 ;
}
int load_inventory( Inventory * inv, const char * filename) {
FILE
* f
= fopen ( filename
, "r" ) ; if ( ! f) return 0 ;
char line[ LINE_BUF] ;
inv-> len = 0 ; // clear current (keeps cap)
while ( fgets ( line
, sizeof ( line
) , f
) ) { // remove newline
char * nl
= strchr ( line
, '\n ' ) ; if ( nl
) * nl
= '\0 ' ; // split by first two commas
char * c
= strtok ( NULL
, "" ) ; // remainder if ( ! a || ! b) continue ;
add_item( inv, a, qty, c? c: "" ) ;
}
return 1 ;
}
void clear_inventory( Inventory * inv) {
inv-> len = 0 ;
puts ( "Inventory cleared." ) ; }
void print_banner( ) {
puts ( "############################################################" ) ; puts ( "# ███████╗ ██████╗ ██╗ ██████╗ ██╗ ██╗ 80s SCI-FI TERMINAL #" ) ; puts ( "# ██╔════╝██╔════╝ ██║██╔═══██╗██║ ██║ #" ) ; puts ( "# ███████╗██║ ███╗██║██║ ██║██║ ██║ #" ) ; puts ( "# ╚════██║██║ ██║██║██║ ██║██║ ██║ #" ) ; puts ( "# ███████║╚██████╔╝██║╚██████╔╝╚██████╔╝ #" ) ; puts ( "############################################################" ) ; puts ( "Type 'help' for commands. (e.g. add, inventory, save file.txt, load file.txt, exit)" ) ; }
void to_lower_str( char * s) {
for ( char * p
= s
; * p
; ++ p
) * p
= ( char ) tolower ( ( unsigned char ) * p
) ; }
void help_text( ) {
puts ( " help - show this help" ) ; puts ( " inventory - list inventory" ) ; puts ( " add NAME QTY [NOTE] - add an item, e.g. add bolts 20 \" for racks\" " ) ; puts ( " remove NAME - remove by exact name" ) ; puts ( " save FILENAME - save inventory to a file (CSV)" ) ; puts ( " load FILENAME - load inventory from a file (replaces current)" ) ; puts ( " clear - clear inventory in memory" ) ; puts ( " echo TEXT - append TEXT to a journal.txt file (light text storage)" ) ; puts ( " view FILE - print a plain text file to screen" ) ; puts ( " exit - exit program" ) ; }
void append_to_file( const char * filename, const char * text) {
FILE
* f
= fopen ( filename
, "a" ) ; if ( ! f
) { printf ( "Couldn't open %s for append.\n " , filename
) ; return ; } }
void view_file( const char * filename) {
FILE
* f
= fopen ( filename
, "r" ) ; if ( ! f
) { printf ( "Couldn't open %s\n " , filename
) ; return ; } char line[ LINE_BUF] ;
while ( fgets ( line
, sizeof ( line
) , f
) ) fputs ( line
, stdout
) ; }
int main( void ) {
Inventory inv;
init_inventory( & inv) ;
print_banner( ) ;
char raw[ LINE_BUF] ;
while ( 1 ) {
if ( ! fgets ( raw
, sizeof ( raw
) , stdin
) ) break ; // trim newline
char * nl
= strchr ( raw
, '\n ' ) ; if ( nl
) * nl
= '\0 ' ; // skip empty
char tmp[ LINE_BUF] ;
strncpy ( tmp
, raw
, LINE_BUF
- 1 ) ; tmp
[ LINE_BUF
- 1 ] = '\0 ' ; // parse first token as command
char * saveptr = NULL;
char * tok = strtok_r( tmp, " " , & saveptr) ;
if ( ! tok) continue ;
char cmd
[ 64 ] ; strncpy ( cmd
, tok
, sizeof ( cmd
) - 1 ) ; cmd
[ sizeof ( cmd
) - 1 ] = '\0 ' ; to_lower_str( cmd) ;
help_text( ) ;
} else if ( strcmp ( cmd
, "inventory" ) == 0 || strcmp ( cmd
, "list" ) == 0 ) { list_inventory( & inv) ;
} else if ( strcmp ( cmd
, "add" ) == 0 ) { // we need real arguments from raw (not lowered tmp), so parse from raw
// format: add NAME QTY [NOTE...]
char * p
= raw
+ strlen ( "add" ) ; while ( * p
&& isspace ( ( unsigned char ) * p
) ) p
++; if ( !* p
) { printf ( "Usage: add NAME QTY [NOTE]\n " ) ; continue ; } // get name
char name[ NAME_LEN] ; long qty = 0 ; char note[ LINE_BUF] = "" ;
// get first token = name
char * s = p;
if ( ! space
) { printf ( "Usage: add NAME QTY [NOTE]\n " ) ; continue ; } size_t namelen = ( size_t ) ( space - s) ;
if ( namelen >= NAME_LEN) namelen = NAME_LEN- 1 ;
strncpy ( name
, s
, namelen
) ; name
[ namelen
] = '\0 ' ; // skip spaces
s = space;
while ( * s
&& isspace ( ( unsigned char ) * s
) ) s
++; if ( !* s
) { printf ( "Usage: add NAME QTY [NOTE]\n " ) ; continue ; } // read qty
char qtystr[ 64 ] ;
int i= 0 ;
while ( * s
&& ! isspace ( ( unsigned char ) * s
) && i
< 63 ) qtystr
[ i
++ ] = * s
++; qtystr[ i] = '\0 ' ;
while ( * s
&& isspace ( ( unsigned char ) * s
) ) s
++; if ( * s) {
// remaining is note
strncpy ( note
, s
, LINE_BUF
- 1 ) ; note
[ LINE_BUF
- 1 ] = '\0 ' ; }
// if item exists, increase qty and optionally update note
int idx = find_item_index( & inv, name) ;
if ( idx >= 0 ) {
inv.items [ idx] .qty += qty;
if ( note
[ 0 ] ) strncpy ( inv.
items [ idx
] .
note , note
, LINE_BUF
- 1 ) ; printf ( "Updated '%s' -> qty=%ld\n " , name
, inv.
items [ idx
] .
qty ) ; } else {
add_item( & inv, name, qty, note) ;
printf ( "Added '%s' qty=%ld\n " , name
, qty
) ; }
} else if ( strcmp ( cmd
, "remove" ) == 0 ) { char * p
= raw
+ strlen ( "remove" ) ; while ( * p
&& isspace ( ( unsigned char ) * p
) ) p
++; if ( !* p
) { printf ( "Usage: remove NAME\n " ) ; continue ; } remove_item( & inv, p) ;
} else if ( strcmp ( cmd
, "save" ) == 0 ) { char * p
= raw
+ strlen ( "save" ) ; while ( * p
&& isspace ( ( unsigned char ) * p
) ) p
++; if ( !* p
) { printf ( "Usage: save filename\n " ) ; continue ; } if ( save_inventory
( & inv
, p
) ) printf ( "Saved to %s\n " , p
) ; else printf ( "Failed to save to %s\n " , p
) ; } else if ( strcmp ( cmd
, "load" ) == 0 ) { char * p
= raw
+ strlen ( "load" ) ; while ( * p
&& isspace ( ( unsigned char ) * p
) ) p
++; if ( !* p
) { printf ( "Usage: load filename\n " ) ; continue ; } if ( load_inventory
( & inv
, p
) ) printf ( "Loaded %s\n " , p
) ; else printf ( "Failed to load %s\n " , p
) ; } else if ( strcmp ( cmd
, "clear" ) == 0 ) { clear_inventory( & inv) ;
} else if ( strcmp ( cmd
, "echo" ) == 0 ) { char * p
= raw
+ strlen ( "echo" ) ; while ( * p
&& isspace ( ( unsigned char ) * p
) ) p
++; if ( !* p
) { printf ( "Usage: echo TEXT\n " ) ; continue ; } append_to_file( "journal.txt" , p) ;
printf ( "Appended to journal.txt\n " ) ; } else if ( strcmp ( cmd
, "view" ) == 0 ) { char * p
= raw
+ strlen ( "view" ) ; while ( * p
&& isspace ( ( unsigned char ) * p
) ) p
++; if ( !* p
) { printf ( "Usage: view filename\n " ) ; continue ; } view_file( p) ;
} else if ( strcmp ( cmd
, "exit" ) == 0 || strcmp ( cmd
, "quit" ) == 0 ) { puts ( "Shutting down..." ) ; break ;
} else {
printf ( "Unknown command: '%s' (type help)\n " , cmd
) ; }
}
free_inventory( & inv) ;
return 0 ;
}
LyoKICBzY2lmaV90ZXJtaW5hbC5jCiAgU2ltcGxlIGludmVudG9yeSAmIHRleHQgc3RvcmFnZSB0ZXJtaW5hbCBpbiBDLgogIC0gQ29tbWFuZC1kcml2ZW4gKHR5cGUgY29tbWFuZHMgbGlrZSAiaW52ZW50b3J5IiwgImFkZCIsICJzYXZlIGZpbGUudHh0IiwgImxvYWQgZmlsZS50eHQiKQogIC0gRmlsZS1iYXNlZCBzdG9yYWdlIChwbGFpbiB0ZXh0IENTVikKICAtIE1pbmltYWwgZGVwZW5kZW5jaWVzOyBpbnRlbmRlZCBmb3Igb2xkIFdpbmRvd3MgbWFjaGluZXMKICAtIDgwcyBzY2ktZmkgdGVybWluYWwgc3R5bGUgKEFTQ0lJKQoqLwoKI2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPHN0cmluZy5oPgojaW5jbHVkZSA8Y3R5cGUuaD4KCiNkZWZpbmUgSU5JVElBTF9DQVAgNjQKI2RlZmluZSBMSU5FX0JVRiA1MTIKI2RlZmluZSBOQU1FX0xFTiAxMjgKCnR5cGVkZWYgc3RydWN0IHsKICAgIGNoYXIgbmFtZVtOQU1FX0xFTl07CiAgICBsb25nIHF0eTsKICAgIGNoYXIgbm90ZVtMSU5FX0JVRl07Cn0gSXRlbTsKCnR5cGVkZWYgc3RydWN0IHsKICAgIEl0ZW0gKml0ZW1zOwogICAgc2l6ZV90IGxlbjsKICAgIHNpemVfdCBjYXA7Cn0gSW52ZW50b3J5OwoKdm9pZCBpbml0X2ludmVudG9yeShJbnZlbnRvcnkgKmludil7CiAgICBpbnYtPmxlbiA9IDA7CiAgICBpbnYtPmNhcCA9IElOSVRJQUxfQ0FQOwogICAgaW52LT5pdGVtcyA9IChJdGVtKiltYWxsb2Moc2l6ZW9mKEl0ZW0pICogaW52LT5jYXApOwogICAgaWYoIWludi0+aXRlbXMpeyBmcHJpbnRmKHN0ZGVyciwiTWVtb3J5IGFsbG9jYXRpb24gZmFpbGVkXG4iKTsgZXhpdCgxKTsgfQp9Cgp2b2lkIGZyZWVfaW52ZW50b3J5KEludmVudG9yeSAqaW52KXsKICAgIGlmKGludi0+aXRlbXMpIGZyZWUoaW52LT5pdGVtcyk7CiAgICBpbnYtPml0ZW1zID0gTlVMTDsKICAgIGludi0+bGVuID0gaW52LT5jYXAgPSAwOwp9Cgp2b2lkIGdyb3dfaWZfbmVlZGVkKEludmVudG9yeSAqaW52KXsKICAgIGlmKGludi0+bGVuID49IGludi0+Y2FwKXsKICAgICAgICBpbnYtPmNhcCAqPSAyOwogICAgICAgIEl0ZW0gKm4gPSAoSXRlbSopcmVhbGxvYyhpbnYtPml0ZW1zLCBzaXplb2YoSXRlbSkgKiBpbnYtPmNhcCk7CiAgICAgICAgaWYoIW4peyBmcHJpbnRmKHN0ZGVyciwiUmVhbGxvY2F0aW9uIGZhaWxlZFxuIik7IGV4aXQoMSk7IH0KICAgICAgICBpbnYtPml0ZW1zID0gbjsKICAgIH0KfQoKdm9pZCBhZGRfaXRlbShJbnZlbnRvcnkgKmludiwgY29uc3QgY2hhciAqbmFtZSwgbG9uZyBxdHksIGNvbnN0IGNoYXIgKm5vdGUpewogICAgZ3Jvd19pZl9uZWVkZWQoaW52KTsKICAgIHN0cm5jcHkoaW52LT5pdGVtc1tpbnYtPmxlbl0ubmFtZSwgbmFtZSwgTkFNRV9MRU4tMSk7CiAgICBpbnYtPml0ZW1zW2ludi0+bGVuXS5uYW1lW05BTUVfTEVOLTFdID0gJ1wwJzsKICAgIGludi0+aXRlbXNbaW52LT5sZW5dLnF0eSA9IHF0eTsKICAgIGlmKG5vdGUpewogICAgICAgIHN0cm5jcHkoaW52LT5pdGVtc1tpbnYtPmxlbl0ubm90ZSwgbm90ZSwgTElORV9CVUYtMSk7CiAgICAgICAgaW52LT5pdGVtc1tpbnYtPmxlbl0ubm90ZVtMSU5FX0JVRi0xXSA9ICdcMCc7CiAgICB9IGVsc2UgewogICAgICAgIGludi0+aXRlbXNbaW52LT5sZW5dLm5vdGVbMF0gPSAnXDAnOwogICAgfQogICAgaW52LT5sZW4rKzsKfQoKaW50IGZpbmRfaXRlbV9pbmRleChJbnZlbnRvcnkgKmludiwgY29uc3QgY2hhciAqbmFtZSl7CiAgICBmb3Ioc2l6ZV90IGk9MDtpPGludi0+bGVuO2krKyl7CiAgICAgICAgaWYoc3RyY21wKGludi0+aXRlbXNbaV0ubmFtZSwgbmFtZSkgPT0gMCkgcmV0dXJuIChpbnQpaTsKICAgIH0KICAgIHJldHVybiAtMTsKfQoKdm9pZCByZW1vdmVfaXRlbShJbnZlbnRvcnkgKmludiwgY29uc3QgY2hhciAqbmFtZSl7CiAgICBpbnQgaWR4ID0gZmluZF9pdGVtX2luZGV4KGludiwgbmFtZSk7CiAgICBpZihpZHggPCAwKXsgcHJpbnRmKCJObyBpdGVtIG5hbWVkICclcycgZm91bmQuXG4iLCBuYW1lKTsgcmV0dXJuOyB9CiAgICBmb3Ioc2l6ZV90IGkgPSBpZHg7IGkrMSA8IGludi0+bGVuOyArK2kpIGludi0+aXRlbXNbaV0gPSBpbnYtPml0ZW1zW2krMV07CiAgICBpbnYtPmxlbi0tOwogICAgcHJpbnRmKCJSZW1vdmVkICclcycuXG4iLCBuYW1lKTsKfQoKdm9pZCBsaXN0X2ludmVudG9yeShJbnZlbnRvcnkgKmludil7CiAgICBwdXRzKCLilIzilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilJAiKTsKICAgIHB1dHMoIuKUgiAgICAgICAgICAgICAgICAgIFMgWSBTIFQgRSBNICBJIE4gViBFIE4gVCBPIFIgWSAgICAgICAgICAg4pSCIik7CiAgICBwdXRzKCLilJTilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilJgiKTsKICAgIGlmKGludi0+bGVuID09IDApewogICAgICAgIHB1dHMoIltlbXB0eV0iKTsKICAgICAgICByZXR1cm47CiAgICB9CiAgICBwcmludGYoIiUtM3MgICUtMzBzICAlLThzICAlc1xuIiwgIk5vIiwgIk5hbWUiLCAiUXVhbnRpdHkiLCAiTm90ZSIpOwogICAgcHV0cygiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIik7CiAgICBmb3Ioc2l6ZV90IGk9MDtpPGludi0+bGVuO2krKyl7CiAgICAgICAgcHJpbnRmKCIlLTN6dSAgJS0zMHMgICUtOGxkICAlc1xuIiwgaSsxLCBpbnYtPml0ZW1zW2ldLm5hbWUsIGludi0+aXRlbXNbaV0ucXR5LCBpbnYtPml0ZW1zW2ldLm5vdGUpOwogICAgfQp9CgppbnQgc2F2ZV9pbnZlbnRvcnkoSW52ZW50b3J5ICppbnYsIGNvbnN0IGNoYXIgKmZpbGVuYW1lKXsKICAgIEZJTEUgKmYgPSBmb3BlbihmaWxlbmFtZSwgInciKTsKICAgIGlmKCFmKSByZXR1cm4gMDsKICAgIC8vIHNpbXBsZSBDU1Y6IG5hbWUscXR5LG5vdGUKICAgIGZvcihzaXplX3QgaT0wO2k8aW52LT5sZW47aSsrKXsKICAgICAgICAvLyBlc2NhcGUgY29tbWFzIGJ5IHJlcGxhY2luZyB3aXRoIHNlbWljb2xvbiB0byBrZWVwIHNpbXBsZQogICAgICAgIGNoYXIgbmFtZV9zYWZlW05BTUVfTEVOXTsgY2hhciBub3RlX3NhZmVbTElORV9CVUZdOwogICAgICAgIHN0cm5jcHkobmFtZV9zYWZlLCBpbnYtPml0ZW1zW2ldLm5hbWUsIE5BTUVfTEVOKTsgbmFtZV9zYWZlW05BTUVfTEVOLTFdPSdcMCc7CiAgICAgICAgc3RybmNweShub3RlX3NhZmUsIGludi0+aXRlbXNbaV0ubm90ZSwgTElORV9CVUYpOyBub3RlX3NhZmVbTElORV9CVUYtMV09J1wwJzsKICAgICAgICBmb3IoY2hhciAqcD1uYW1lX3NhZmU7ICpwOyArK3ApIGlmKCpwPT0nLCcpICpwPSc7JzsKICAgICAgICBmb3IoY2hhciAqcD1ub3RlX3NhZmU7ICpwOyArK3ApIGlmKCpwPT0nLCcpICpwPSc7JzsKICAgICAgICBmcHJpbnRmKGYsICIlcywlbGQsJXNcbiIsIG5hbWVfc2FmZSwgaW52LT5pdGVtc1tpXS5xdHksIG5vdGVfc2FmZSk7CiAgICB9CiAgICBmY2xvc2UoZik7CiAgICByZXR1cm4gMTsKfQoKaW50IGxvYWRfaW52ZW50b3J5KEludmVudG9yeSAqaW52LCBjb25zdCBjaGFyICpmaWxlbmFtZSl7CiAgICBGSUxFICpmID0gZm9wZW4oZmlsZW5hbWUsICJyIik7CiAgICBpZighZikgcmV0dXJuIDA7CiAgICBjaGFyIGxpbmVbTElORV9CVUZdOwogICAgaW52LT5sZW4gPSAwOyAvLyBjbGVhciBjdXJyZW50IChrZWVwcyBjYXApCiAgICB3aGlsZShmZ2V0cyhsaW5lLCBzaXplb2YobGluZSksIGYpKXsKICAgICAgICAvLyByZW1vdmUgbmV3bGluZQogICAgICAgIGNoYXIgKm5sID0gc3RyY2hyKGxpbmUsICdcbicpOyBpZihubCkgKm5sID0gJ1wwJzsKICAgICAgICAvLyBzcGxpdCBieSBmaXJzdCB0d28gY29tbWFzCiAgICAgICAgY2hhciAqYSA9IHN0cnRvayhsaW5lLCAiLCIpOwogICAgICAgIGNoYXIgKmIgPSBzdHJ0b2soTlVMTCwgIiwiKTsKICAgICAgICBjaGFyICpjID0gc3RydG9rKE5VTEwsICIiKTsgLy8gcmVtYWluZGVyCiAgICAgICAgaWYoIWEgfHwgIWIpIGNvbnRpbnVlOwogICAgICAgIGxvbmcgcXR5ID0gYXRvbChiKTsKICAgICAgICBhZGRfaXRlbShpbnYsIGEsIHF0eSwgYz9jOiIiKTsKICAgIH0KICAgIGZjbG9zZShmKTsKICAgIHJldHVybiAxOwp9Cgp2b2lkIGNsZWFyX2ludmVudG9yeShJbnZlbnRvcnkgKmludil7CiAgICBpbnYtPmxlbiA9IDA7CiAgICBwdXRzKCJJbnZlbnRvcnkgY2xlYXJlZC4iKTsKfQoKdm9pZCBwcmludF9iYW5uZXIoKXsKICAgIHB1dHMoIiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyIpOwogICAgcHV0cygiIyAg4paI4paI4paI4paI4paI4paI4paI4pWXIOKWiOKWiOKWiOKWiOKWiOKWiOKVlyDilojilojilZcg4paI4paI4paI4paI4paI4paI4pWXIOKWiOKWiOKVlyAgIOKWiOKWiOKVlyAgODBzIFNDSS1GSSBURVJNSU5BTCAjIik7CiAgICBwdXRzKCIjICDilojilojilZTilZDilZDilZDilZDilZ3ilojilojilZTilZDilZDilZDilZDilZ0g4paI4paI4pWR4paI4paI4pWU4pWQ4pWQ4pWQ4paI4paI4pWX4paI4paI4pWRICAg4paI4paI4pWRICAgICAgICAgICAgICAgICAgICAgICMiKTsKICAgIHB1dHMoIiMgIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKVl+KWiOKWiOKVkSAg4paI4paI4paI4pWX4paI4paI4pWR4paI4paI4pWRICAg4paI4paI4pWR4paI4paI4pWRICAg4paI4paI4pWRICAgICAgICAgICAgICAgICAgICAgICMiKTsKICAgIHB1dHMoIiMgIOKVmuKVkOKVkOKVkOKVkOKWiOKWiOKVkeKWiOKWiOKVkSAgIOKWiOKWiOKVkeKWiOKWiOKVkeKWiOKWiOKVkSAgIOKWiOKWiOKVkeKWiOKWiOKVkSAgIOKWiOKWiOKVkSAgICAgICAgICAgICAgICAgICAgICAjIik7CiAgICBwdXRzKCIjICDilojilojilojilojilojilojilojilZHilZrilojilojilojilojilojilojilZTilZ3ilojilojilZHilZrilojilojilojilojilojilojilZTilZ3ilZrilojilojilojilojilojilojilZTilZ0gICAgICAgICAgICAgICAgICAgICAgIyIpOwogICAgcHV0cygiIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIik7CiAgICBwdXRzKCJUeXBlICdoZWxwJyBmb3IgY29tbWFuZHMuIChlLmcuIGFkZCwgaW52ZW50b3J5LCBzYXZlIGZpbGUudHh0LCBsb2FkIGZpbGUudHh0LCBleGl0KSIpOwp9Cgp2b2lkIHRvX2xvd2VyX3N0cihjaGFyICpzKXsKICAgIGZvcihjaGFyICpwPXM7ICpwOyArK3ApICpwID0gKGNoYXIpdG9sb3dlcigodW5zaWduZWQgY2hhcikqcCk7Cn0KCnZvaWQgaGVscF90ZXh0KCl7CiAgICBwdXRzKCJDb21tYW5kczoiKTsKICAgIHB1dHMoIiAgaGVscCAgICAgICAgICAgICAgICAgICAgIC0gc2hvdyB0aGlzIGhlbHAiKTsKICAgIHB1dHMoIiAgaW52ZW50b3J5ICAgICAgICAgICAgICAgIC0gbGlzdCBpbnZlbnRvcnkiKTsKICAgIHB1dHMoIiAgYWRkIE5BTUUgUVRZIFtOT1RFXSAgICAgIC0gYWRkIGFuIGl0ZW0sIGUuZy4gYWRkIGJvbHRzIDIwIFwiZm9yIHJhY2tzXCIiKTsKICAgIHB1dHMoIiAgcmVtb3ZlIE5BTUUgICAgICAgICAgICAgIC0gcmVtb3ZlIGJ5IGV4YWN0IG5hbWUiKTsKICAgIHB1dHMoIiAgc2F2ZSBGSUxFTkFNRSAgICAgICAgICAgIC0gc2F2ZSBpbnZlbnRvcnkgdG8gYSBmaWxlIChDU1YpIik7CiAgICBwdXRzKCIgIGxvYWQgRklMRU5BTUUgICAgICAgICAgICAtIGxvYWQgaW52ZW50b3J5IGZyb20gYSBmaWxlIChyZXBsYWNlcyBjdXJyZW50KSIpOwogICAgcHV0cygiICBjbGVhciAgICAgICAgICAgICAgICAgICAgLSBjbGVhciBpbnZlbnRvcnkgaW4gbWVtb3J5Iik7CiAgICBwdXRzKCIgIGVjaG8gVEVYVCAgICAgICAgICAgICAgICAtIGFwcGVuZCBURVhUIHRvIGEgam91cm5hbC50eHQgZmlsZSAobGlnaHQgdGV4dCBzdG9yYWdlKSIpOwogICAgcHV0cygiICB2aWV3IEZJTEUgICAgICAgICAgICAgICAgLSBwcmludCBhIHBsYWluIHRleHQgZmlsZSB0byBzY3JlZW4iKTsKICAgIHB1dHMoIiAgZXhpdCAgICAgICAgICAgICAgICAgICAgIC0gZXhpdCBwcm9ncmFtIik7Cn0KCnZvaWQgYXBwZW5kX3RvX2ZpbGUoY29uc3QgY2hhciAqZmlsZW5hbWUsIGNvbnN0IGNoYXIgKnRleHQpewogICAgRklMRSAqZiA9IGZvcGVuKGZpbGVuYW1lLCAiYSIpOwogICAgaWYoIWYpeyBwcmludGYoIkNvdWxkbid0IG9wZW4gJXMgZm9yIGFwcGVuZC5cbiIsIGZpbGVuYW1lKTsgcmV0dXJuOyB9CiAgICBmcHJpbnRmKGYsICIlc1xuIiwgdGV4dCk7CiAgICBmY2xvc2UoZik7Cn0KCnZvaWQgdmlld19maWxlKGNvbnN0IGNoYXIgKmZpbGVuYW1lKXsKICAgIEZJTEUgKmYgPSBmb3BlbihmaWxlbmFtZSwgInIiKTsKICAgIGlmKCFmKXsgcHJpbnRmKCJDb3VsZG4ndCBvcGVuICVzXG4iLCBmaWxlbmFtZSk7IHJldHVybjsgfQogICAgY2hhciBsaW5lW0xJTkVfQlVGXTsKICAgIHdoaWxlKGZnZXRzKGxpbmUsIHNpemVvZihsaW5lKSwgZikpIGZwdXRzKGxpbmUsIHN0ZG91dCk7CiAgICBmY2xvc2UoZik7Cn0KCmludCBtYWluKHZvaWQpewogICAgSW52ZW50b3J5IGludjsKICAgIGluaXRfaW52ZW50b3J5KCZpbnYpOwogICAgcHJpbnRfYmFubmVyKCk7CgogICAgY2hhciByYXdbTElORV9CVUZdOwogICAgd2hpbGUoMSl7CiAgICAgICAgcHJpbnRmKCJcbj4gIik7CiAgICAgICAgaWYoIWZnZXRzKHJhdywgc2l6ZW9mKHJhdyksIHN0ZGluKSkgYnJlYWs7CiAgICAgICAgLy8gdHJpbSBuZXdsaW5lCiAgICAgICAgY2hhciAqbmwgPSBzdHJjaHIocmF3LCAnXG4nKTsgaWYobmwpICpubCA9ICdcMCc7CiAgICAgICAgLy8gc2tpcCBlbXB0eQogICAgICAgIGNoYXIgdG1wW0xJTkVfQlVGXTsKICAgICAgICBzdHJuY3B5KHRtcCwgcmF3LCBMSU5FX0JVRi0xKTsgdG1wW0xJTkVfQlVGLTFdPSdcMCc7CiAgICAgICAgLy8gcGFyc2UgZmlyc3QgdG9rZW4gYXMgY29tbWFuZAogICAgICAgIGNoYXIgKnNhdmVwdHIgPSBOVUxMOwogICAgICAgIGNoYXIgKnRvayA9IHN0cnRva19yKHRtcCwgIiAiLCAmc2F2ZXB0cik7CiAgICAgICAgaWYoIXRvaykgY29udGludWU7CiAgICAgICAgY2hhciBjbWRbNjRdOyBzdHJuY3B5KGNtZCwgdG9rLCBzaXplb2YoY21kKS0xKTsgY21kW3NpemVvZihjbWQpLTFdID0gJ1wwJzsKICAgICAgICB0b19sb3dlcl9zdHIoY21kKTsKCiAgICAgICAgaWYoc3RyY21wKGNtZCwgImhlbHAiKSA9PSAwKXsKICAgICAgICAgICAgaGVscF90ZXh0KCk7CiAgICAgICAgfSBlbHNlIGlmKHN0cmNtcChjbWQsICJpbnZlbnRvcnkiKSA9PSAwIHx8IHN0cmNtcChjbWQsICJsaXN0IikgPT0gMCl7CiAgICAgICAgICAgIGxpc3RfaW52ZW50b3J5KCZpbnYpOwogICAgICAgIH0gZWxzZSBpZihzdHJjbXAoY21kLCAiYWRkIikgPT0gMCl7CiAgICAgICAgICAgIC8vIHdlIG5lZWQgcmVhbCBhcmd1bWVudHMgZnJvbSByYXcgKG5vdCBsb3dlcmVkIHRtcCksIHNvIHBhcnNlIGZyb20gcmF3CiAgICAgICAgICAgIC8vIGZvcm1hdDogYWRkIE5BTUUgUVRZIFtOT1RFLi4uXQogICAgICAgICAgICBjaGFyICpwID0gcmF3ICsgc3RybGVuKCJhZGQiKTsKICAgICAgICAgICAgd2hpbGUoKnAgJiYgaXNzcGFjZSgodW5zaWduZWQgY2hhcikqcCkpIHArKzsKICAgICAgICAgICAgaWYoISpwKXsgcHJpbnRmKCJVc2FnZTogYWRkIE5BTUUgUVRZIFtOT1RFXVxuIik7IGNvbnRpbnVlOyB9CiAgICAgICAgICAgIC8vIGdldCBuYW1lCiAgICAgICAgICAgIGNoYXIgbmFtZVtOQU1FX0xFTl07IGxvbmcgcXR5ID0gMDsgY2hhciBub3RlW0xJTkVfQlVGXSA9ICIiOwogICAgICAgICAgICAvLyBnZXQgZmlyc3QgdG9rZW4gPSBuYW1lCiAgICAgICAgICAgIGNoYXIgKnMgPSBwOwogICAgICAgICAgICBjaGFyICpzcGFjZSA9IHN0cmNocihzLCAnICcpOwogICAgICAgICAgICBpZighc3BhY2UpeyBwcmludGYoIlVzYWdlOiBhZGQgTkFNRSBRVFkgW05PVEVdXG4iKTsgY29udGludWU7IH0KICAgICAgICAgICAgc2l6ZV90IG5hbWVsZW4gPSAoc2l6ZV90KShzcGFjZSAtIHMpOwogICAgICAgICAgICBpZihuYW1lbGVuID49IE5BTUVfTEVOKSBuYW1lbGVuID0gTkFNRV9MRU4tMTsKICAgICAgICAgICAgc3RybmNweShuYW1lLCBzLCBuYW1lbGVuKTsgbmFtZVtuYW1lbGVuXSA9ICdcMCc7CiAgICAgICAgICAgIC8vIHNraXAgc3BhY2VzCiAgICAgICAgICAgIHMgPSBzcGFjZTsKICAgICAgICAgICAgd2hpbGUoKnMgJiYgaXNzcGFjZSgodW5zaWduZWQgY2hhcikqcykpIHMrKzsKICAgICAgICAgICAgaWYoISpzKXsgcHJpbnRmKCJVc2FnZTogYWRkIE5BTUUgUVRZIFtOT1RFXVxuIik7IGNvbnRpbnVlOyB9CiAgICAgICAgICAgIC8vIHJlYWQgcXR5CiAgICAgICAgICAgIGNoYXIgcXR5c3RyWzY0XTsKICAgICAgICAgICAgaW50IGk9MDsKICAgICAgICAgICAgd2hpbGUoKnMgJiYgIWlzc3BhY2UoKHVuc2lnbmVkIGNoYXIpKnMpICYmIGkgPCA2MykgcXR5c3RyW2krK10gPSAqcysrOwogICAgICAgICAgICBxdHlzdHJbaV0gPSAnXDAnOwogICAgICAgICAgICBxdHkgPSBhdG9sKHF0eXN0cik7CiAgICAgICAgICAgIHdoaWxlKCpzICYmIGlzc3BhY2UoKHVuc2lnbmVkIGNoYXIpKnMpKSBzKys7CiAgICAgICAgICAgIGlmKCpzKXsKICAgICAgICAgICAgICAgIC8vIHJlbWFpbmluZyBpcyBub3RlCiAgICAgICAgICAgICAgICBzdHJuY3B5KG5vdGUsIHMsIExJTkVfQlVGLTEpOyBub3RlW0xJTkVfQlVGLTFdPSdcMCc7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gaWYgaXRlbSBleGlzdHMsIGluY3JlYXNlIHF0eSBhbmQgb3B0aW9uYWxseSB1cGRhdGUgbm90ZQogICAgICAgICAgICBpbnQgaWR4ID0gZmluZF9pdGVtX2luZGV4KCZpbnYsIG5hbWUpOwogICAgICAgICAgICBpZihpZHggPj0gMCl7CiAgICAgICAgICAgICAgICBpbnYuaXRlbXNbaWR4XS5xdHkgKz0gcXR5OwogICAgICAgICAgICAgICAgaWYobm90ZVswXSkgc3RybmNweShpbnYuaXRlbXNbaWR4XS5ub3RlLCBub3RlLCBMSU5FX0JVRi0xKTsKICAgICAgICAgICAgICAgIHByaW50ZigiVXBkYXRlZCAnJXMnIC0+IHF0eT0lbGRcbiIsIG5hbWUsIGludi5pdGVtc1tpZHhdLnF0eSk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBhZGRfaXRlbSgmaW52LCBuYW1lLCBxdHksIG5vdGUpOwogICAgICAgICAgICAgICAgcHJpbnRmKCJBZGRlZCAnJXMnIHF0eT0lbGRcbiIsIG5hbWUsIHF0eSk7CiAgICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgaWYoc3RyY21wKGNtZCwgInJlbW92ZSIpID09IDApewogICAgICAgICAgICBjaGFyICpwID0gcmF3ICsgc3RybGVuKCJyZW1vdmUiKTsKICAgICAgICAgICAgd2hpbGUoKnAgJiYgaXNzcGFjZSgodW5zaWduZWQgY2hhcikqcCkpIHArKzsKICAgICAgICAgICAgaWYoISpwKXsgcHJpbnRmKCJVc2FnZTogcmVtb3ZlIE5BTUVcbiIpOyBjb250aW51ZTsgfQogICAgICAgICAgICByZW1vdmVfaXRlbSgmaW52LCBwKTsKICAgICAgICB9IGVsc2UgaWYoc3RyY21wKGNtZCwgInNhdmUiKSA9PSAwKXsKICAgICAgICAgICAgY2hhciAqcCA9IHJhdyArIHN0cmxlbigic2F2ZSIpOwogICAgICAgICAgICB3aGlsZSgqcCAmJiBpc3NwYWNlKCh1bnNpZ25lZCBjaGFyKSpwKSkgcCsrOwogICAgICAgICAgICBpZighKnApeyBwcmludGYoIlVzYWdlOiBzYXZlIGZpbGVuYW1lXG4iKTsgY29udGludWU7IH0KICAgICAgICAgICAgaWYoc2F2ZV9pbnZlbnRvcnkoJmludiwgcCkpIHByaW50ZigiU2F2ZWQgdG8gJXNcbiIsIHApOwogICAgICAgICAgICBlbHNlIHByaW50ZigiRmFpbGVkIHRvIHNhdmUgdG8gJXNcbiIsIHApOwogICAgICAgIH0gZWxzZSBpZihzdHJjbXAoY21kLCAibG9hZCIpID09IDApewogICAgICAgICAgICBjaGFyICpwID0gcmF3ICsgc3RybGVuKCJsb2FkIik7CiAgICAgICAgICAgIHdoaWxlKCpwICYmIGlzc3BhY2UoKHVuc2lnbmVkIGNoYXIpKnApKSBwKys7CiAgICAgICAgICAgIGlmKCEqcCl7IHByaW50ZigiVXNhZ2U6IGxvYWQgZmlsZW5hbWVcbiIpOyBjb250aW51ZTsgfQogICAgICAgICAgICBpZihsb2FkX2ludmVudG9yeSgmaW52LCBwKSkgcHJpbnRmKCJMb2FkZWQgJXNcbiIsIHApOwogICAgICAgICAgICBlbHNlIHByaW50ZigiRmFpbGVkIHRvIGxvYWQgJXNcbiIsIHApOwogICAgICAgIH0gZWxzZSBpZihzdHJjbXAoY21kLCAiY2xlYXIiKSA9PSAwKXsKICAgICAgICAgICAgY2xlYXJfaW52ZW50b3J5KCZpbnYpOwogICAgICAgIH0gZWxzZSBpZihzdHJjbXAoY21kLCAiZWNobyIpID09IDApewogICAgICAgICAgICBjaGFyICpwID0gcmF3ICsgc3RybGVuKCJlY2hvIik7CiAgICAgICAgICAgIHdoaWxlKCpwICYmIGlzc3BhY2UoKHVuc2lnbmVkIGNoYXIpKnApKSBwKys7CiAgICAgICAgICAgIGlmKCEqcCl7IHByaW50ZigiVXNhZ2U6IGVjaG8gVEVYVFxuIik7IGNvbnRpbnVlOyB9CiAgICAgICAgICAgIGFwcGVuZF90b19maWxlKCJqb3VybmFsLnR4dCIsIHApOwogICAgICAgICAgICBwcmludGYoIkFwcGVuZGVkIHRvIGpvdXJuYWwudHh0XG4iKTsKICAgICAgICB9IGVsc2UgaWYoc3RyY21wKGNtZCwgInZpZXciKSA9PSAwKXsKICAgICAgICAgICAgY2hhciAqcCA9IHJhdyArIHN0cmxlbigidmlldyIpOwogICAgICAgICAgICB3aGlsZSgqcCAmJiBpc3NwYWNlKCh1bnNpZ25lZCBjaGFyKSpwKSkgcCsrOwogICAgICAgICAgICBpZighKnApeyBwcmludGYoIlVzYWdlOiB2aWV3IGZpbGVuYW1lXG4iKTsgY29udGludWU7IH0KICAgICAgICAgICAgdmlld19maWxlKHApOwogICAgICAgIH0gZWxzZSBpZihzdHJjbXAoY21kLCAiZXhpdCIpID09IDAgfHwgc3RyY21wKGNtZCwgInF1aXQiKSA9PSAwKXsKICAgICAgICAgICAgcHV0cygiU2h1dHRpbmcgZG93bi4uLiIpOwogICAgICAgICAgICBicmVhazsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBwcmludGYoIlVua25vd24gY29tbWFuZDogJyVzJyAodHlwZSBoZWxwKVxuIiwgY21kKTsKICAgICAgICB9CiAgICB9CgogICAgZnJlZV9pbnZlbnRvcnkoJmludik7CiAgICByZXR1cm4gMDsKfQo=