Emacs not indenting PHP correctly, although C/C++ do? - php

I am running GNU Emacs 22.2.1 on a HP notebook running Ubuntu 9.04 with the latest patches.
Recently, I need to handle some PHP codes, so I added Ubuntu's php-mode package, thinking what I have in my .emacs would cover the basics. Well, almost. The following short snippet shows the symptom:
<?php
# main()
/*
*
*
*/
{
$fpath="/tmp";
// This is a comment
if (!file_exists($fpath)) {
// This is another comment
print "$fpath doesn't exist on the system!\n";
exit(1);
} elseif (!is_dir($fpath)) {
print "$fpath is not a directory\n";
exit(2);
} else
// I don't know why it doesn't use the } as the anchor position
// in PHP, but in C and C++?
print "Found $fpath on the system. Good...\n";
} # end of main()
Notice that both the two comments and the print statement are offset by 6 spaces, rather than 4 as I desired. I have only a simple .emacs, with the following for C/C++, the two languages that I use most extensively:
[...]
(defconst my-c-style
'((c-comment-only-line-offset . 0)
(c-hanging-braces-alist . ((substatement-open after)
(brace-list-open)))
(c-hanging-colons-alist . ((member-init-intro before)
(inher-intro)
(case-label after)
(label after)
(access-label after)))
(c-cleanup-list . (scope-operator
empty-defun-braces
defun-close-semi))
(c-offsets-alist . ((arglist-close . c-lineup-arglist)
(substatement-open . 0)
(case-label . 4)
(block-open . 0)
(defun-block-intro . 0)
(statement-block-intro . 4)
(substatement . 4)
(knr-argdecl-intro . -)))
(c-echo-syntactic-information-p . t)
)
"My C Programming Style")
;; Customizations for all of c-mode, c++-mode, and objc-mode
(defun my-c-mode-common-hook ()
;; add my personal style and set it for the current buffer
(c-add-style "PERSONAL" my-c-style t)
;; offset customizations not in my-c-style
(c-set-offset 'defun-block-intro' +)
;; other customizations
;
(setq-default indent-tabs-mode nil)
;; make sure that comments don't get moved when you do a //
(c-set-offset 'comment-intro 0)
;; keybindings for all supported languages. We can put these in
;; c-mode-base-map because c-mode-map, c++-mode-map, objc-mode-map,
;; java-mode-map, and idl-mode-map inherit from it.
(define-key c-mode-base-map "\C-m" 'newline-and-indent)
)
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)
(require 'php-mode)
[...]
What's puzzling to me is that with C or C++, emacs is able to indent my codes as desired, e.g:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
[...]
if ((cond = strcmp(word, mid->word)) < 0) {
high = mid;
low = mid - 1;
} else if (cond > 0) {
low = mid + 1;
high = mid + 2;
} else
return mid;
}
I reviewed the CC Mode manual again, but couldn't figure out what's causing emacs to behave like so. I did the typical C-c C-s and the syntatical element is "statement" in PHP as well, so why in the case of PHP, emacs uses the 'e' in else as the anchor for offset calculation, but in C/C++, it uses the closing brace '}' as it should? I would appreciate any tips and/or pointers.

Your problem is a missing { after the else. Emacs is indenting as if you were continuing the else. Add the { and it'll work fine

Related

Looking for correct PHP socket error constants

I have an odd problem that's likely due to my inexperience with socket programming.
I'm currently using the raw error code numbers I'm getting from socket_last_error() as I see I need to handle them. This is getting unwieldy.
I'd like to use predefined constants (either my own or builtin) to refer to the different types of socket errors/conditions I need to deal with.
The error tables I've found all use conflicting values.
At http://php.net/manual/en/sockets.constants.php (in a comment that lists the raw numbers), I see things like (excerpted):
SOCKET_EINPROGRESS 10036
SOCKET_EALREADY 10037
SOCKET_ENETUNREACH 10051
The one comment at http://php.net/socket_last_error contains a list of what are apparently the "standard C defines" for socket errors (?):
define('EINPROGRESS', 115); /* Operation now in progress */
define('EALREADY', 114); /* Operation already in progress */
define('ENETUNREACH', 101); /* Network is unreachable */
The errno.h file on my own system (hiding in /usr/include/asm-generic/) seems to support this:
#define EINPROGRESS 115 /* Operation now in progress */
#define EALREADY 114 /* Operation already in progress */
#define ENETUNREACH 101 /* Network is unreachable */
However those "standard definitions" seem to be subject to change depending on what OS you're on: BSD4.4's errno.h has things like
#define EINPROGRESS 36 /* Operation now in progress */
#define EALREADY 37 /* Operation already in progress */
#define ENETUNREACH 51 /* Network is unreachable */
Now we know what the socket_* functions were inspired by though!
Finally, I find what seems to be a hint of an explanation hiding in the VirtualBox source code:
#ifndef EALREADY
# if defined(RT_ERRNO_OS_BSD)
# define EALREADY (37)
# elif defined(RT_OS_LINUX)
# define EALREADY (114)
# else
# define EALREADY (149)
# endif
#endif
With all of this taken into account...
socket_last_error() returns an errno of 101 when Network is unreachable, as opposed to 51 or 10051. So this function appears to be in apparent violation of the socket library's officially-supplied constants, and seems to be using Linux's error codes instead.
([EDIT after adding my answer]: The 101 stated above was obtained on Linux.)
So now that I seem to be in Undocumented and/or Seemingly Undefined Behavior land... what do I do now? I'm on Linux right now; do these values ever change?
Is there some way I can use the offical SOCKET_* constants? I certainly wouldn't mind doing so.
Sounds like you've been researching this hard -- and also that the platform-specific stuff might be a nuisance. Let me suggest this code which will ostensibly fetch all defined constants grouped together as "sockets" constants:
$consts = get_defined_constants(TRUE);
$socket_constants = $consts["sockets"];
foreach($socket_constants as $key => $value){
echo $key . '=' . $value . "\n";
}
From that, I was able to construct this function which you may find useful on any platform for finding the names of socket constants which might match
function get_socket_constant_names($to_check) {
$consts = get_defined_constants(TRUE);
$socket_constants = $consts["sockets"];
$matches = array();
foreach($socket_constants as $key => $value){
if ($value == $to_check) {
$matches[] = $key;
}
}
return $matches;
}
This:
var_dump(get_socket_constant_names(101));
Yields this:
array(1) {
[0] =>
string(18) "SOCKET_ENETUNREACH"
}
I just did some digging.
WARNING. PHP returns OS-specific socket error codes.
I do not know how to retrieve error codes compatible with the socket_* constants, so you have to detect the OS :'(
See proof after source code.
The following are heavily elided to aid focus.
From https://github.com/php/php-src/blob/master/ext/sockets/sockets.c:
PHP_FUNCTION(socket_connect) {
// will set errno
retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
if (retval != 0) {
// call macro defined in php_sockets.h with errno value
PHP_SOCKET_ERROR(php_sock, "unable to connect", errno);
RETURN_FALSE;
}
RETURN_TRUE;
}
PHP_FUNCTION(socket_last_error) {
// check for argument
if (arg1) {
if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
RETURN_FALSE;
}
// return errno from passed socket resource
RETVAL_LONG(php_sock->error);
} else {
// return errno from last globally set value
RETVAL_LONG(SOCKETS_G(last_error));
}
}
From https://github.com/php/php-src/blob/master/ext/sockets/php_sockets.h:
#define PHP_SOCKET_ERROR(socket, msg, errn) \
// store the value for this socket resource
(socket)->error = _err; \
// store the value globally
SOCKETS_G(last_error) = _err
Proof:
<?php
$s = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_nonblock($s);
socket_connect($s, "google.com", "80");
var_dump(socket_last_error());
var_dump(socket_strerror(socket_last_error()));
Observe the difference in socket_last_error():
linux$ php asdf.php
int(115)
string(25) "Operation now in progress"
freebsd$ php asdf.php
int(36)
string(25) "Operation now in progress"
TL;DR: There's no defined list of constants inside PHP (that I can see how to use). You must supply your own OS-correct list of constants.

PHP extension seg fault when modifying a zval by reference

PHP:
$publickey = pack('H*', "03ca473d3c0cccbf600d1c89fa33b7f6b1f2b4c66f1f11986701f4b6cc4f54c360");
$pubkeylen = strlen($publickey);
$result = secp256k1_ec_pubkey_decompress($publickey, $pubkeylen);
C extension:
PHP_FUNCTION(secp256k1_ec_pubkey_decompress) {
secp256k1_start(SECP256K1_START_SIGN);
zval *pubkey, *pubkeylen;
unsigned char* newpubkey;
int newpubkeylen;
int result;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &pubkey, &pubkeylen) == FAILURE) {
return;
}
newpubkey = Z_STRVAL_P(pubkey);
newpubkeylen = Z_LVAL_P(pubkeylen);
result = secp256k1_ec_pubkey_decompress(newpubkey, &newpubkeylen);
if (result == 1) {
newpubkey[newpubkeylen] = 0U;
ZVAL_STRINGL(pubkey, newpubkey, newpubkeylen, 0);
ZVAL_LONG(pubkeylen, newpubkeylen);
}
RETURN_LONG(result);
}
the $publickey is decompressed from a 32 byte to a 65 byte string, for w/e reason when we're doing this we get a Segmentation Fault.
I asume we're doing something structurally wrong ... considering this is our first PHP extension.
full code; https://github.com/afk11/secp256k1-php
After looking at your extension code, you haven't linked the actual secp256k1 lib (.so) while building your extension ( #include "secp256k1.h" does not include actual bitcoin/secp256k1 code c library ).
You need to change your config.m4 in any of the following ways
1) Add "-l/path/to/bitcoin/secp256k1/lib" to the "gcc" options.
Help: here, I am talking about once you "make install" on
bitcoin/secp256k1, some libraries will be installed to /usr/lib or
/usr/lib64 or /usr/lib/secp256k1 etc....
-lsecp256k1
// i.e. something like...
PHP_NEW_EXTENSION(secp256k1, secp256k1.c, $ext_shared,, "-lsecp256k1 -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1")
2) Or, include actual *.c files in from actual secp256k1 library
PHP_NEW_EXTENSION(secp256k1, secp256k1.c ../secp256k1/src/secp256k1.c ../secp256k1/src/others.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
I would recommend option-1

Run executable from php without spawning a shell

I need to call an executable from an imposed context of a PHP script. Both performance and security wise it's better not to call a shell at all between web server process and executable.
Of course I searched the web, without success (in such a PHP context). Many other languages allow that and document it clearly.
Alas, backticks, exec(), shell_exec(), passthru(), system(), proc_open(), popen() call a shell.
And pcntl_fork() seems unavailable.
How to test if a function calls a shell or not.
This was tested on a Debian 6 64bit with PHP 5.3.3-7+squeeze15 .
Test code on http://pastebin.com/y4C7MeJz
To get a meaningful test I used a trick which is to ask to execute a shell command not also available as an executable. A good example is umask . Any function returning something like 0022 definitely called a shell. exec(), shell_exec(), passthru(), system(), proc_open() all did.
See detailed results on http://pastebin.com/RBcBz02F .
pcntl_fork fails
Now, back the the goal : how to execute arbitrary program without launching a shell ?
Php's exec takes as expected an array of string args instead of a unique string. But pcntl_fork just stops the requests without even a log.
Edit: pcntl_fork failure is because the server uses Apache's mod_php, see http://www.php.net/manual/en/function.pcntl-fork.php#49949 .
Edit: added popen() to the tests, following #hakre suggestion.
Any hint appreciated.
To answer your sentence :
Both performance and security wise it's better not to call a shell at
all between web server process and executable.
About performances, well, yes, php internals forks, and the shell itself forks too so that's a bit heavy. But you really need to execute a lot of processes to consider those performances issues.
About security, I do not see any issue here. PHP has the escapeshellarg function to sanitize arguments.
The only real problem I met with exec without pcntl is not a resource nor security issue : it is really difficult to create real deamons (without any attachment to its parent, particularily Apache). I solved this by using at, after double-escaping my command:
$arg1 = escapeshellarg($arg1);
$arg2 = escapeshellarg($arg2);
$command = escapeshellarg("/some/bin $arg1 $arg2 > /dev/null 2>&1 &");
exec("$command | at now -M");
To get back to your question, the only way I know to execute programs in a standard (fork+exec) way is to use the PCNTL extension (as already mentionned). Anyway, good luck!
To complete my answer, you can create an exec function yourself that does the same thing as pcntl_fork+pcntl_exec.
I made a my_exec extension that does a classic exec+fork, but actually, I do not think it will solve your issues if you're running this function under apache, because the same behaviour as pcntl_fork will apply (apache2 will be forked and there may be unexpected behaviours with signal catching and so on when execv does not succeed).
config.m4 the phpize configuration file
PHP_ARG_ENABLE(my_exec_extension, whether to enable my extension,
[ --enable-my-extension Enable my extension])
if test "$PHP_MY_EXEC_EXTENSION" = "yes"; then
AC_DEFINE(HAVE_MY_EXEC_EXTENSION, 1, [Whether you have my extension])
PHP_NEW_EXTENSION(my_exec_extension, my_exec_extension.c, $ext_shared)
fi
my_exec_extension.c the extension
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define PHP_MY_EXEC_EXTENSION_VERSION "1.0"
#define PHP_MY_EXEC_EXTENSION_EXTNAME "my_exec_extension"
extern zend_module_entry my_exec_extension_module_entry;
#define phpext_my_exec_extension_ptr &my_exec_extension_module_entry
// declaration of a custom my_exec()
PHP_FUNCTION(my_exec);
// list of custom PHP functions provided by this extension
// set {NULL, NULL, NULL} as the last record to mark the end of list
static function_entry my_functions[] = {
PHP_FE(my_exec, NULL)
{NULL, NULL, NULL}
};
// the following code creates an entry for the module and registers it with Zend.
zend_module_entry my_exec_extension_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_MY_EXEC_EXTENSION_EXTNAME,
my_functions,
NULL, // name of the MINIT function or NULL if not applicable
NULL, // name of the MSHUTDOWN function or NULL if not applicable
NULL, // name of the RINIT function or NULL if not applicable
NULL, // name of the RSHUTDOWN function or NULL if not applicable
NULL, // name of the MINFO function or NULL if not applicable
#if ZEND_MODULE_API_NO >= 20010901
PHP_MY_EXEC_EXTENSION_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(my_exec_extension)
char *concat(char *old, char *buf, int buf_len)
{
int str_size = strlen(old) + buf_len;
char *str = malloc((str_size + 1) * sizeof(char));
snprintf(str, str_size, "%s%s", old, buf);
str[str_size] = '\0';
free(old);
return str;
}
char *exec_and_return(char *command, char **argv)
{
int link[2], readlen;
pid_t pid;
char buffer[4096];
char *output;
output = strdup("");
if (pipe(link) < 0)
{
return strdup("Could not pipe!");
}
if ((pid = fork()) < 0)
{
return strdup("Could not fork!");
}
if (pid == 0)
{
dup2(link[1], STDOUT_FILENO);
close(link[0]);
if (execv(command, argv) < 0)
{
printf("Command not found or access denied: %s\n", command);
exit(1);
}
}
else
{
close(link[1]);
while ((readlen = read(link[0], buffer, sizeof(buffer))) > 0)
{
output = concat(output, buffer, readlen);
}
wait(NULL);
}
return output;
}
PHP_FUNCTION(my_exec)
{
char *command;
int command_len, argc, i;
zval *arguments, **data;
HashTable *arr_hash;
HashPosition pointer;
char **argv;
// recovers a string (s) and an array (a) from arguments
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &command, &command_len, &arguments) == FAILURE) {
RETURN_NULL();
}
arr_hash = Z_ARRVAL_P(arguments);
// creating argc and argv from our argument array
argc = zend_hash_num_elements(arr_hash);
argv = malloc((argc + 1) * sizeof(char *));
argv[argc] = NULL;
for (
i = 0, zend_hash_internal_pointer_reset_ex(arr_hash, &pointer);
zend_hash_get_current_data_ex(arr_hash, (void**) &data, &pointer) == SUCCESS;
zend_hash_move_forward_ex(arr_hash, &pointer)
)
{
if (Z_TYPE_PP(data) == IS_STRING) {
argv[i] = malloc((Z_STRLEN_PP(data) + 1) * sizeof(char));
argv[i][Z_STRLEN_PP(data)] = '\0';
strncpy(argv[i], Z_STRVAL_PP(data), Z_STRLEN_PP(data));
i++;
}
}
char *output = exec_and_return(command, argv);
// freeing allocated memory
for (i = 0; (i < argc); i++)
{
free(argv[i]);
}
free(argv);
// WARNING! I guess there is a memory leak here.
// Second arguemnt to 1 means to PHP: do not free memory
// But if I put 0, I get a segmentation fault
// So I think I do not malloc correctly for a PHP extension.
RETURN_STRING(output, 1);
}
test.php a usage sample
<?php
dl("my_exec.so");
$output = my_exec("/bin/ls", array("-l", "/"));
var_dump($output);
shell script run those commands, of course use your own module directory
phpize
./configure
make
sudo cp modules/my_exec_extension.so /opt/local/lib/php/extensions/no-debug-non-zts-20090626/my_exec.so
Result
KolyMac:my_fork ninsuo$ php test.php
string(329) ".DS_Store
.Spotlight-V100
.Trashes
.file
.fseventsd
.hidden
.hotfiles.btree
.vol
AppleScript
Applications
Developer
Installer Log File
Library
Microsoft Excel Documents
Microsoft Word Documents
Network
System
Users
Volumes
bin
cores
dev
etc
home
lost+found
mach_kernel
net
opt
private
sbin
tmp
usr
var
vc_command.txt
vidotask.txt"
I am not a C dev, so I think there are cleaner ways to achieve this. But you get the idea.
In PHP 7.4+, proc_open open processes directly if cmd is passed as array.
As of PHP 7.4.0, cmd may be passed as array of command parameters. In this case the process will be opened directly (without going through a shell) and PHP will take care of any necessary argument escaping.
So this example:
<?php
$file_descriptors = [
0=>['pipe','r'],
1=>['pipe','w'],
2=>['pipe','w']
];
$cmd_string = 'ps -o comm=';
$cmd_array = [
'ps',
'-o',
'comm='
];
// This is executed by shell:
$process = proc_open($cmd_string,$file_descriptors,$pipes);
$output = stream_get_contents($pipes[1]);
$return = proc_close($process);
printf("cmd_string:\n%s\n",$output);
// This is executed directly:
$process = proc_open($cmd_array,$file_descriptors,$pipes);
$output = stream_get_contents($pipes[1]);
$return = proc_close($process);
printf("cmd_array:\n%s\n",$output);
outputs:
cmd_string:
bash
php
sh
ps
cmd_array:
bash
php
ps
Id consider trying pcntl_exec()

