void term_write(char const* str) { size_t i, len = strlen(str); for(i=0; i<len; ++i) { term_putch(str[i]); } }
// picoc: term_puts(x, y, string); static void pterm_puts(pstate *p, val *r, val **param, int n) { const char *buf = param[2]->Val->Identifier; size_t len = strlen(buf), i; term_gotoxy(param[0]->Val->UnsignedInteger, param[1]->Val->UnsignedInteger); for (i = 0; i < len; i++) term_putch(buf[i]); r->Val->UnsignedLongInteger = len; }
static void ptermh_prin(any x) { if (!isNil(x)) { if (isNum(x)) outNum_term(unBox(x)); else if (isSym(x)) { int i, c; word w; u8 byte; for (x = name(x), c = getByte1(&i, &w, &x); c; c = getByte(&i, &w, &x)) { if (c != '^') { byte = c; term_putch(byte); } else if (!(c = getByte(&i, &w, &x))) { byte = '^'; term_putch(byte); } else if (c == '?') { byte = 127; term_putch(byte); } else { c &= 0x1F; byte = (u8)c; term_putch(byte); } } } else { while (ptermh_prin(car(x)), !isNil(x = cdr(x))) { if (!isCell(x)) { ptermh_prin(x); break; } } } } }
// Lua: print( string1, string2, ... ) // or print( x, y, string1, string2, ... ) static int luaterm_print( lua_State *L ) { const char *buf; size_t len, i; int total = lua_gettop( L ), s = 1; int x = -1, y = -1; // Check if the function has integer arguments if( lua_isnumber( L, 1 ) && lua_isnumber( L, 2 ) ) { x = lua_tointeger( L, 1 ); y = lua_tointeger( L, 2 ); term_gotoxy( x, y ); s = 3; } for( ; s <= total; s ++ ) { luaL_checktype( L, s, LUA_TSTRING ); buf = lua_tolstring( L, s, &len ); for( i = 0; i < len; i ++ ) term_putch( buf[ i ] ); } return 0; }
static int linenoisePrompt(int id, char *buf, size_t buflen, const char *prompt) { size_t plen = strlen(prompt); size_t pos = 0; size_t len = 0; size_t cols = TERM_COLS; int history_index = 0; buf[0] = '\0'; buflen--; /* Make sure there is always space for the nulterm */ /* The latest history entry is always our current buffer, that * initially is just an empty string. */ linenoise_internal_addhistory( id, "", LINENOISE_PUSH_EMPTY ); term_putstr( prompt, plen ); while(1) { int c; c = term_getch( TERM_INPUT_WAIT ); switch(c) { case KC_ENTER: case KC_CTRL_C: case KC_CTRL_Z: history_lengths[ id ] --; free( histories[ id ][history_lengths[ id ]] ); if( c == KC_CTRL_C ) return LINENOISE_CTRL_C; else if( c == KC_CTRL_Z ) return -1; return len; case KC_BACKSPACE: if (pos > 0 && len > 0) { memmove(buf+pos-1,buf+pos,len-pos); pos--; len--; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); } break; case KC_CTRL_T: /* ctrl-t */ // bogdanm: this seems to be rather useless and also a bit buggy, // so it's not enabled /* if (pos > 0 && pos < len) { int aux = buf[pos-1]; buf[pos-1] = buf[pos]; buf[pos] = aux; if (pos != len-1) pos++; refreshLine(prompt,buf,len,pos,cols); }*/ break; case KC_LEFT: /* left arrow */ if (pos > 0) { pos--; refreshLine(prompt,buf,len,pos,cols); } break; case KC_RIGHT: /* right arrow */ if (pos != len) { pos++; refreshLine(prompt,buf,len,pos,cols); } break; case KC_UP: case KC_DOWN: /* up and down arrow: history */ if (history_lengths[ id ] > 1) { /* Update the current history entry before to * overwrite it with tne next one. */ free(histories[ id ][history_lengths[ id ]-1-history_index]); histories[ id ][history_lengths[ id ]-1-history_index] = strdup(buf); /* Show the new entry */ history_index += (c == KC_UP) ? 1 : -1; if (history_index < 0) { history_index = 0; break; } else if (history_index >= history_lengths[ id ]) { history_index = history_lengths[ id ]-1; break; } strncpy(buf,histories[ id ][history_lengths[ id ]-1-history_index],buflen); buf[buflen] = '\0'; len = pos = strlen(buf); refreshLine(prompt,buf,len,pos,cols); } break; case KC_DEL: /* delete */ if (len > 0 && pos < len) { memmove(buf+pos,buf+pos+1,len-pos-1); len--; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); } break; case KC_HOME: /* Ctrl+a, go to the start of the line */ pos = 0; refreshLine(prompt,buf,len,pos,cols); break; case KC_END: /* ctrl+e, go to the end of the line */ pos = len; refreshLine(prompt,buf,len,pos,cols); break; case KC_CTRL_U: /* Ctrl+u, delete the whole line. */ buf[0] = '\0'; pos = len = 0; refreshLine(prompt,buf,len,pos,cols); break; case KC_CTRL_K: /* Ctrl+k, delete from current to end of line. */ buf[pos] = '\0'; len = pos; refreshLine(prompt,buf,len,pos,cols); break; default: if( isprint( c ) && len < buflen ) { if(len == pos) { buf[pos] = c; pos++; len++; buf[len] = '\0'; if (plen+len < cols) { /* Avoid a full update of the line in the * trivial case. */ term_putch( c ); } else { refreshLine(prompt,buf,len,pos,cols); } } else { memmove(buf+pos+1,buf+pos,len-pos); buf[pos] = c; len++; pos++; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); } } break; } } return len; }
// picoc: term_putch(ch); static void pterm_putch(pstate *p, val *r, val **param, int n) { term_putch(param[0]->Val->Character); r->Val->UnsignedInteger = 1; }
// Helpers for picoLisp terminal print // function. static void outString_term(char *s) { while (*s) term_putch((u8)*s++); }
//-------------------------------------------------------------------- int linenoisePrompt(int id, char *buf, int buflen, const char *prompt) { size_t plen = strlen(prompt); size_t pos = 0; size_t len = 0; size_t cols = term_num_cols; int history_index = 0; int c; int ins = 1; buf[0] = '\0'; buflen--; // Make sure there is always space for the nulterm // The latest history entry is always our current buffer, that initially is just an empty string. linenoise_internal_addhistory( id, "", LINENOISE_PUSH_EMPTY ); term_putstr( prompt, plen ); term_curs(0); while(1) { c = term_getch(TERM_INPUT_WAIT); if (c < 0) continue; switch(c) { case KC_ENTER: history_lengths[ id ] --; free( histories[ id ][history_lengths[ id ]] ); return len; break; case KC_CTRL_D: if (len == 0) return LINENOISE_CTRL_D; break; case KC_CTRL_C: len = 0; pos = 0; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); break; case KC_BACKSPACE: if (pos > 0 && len > 0) { memmove(buf+pos-1,buf+pos,len-pos); pos--; len--; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); } break; case KC_INS: ins ^= 1; if (ins) term_curs(0); else term_curs(4); break; case KC_CTRL_T: // bogdanm: this seems to be rather useless and also a bit buggy, // so it's not enabled /* if (pos > 0 && pos < len) { int aux = buf[pos-1]; buf[pos-1] = buf[pos]; buf[pos] = aux; if (pos != len-1) pos++; refreshLine(prompt,buf,len,pos,cols); } */ break; case KC_LEFT: // left arrow if (pos > 0) { pos--; refreshLine(prompt,buf,len,pos,cols); } break; case KC_RIGHT: // right arrow if (pos != len) { pos++; refreshLine(prompt,buf,len,pos,cols); } break; case KC_UP: case KC_DOWN: // up and down arrow: history if (history_lengths[ id ] > 1) { // Update the current history entry before to overwrite it with tne next one. free(histories[ id ][history_lengths[ id ]-1-history_index]); histories[ id ][history_lengths[ id ]-1-history_index] = strdup(buf); // Show the new entry history_index += (c == KC_UP) ? 1 : -1; if (history_index < 0) { history_index = 0; break; } else if (history_index >= history_lengths[ id ]) { history_index = history_lengths[ id ]-1; break; } strncpy(buf, histories[ id ][history_lengths[ id ]-1-history_index], buflen); buf[buflen] = '\0'; if ((strlen(buf) > 7) && (strstr(buf, "return ")) == buf) { memmove(buf+1, buf+7, strlen(buf)-6); buf[0] = '='; } len = pos = strlen(buf); refreshLine(prompt,buf,len,pos,cols); } break; case KC_DEL: // delete if (len > 0 && pos < len) { memmove(buf+pos,buf+pos+1,len-pos-1); len--; buf[len] = '\0'; refreshLine(prompt,buf,len,pos,cols); } break; case KC_HOME: // Ctrl+a, go to the start of the line pos = 0; refreshLine(prompt,buf,len,pos,cols); break; case KC_END: // ctrl+e, go to the end of the line pos = len; refreshLine(prompt,buf,len,pos,cols); break; case KC_CTRL_U: // Ctrl+u, delete the whole line. buf[0] = '\0'; pos = len = 0; refreshLine(prompt,buf,len,pos,cols); break; case KC_CTRL_K: // Ctrl+k, delete from current to end of line. buf[pos] = '\0'; len = pos; refreshLine(prompt,buf,len,pos,cols); break; default: if( isprint( c ) && len < buflen ) { if(len == pos) { buf[pos] = c; pos++; len++; buf[len] = '\0'; if (plen+len < cols) { // Avoid a full update of the line in the trivial case. term_putch( c ); } else { refreshLine(prompt,buf,len,pos,cols); } } else { if (ins) { memmove(buf+pos+1,buf+pos,len-pos); buf[pos] = c; len++; pos++; buf[len] = '\0'; } else { buf[pos] = c; pos++; } refreshLine(prompt,buf,len,pos,cols); } } break; } } return len; }