Zend extension, get arguments of echo? - php-internals

We have made a Zend extension which we want to write the addresses of the zval's echo is supposed to write out, but we cannot figure how to receive them because we have noticed that there is difference between echo "test"; and $a = "test"; echo $a;
.... Some stuff that overrides the echo opcode ....
FILE *tmpfile;
int echo_handler(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = execute_data->opline;
tmpfile = fopen("/tmp/echo.test","a+");
fprintf(tmpfile,"Echo was called\n");
fclose(tmpfile);
return ZEND_USER_OPCODE_DISPATCH;
}
How do we get the arguments no matter if it is a variable or not?

The handler for echo is
static int ZEND_FASTCALL ZEND_ECHO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);
zval z_copy;
zval *z = &opline->op1.u.constant;
if (IS_CONST != IS_CONST &&
Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL &&
zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
zend_print_variable(&z_copy);
zval_dtor(&z_copy);
} else {
zend_print_variable(z);
}
ZEND_VM_NEXT_OPCODE();
}
from Zend/zend_vm_execute.h, and as you can see all it basically does is to call zend_print_variable().
Hook that function and you should be on the right track.
Bonus: it works for print statements too.

Related

variables in groovy how to set a condition by variable type

I'm a total newbie and I'm looking for some advice.
how to make a condition in Groovy so that if the variable is a string, then one action is performed, and if the sheet is another
and just as it is necessary to do, if the variable is equal to zero, then nothing is transmitted
//aditionalArgs= "test1 = add1 , tets2= add2 "
aditionalArgs = ["test1=arg1", "test2=arg2"]
println(aditionalArgs.class)
def args = ""
if ((aditionalArgs != "class java.lang.String" ) || (aditionalArgs > 0)){
def list = aditionalArgs.replace("--build-arg", "").split(',')
list.each { val->
args += " --build-arg $val"
}
println(args.replace("",""))
}
if (aditionalArgs == "ArrayList" ){
def list = aditionalArgs("--build-arg", "").split('[' , ']')
list.each { val->
args += " --build-arg $val"
}
println(args.replace("",""))
}
else(aditionalArgs.length() > 0){
println "empty aditionalArgs"
}```
if (aditionalArgs instanceof String && aditionalArgs.length() > 0) {
...
} else if (aditionalArgs instanceof List && aditionalArgs.size() > 0) {
...
} else {
println "unsupported arg type '${aditionalArgs?.getClass()}' or value '${aditionalArgs}'"
}
Your code suggests that you rather want to use a switch op:
switch( aditionalArgs ){
case String:
// do stuff with String
break
case List:
// do stuff with (Array)List
break
case Number:
// do something with Number
break
default:
throw new Exception( 'I have no idea' )
}
More on the statement is in the docs

What is wrong in this grep command?

Okay... so I'm trying to make a dictionary using Crunch and Grep I've also tried using Perl instead.
crunch 8 12 1234567890 -d 2# | grep -v '\([0-9]\) .*\1.*\1.*\1.*' | grep 41106041
So, basically i want to filter all passwords which numbers appear 3 times
grep 41106041
Is just to test if the code works.. and it doesn't.
I've also tried some "C style" perl code as I'm still a newbie to perl:
#! /bin/perl
#lines=<STDIN>;
$c=0;
foreach $number(#lines)
{
$acum=undef;
$pos=0;
while($pos <= &countdig($number))
{
if ($acum=$digit)
{
$c=$c+1;
}
else
{
$c=0;
}
$acum=$digit;
}
if ($c=3)
{
print "$number"." ";
}
$c=0;
}
sub countdig
{
my($j)=0;
chomp(my(#n)=#_);
print "first dig $n[$j] \n";
while($_[0][$j]>=0 && $_[0][j]<=9)
{
$j+=1;
}
print "j total : $j \n";
$j;
}
Countdig is supposed to count the number of digits but thing is.. I can't access a scalar variable as a list.. so well if you guys could explain me how to make it work it would be very appreciated.
Your grep is failing because there is a stray space in your pattern, and you are searching for 4 identical digits (the one captured, plus three more by backreference).
$ printf '12345678\n41106041\n87654321\n' | grep -v '\(.\).*\1.*\1'
12345678
87654321
The problem is not being a newbie to Perl, cause it's easy to turn a C solution
// For each line
char *num = ...;
int digits[10];
for (int i=0; i<10; ++i) {
digits[i] = 0;
}
const char *p = num;
int triple = 0;
for (; *p && *p != '\n'; ++p) {
if (++digits[*p - '0'] == 3) {
triple = 1;
break;
}
}
if (triple) {
...
}
into a Perl solution
while (my $num = <>) {
chomp($num);
my #digits;
my $triple;
for my $digit (split //, $num) {
if (++$digits[$digit] == 3) {
$triple = 1;
last;
}
}
say $num if $triple;
}
Of course, a Perl programmer might very well use the same approach you used for grep.
while (<>) {
if (!/(.).*\1.*\1/) {
print;
}
}
echo 41106041 | grep -v '\([0-9]\).*\1.*\1.*

Lex analyzer for generating file not producing a listing of program with lexical error messages

I am attempting to build a lex analyzer that produces a listing of the program with lexical error messages included after the line in which they occur. In other words if the character read cannot start a token it is considered an error. It is also supposed to generate a file with the lexeme-token pairs so that it can verify that the analyzer is working. I can get an output file but it is not working correctly as when I attempt to run it it just gives me a command screen like I'm inside the file working. Here is my code for my scanner file that reads an input text:
%{
#include <stdio.h>
#include <ctype.h>
#include "tokens.h"
void toTitle(char* yytext, int yyleng);
%}
%option noyywrap
ws [ \t\r\n]+
quoted \".*\"
letter [A-Za-z]
digit [0-9]
word {letter}+(\-{letter}+)?
number {digit}+
punc [,:;()]
begin { ECHO; return(begin);}
boolean { ECHO; return(BOOLEAN);}
else { ECHO; return(ELSE); }
end { ECHO; return(END); }
endif void toTitle(char* yytext, int yyleng){ ECHO; return(ENDIF); }
function { ECHO; return(FUNCTION); }
if { ECHO; return(IF); }
is { ECHO; return(IS); }
integer { ECHO; return(INTEGER); }
real { ECHO; return(REAL); }
returns { ECHO; return(RETURNS); }
then { ECHO; return(THEN); }
line [\n]
%%
"&&" { return(LOGOPAND); }
"||" { return(LOGOPOR); }
"!=" { return(LOGOPNOT); }
[ \t\n] ;
{ws} { ECHO; }
"<" { ECHO; return(RELOP); }
"=" { ECHO; return(RELOP); }
"/=" { ECHO; return(RELOP); }
">" { ECHO; return(RELOP); }
">=" { ECHO; return(RELOP); }
"<=" { ECHO; return(RELOP); }
"*" { ECHO; return(MULTOP); }
"/" { ECHO; return(MULTOP); }
"+" { ECHO; return(ADDOP); }
"-" { ECHO; return(ADDOP); }
"true" { ECHO; return(BOOLLITERAL); }
"false" { ECHO; return(BOOLLITERAL); }
{digit} { ECHO; return(I_LITERAL); }
{digit}+"."{digit}* { ECHO; return(R_LITERAL); }
begins { ECHO; return(BEGINS); }
{punc} { ECHO; return yytext[0]; }
{quoted} { ECHO; }
{word} {toTitle(yytext, yyleng); }
{number} { ECHO; }
%%
void toTitle(char* yytext, int yyleng)
{
}
void tokenCount(int token)
{
while (token = yylex())
fprintf(yyout, "%d %s\n", token, yytext);
}
int main() {
while (yylex());
return 0;
}
I have a header file with my defined tokens:
#ifndef TOKENS_H
#define TOKENS_H
typedef enum Tokens {RELOP = 256, ADDOP = 257, MULTOP = 258, LOGOPNOT = 259, BOOLLITERAL = 260, I_LITERAL = 261, R_LITERAL = 262, IDENTIFIER = 263, PUNCTUATION = 264, BEGINS = 265, BOOLEAN = 266, ELSE = 267, END = 268, ENDIF = 269, FUNCTION = 270, IF = 271, IS = 272, INTEGER = 273, REAL = 274, RETURNS = 275, THEN = 276, LOGOPAND = 277, LOGOPOR = 278, begin = 279} Tokens;
#endif
My output is supposed to look something like this:
1 -- Simple program with one function
2
3 function main a: integer returns integer;
4 b: integer is a * 2;
5 begin
6 if a <= 0 then
7 b + b;
8 else
9 b * b;
10 endif;
11 end;
Compiled Successfully
I've noticed that this is third question you've asked on the same problem and suspect that you might not be fully understanding how to complete this task or the documentation and answers you've seen so far. Stackoverflow has guidance and standards on the best ways of forming a question to get the best value and service from the many world class experts available here, such as this guidance on asking questions on StackOverflow. I see that you might be a beginner at this, and in the case of your problem it would have been to your advantage to learn how to simplify the problem. I'll demonstrate how you could simplify the problem, using your code as an example, and thus arrive at a good description of the problem and eventually the solution.
The problem with your code, is the same problem identified in comments by #rici to your earlier question "That lex file looks like it was pasted together from random snippets using different styles".
Let's go back to the flex manual and look at the overall structure of a flex program:
definitions
%%
rules
%%
user code
The position of the %% lines divide the code into three sections, and thus what you put before the %% and what you put after %% is really important.
Now in the answer to your last question #nlu wrote:
ECHO is a special statement, that can only be used in the actions section.
and then you replied:
I rectified the code by moving all the reserved words and their actions to the first part before the %% syntax
Unfortunately you misread that suggestion and left code for the rules/action section in the declaration section. Unfortunately this did not cause flex to give you any helpful messages, as it remained a meaningful flex program; just not the one you were expecting!
To clarify, you cannot have any actions, including an ECHO, before the first %%, because then it would be in the definitions section. They must be after the first %% so the are in the rules/actions section. So, as a consequence, all these lines are in the wrong place:
begin { ECHO; return(begin);}
boolean { ECHO; return(BOOLEAN);}
else { ECHO; return(ELSE); }
end { ECHO; return(END); }
endif void toTitle(char* yytext, int yyleng){ ECHO; return(ENDIF); }
function { ECHO; return(FUNCTION); }
if { ECHO; return(IF); }
is { ECHO; return(IS); }
integer { ECHO; return(INTEGER); }
real { ECHO; return(REAL); }
returns { ECHO; return(RETURNS); }
then { ECHO; return(THEN); }
How could you have debugged this on your own? As its suggests in the SO help pages: simplify. I'll demonstrate by example how that could be done. If you reduced the problem to a language with only one keyword, lets says begin and some whitespace, and deleted all the other lines, for all the other keywords and symbols, then there would be a much simpler problem to address. Lets try this with your code:
%option noyywrap
ws [ \t\r\n]+
begin { ECHO; return(begin);}
line [\n]
%%
[ \t\n] ;
{ws} { ECHO; }
begins { ECHO; return(BEGINS); }
%%
int main() {
while (yylex());
return 0;
}
You will note I have just deleted all the lines that relate to other keywords and symbols as they are confusing the picture with a jumble of extra lines. This is exactly what expert and professional programmers do in their day to day problem solving. You don't think we have some psychic way of finding bugs do you? :-) This is the skill that comes with practise.
Now, focussing on this simpler program, there are things we can see. It does compile and run by the way, and its all your code (just simpler). If we run it, the keyword begins gets ECHOed but the keyword begin does not. There is a clue there. If the line for begin was moved to below the %% it would work just as the begins line did. But why did flex accept the bad program and not give you a helpful error? This is because that line is still a valid definition of a lexeme according to flex regular expression notation. What you defined was a lexeme called begin (which you access using the notation {begin} in the rules section) which is defined as matching the string "{ ECHO; return(begin);}". However, as you never typed that string, and also never used the name {begin} that fragment of definition never gets used.
There is also the question: Does your language really have a keyword called begin and another one called begins. Seems fishy to me. Another bug perhaps?
Similarly we cans see the same with the white space. You have tried to match a newline \n in three places. This is going to be confusing, as you cannot be sure which of the definitions and actions flex will perform when encountering a newline. As you want to number the lines at some point this might be a problem for you. You've also told it to both ignore and ECHO whitespace. Which is it to be? It cannot do both. From your example output, perhaps you wanted them echoed. Making all these fixes to the simple program we get this:
%option noyywrap
ws [ \t\r]+
line [\n]
%%
{ws} { ECHO; }
begin { ECHO; return(BEGIN); }
%%
int main() {
while (yylex());
return 0;
}
which works for a simple language with only the keyword begin. All we now have to do is put the other bits back in, slowly and carefully. Next, lets add the keyword endif to the code, and we get:
%option noyywrap
ws [ \t\r]+
line [\n]
%%
{ws} { ECHO; }
begin { ECHO; return(BEGIN); }
endif void toTitle(char* yytext, int yyleng){ ECHO; return(ENDIF); }
%%
int main() {
while (yylex());
return 0;
}
However, this does not compile. The piece of code void toTitle(char* yytext, int yyleng) looks like an erroneous paste, when you were hacking the code together from other peoples solutions -- doh!.
Now, that has dealt with all the faults in your code, and if you understood them you could get all your code working. Now, there is a bit more programming to do before you have completed the whole assignment. You need to add line counting, handling of variables and constants, and a few other bits and then you are done.
I hope you found that helpful, and leads to you being able to solve the rest of your coding exercise.

AWK file multiline command not working

I have an awk file get_PV_sql_from_file.awk:
#! /bin/awk -f
/^CREATE.*VIEW.*PV_/
{
inside_create = 1; print "view found"
}
{
if(inside_create == 1)
{
print $0
}
}
/.*;$/
{
if(inside_create == 1){
inside_create = 0;
}
}
And when i run it:
awk -f get_PV_sql_from_file.awk test_PV_sql.txt
I have got "view found" phrase in each line:
view found
CREATE FORCE VIEW "POSC"."P3V_SEC_TREES_V" ("BSASC_ID", "BSASC_S", "LV0_K", "LV0_V", "LV1_K", "LV1_V", "LV2_K", "LV2_V", "LV3_K", "LV3_V", "LV4_K", "LV4_V", "LV5_K", "LV5_V") AS
view found
SELECT DISTINCT
view found
B1.BSASC_ID,
view found
B2.BSASC_S,
view found
R_SEC_TREES.LV0_K,
view found
R_SEC_TREES.LV0_V,
...
etc
But if i write each command in awk file on a single line:
#! /bin/awk -f
/^CREATE.*VIEW.*PV_/ { inside_create = 1; print "view found" }
{ if(inside_create == 1) { print $0 } }
/.*;$/ { if(inside_create == 1) { inside_create = 0; } }
It is works right:
view found
CREATE FORCE VIEW "POSC"."PV_SEC_MODULES_V" ("BSASC_ID", "MODULE", "ACT") AS
SELECT DISTINCT
B1.BSASC_ID BSASC_ID,
BSASC_PRIVILEGE.GDLN_OR_PRIV_ID MODULE,
BSASC_PRIVILEGE.R_BSASC_PRIV_KIND ACT
...
etc
Why is this happening? And where i made mistake?
You need to put the pattern and the opening brace that begins the action on the same line. Otherwise the pattern is treated as not having any action, so the default action, print the line, is performed. The action on the next line is then treated as having no pattern which means it matches every line. So write your AWK code like this:
/^CREATE.*VIEW.*PV_/ {
inside_create = 1; print "view found"
}
{
if(inside_create == 1)
{
print $0
}
}
/.*;$/ {
if(inside_create == 1) {
inside_create = 0;
}
}

wxDirDialog Returns the Wrong Directory on Vista

I recently ported the following code to wx3.0 under visual studio 2013:
void PanelFileControl::on_retrieve_clicked(wxCommandEvent &event)
{
if(!chosen_files.empty())
{
Csi::ModalCounter counter;
wxDirDialog query(
this,
make_wxString(my_strings[strid_choose_retrieve_dir]),
make_wxString(wxGetApp().get_config()->get_last_prog_dir()));
int rcd;
query.CentreOnParent();
rcd = query.ShowModal();
if(rcd == wxID_OK)
{
// we need to generate an operation for every selected file.
StrAsc path(make_StrAsc(query.GetPath()));
DlgFileControl::operations_type operations;
if(path.last() != Csi::FileSystemObject::dir_separator())
path.append(Csi::FileSystemObject::dir_separator());
for(files_type::iterator fi = chosen_files.begin(); fi != chosen_files.end(); ++fi)
{
file_type const &file(*fi);
StrAsc file_path(path + file.get_file_name());
bool use_file(true);
if(Csi::file_exists(file_path.c_str()))
{
OwxStringStream message;
message << boost::format(my_strings[strid_overwrite_file_confirm].c_str()) %
file_path;
wxMessageDialog overwrite_query(
this,
message.str(),
wxT(""),
wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
int rcd;
overwrite_query.CentreOnParent();
rcd = overwrite_query.ShowModal();
if(rcd != wxID_YES)
use_file = false;
}
if(use_file)
operations.push_back(new ReceiveFileOperation(file, file_path));
}
// we can now display the operation dialogue
if(!operations.empty())
{
DlgFileControl dialogue(this, device_name, operations);
dialogue.show_modal();
}
}
}
} // on_retrieve_clicked
Following this change (which didn't require any changes to the code above), I have received complaints that, if the user selects the desktop and then double clicks on a directory on the desktop, that the file save operation fails. This appears to be a result of the path produced by the wxDirDialog::GetPath() and has only been seen under windows vista. I have followed up some testing and I find that, under Vista, the last path component is mentioned twice in the string returned by GetPath().
Has anyone seen this issue? Are there any work arounds?
I found that I can address the issue by preventing the wxDirDialog from using the IFILEDIALOG interface from being used. My ShowModal() method now looks like this:
int wxDirDialog::ShowModal()
{
WX_HOOK_MODAL_DIALOG();
wxWindow* const parent = GetParent();
WXHWND hWndParent = parent ? GetHwndOf(parent) : NULL;
// Use IFileDialog under new enough Windows, it's more user-friendly.
int rc;
#if wxUSE_IFILEDIALOG
if ( wxGetWinVersion() > wxWinVersion_Vista )
{
rc = ShowIFileDialog(hWndParent);
}
else
{
rc = wxID_NONE;
}
if ( rc == wxID_NONE )
#endif // wxUSE_IFILEDIALOG
{
rc = ShowSHBrowseForFolder(hWndParent);
}
// change current working directory if asked so
if ( rc == wxID_OK && HasFlag(wxDD_CHANGE_DIR) )
wxSetWorkingDirectory(m_path);
return rc;
}

Resources