Generating PHP code (from Parser Tokens)

Is there any available solution for (re-)generating PHP code from the Parser Tokens returned by token_get_all? Other solutions for generating PHP code are welcome as well, preferably with the associated lexer/parser (if any).
From my comment:
Does anyone see a potential problem,
if I simply write a large switch
statement to convert tokens back to
their string representations (i.e.
T_DO to 'do'), map that over the
tokens, join with spaces, and look for
some sort of PHP code pretty-printing
solution?
After some looking, I found a PHP homemade solution in this question, that actually uses the PHP Tokenizer interface, as well as some PHP code formatting tools which are more configurable (but would require the solution as described above).
These could be used to quickly realize a solution. I'll post back here when I find some time to cook this up.
Solution with PHP_Beautifier
This is the quick solution I cooked up, I'll leave it here as part of the question. Note that it requires you to break open the PHP_Beautifier class, by changing everything (probably not everything, but this is easier) that is private to protected, to allow you to actually use the internal workings of PHP_Beautifier (otherwise it was impossible to reuse the functionality of PHP_Beautifier without reimplementing half their code).
An example usage of the class would be:
file: main.php
<?php
// read some PHP code (the file itself will do)
$phpCode = file_get_contents(__FILE__);
// create a new instance of PHP2PHP
$php2php = new PHP2PHP();
// tokenize the code (forwards to token_get_all)
$phpCode = $php2php->php2token($phpCode);
// print the tokens, in some way
echo join(' ', array_map(function($token) {
return (is_array($token))
? ($token[0] === T_WHITESPACE)
? ($token[1] === "\n")
? "\n"
: ''
: token_name($token[0])
: $token;
}, $phpCode));
// transform the tokens back into legible PHP code
$phpCode = $php2php->token2php($phpCode);
?>
As PHP2PHP extends PHP_Beautifier, it allows for the same fine-tuning under the same API that PHP_Beautifier uses. The class itself is:
file: PHP2PHP.php
class PHP2PHP extends PHP_Beautifier {
function php2token($phpCode) {
return token_get_all($phpCode);
}
function token2php(array $phpToken) {
// prepare properties
$this->resetProperties();
$this->aTokens = $phpToken;
$iTotal = count($this->aTokens);
$iPrevAssoc = false;
// send a signal to the filter, announcing the init of the processing of a file
foreach($this->aFilters as $oFilter)
$oFilter->preProcess();
for ($this->iCount = 0;
$this->iCount < $iTotal;
$this->iCount++) {
$aCurrentToken = $this->aTokens[$this->iCount];
if (is_string($aCurrentToken))
$aCurrentToken = array(
0 => $aCurrentToken,
1 => $aCurrentToken
);
// ArrayNested->off();
$sTextLog = PHP_Beautifier_Common::wsToString($aCurrentToken[1]);
// ArrayNested->on();
$sTokenName = (is_numeric($aCurrentToken[0])) ? token_name($aCurrentToken[0]) : '';
$this->oLog->log("Token:" . $sTokenName . "[" . $sTextLog . "]", PEAR_LOG_DEBUG);
$this->controlToken($aCurrentToken);
$iFirstOut = count($this->aOut); //5
$bError = false;
$this->aCurrentToken = $aCurrentToken;
if ($this->bBeautify) {
foreach($this->aFilters as $oFilter) {
$bError = true;
if ($oFilter->handleToken($this->aCurrentToken) !== FALSE) {
$this->oLog->log('Filter:' . $oFilter->getName() , PEAR_LOG_DEBUG);
$bError = false;
break;
}
}
} else {
$this->add($aCurrentToken[1]);
}
$this->controlTokenPost($aCurrentToken);
$iLastOut = count($this->aOut);
// set the assoc
if (($iLastOut-$iFirstOut) > 0) {
$this->aAssocs[$this->iCount] = array(
'offset' => $iFirstOut
);
if ($iPrevAssoc !== FALSE)
$this->aAssocs[$iPrevAssoc]['length'] = $iFirstOut-$this->aAssocs[$iPrevAssoc]['offset'];
$iPrevAssoc = $this->iCount;
}
if ($bError)
throw new Exception("Can'process token: " . var_dump($aCurrentToken));
} // ~for
// generate the last assoc
if (count($this->aOut) == 0)
throw new Exception("Nothing on output!");
$this->aAssocs[$iPrevAssoc]['length'] = (count($this->aOut) -1) - $this->aAssocs[$iPrevAssoc]['offset'];
// post-processing
foreach($this->aFilters as $oFilter)
$oFilter->postProcess();
return $this->get();
}
}
?>
In the category of "other solutions", you could try PHP Parser.
The parser turns PHP source code into an abstract syntax tree....Additionally, you can convert a syntax tree back to PHP code.
If I'm not mistaken http://pear.php.net/package/PHP_Beautifier uses token_get_all() and then rewrites the stream. It uses heaps of methods like t_else and t_close_brace to output each token. Maybe you can hijack this for simplicity.
See our PHP Front End. It is a full PHP parser, automatically building ASTs, and a matching prettyprinter that regenerates compilable PHP code complete with the original commments. (EDIT 12/2011:
See this SO answer for more details on what it takes to prettyprint from ASTs, which are just an organized version of the tokens: https://stackoverflow.com/a/5834775/120163)
The front end is built on top of our DMS Software Reengineering Toolkit, enabling the analysis and transformation of PHP ASTs (and then via the prettyprinter code).

Dump facility in C++ like var_dump() in PHP?

When I was in college i did some C/C++, but in near future i was working in PHP, and now I wish to put more time in learning C/C++.
In PHP i was using print_r() or var_dump() in order to display datas from structures or arrays. Do I have such a default functionality in C, in order to see what do i have in a struct or array?
There is no such functionality in C++. You can of course write your own Dump() functions. The reason such a feature cannot be generally provided is that the C++ compilation process removes the object metadata needed to structure the dump output. You can of course display structure contents in a debugger, where such metadata is maintained in the debug information.
BTW, are you asking about C or C++? The two languages are quite different, both in features and approach, although neither has var_dump() or similar.
C++ in itself doesn't provide something like var_dump, but with libraries like Boost.Fusion and the ADAPT_STRUCT and ADAPT_ADT facility it's easily doable.
Indeed as told in the other response, the C++ compiler doesn't generate the metadata needed to generate such an output. However it is possible to generate these metadata and use a bit of template metaprogramming to use them.
That way I've implemented here an adapted_struct_printer, which can print std::container, any classes or structures, boost::variant and boost::tuple.
New solution
Now you can easily do the following :
#include <iostream>
#include <pre/json/to_json.hpp>
struct customer {
std::string name;
size_t money_spent;
std::vector<std::string> interests;
};
BOOST_FUSION_ADAPT_STRUCT(customer,
name,
money_spent,
interests)
...
customer my_customer{
"Mr. Dupond",
1000,
{"sport articles", "food", "tools"}
};
std::cout << pre::json::to_json(my_customer) << std::endl;
You can inversely with this library also do from_json to populate structures from json.
A documentation is available here : http://daminetreg.github.io/lib-cpp-pre/html/namespacepre_1_1json.html#a4325d2cdd64a7e321303fd4428f298b9
OLD Response
The only requirement is that you call BOOST_FUSION_ADAPT_STRUCT/BOOST_FUSION_ADAPT_ADT on your classes (See http://www.boost.org/doc/libs/1_57_0/libs/fusion/doc/html/fusion/adapted.html)
So that this example :
#include <iostream>
#include <swissarmyknife/boost/fusion/adapted_struct_printer.hpp>
#include <boost/fusion/include/define_struct.hpp>
#include <boost/variant.hpp>
#include <boost/tuple/tuple.hpp>
namespace bla {
struct someclass {
int i = 12;
int j = 15;
};
using boost::fusion::detail::operator <<;
}
BOOST_FUSION_ADAPT_STRUCT(bla::someclass,
(int, i)
(int, j)
)
BOOST_FUSION_DEFINE_STRUCT((bla), innerbim,
(std::string, mystring)
)
BOOST_FUSION_DEFINE_STRUCT((bla), bimbim,
(int, boom)
(int, bam)
(bla::innerbim, my_inner_bim)
)
typedef boost::variant<int, double, bla::innerbim> myvariant_t;
typedef boost::tuple<std::string, int, bla::innerbim, myvariant_t> my_tuple_t;
BOOST_FUSION_DEFINE_STRUCT((bla), blabla,
(bla::bimbim, bim)
(int, i)
(int, j)
(std::vector<double>, list)
(std::list<bla::bimbim>, list_of_bimbim)
(my_tuple_t, mytuple)
(myvariant_t, myvariant)
)
int main(int argc, char** argv) {
using namespace swak;
bla::blabla instance{
{22, 12, bla::innerbim{"COOL"} },
23,
43,
{2.00, 39.07, 24.05},
{
{24, 9, bla::innerbim{"FEEL GOOD"} },
{26, 14, bla::innerbim{"SO BAD"} },
},
{"Hey that's not an int", 1, bla::innerbim{"hello"}, 12},
bla::innerbim("I'm in the variant")
};
std::cout << instance << std::endl;
bla::someclass otherinstance{};
std::cout << "Other instance : " << otherinstance << std::endl;
return 0;
}
Prints out the following :
{
bim :
{
boom : 22,
bam : 12,
my_inner_bim :
{
mystring : COOL,
}
}
i : 23,
j : 43,
list : [2, 39.07, 24.05],
list_of_bimbim : [
{
boom : 24,
bam : 9,
my_inner_bim :
{
mystring : FEEL GOOD,
}
}
,
{
boom : 26,
bam : 14,
my_inner_bim :
{
mystring : SO BAD,
}
}
],
mytuple :
{
0 (Ss) : Hey that's not an int,
1 (i) : 1,
2 (N3bla8innerbimE) :
{
mystring : hello,
}
3 (N5boost7variantIidN3bla8innerbimENS_6detail7variant5void_ES5_S5_S5_S5_S5_S5_S5_S5_S5_S5_S5_S5_S5_S5_S5_S5_EE) :
{
12}
}
myvariant :
{
{
mystring : I'm in the variant,
}
}
}
Other instance :
{
i : 12,
j : 15,
}
I'm improving the implementation to get it at some point as a possible new feature in boost fusion, but it's already usable as shown there :
https://github.com/daminetreg/lib-cpp-swissarmyknife/blob/feature/adapted_struct_printer_improved/test/adapted_struct_printer.cpp
It is possible but it would take a lot of work if debug symbols were enabled and all optimisations were disabled. Also it would be slow and perhaps not very reliable[*1].
Anything that a debugger can do could be replicated by a dump() function that causes a breakpoint, and logged out information.
Some debuggers can be automated, so perhaps the dump function itself would be written in the debugger.
*1 e.g. debuggers sometimes crash when dealing with some breakpoints. e.g. the program would need to have a breakpoint and halt all threads before trying to dump data. e.g. programs that need to deal with realtime interrupts probably wouldn't work. e.g. the debugger needs to be reliable enough to deal with many many breakpoints and not introduce other issues.
In microsoft article have some solution:
vector::push_back
https://msdn.microsoft.com/pt-br/library/7fthz5xd.aspx
template <typename T> void print_elem(const T& t) {
cout << "(" << t << ") ";
}
template <typename T> void print_collection(const T& t) {
cout << " " << t.size() << " elements: ";
for (const auto& p : t) {
print_elem(p);
}
cout << endl;
}
and the call for this:
cout << "vector data: " << endl;
print_collection(v);
No, you have to roll your own using one from the cout or C style printf family of output functions for user defined data structures. Similarly, for arrays, (except C-style strings) you will have to loop over all the elements and print each one.
No, there isn't. Use a debugger like ddd, for example. Most IDEs have one integrated.
I usually use GDB printing.
for example this code:
#include <string.h>
struct _example_ {
int a;
int b;
char c[20];
};
int main(){
struct _example_ example;
example.a = 1;
example.b = 2;
strcpy(example.c,"example_c");
}
compile with gcc main.c -o executable -g
if you want to know the values for the struct example, you should execute the program with GDB, put a break on the line that you want and then print the variable, like below.
Breakpoint 1, main () at main.c:12
12 strcpy(example.c,"example_c");
(gdb) n
13 }
(gdb) print example
$1 = {a = 1, b = 2, c = "example_c\000\000\000\000\000\000\000`PUU"}
(gdb)
In this case i put breakpoint on line 12, and print the variable example, then i got all the variables and values on the struct example

Categories