Raspberry Pi C++ PHP Gpio - php

I'm quite new at programming and I need some help with an understanding of the following problem. I have PHP page which controls some C++ functions and These functions control GPIO of RPi. when I run C++ function everything runs without any problem then I try to run a same C++ function with PHP script it doesn't work.
Thank you a lot for your help and advice
Have a nice Holidays
C++
> #include <iostream>
> #include <wiringPi.h>
>
> int main(int argc,char* argv[]) {
>
> std::cout<< argc+5; // this line returns the value to PHP script
> wiringPiSetupGpio(); pinMode (17, OUTPUT) ;
>
> for (int i=0; i < 10; i++) {
> digitalWrite (17, HIGH) ; delay (500) ;
> digitalWrite (17, LOW) ; delay (500) ; }
> return 0;
PHP
<?php
$foo = True;
if(isset($_GET['on'])){
exec('./blink a b c d',$result);
echo implode($result);
}
?>

Related

Why boost::asio::async_write works well at the first time and something goes wrong for the second time?

I can successfully send out data via TCP by invoking async_write at first, whereas it goes wrong when the async_write is called again.
Here is the code snippet:
#include <algorithm>
#include <array>
#include <boost/asio.hpp>
#include <boost/range.hpp>
#include <chrono>
#include <iostream>
#include <random>
#include <vector>
const std::size_t buf_size = 500*1024;
const int test_cycles = 1.024e5;
namespace asio = boost::asio;
int main()
{
std::vector<char> send_data(buf_size);
std::vector<char> recv_buf(buf_size);
asio::io_service ios;
asio::ip::tcp::socket socket1(ios);
asio::ip::tcp::socket socket2(ios);
asio::ip::tcp::acceptor acceptor(ios, {asio::ip::tcp::v4(), 55557});
socket1.connect({asio::ip::address_v4::loopback(), 55557});
acceptor.accept(socket2);
for (std::size_t i = 0; i < 1; ++i)
{
auto start = std::chrono::steady_clock::now();
for(int j=0; j < test_cycles; ++j)
{
size_t written_bytes = 0;
auto to_send_data = send_data;
asio::async_write(socket1,
asio::dynamic_buffer(send_data),
[&](auto ec, auto n)
{
if(!ec)
{
std::cout << "successfully sent " << n << std::endl;
}
else
{
std::cout << ec.message() << std::endl;
}
if(0==n)
{
std::cout << "send error" << std::endl;
}
written_bytes = n;
});
asio::async_read(socket2, asio::buffer(recv_buf),
[&](auto ec, auto n)
{
if(!ec)
{
//std::cout << "received " << n << std::endl;
}
else
{
std::cout << ec.message() << std::endl;
}
if(0==n)
{
std::cout << "received error" << std::endl;
}
if(written_bytes != n)
{
std::cout << "received is not same with the sent" << std::endl;
}
});
ios.run();
ios.reset();
}
auto end = std::chrono::steady_clock::now();
std::chrono::duration<float> elapsed = end - start;
std::cout << elapsed.count() << " seconds\n";
std::cout << (buf_size * test_cycles / elapsed.count() / 1024 / 1024/ 1024) << " GB/s\n";
}
}
Here is the output:
successfully sent 512000
successfully sent 0
send error
Some hint
I found a workaround method and the program goes well.Here is the related code snippet:
auto to_send_data = send_data;
asio::async_write(socket1,
asio::dynamic_buffer(to_send_data),
Why the aforementioned code snippet goes wrong?
UPDATE:
I try to set the breakpoint in the implementation of STD:: vector:: resize() via VsCode IDE(I did this test on Ubuntu. ), but the breakpoint does not work indeed(i.e the breakpoint is grey.). I could guarantee that binary program is built as debug mode. I also try to set the breakpoint by GDB, but GDB outputs "Function "std::vector::resize" not defined."
I set breakpoints in the implementation of the aforementioned operator(), I found the default has never been triggered indeed, in other words, start is always 1.
Unfortunately boost documentation on dynamic_buffer is extremely laconic:
A dynamic buffer encapsulates memory storage that may be automatically resized as required.
meaning that dynamic_buffer will manipulate the underlying vector during IO operations.
Boost ASIO tutorial is more explicit:
Dynamic buffer is a concept. Dynamic buffer is a buffer that you can write data into or read from it. If the buffer isn't big enough to fit your data then it will resize (grow) dynamically. So when you write into the dynamic buffer you don't have to worry if there is enough space left in the buffer. On the other hand, when you read data from a dynamic buffer, you are responsible to throw away (consume) bytes read and no longer needed so the buffer won't grow permanently.
Write operation on dynamic buffer in boost calls consume method of dynamic_buffer that erases bytes_tranferred from it:
class write_dynbuf_v2_op
....
void operator()(const boost::system::error_code& ec,
std::size_t bytes_transferred, int start = 0)
{
switch (start)
{
case 1:
// write operation
async_write(stream_, buffers_.data(0, buffers_.size()),
BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition_),
BOOST_ASIO_MOVE_CAST(write_dynbuf_v2_op)(*this));
return;
default:
// write completed, consume transferred bytes and call handler
buffers_.consume(bytes_transferred);
handler_(ec, static_cast<const std::size_t&>(bytes_transferred));
}
}
Hence in the original example, we would queue an async write on the vector, then queue async operation on the same vector again and again.
After the first callback finishes, transferring 512000 bytes, the second callback has an empty vector (as it was erased by dynamic_buffer) and the callback prints
Successfully sent 0
As the error code is 0 and then
Send error
As send error is printed when the number of bytes transferred is 0.
io_context.run() is stuck as it has a pending read operation.
The workaround helps as we schedule a copy of the vector for each async_write operation.
An alternative would be resizing the vector back to the original size after io_context.run()

PHP extension: why int var changes to 0?

I am developing some PHP extension on C. I have few functions and several variables (char and int) defined globally at the top of C code. At php side I call the first function and pass some value for ssh_port argument - 22. this value set to global var. Then I call second function. But when I call third function - ssh_port variable suddenly gets 0 value ? Why ? The code is following:
#include <php.h>
#include "super_ssh.h"
#include <libssh2.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifndef INADDR_NONE
#define INADDR_NONE (in_addr_t)-1
#endif
char *ssh_ip, *ssh_username, *ssh_password, *remote_host, *last_error = "";
size_t ssh_ip_len, ssh_username_len, ssh_password_len, remote_host_len;
int ssh_port = 0, remote_port = 0, local_port = 0, to_close_tunnel = 0, thread_is_runnning = 0, is_authenticated = 0;
PHP_FUNCTION(super_ssh_connect) {
if (zend_parse_parameters(
ZEND_NUM_ARGS(),
"sl",
&ssh_ip,
&ssh_ip_len,
&ssh_port
) == FAILURE) {
return;
}
RETURN_LONG(ssh_port);
}
PHP_FUNCTION(super_ssh_authenticate) {
if (zend_parse_parameters(
ZEND_NUM_ARGS(),
"ss",
&ssh_username,
&ssh_username_len,
&ssh_password,
&ssh_password_len
) == FAILURE) {
return;
}
RETURN_LONG(ssh_port);
}
PHP_FUNCTION(super_ssh_open_tunnel) {
if (zend_parse_parameters(
ZEND_NUM_ARGS(),
"sll",
&remote_host,
&remote_host_len,
&remote_port,
&local_port
) == FAILURE) {
return;
}
RETURN_LONG(ssh_port);
}
ZEND_BEGIN_ARG_INFO_EX(arginfo_super_ssh_connect, 0, 0, 2)
ZEND_ARG_INFO(0, ssh_ip)
ZEND_ARG_INFO(0, ssh_port)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_super_ssh_authenticate, 0, 0, 2)
ZEND_ARG_INFO(0, ssh_username)
ZEND_ARG_INFO(0, ssh_password)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_super_ssh_open_tunnel, 0, 0, 3)
ZEND_ARG_INFO(0, remote_host)
ZEND_ARG_INFO(0, remote_port)
ZEND_ARG_INFO(0, local_port)
ZEND_END_ARG_INFO()
zend_function_entry super_ssh_functions[] = {
PHP_FE(super_ssh_connect, arginfo_super_ssh_connect)
PHP_FE(super_ssh_authenticate, arginfo_super_ssh_authenticate)
PHP_FE(super_ssh_open_tunnel, arginfo_super_ssh_open_tunnel)
PHP_FE_END
};
zend_module_entry super_ssh_module_entry = {
STANDARD_MODULE_HEADER,
PHP_SUPER_SSH_EXTNAME,
super_ssh_functions,
NULL,
PHP_MSHUTDOWN(super_ssh),
NULL,
NULL,
NULL,
PHP_SUPER_SSH_VERSION,
STANDARD_MODULE_PROPERTIES,
};
ZEND_GET_MODULE(super_ssh);
And the code of PHP side:
<?php
var_dump(super_ssh_connect("234.43.23.3", 22));
var_dump(super_ssh_authenticate("dfds", "mofsdfdsnitor"));
var_dump(super_ssh_open_tunnel("server", 993, 4444));
Actual result is:
int(22) int(22) int(0)
Expected result is:
int(22) int(22) int(22)
So the question is why the ssh_port variable gets 0 value ? I don't set it anywhere! Really can't understand it :(
The interesting thing is that the problem is actual for apache php. So it happens when I run the script from browser. (apache2 + php)
If I try the same compilation for PHP CLI it works as expected, the output is:
int(22) int(22) int(22)
May be it is somehow touching with garbage collector ? Or maybe you just can me suggest better way for my code how to work with variables?
My environment:
Ubuntu 18.04.1 LTS, apache2 + PHP Version 7.2.17-1, and PHP CLI is PHP 7.2.2 (cli) (built: Apr 29 2019 09:57:40) ( ZTS DEBUG )
I noticed problematic code, if I comment the following code frpm third super_ssh_open_tunnel function - it works.
Commenting this code make it work, without this code I still have 22 in the ssh_port var
if (zend_parse_parameters(
ZEND_NUM_ARGS(),
"sll",
&remote_host,
&remote_host_len,
&remote_port,
&local_port
) == FAILURE) {
return;
}
Actually, I think you have is an undefined behavior.
Firstly PHP_FUNCTION is expanded to void zif_FUNCNAME(zend_execute_data *execute_data, zval *return_value).
According to C Standard:
6.8.6.4 The return statement
Constraints
A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.
6.9.1 Function definitions
If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.
So, in your case zend_parse_parameters returns FAILURE which is then translated into "ending before reaching closing {, so that's why the value of ssh_port is never returned.
The reason why zend_parse_parameters fails is because one of the arguments is not initialized different than 0

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()

I want to ask you how it should look this code to C++

I want to ask you how it should look this code to C++:
<?php
for ($i = 1; $i <= 10; $i++) {
$array[$i]="test".$i;
}
?>
It would look something like this (a complete program).
/* required headers */
#include <map>
#include <cstdlib>
/* code has to be inside a function; main is the start-point of the program */
int main() {
std::map<int, int> array;
for (int i = 1; i <= 10; ++i) {
array[i] = i;
}
return EXIT_SUCCESS;
}
I use a map above, since PHP "arrays" are actually like maps in other languages (although completely mimicing their behaviour in a statically-typed language is a hassle). Of course, since the program does little, you could save yourself some typing and not type something that effectively does nothing.
EDIT:
/* required headers */
#include <map>
#include <string>
#include <sstream>
#include <cstdlib>
/* code has to be inside a function; main is the start-point of the program */
int main() {
std::map<int, std::string> array;
for (int i = 1; i <= 10; ++i) {
std::ostringstream stream;
stream << "test" << i;
array[i] = stream.str();
}
return EXIT_SUCCESS;
}
Edit based on your edits
Important addition to the other answers that php doesn't require:
#include <sstream>
#include <string>
int main
{
using namespace std;
string array[11]; // tell the compiler array is an array of size 11
// this array starts at index 0 and goes up to 10
// totaling 11 elements
for ( int i=1; i<=10; i++){ // you might want to start at 0 here
ostringstream strStream
strStream << "test" << i;
array[i] = strStream.str();
}
return 0;
}
// accessing array outside the bounds you told the compiler
// results in undefined behavior, practically this means crash
// or data corruption
This is the most direct conversion. However, you probably wish to look into std::map in #eq-'s answer for general associative containers where you don't care if the index space is contiguous and just general safety. C style arrays are considered a code smell these days.
for ( int i=1; i<=10; i++){
array[i] = i;
}

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

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

Categories