static void cellToQString( const UCell* val, QString& str ) { switch( ur_type(val) ) { case UT_NONE: str.clear(); break; case UT_CHAR: str = QChar( ur_int(val) ); break; case UT_INT: str.setNum( ur_int(val) ); break; case UT_DECIMAL: str.setNum( ur_decimal(val) ); break; case UT_BIGNUM: str.setNum( bignum_l(val) ); break; case UT_STRING: case UT_FILE: { USeriesIter si; int len; ur_seriesSlice( UT, &si, val ); len = si.end - si.it; switch( si.buf->form ) { case UR_ENC_LATIN1: str = QString::fromLatin1( si.buf->ptr.c + si.it, len ); break; case UR_ENC_UTF8: str = QString::fromUtf8( si.buf->ptr.c + si.it, len ); break; case UR_ENC_UCS2: str = QString::fromUtf16( si.buf->ptr.u16 + si.it, len ); break; } } break; default: { UBuffer buf; ur_strInit( &buf, UR_ENC_LATIN1, 0 ); ur_toStr( UT, val, &buf, 0 ); str = QString::fromLatin1( buf.ptr.c, buf.used ); ur_strFree( &buf ); } break; } }
/* line-edit word!/string! <max-chars> */ static GWidget* ledit_make( UThread* ut, UBlockIter* bi, const GWidgetClass* wclass ) { LineEdit* ep; const UCell* arg[2]; int maxChars = 32; if( ! gui_parseArgs( ut, bi, wclass, ledit_args, arg ) ) return 0; if( ur_isShared( arg[0]->series.buf ) ) { ur_error( ut, UR_ERR_SCRIPT, "line-edit cannot modify shared string" ); return 0; } if( arg[1] ) maxChars = ur_int(arg[1]); ep = (LineEdit*) gui_allocWidget( sizeof(LineEdit), wclass ); ep->wid.flags |= CHANGED; //ep->state = LEDIT_STATE_DISPLAY; ep->strN = arg[0]->series.buf; ep->maxChars = maxChars; ep->vboN = ledit_vbo( ut, maxChars ); return (GWidget*) ep; }
void setUniform( UThread* ut, UCell* path, UCell* val ) { if( ur_is(path, UT_SELECT) ) { UCell* cval; Shader* sh; ShaderParam* pi; ShaderParam* pend; cval = ur_buffer( ctx->ctx.valBlk )->ptr.cell; if( cval && ur_is(cval, UT_SHADER) ) { sh = (Shader*) ur_resPtr( cval->series.n )->ptr; pi = sh->param; pend = sh->param + sh->paramCount; while( pi != pend ) { if( pi->name == sel ) { switch( pi->type ) { case GL_INT: case GL_BOOL: glUniform1i( pi->location, ur_int(val) ); break; } return; } ++pi; } } } }
static int _execSpawn( UThread* ut, char* cmd, UCell* res ) { STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); // Start the child process. if( ! CreateProcess( NULL, // No module name (use command line). TEXT(cmd), // Command line. NULL, // Process handle not inheritable. NULL, // Thread handle not inheritable. FALSE, // Set handle inheritance to FALSE. 0, // No creation flags. NULL, // Use parent's environment block. NULL, // Use parent's starting directory. &si, // Pointer to STARTUPINFO structure. &pi ) // Pointer to PROCESS_INFORMATION structure. ) { return ur_error( ut, UR_ERR_INTERNAL, "CreateProcess failed (%d).\n", GetLastError() ); } // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); ur_setId(res, UT_INT); ur_int(res) = pi.dwProcessId; return UR_OK; }
static void setWID( const UCell*& prev, int id ) { if( prev ) { UCell* val = ur_wordCellM( UT, prev ); assert( val ); ur_setId(val, UT_INT); ur_int(val) = id; prev = 0; } }
int ur_readDir( UThread* ut, const char* filename, UCell* res ) { char filespec[ _MAX_PATH ]; struct _finddata_t fileinfo; intptr_t handle; // Look for all files. We ensure there is a slash before the wildcard. // It's OK if the path is already terminated with a slash - multiple // slashes are filtered by _findfirst. strcpy( filespec, filename ); strcat( filespec, "\\*.*" ); handle = _findfirst( filespec, &fileinfo ); if( handle != -1 ) { UCell* cell; UIndex blkN; UIndex hold; UIndex strN; blkN = ur_makeBlock( ut, 0 ); hold = ur_hold( blkN ); do { const char* cp = fileinfo.name; if( cp[0] == '.' && (cp[1] == '.' || cp[1] == '\0') ) continue; strN = ur_makeStringUtf8( ut, (const uint8_t*) cp, (const uint8_t*) (cp + strlen(cp)) ); cell = ur_blkAppendNew( ur_buffer(blkN), UT_FILE ); ur_setSeries( cell, strN, 0 ); } while( _findnext( handle, &fileinfo ) != -1 ); _findclose( handle ); ur_release( hold ); ur_setId(res, UT_BLOCK); ur_setSeries(res, blkN, 0); } else { ur_setId(res, UT_LOGIC); ur_int(res) = 0; } return UR_OK; }
static int slider_select( GWidget* wp, UAtom atom, UCell* res ) { EX_PTR; if( atom == UR_ATOM_VALUE ) { ur_setId(res, ep->dataType); if( ep->dataType == UT_INT ) ur_int(res) = (int32_t) ep->data.val; else ur_decimal(res) = ep->data.val; return UR_OK; } return gui_areaSelect( wp, atom, res ); }
static void slider_setValue( GSlider* ep, const UCell* cell ) { struct Value* da = &ep->data; float n; if( ur_is(cell, UT_INT) ) n = (float) ur_int(cell); else if( ur_is(cell, UT_DECIMAL) ) n = (float) ur_decimal(cell); else n = 0.0; if( n < da->min ) n = da->min; else if( n > da->max ) n = da->max; da->val = n; }
void setUniform( UThread* ut, UAtom name, UCell* cell ) { GLint loc; loc = glGetUniformLocation( grState.shaderProg, ur_atomCStr(name, 0) ); if( loc == -1 ) { printf( "KR setUniform failed %d\n", grState.shaderProg ); return; } switch( ur_type(cell) ) { case UT_LOGIC: case UT_INT: glUniform1i( loc, ur_int(cell) ); break; } }
/* Updates DrawContext attr & drawCount. Return UR_OK/UR_THROW. */ int itemview_parse( DrawContext* dc, UThread* ut, UBlockIter* bi, GWidget* wp ) { const UCell* arg[3]; UAtom atom; int opcode; float x, y; while( bi->it != bi->end ) { if( ur_is(bi->it, UT_WORD) ) { atom = ur_atom( bi->it ); opcode = ur_atomsSearch( glEnv.drawOpTable, DOP_COUNT, atom ); switch( opcode ) { case DOP_IMAGE: { QuadDim qd; int16_t rect[4]; const int16_t* coord; FETCH_ARGS( iv_args_image ); //printf( "KR IV image\n" ); coord = arg[0]->coord.n; rect[0] = coord[0] + dc->penX; rect[1] = coord[1] + dc->penY; rect[2] = coord[2]; rect[3] = coord[3]; quad_init( &qd, rect, arg[1]->coord.n, arg[2]->coord.n ); quad_emitVT( &qd, dc->attr, dc->attr + 3, AttrCount ); vbo_setVec3( dc->attr + 5, AttrCount, 6, dc->color ); dc->attr += 6 * AttrCount; dc->drawCount += 6; } break; case DOP_COLOR: FETCH_ARGS( iv_args_color ); dc->color[0] = (GLfloat) ur_int( arg[0] ); break; case DOP_FONT: FETCH_ARGS( iv_args_font ); dc->fontN = ur_fontTF( arg[0] ); break; case DOP_TEXT: FETCH_ARGS( iv_args_text ); x = dc->penX + (float) arg[0]->coord.n[0]; y = dc->penY + (float) arg[0]->coord.n[1]; { DrawTextState dts; UBinaryIter si; int glyphCount; //printf( "KR IV text\n" ); dp_toString( ut, arg[1], &si ); vbo_drawTextInit( &dts, (TexFont*) ur_buffer( dc->fontN )->ptr.v, x, y ); dts.emitTris = 1; glyphCount = vbo_drawText( &dts, dc->attr + 3, dc->attr, AttrCount, si.it, si.end ); glyphCount *= 6; vbo_setVec3( dc->attr + 5, AttrCount, glyphCount, dc->color ); /* while( si.it != si.end ) putchar( *si.it++ ); putchar( '\n' ); */ dc->attr += glyphCount * AttrCount; dc->drawCount += glyphCount; } break; default: goto invalid_op; } } else { goto invalid_op; } } return UR_OK; invalid_op: return ur_error( ut, UR_ERR_SCRIPT, "Invalid item-view instruction" ); }
void setShaderUniforms( const Shader* sh, const UBuffer* blk ) { const ShaderParam* pi = sh->param; const ShaderParam* pend = sh->param + sh->paramCount; const UCell* cval = blk->ptr.cell; int texUnit = 0; #ifdef GL_ES_VERSION_2_0 es_matrixUsed = 0; #endif while( pi != pend ) { // There is no cell type checking or conversion here for speed. // If the user loads bad types then we'll just get garbage. ++cval; switch( pi->type ) { case GL_FLOAT: glUniform1f( pi->location, ur_decimal(cval) ); break; case GL_FLOAT_VEC2: glUniform2fv( pi->location, 1, cval->vec3.xyz ); break; case GL_FLOAT_VEC3: glUniform3fv( pi->location, 1, cval->vec3.xyz ); break; //case GL_FLOAT_VEC4: case GL_INT: case GL_BOOL: glUniform1i( pi->location, ur_int(cval) ); break; case GL_INT_VEC2: glUniform2i( pi->location, cval->coord.n[0], cval->coord.n[1] ); break; case GL_INT_VEC3: glUniform3i( pi->location, cval->coord.n[0], cval->coord.n[1], cval->coord.n[2] ); break; //case GL_INT_VEC4: #ifndef GL_ES_VERSION_2_0 case GL_SAMPLER_1D: glActiveTexture( GL_TEXTURE0 + texUnit ); glEnable( GL_TEXTURE_1D ); glBindTexture( GL_TEXTURE_1D, ur_texId(cval) ); glUniform1i( pi->location, texUnit ); ++texUnit; break; #endif case GL_SAMPLER_2D: #ifndef GL_ES_VERSION_2_0 case GL_SAMPLER_2D_SHADOW: #endif glActiveTexture( GL_TEXTURE0 + texUnit ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, ur_texId(cval) ); glUniform1i( pi->location, texUnit ); ++texUnit; break; //case GL_SAMPLER_3D: #ifdef GL_ES_VERSION_2_0 case GL_FLOAT_MAT4: /* fprintf( stderr, "sha %f,%f,%f\n %f,%f,%f\n %f,%f,%f\n", matrixTop[0], matrixTop[1], matrixTop[2], matrixTop[4], matrixTop[5], matrixTop[6], matrixTop[8], matrixTop[9], matrixTop[10] ); */ es_matrixLoc = pi->location; es_matrixUsed = 1; //glUniformMatrix4fv( pi->location, 1, GL_FALSE, matrixTop ); break; #endif } ++pi; } }
/* Sets res to either a shader! or a context! whose first value is a shader!. Returns UR_OK/UR_THROW. */ int ur_makeShader( UThread* ut, const char* vert, const char* frag, UCell* res ) { #define MAX_SHADER_PARAM 16 // LIMIT: User parameters per shader. Shader shad; Shader* sh; UIndex bufN; UBuffer* buf; int i; char name[ 128 ]; ShaderParam param[ MAX_SHADER_PARAM ]; ShaderParam* pi; GLsizei length; GLint size; GLenum type; GLint count = 0; if( ! createShader( ut, &shad, vert, frag ) ) return UR_THROW; glGetProgramiv( shad.program, GL_ACTIVE_UNIFORMS, &count ); // Collect non-gl parameters. pi = param; for( i = 0; i < count; ++i ) { glGetActiveUniform( shad.program, i, 128, &length, &size, &type, name ); if( name[0] == 'g' && name[1] == 'l' && name[2] == '_' ) continue; pi->type = type; pi->location = glGetUniformLocation( shad.program, name ); pi->name = ur_internAtom( ut, name, name + length ); if( pi->name == UR_INVALID_ATOM ) return UR_THROW; ++pi; } count = pi - param; if( count ) { ShaderParam* pend; UBuffer* ctx; UCell* cval; // We have parameters - make context to hold shader & params. ctx = ur_makeContextCell( ut, count + 1, res ); cval = ur_ctxAddWord( ctx, UR_ATOM_SHADER ); pi = param; pend = param + count; while( pi != pend ) { cval = ur_ctxAddWord( ctx, pi->name ); #if 0 printf( "KR Shader Param %d is type %d\n", (int) (pi - param), pi->type ); #endif switch( pi->type ) { case GL_FLOAT: ur_setId( cval, UT_DECIMAL ); ur_decimal( cval ) = 0.0; break; case GL_FLOAT_VEC2: case GL_FLOAT_VEC3: //case GL_FLOAT_VEC4: ur_setId( cval, UT_VEC3 ); cval->vec3.xyz[0] = cval->vec3.xyz[1] = cval->vec3.xyz[2] = 0.0f; break; case GL_INT: ur_setId( cval, UT_INT ); ur_int( cval ) = 0; break; case GL_INT_VEC2: case GL_INT_VEC3: //case GL_INT_VEC4: ur_setId( cval, UT_COORD ); break; case GL_BOOL: ur_setId( cval, UT_LOGIC ); ur_int( cval ) = 0; break; case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: #ifndef GL_ES_VERSION_2_0 case GL_SAMPLER_1D: case GL_SAMPLER_3D: case GL_SAMPLER_1D_SHADOW: case GL_SAMPLER_2D_SHADOW: #endif ur_setId( cval, UT_NONE ); ur_texId(cval) = 0; // Expecting texture!. break; #ifdef GL_ES_VERSION_2_0 case GL_FLOAT_MAT4: ur_setId( cval, UT_NONE ); break; #endif default: ur_setId( cval, UT_NONE ); break; /* GL_BOOL_VEC2: GL_BOOL_VEC3: GL_BOOL_VEC4: GL_FLOAT_MAT2: GL_FLOAT_MAT3: GL_FLOAT_MAT4: GL_SAMPLER_2D_RECT: GL_SAMPLER_2D_RECT_SHADOW: */ } ++pi; } ur_ctxSort( ctx ); } ur_genBuffers( ut, 1, &bufN ); buf = ur_buffer( bufN ); buf->type = UT_SHADER; buf->ptr.v = memAlloc( sizeof(Shader) + sizeof(ShaderParam) * (count - 1) ); sh = (Shader*) buf->ptr.v; sh->program = shad.program; sh->paramCount = count; if( count ) { memCpy( sh->param, param, sizeof(ShaderParam) * count ); // First context value will be set to shader!. res = ur_buffer( res->series.buf )->ptr.cell; } ur_setId( res, UT_SHADER ); ur_setSeries( res, bufN, 0 ); return UR_OK; }
static int _execIO( UThread* ut, char* cmd, UCell* res, const UBuffer* in, UBuffer* out, UBuffer* err ) { HANDLE childStdInR; HANDLE childStdInW; HANDLE childStdOutR; HANDLE childStdOutW; HANDLE childStdErrR; HANDLE childStdErrW; SECURITY_ATTRIBUTES sec; STARTUPINFO si; PROCESS_INFORMATION pi; DWORD flags = 0; sec.nLength = sizeof(SECURITY_ATTRIBUTES); sec.lpSecurityDescriptor = NULL; sec.bInheritHandle = TRUE; childStdOutR = childStdErrR = INVALID_HANDLE_VALUE; if( in ) { if( ! CreatePipe( &childStdInR, &childStdInW, &sec, 0 ) ) { fail0: return ur_error( ut, UR_ERR_INTERNAL, "CreatePipe failed\n" ); } // Child does not inherit our end of pipe. SetHandleInformation( childStdInW, HANDLE_FLAG_INHERIT, 0 ); } if( out ) { if( ! CreatePipe( &childStdOutR, &childStdOutW, &sec, 0 ) ) { fail1: if( in ) _closePipe( childStdInR, childStdInW ); goto fail0; } // Child does not inherit our end of pipe. SetHandleInformation( childStdOutR, HANDLE_FLAG_INHERIT, 0 ); flags = DETACHED_PROCESS; } if( err ) { if( ! CreatePipe( &childStdErrR, &childStdErrW, &sec, 0 ) ) { if( out ) _closePipe( childStdOutR, childStdOutW ); goto fail1; } // Child does not inherit our end of pipe. SetHandleInformation( childStdErrR, HANDLE_FLAG_INHERIT, 0 ); flags = DETACHED_PROCESS; } ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); if( in || out || err ) { si.hStdInput = in ? childStdInR : NULL; si.hStdOutput = out ? childStdOutW : GetStdHandle( STD_OUTPUT_HANDLE ); si.hStdError = err ? childStdErrW : GetStdHandle( STD_ERROR_HANDLE ); si.dwFlags = STARTF_USESTDHANDLES; } ZeroMemory( &pi, sizeof(pi) ); // Start the child process. if( ! CreateProcess( NULL, // No module name (use command line). TEXT(cmd), // Command line. NULL, // Process handle not inheritable. NULL, // Thread handle not inheritable. TRUE, // Handle inheritance. flags, // Creation flags. NULL, // Use parent's environment block. NULL, // Use parent's starting directory. &si, // Pointer to STARTUPINFO structure. &pi ) // Pointer to PROCESS_INFORMATION structure. ) { if( in ) _closePipe( childStdInR, childStdInW ); if( out ) _closePipe( childStdOutR, childStdOutW ); if( err ) _closePipe( childStdErrR, childStdErrW ); return ur_error( ut, UR_ERR_INTERNAL, "CreateProcess failed (%d).\n", GetLastError() ); } if( in ) { DWORD nw; CloseHandle( childStdInR ); WriteFile( childStdInW, in->ptr.v, (in->type == UT_STRING) ? in->used * in->elemSize : in->used, &nw, NULL ); CloseHandle( childStdInW ); } if( out || err ) { if( out ) CloseHandle( childStdOutW ); if( err ) CloseHandle( childStdErrW ); _readPipes( childStdOutR, out, childStdErrR, err ); if( out ) CloseHandle( childStdOutR ); if( err ) CloseHandle( childStdErrR ); } { DWORD code; // Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); if( GetExitCodeProcess( pi.hProcess, &code ) ) { ur_setId(res, UT_INT); ur_int(res) = code; } else { ur_setId(res, UT_NONE); } } // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); return UR_OK; }
/* Recursively evaluate math expression. \param cell Cell to evaluate. \param res Result. \return UR_OK or UR_THROW. */ int calc_eval( UThread* ut, UCell* cell, double* res ) { switch( ur_type(cell) ) { case UT_WORD: { const UCell* val = ur_wordCell( ut, cell ); if( ! val ) return UR_THROW; if( ur_is(val, UT_DECIMAL) ) *res = ur_decimal(val); else if( ur_is(val, UT_INT) || ur_is(val, UT_CHAR) ) *res = (double) ur_int(val); else { return ur_error( ut, UR_ERR_SCRIPT, "Invalid word '%s", ur_wordCStr( cell ) ); } } break; case UT_DECIMAL: *res = ur_decimal(cell); break; case UT_INT: case UT_CHAR: *res = (double) ur_int(cell); break; case UT_BLOCK: case UT_PAREN: { UBlockIterM bi; double num = 0.0; double right; #define RIGHT_VAL \ if( ++bi.it == bi.end ) \ return ur_error( ut, UR_ERR_SCRIPT, "Expected operator r-value" ); \ if( ! calc_eval( ut, bi.it, &right ) ) \ return UR_THROW; if( ! ur_blkSliceM( ut, &bi, cell ) ) return UR_THROW; ur_foreach( bi ) { if( ur_is(bi.it, UT_WORD) ) { switch( ur_atom(bi.it) ) { case UR_ATOM_PLUS: RIGHT_VAL num += right; break; case UR_ATOM_MINUS: RIGHT_VAL num -= right; break; case UR_ATOM_ASTERISK: RIGHT_VAL num *= right; break; case UR_ATOM_SLASH: RIGHT_VAL num /= right; break; default: if( ! calc_eval( ut, bi.it, &num ) ) return UR_THROW; } } else if( ur_is(bi.it, UT_SETWORD) ) { cell = ur_wordCellM( ut, bi.it ); if( ! cell ) return UR_THROW; ur_setId( cell, UT_DECIMAL ); ur_decimal(cell) = num; } else { if( ! calc_eval( ut, bi.it, &num ) ) return UR_THROW; } } *res = num; } break; default: *res = 0.0; break; } return UR_OK; }
/* Returns zero if matching rule not found or exception occured. */ static const UCell* _parseBin( UThread* ut, BinaryParser* pe, const UCell* rit, const UCell* rend, UIndex* spos ) { const UCell* set = 0; const UCell* tval; uint32_t bitCount; uint32_t field; UBuffer* ibin = ur_buffer( pe->inputBufN ); uint8_t* in = ibin->ptr.b + *spos; uint8_t* inEnd = ibin->ptr.b + pe->inputEnd; match: while( rit != rend ) { switch( ur_type(rit) ) { case UT_INT: bitCount = ur_int(rit); if( bitCount < 1 || bitCount > 32 ) { ur_error( PARSE_ERR, "bit-field size must be 1 to 32" ); goto parse_err; } if( bitCount > 24 ) { uint32_t high; in = pullBits( pe, bitCount - 16, in, inEnd, &high ); if( ! in ) goto failed; in = pullBits( pe, 16, in, inEnd, &field ); if( ! in ) goto failed; field |= high << 16; } else { in = pullBits( pe, bitCount, in, inEnd, &field ); if( ! in ) goto failed; } goto set_field; case UT_WORD: switch( ur_atom(rit) ) { case UR_ATOM_U8: if( in == inEnd ) goto failed; field = *in++; goto set_field; case UR_ATOM_U16: if( (inEnd - in) < 2 ) goto failed; if( pe->bigEndian ) field = (in[0] << 8) | in[1]; else field = (in[1] << 8) | in[0]; in += 2; goto set_field; case UR_ATOM_U32: if( (inEnd - in) < 4 ) goto failed; if( pe->bigEndian ) field = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3]; else field = (in[3] << 24) | (in[2] << 16) | (in[1] << 8) | in[0]; in += 4; goto set_field; case UR_ATOM_SKIP: ++rit; ++in; break; #if 0 case UR_ATOM_MARK: break; case UR_ATOM_PLACE: ++rit; if( (rit != rend) && ur_is(rit, UT_WORD) ) { tval = ur_wordCell( ut, rit++ ); CHECK_WORD(tval); if( ur_is(tval, UT_BINARY) ) { pos = tval->series.it; break; } } ur_error( PARSE_ERR, "place expected series word" ); goto parse_err; #endif case UR_ATOM_COPY: // copy dest size // word! int!/word! ++rit; if( (rit != rend) && ur_is(rit, UT_WORD) ) { UCell* res = ur_wordCellM( ut, rit ); CHECK_WORD(res); if( ++rit != rend ) { tval = rit++; if( ur_is(tval, UT_WORD) ) { tval = ur_wordCell( ut, tval ); CHECK_WORD(tval); } if( ur_is(tval, UT_INT) ) { UBuffer* cb; int size = ur_int(tval); cb = ur_makeBinaryCell( ut, size, res ); cb->used = size; memCpy( cb->ptr.b, in, size ); in += size; break; } } ur_error( PARSE_ERR, "copy expected int! count" ); goto parse_err; } ur_error( PARSE_ERR, "copy expected word! destination" ); goto parse_err; case UR_ATOM_BIG_ENDIAN: ++rit; pe->bigEndian = 1; break; case UR_ATOM_LITTLE_ENDIAN: ++rit; pe->bigEndian = 0; break; default: tval = ur_wordCell( ut, rit ); CHECK_WORD(tval); if( ur_is(tval, UT_CHAR) ) goto match_char; else if( ur_is(tval, UT_STRING) ) goto match_string; else if( ur_is(tval, UT_BLOCK) ) goto match_block; /* else if( ur_is(tval, UT_BITSET) ) goto match_bitset; */ else { ur_error( PARSE_ERR, "parse expected char!/string!/block!" ); goto parse_err; } break; } break; case UT_SETWORD: set = rit++; while( (rit != rend) && ur_is(rit, UT_SETWORD) ) ++rit; break; #if 0 case UT_GETWORD: break; case UT_INT: repMin = ur_int(rit); ++rit; if( rit == rend ) return 0; if( ur_is(rit, UT_INT) ) { repMax = ur_int(rit); ++rit; } else { repMax = repMin; } goto repeat; #endif case UT_CHAR: match_char: if( *in != ur_int(rit) ) goto failed; ++in; ++rit; break; case UT_BLOCK: tval = rit; match_block: { UBlockIter bi; UIndex pos = in - ibin->ptr.b; UIndex rblkN = tval->series.buf; ur_blkSlice( ut, &bi, tval ); tval = _parseBin( ut, pe, bi.it, bi.end, &pos ); ibin = ur_buffer( pe->inputBufN ); if( ! tval ) { if( pe->exception == PARSE_EX_ERROR ) { ur_appendTrace( ut, rblkN, 0 ); return 0; } if( pe->exception == PARSE_EX_BREAK ) pe->exception = PARSE_EX_NONE; else goto failed; } in = ibin->ptr.b + pos; inEnd = ibin->ptr.b + pe->inputEnd; ++rit; } break; case UT_PAREN: { UIndex pos = in - ibin->ptr.b; if( UR_OK != pe->eval( ut, rit ) ) goto parse_err; /* Re-acquire pointer & check if input modified. */ ibin = ur_buffer( pe->inputBufN ); if( pe->sliced ) { // We have no way to track changes to the end of a slice, // so just make sure we remain in valid memery. if( ibin->used < pe->inputEnd ) pe->inputEnd = ibin->used; } else { // Not sliced, track input end. if( ibin->used != pe->inputEnd ) pe->inputEnd = ibin->used; } in = ibin->ptr.b + pos; inEnd = ibin->ptr.b + pe->inputEnd; ++rit; } break; case UT_STRING: tval = rit; match_string: { UBinaryIter bi; int size; ur_binSlice( ut, &bi, tval ); if( ur_strIsUcs2(bi.buf) ) goto bad_enc; size = bi.end - bi.it; if( size > (inEnd - in) ) goto failed; if( match_pattern_8(in, inEnd, bi.it, bi.end) == bi.end ) { in += size; ++rit; } else goto failed; } break; #if 0 case UT_BITSET: tval = rit; match_bitset: if( pos >= pe->inputEnd ) goto failed; { const UBuffer* bin = ur_bufferSer( tval ); int c = istr->ptr.c[ pos ]; if( bitIsSet( bin->ptr.b, c ) ) { ++rit; ++pos; } else goto failed; } break; #endif default: ur_error( PARSE_ERR, "invalid parse value" ); //orDatatypeName( ur_type(rit) ) ); goto parse_err; } } //complete: *spos = in - ibin->ptr.b; return rit; set_field: if( set ) { UCell* val; while( set != rit ) { val = ur_wordCellM( ut, set++ ); CHECK_WORD(val); ur_setId(val, UT_INT); ur_int(val) = field; } set = 0; } ++rit; goto match; failed: *spos = in - ibin->ptr.b; return 0; bad_enc: ur_error( ut, UR_ERR_INTERNAL, "parse binary does not handle UCS2 strings" ); //goto parse_err; parse_err: pe->exception = PARSE_EX_ERROR; return 0; }
/* Layout Language \return Layout pointer or zero if error generated. */ QLayout* ur_qtLayout( UThread* ut, LayoutInfo& parent, const UCell* blkC ) { CBParser cbp; UBlockIter bi; LayoutInfo lo; const UCell* val; const UCell* setWord = 0; QWidget* wid = 0; int match; ur_blkSlice( ut, &bi, blkC ); cbp_beginParse( ut, &cbp, bi.it, bi.end, qEnv.layoutRules ); while( (match = cbp_matchRule( &cbp )) > -1 ) { switch( match ) { case LD_HBOX: case LD_VBOX: { wid = 0; lo.grid = 0; lo.box = new QBoxLayout( (match == LD_HBOX) ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom ); if( parent.layout() ) parent.addLayout( lo.box ); val = cbp.values + 1; //TODO: Handle error. ur_qtLayout( ut, lo, val ); } break; case LD_LABEL: { QString txt; if( ! getString( ut, cbp.values + 1, txt ) ) return 0; MAKE_WIDGET( SLabel ) pw->setText( txt ); } break; case LD_BUTTON: { MAKE_WIDGET( SButton ) pw->setText( qstring( cbp.values + 1 ) ); pw->setBlock( cbp.values + 2 ); } break; case LD_CHECKBOX: { MAKE_WIDGET( SCheck ) pw->setText( qstring( cbp.values + 1 ) ); } break; case LD_SPIN_BOX: { MAKE_WIDGET( SSpinBox ) pw->setRange( ur_int( cbp.values + 1 ), ur_int( cbp.values + 2 ) ); } break; case LD_COMBO: { MAKE_WIDGET( SCombo ) val = cbp.values + 1; if( ur_is(val, UT_GETWORD) ) { if( ! (val = ur_wordCell( ut, val )) ) return 0; } if( ur_is(val, UT_BLOCK) ) { UBlockIter bi2; ur_blkSlice( ut, &bi2, val ); ur_foreach( bi2 ) { if( ur_is(bi2.it, UT_STRING) ) pw->addItem( qstring( bi2.it ) ); } } else { pw->addItem( qstring( val ) ); } } break; case LD_SPACER: if( ! parent.box ) goto no_layout; parent.box->addStretch( 1 ); break; case LD_SPACE: if( ! parent.box ) goto no_layout; val = cbp.values + 1; parent.box->addSpacing( ur_int(val) ); break; case LD_TAB: { MAKE_WIDGET( STabWidget ) if( ! tabWidgetBlock( ut, pw, cbp.values + 1 ) ) return 0; } break; case LD_TIP: if( wid ) wid->setToolTip( qstring(cbp.values + 1) ); break; case LD_TITLE: if( qEnv.curWidget ) { QString str; if( ! getString( ut, cbp.values + 1, str ) ) return 0; qEnv.curWidget->setWindowTitle( str ); } break; case LD_RESIZE: if( qEnv.curWidget ) { val = cbp.values + 1; qEnv.curWidget->resize( val->coord.n[0], val->coord.n[1] ); } break; case LD_LINE_EDIT_STR: case LD_LINE_EDIT: { MAKE_WIDGET( SLineEdit ) if( match == LD_LINE_EDIT_STR ) pw->setText( qstring( cbp.values + 1 ) ); } break; case LD_LIST: { const UCell* hdr = cbp.values + 1; if( ur_is(hdr, UT_GETWORD) ) { if( ! (hdr = ur_wordCell( ut, hdr )) ) return 0; } val = cbp.values + 2; if( ur_is(val, UT_GETWORD) ) { if( ! (val = ur_wordCell( ut, val )) ) return 0; } MAKE_WIDGET( STreeView ) pw->setRootIsDecorated( false ); pw->setModel( new UTreeModel( pw, hdr, val ) ); } break; case LD_TEXT_EDIT_STR: case LD_TEXT_EDIT: { MAKE_WIDGET( STextEdit ) if( match == LD_TEXT_EDIT_STR ) { QString str; if( ! getString( ut, cbp.values + 1, str ) ) return 0; if( str[0] == '<' ) pw->setHtml( str ); else pw->setPlainText( str ); } } break; case LD_GROUP: case LD_GROUP_CHECKABLE: { MAKE_WIDGET( SGroup ) val = cbp.values + 1; if( match == LD_GROUP_CHECKABLE ) { const UCell* enabled; if( ! (enabled = ur_wordCell( ut, val )) ) return 0; pw->setCheckable( true ); pw->setChecked( ur_isTrue( enabled ) ); ++val; } pw->setTitle( qstring( val ) ); ++val; LayoutInfo lo2; QLayout* lr2 = ur_qtLayout(ut, lo2, val); if( ! lr2 ) return 0; pw->setLayout( lr2 ); } break; case LD_READ_ONLY: if( wid ) { QTextEdit* tedit = qobject_cast<QTextEdit*>( wid ); if( tedit ) tedit->setReadOnly( true ); } break; case LD_ON_EVENT: if( qEnv.curWidget ) { SWidget* sw = qobject_cast<SWidget*>( qEnv.curWidget ); if( sw ) sw->setEventBlock( cbp.values + 1 ); } break; case LD_STRING: if( wid ) { SCombo* combo = qobject_cast<SCombo*>( wid ); if( combo ) { combo->addItem( qstring( cbp.values ) ); break; } QTextEdit* texted = qobject_cast<QTextEdit*>( wid ); if( texted ) { QString str; cellToQString( cbp.values, str ); if( str[0] == '<' ) texted->setHtml( str ); else texted->setPlainText( str ); } } break; case LD_BLOCK: if( wid ) { SCombo* combo = qobject_cast<SCombo*>( wid ); if( combo ) { combo->setBlock( cbp.values ); break; } STreeView* tree = qobject_cast<STreeView*>( wid ); if( tree ) { tree->setBlock( cbp.values ); break; } } break; case LD_SET_WORD: setWord = cbp.values; break; case LD_GRID: val = cbp.values + 1; wid = 0; lo.box = 0; lo.grid = new QGridLayout; lo.columns = ur_int(val); lo.colN = 0; lo.rowN = 0; if( parent.layout() ) parent.addLayout( lo.grid ); ++val; //TODO: Handle error. ur_qtLayout( ut, lo, val ); break; case LD_PROGRESS: { MAKE_WIDGET( SProgress ) pw->setRange( 0, ur_int(cbp.values+1) ); } break; case LD_WEIGHT: if( parent.box && wid ) { parent.box->setStretchFactor(wid, ur_int(cbp.values+1)); } break; } }
/* Returns zero if matching rule not found or exception occured. */ static const UCell* _parseBlock( UThread* ut, BlockParser* pe, const UCell* rit, const UCell* rend, UIndex* spos ) { const UCell* tval; int32_t repMin; int32_t repMax; UAtom atom; const UBuffer* iblk = pe->blk; UIndex pos = *spos; match: while( rit != rend ) { switch( ur_type(rit) ) { case UT_WORD: atom = ur_atom(rit); if( atom < UT_BI_COUNT ) { // Datatype if( pos >= pe->inputEnd ) goto failed; tval = iblk->ptr.cell + pos; if( ur_type(tval) != atom ) { /* if( atom == UT_NUMBER ) { if( ur_is(tval,UT_INT) || ur_is(tval,UT_DECIMAL) ) goto type_matched; } */ goto failed; } //type_matched: ++rit; ++pos; } else switch( atom ) { case UR_ATOM_OPT: ++rit; repMin = 0; repMax = 1; goto repeat; case UR_ATOM_ANY: ++rit; repMin = 0; repMax = 0x7fffffff; goto repeat; case UR_ATOM_SOME: ++rit; repMin = 1; repMax = 0x7fffffff; goto repeat; case UR_ATOM_BREAK: pe->exception = PARSE_EX_BREAK; *spos = pos; return 0; case UR_ATOM_BAR: goto complete; case UR_ATOM_TO: case UR_ATOM_THRU: { const UCell* ci; const UCell* ce; UAtom ratom = ur_atom(rit); ++rit; if( rit == rend ) return 0; ci = iblk->ptr.cell + pos; ce = iblk->ptr.cell + pe->inputEnd; if( ur_is(rit, UT_WORD) ) { if( ur_atom(rit) < UT_BI_COUNT ) { atom = ur_atom(rit); while( ci != ce ) { if( ur_type(ci) == atom ) break; ++ci; } if( ci == ce ) goto failed; pos = ci - iblk->ptr.cell; if( ratom == UR_ATOM_THRU ) ++pos; ++rit; break; } else { tval = ur_wordCell( ut, rit ); CHECK_WORD( tval ) } } else { tval = rit; } if( ur_is(tval, UT_BLOCK) ) { // TODO: If block then all values must match. BLK_RULE_ERROR( "to/thru block! not implemented" ); } else { while( ci != ce ) { if( ur_equal(ut, ci, tval) ) break; ++ci; } if( ci == ce ) goto failed; pos = ci - iblk->ptr.cell; if( ratom == UR_ATOM_THRU ) ++pos; } ++rit; } break; case UR_ATOM_INTO: ++rit; if( rit == rend || ! ur_is(rit, UT_BLOCK) ) { BLK_RULE_ERROR( "parse into expected block" ); } tval = iblk->ptr.cell + pos; if( ! ur_is(tval, UT_BLOCK) ) goto failed; if( ur_isShared( tval->series.buf ) ) goto failed; { BlockParser ip; UBlockIter bi; UIndex parsePos = 0; ip.eval = pe->eval; ip.blk = ur_bufferSer( tval ); ip.inputBuf = tval->series.buf; ip.inputEnd = ip.blk->used; ip.sliced = 0; ip.exception = PARSE_EX_NONE; ur_blkSlice( ut, &bi, rit ); tval = _parseBlock( ut, &ip, bi.it, bi.end, &parsePos ); iblk = _acquireInput( ut, pe ); if( ! tval ) { if( ip.exception == PARSE_EX_ERROR ) { pe->exception = PARSE_EX_ERROR; ur_appendTrace( ut, rit->series.buf, 0 ); return 0; } if( ip.exception != PARSE_EX_BREAK ) goto failed; } } ++rit; ++pos; break; case UR_ATOM_SKIP: repMin = 1; skip: if( (pos + repMin) > pe->inputEnd ) goto failed; pos += repMin; ++rit; break; case UR_ATOM_SET: ++rit; if( rit == rend ) goto unexpected_end; if( ! ur_is(rit, UT_WORD) ) { BLK_RULE_ERROR( "parse set expected word" ); } { UCell* cell = ur_wordCellM( ut, rit ); CHECK_WORD( cell ) *cell = iblk->ptr.cell[ pos ]; } ++rit; break; case UR_ATOM_PLACE: ++rit; if( (rit != rend) && ur_is(rit, UT_WORD) ) { tval = ur_wordCell( ut, rit++ ); CHECK_WORD( tval ) if( ur_is(tval, UT_BLOCK) ) { pos = tval->series.it; break; } } BLK_RULE_ERROR( "place expected series word" ); //case UR_ATOM_COPY: default: { tval = ur_wordCell( ut, rit ); CHECK_WORD( tval ) if( ur_is(tval, UT_BLOCK) ) { goto match_block; } else { BLK_RULE_ERROR( "parse expected block" ); } } break; } break; case UT_SETWORD: { UCell* cell = ur_wordCellM( ut, rit ); CHECK_WORD( cell ) ++rit; ur_setId( cell, UT_BLOCK ); ur_setSlice( cell, pe->inputBuf, pos, pe->inputEnd ); } break; case UT_GETWORD: { UCell* cell = ur_wordCellM( ut, rit ); CHECK_WORD( cell ) ++rit; if( ur_is(cell, UT_BLOCK) && (cell->series.buf == pe->inputBuf) ) cell->series.end = pos; } break; case UT_LITWORD: if( pos >= pe->inputEnd ) goto failed; tval = iblk->ptr.cell + pos; if( (ur_is(tval, UT_WORD) || ur_is(tval, UT_LITWORD)) && (ur_atom(tval) == ur_atom(rit)) ) { ++rit; ++pos; } else goto failed; break; case UT_INT: repMin = ur_int(rit); ++rit; if( rit == rend ) return 0; if( ur_is(rit, UT_INT) ) { repMax = ur_int(rit); ++rit; } else if( ur_is(rit, UT_WORD) && ur_atom(rit) == UR_ATOM_SKIP ) { goto skip; } else { repMax = repMin; } goto repeat; case UT_DATATYPE: if( pos >= pe->inputEnd ) goto failed; if( ! ur_isDatatype( iblk->ptr.cell + pos, rit ) ) goto failed; ++rit; ++pos; break; case UT_CHAR: case UT_BINARY: case UT_STRING: case UT_FILE: if( pos >= pe->inputEnd ) goto failed; if( ! ur_equal( ut, iblk->ptr.cell + pos, rit ) ) goto failed; ++rit; ++pos; break; case UT_BLOCK: tval = rit; match_block: { UBlockIter bi; UIndex rblkN = tval->series.buf; ur_blkSlice( ut, &bi, tval ); tval = _parseBlock( ut, pe, bi.it, bi.end, &pos ); iblk = pe->blk; if( ! tval ) { if( pe->exception == PARSE_EX_ERROR ) { ur_appendTrace( ut, rblkN, 0 ); return 0; } if( pe->exception == PARSE_EX_BREAK ) pe->exception = PARSE_EX_NONE; else goto failed; } } ++rit; break; case UT_PAREN: if( UR_OK != pe->eval( ut, rit ) ) goto parse_err; iblk = _acquireInput( ut, pe ); ++rit; break; default: BLK_RULE_ERROR( "invalid parse value" ); }