/*:::::*/ FBCALL int fb_ConsoleInput( FBSTRING *text, int addquestion, int addnewline ) { FB_INPUTCTX *ctx; int res; fb_DevScrnInit_Read( ); if( fb_IsRedirected( TRUE ) ) { /* del if temp */ fb_hStrDelTemp( text ); return fb_FileInput( 0 ); } ctx = FB_TLSGETCTX( INPUT ); fb_StrDelete( &ctx->str ); ctx->handle = 0; ctx->status = 0; ctx->index = 0; res = fb_LineInput( text, &ctx->str, -1, 0, addquestion, addnewline ); return res; }
int fb_DevFileReadLineWstr( FB_FILE *handle, FB_WCHAR *dst, int dst_chars ) { int res; FILE *fp; FBSTRING temp = { 0 }; FB_LOCK(); fp = (FILE *)handle->opaque; if( fp == stdout || fp == stderr ) fp = stdin; if( fp == NULL ) { FB_UNLOCK(); return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); } res = fb_DevFileReadLineDumb( fp, &temp, NULL ); /* convert to wchar, file should be opened with the ENCODING option to allow UTF characters to be read */ if( (res == FB_RTERROR_OK) || (res == FB_RTERROR_ENDOFFILE) ) fb_WstrAssignFromA( dst, dst_chars, (void *)&temp, -1 ); fb_StrDelete( &temp ); FB_UNLOCK(); return res; }
/*:::::*/ int fb_ConsoleLineInputWstr( const FB_WCHAR *text, FB_WCHAR *dst, int max_chars, int addquestion, int addnewline ) { int res; size_t len; int old_x, old_y; /* !!!FIXME!!! no support for unicode input */ fb_PrintBufferEx( NULL, 0, FB_PRINT_FORCE_ADJUST ); fb_GetXY( &old_x, &old_y ); FB_LOCK(); if( text != NULL ) { fb_PrintWstr( 0, text, 0 ); if( addquestion != FB_FALSE ) fb_PrintFixString( 0, pszDefaultQuestion, 0 ); } { FBSTRING str_result = { 0 }; res = fb_DevFileReadLineDumb( stdin, &str_result, hWrapper ); len = FB_STRSIZE(&str_result); if( !addnewline ) { int cols, rows; int old_y; fb_GetSize( &cols, &rows ); fb_GetXY( NULL, &old_y ); old_x += len - 1; old_x %= cols; old_x += 1; old_y -= 1; fb_Locate( old_y, old_x, -1, 0, 0 ); } fb_WstrAssignFromA( dst, max_chars, (void *)&str_result, -1 ); fb_StrDelete( &str_result ); } FB_UNLOCK(); return res; }
/*:::::*/ FBCALL void fb_StrSwap( void *str1, int size1, int fillrem1, void *str2, int size2, int fillrem2 ) { char *p1, *p2; int len1, len2; if( (str1 == NULL) || (str2 == NULL) ) return; /* both var-len? */ if( (size1 == -1) && (size2 == -1) ) { FBSTRING td; /* just swap the descriptors */ td.data = ((FBSTRING *)str1)->data; td.len = ((FBSTRING *)str1)->len; td.size = ((FBSTRING *)str1)->size; ((FBSTRING *)str1)->data = ((FBSTRING *)str2)->data; ((FBSTRING *)str1)->len = ((FBSTRING *)str2)->len; ((FBSTRING *)str1)->size = ((FBSTRING *)str2)->size; ((FBSTRING *)str2)->data = td.data; ((FBSTRING *)str2)->len = td.len; ((FBSTRING *)str2)->size = td.size; return; } FB_STRSETUP_FIX( str1, size1, p1, len1 ); FB_STRSETUP_FIX( str2, size2, p2, len2 ); /* Same length? Only need to do an fb_MemSwap() */ if( len1 == len2 ) { if( len1 > 0 ) { fb_MemSwap( (unsigned char *)p1, (unsigned char *)p2, len1 ); /* null terminators don't need to change */ } return; } /* Note: user-allocated zstrings are assumed to be large enough */ /* Is one of them a var-len string? Might need to be (re)allocated */ if( (size1 == -1) || (size2 == -1) ) { FBSTRING td = { 0 }; fb_StrAssign( &td, -1, str1, size1, FALSE ); fb_StrAssign( str1, size1, str2, size2, fillrem1 ); fb_StrAssign( str2, size2, &td, -1, fillrem2 ); fb_StrDelete( &td ); return; } /* Both are fixed-size/user-allocated [z]strings */ /* Make str1/str2 be the smaller/larger string respectively */ if( len1 > len2 ) { { char* p = p1; p1 = p2; p2 = p; } { int len = len1; len1 = len2; len2 = len; } { int size = size1; size1 = size2; size2 = size; } { int fillrem = fillrem1; fillrem1 = fillrem2; fillrem2 = fillrem; } } /* MemSwap as much as possible (i.e. the smaller length) */ if( len1 > 0 ) { fb_MemSwap( (unsigned char *)p1, (unsigned char *)p2, len1 ); } /* and copy over the remainder from larger to smaller, unless it's a fixed-size [z]string that doesn't have enough room left (not even for the null terminator) */ if( (size1 > 0) && (len2 >= size1) ) { len2 = len1; } else if( len2 > len1 ) { FB_MEMCPYX( (unsigned char *)(p1 + len1), (unsigned char *)(p2 + len1), len2 - len1 ); } /* set null terminators */ p1[len2] = '\0'; p2[len1] = '\0'; /* Clear remainder of the larger (now smaller) string with nulls if requested (see also fb_StrAssign()). We can assume that the strings were originally cleared properly, because uninitialized strings mustn't be used in rvalues, FB_STRSETUP_FIX() doesn't handle that. The smaller (now larger) string doesn't need to be touched, as it's remainder didn't increase */ if( fillrem2 ) { int used2 = len1 + 1; if( size2 > used2 ) { memset( p2 + used2, 0, size2 - used2 ); } } }
static int fb_hFileLineInputEx ( FB_FILE *handle, void *dst, ssize_t dst_len, int fillrem ) { ssize_t len, readlen; char buffer[BUFFER_LEN]; eInputMode mode = eIM_Invalid; if( !FB_HANDLE_USED(handle) ) return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); FB_LOCK(); if( handle->hooks->pfnReadLine != NULL ) { mode = eIM_ReadLine; } else if( handle->hooks->pfnRead != NULL && handle->hooks->pfnEof != NULL ) { mode = eIM_Read; } if( mode==eIM_Invalid ) { FB_UNLOCK(); return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); } switch( mode ) { case eIM_Read: /* This is the VFS-compatible way to read a line ... but it's slow */ len = readlen = 0; while (!handle->hooks->pfnEof(handle)) { int do_add = FALSE, do_break = FALSE; size_t read_len; int res = fb_FileGetDataEx( handle, 0, buffer+len, 1, &read_len, FALSE, FALSE ); if( res==FB_RTERROR_OK && read_len==1) { char ch = buffer[len]; if( ch==13 ) { res = fb_FileGetDataEx( handle, 0, &ch, 1, &read_len, FALSE, FALSE ); if( res==FB_RTERROR_OK && ch!=10 && read_len==1) { fb_FilePutBackEx( handle, &ch, 1 ); } ch = 10; } if( ch==10 ) { do_add = do_break = TRUE; } else { do_add = len==(sizeof(buffer)-1); } } else { do_add = len!=0; } if( do_add || handle->hooks->pfnEof( handle ) ) { /* create temporary string to ensure that NUL's are preserved ... * this function wants the length WITH the NUL character!!! */ buffer[len] = 0; FBSTRING *src = fb_StrAllocTempDescF( buffer, len + 1); if( readlen==0 ) { fb_StrAssign( dst, dst_len, src, -1, fillrem ); } else { fb_StrConcatAssign ( dst, dst_len, src, -1, fillrem ); } readlen += len; len = 0; } else { ++len; } if( res!=FB_RTERROR_OK || do_break ) break; } if( readlen == 0 ) { /* del destine string */ if( dst_len == -1 ) fb_StrDelete( (FBSTRING *)dst ); else *(char *)dst = '\0'; } break; case eIM_ReadLine: /* The read line mode is the most comfortable ... but IMHO it's * only useful for special devices (like SCRN:) */ { /* destine is a var-len string? read directly */ if( dst_len == -1 ) { handle->hooks->pfnReadLine( handle, dst ); } /* fixed-len or unknown size (ie: pointers)? use a temp var-len */ else { FBSTRING str_result = { 0, 0, 0 }; /* read complete line (may include NULs) */ handle->hooks->pfnReadLine( handle, &str_result ); /* add contents of tempporary string to result buffer */ fb_StrAssign( dst, dst_len, (void *)&str_result, -1, fillrem ); /* delete result */ fb_StrDelete( &str_result ); } } break; case eIM_Invalid: /* the "invalid" mode was already handled above ... so we don't * need to do anything here ... */ break; } FB_UNLOCK(); return fb_ErrorSetNum( FB_RTERROR_OK ); }
int fb_DevFileReadLineDumb ( FILE *fp, FBSTRING *dst, fb_FnDevReadString pfnReadString ) { int res = fb_ErrorSetNum( FB_RTERROR_OK ); size_t buffer_len; int found, first_run; char buffer[512]; FBSTRING src = { &buffer[0], 0, 0 }; DBG_ASSERT( dst!=NULL ); buffer_len = sizeof(buffer); first_run = TRUE; FB_LOCK(); if( pfnReadString == NULL ) pfnReadString = hWrapper; found = FALSE; while (!found) { memset( buffer, 0, buffer_len ); if( pfnReadString( buffer, sizeof( buffer ), fp ) == NULL ) { /* EOF reached ... this is not an error !!! */ res = FB_RTERROR_ENDOFFILE; /* but we have to notify the caller */ if( first_run ) fb_StrDelete( dst ); break; } /* the last character always is NUL */ buffer_len = sizeof(buffer) - 1; /* now let's find the end of the buffer */ while (buffer_len--) { char ch = buffer[buffer_len]; if (ch==13 || ch==10) { /* accept both CR and LF */ found = TRUE; break; } else if( ch!=0 ) { /* a character other than CR/LF found ... i.e. buffer full */ break; } } int tmp_buf_len; if( !found ) { /* remember the real length */ tmp_buf_len = buffer_len += 1; /* not found ... so simply add this to the result string */ } else { /* remember the real length */ tmp_buf_len = buffer_len + 1; /* filter a (possibly valid) CR/LF sequence */ if( buffer[buffer_len]==10 && buffer_len!=0 ) { if( buffer[buffer_len-1]==13 ) { --buffer_len; } } /* set the CR or LF to NUL */ buffer[buffer_len] = 0; } src.size = src.len = buffer_len; /* assign or concatenate */ if( first_run ) fb_StrAssign( dst, -1, &src, -1, FALSE ); else fb_StrConcatAssign( dst, -1, &src, -1, FALSE ); first_run = FALSE; buffer_len = tmp_buf_len; } FB_UNLOCK(); return res; }
/*:::::*/ int fb_ConsoleLineInput( FBSTRING *text, void *dst, int dst_len, int fillrem, int addquestion, int addnewline ) { int res; size_t len; int old_x, old_y; fb_PrintBufferEx( NULL, 0, FB_PRINT_FORCE_ADJUST ); fb_GetXY( &old_x, &old_y ); FB_LOCK(); if( text != NULL ) { if( text->data != NULL ) { fb_PrintString( 0, text, 0 ); } /* del if temp */ else { fb_hStrDelTemp( text ); } if( addquestion != FB_FALSE ) { fb_PrintFixString( 0, pszDefaultQuestion, 0 ); } } { /* create temporary string */ FBSTRING str_result = { 0 }; res = fb_DevFileReadLineDumb( stdin, &str_result, hWrapper ); len = FB_STRSIZE(&str_result); /* We have to handle the NEWLINE stuff here because we *REQUIRE* * the *COMPLETE* temporary input string for the correct position * adjustment. */ if( !addnewline ) { /* This is the easy and dumb method to do the position adjustment. * The problem is that it doesn't take TAB's into account. */ int cols, rows; int old_y; fb_GetSize( &cols, &rows ); fb_GetXY( NULL, &old_y ); old_x += len - 1; old_x %= cols; old_x += 1; old_y -= 1; fb_Locate( old_y, old_x, -1, 0, 0 ); } /* add contents of tempporary string to result buffer */ fb_StrAssign( dst, dst_len, (void *)&str_result, -1, fillrem ); fb_StrDelete( &str_result ); } FB_UNLOCK(); return res; }
FBCALL void *fb_WstrAssignToAEx ( void *dst, ssize_t dst_chars, FB_WCHAR *src, int fill_rem, int is_init ) { ssize_t src_chars; if( dst == NULL ) return dst; if( src != NULL ) src_chars = fb_wstr_Len( src ); else src_chars = 0; /* is dst var-len? */ if( dst_chars == -1 ) { /* src NULL? */ if( src_chars == 0 ) { if( is_init == FB_FALSE ) { fb_StrDelete( (FBSTRING *)dst ); } else { ((FBSTRING *)dst)->data = NULL; ((FBSTRING *)dst)->len = 0; ((FBSTRING *)dst)->size = 0; } } else { /* realloc dst if needed and copy src */ if( is_init == FB_FALSE ) { if( FB_STRSIZE( dst ) != src_chars ) fb_hStrRealloc( (FBSTRING *)dst, src_chars, FB_FALSE ); } else { fb_hStrAlloc( (FBSTRING *)dst, src_chars ); } fb_wstr_ConvToA( ((FBSTRING *)dst)->data, src, src_chars ); } } /* fixed-len or zstring.. */ else { /* src NULL? */ if( src_chars == 0 ) { *(char *)dst = '\0'; } else { /* byte ptr? as in C, assume dst is large enough */ if( dst_chars == 0 ) dst_chars = src_chars; fb_wstr_ConvToA( (char *)dst, src, (dst_chars <= src_chars? dst_chars : src_chars) ); } /* fill reminder with null's */ if( fill_rem != 0 ) { dst_chars -= src_chars; if( dst_chars > 0 ) memset( &(((char *)dst)[src_chars]), 0, dst_chars ); } } return dst; }