Skip to content

Instantly share code, notes, and snippets.

@david0
Last active March 23, 2017 00:14
Show Gist options
  • Save david0/6ec407c2d6f7abd62980 to your computer and use it in GitHub Desktop.
Save david0/6ec407c2d6f7abd62980 to your computer and use it in GitHub Desktop.
PHPStorm+cygwin path helpler
Helper utility for php from cygwin for using with phpStorm

Helper utility for php from cygwin for using with phpStorm

PHPStorm expects an file called php.exe and phpStrom will provide windows pathnames thus this program will convert windows pathnames to unix paths and pass them to php.exe

prerequisites:

  • cygwin
  • php (from cygwinports)
  • make
  • mingw-gcc

usage:

  1. compile with

    make

    This will generate a wrapper php.exe

  2. in PHPStorm: Settings->PHP->Interpreter->"..."->Click Add->PHP Home "..."
    select path to wrapper php.exe

CC=i686-pc-mingw32-gcc
CFLAGS=-Wall -std=c99 -DPHP_EXECUTABLE=\"$$(cygpath -m /bin/php)\"
all: php.exe
clean:
rm php.exe *.o
php.exe: php-winpath-helper.o
$(CC) $< $(LDFLAGS) -o php.exe
install: php.exe
# -mkdir /bin/winpath/
cp php.exe /bin/winpath
/**
* Helper utility for php from cygwin
* for using with phpStorm
*
* PHPStorm expects an file called php.exe and phpStrom will provide windows pathnames
* thus this program will convert windows pathnames to unix paths and pass them to
* php.exe
*
* compile with
*
* i686-mingw-gcc --std=c99 -Wall php-winpath-helper.c -o /bin/winpath/php.exe -DPHP_EXECUTABLE=[windows path to cygwin php.exe]
**/
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <malloc.h>
#include <process.h>
#include <assert.h>
#include <errno.h>
#define PATH_SEPARATOR ";"
#define BUFFER_SIZE 1024*1000
#define CYGWIN_PREFIX "/cygdrive/"
#define MAX_CMD 10000
/**
* Checks if parameter looks like an (absolute) path
**/
bool
is_path(const char* testString) {
if(strlen(testString) < 2)
return false;
if(!isalpha((int)testString[0]))
return false;
if(testString[1] != ':')
return false;
return true;
}
bool is_cygwin_path(const char* str) {
return strncmp(str, CYGWIN_PREFIX, strlen(CYGWIN_PREFIX)) == 0;
}
/**
* Convert absolute windows path name to cygwin path
**/
void
convert_path(char* path, char *newPath) {
assert(is_path(path));
strcpy(newPath, CYGWIN_PREFIX);
char drive[2];
drive[0] = path[0];
drive[1] = '\0';
strcat(newPath, drive);
strcat(newPath, path+2);
for(int i=0; i<strlen(newPath); i++)
if(newPath[i] == '\\')
newPath[i] = '/';
}
/**
* Convert absolute cygwin path name to windows path
**/
void
convert_path_to_win(char* path, char *newPath) {
assert(is_cygwin_path(path));
assert(strlen(path)>strlen(CYGWIN_PREFIX)+2);
strcpy(newPath+1, path+strlen(CYGWIN_PREFIX));
newPath[0]=newPath[1];
newPath[1]=':';
for(; *newPath; newPath++)
if(*newPath == '/')
*newPath = '\\';
}
/**
* convert list of paths (path1;path2) to cygwin paths
**/
void
adjust_path_list(char *oldPathList, char *newPathList) {
strcpy(newPathList, "");
char *part = strtok(oldPathList, PATH_SEPARATOR);
while(part!=NULL) {
strcat(newPathList, PATH_SEPARATOR);
if(is_path(part)) {
char newPath[MAX_PATH];
convert_path(part, newPath);
strcat(newPathList, newPath);
}
strtok(NULL, PATH_SEPARATOR);
}
}
unsigned run_piped(char *cmd, char *envStr, char *buffer) {
HANDLE child_input_read;
HANDLE child_input_write;
HANDLE child_output_read;
HANDLE child_output_write;
DWORD bytes_read=0, processExitCode;
PROCESS_INFORMATION process_info;
STARTUPINFO startup_info;
SECURITY_ATTRIBUTES security_attributes;
// Set the security attributes for the pipe handles created
security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
security_attributes.bInheritHandle = TRUE;
security_attributes.lpSecurityDescriptor = NULL;
CreatePipe(&child_output_read, &child_output_write, &security_attributes, 0);
CreatePipe(&child_input_read, &child_input_write, &security_attributes, 0);
// Create the child process
ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(STARTUPINFO);
startup_info.hStdInput = child_input_read;
startup_info.hStdOutput = child_output_write;
startup_info.hStdError = child_output_write;
startup_info.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess(NULL, cmd , NULL, NULL, TRUE, 0, envStr, NULL, &startup_info, &process_info);
DWORD numCharsPending, curBytesRead=0, clientRunning=true;
while(clientRunning){
Sleep(1);
numCharsPending=0;
// Look if we have data, but dont read it (ReadFile would block)
while(numCharsPending == 0 && clientRunning) {
GetExitCodeProcess(process_info.hProcess, &processExitCode);
if(processExitCode != STILL_ACTIVE) {
clientRunning=false;
break;
}
PeekNamedPipe(child_output_read, NULL, 0, NULL, &numCharsPending, NULL);
if (GetLastError() == ERROR_BROKEN_PIPE)
clientRunning=false;
}
if(bytes_read >= BUFFER_SIZE){
perror("buffer size exceeded");
exit(-1);
}
if(numCharsPending>0){
ReadFile( child_output_read, buffer, BUFFER_SIZE-bytes_read-1, &curBytesRead, NULL);
buffer+=curBytesRead;
bytes_read+=curBytesRead;
}
}
buffer[0]=0;
return processExitCode;
}
char *
convertOutputPaths(char *buffer) {
char *newBuffer=malloc(BUFFER_SIZE);
char *newBufferStart = newBuffer;
char *nextPath=newBuffer;
while(*buffer) {
if(*buffer==' ' || *buffer=='(' || *buffer=='\n') {
*newBuffer=0;
if(is_cygwin_path(nextPath)) {
char new_path[MAX_PATH];
convert_path_to_win(nextPath, new_path);
strcpy(nextPath,new_path);
newBuffer = nextPath+strlen(new_path);
}
nextPath=newBuffer+1;
}
*newBuffer++=*buffer++;
}
strcpy(buffer, newBufferStart);
return buffer;
}
int
main(int argc, char* argv[]) {
// convert all arguments
for(int i=1; i<argc; i++)
if(is_path(argv[i])) {
char *buf = malloc(MAX_PATH);
convert_path(argv[i], buf);
free(argv[i]);
argv[i] = buf;
}
// adjust environment
const char* env_file_vars[] = {
"IDE_PHPUNIT_CUSTOM_LOADER",
"IDE_PHPUNIT_PHPUNIT_PHAR"
};
char environmentBlock[BUFFER_SIZE]; // null terminated block of null terminated strings var=value for for createProcess()
char *envStr = environmentBlock;
for(int i=0; i<(sizeof(env_file_vars)/sizeof(char*)); i++) {
const char *variable_name = env_file_vars[i];
char *value = getenv(env_file_vars[i]);
if(value != NULL)
if(is_path(value)) {
char *new_path = malloc(MAX_PATH);
convert_path(value, new_path);
//setenv(variable_name, new_path, 1);
sprintf(envStr, "%s=%s", variable_name, new_path);
envStr+=strlen(envStr)+1;
}
}
char *oldPhpInclude = getenv("IDE_PHPUNIT_PHPUNIT_INCLUDE");
if(oldPhpInclude != NULL) {
char newPhpInclude[MAX_PATH];
adjust_path_list(oldPhpInclude, newPhpInclude);
sprintf(envStr, "%s=%s", "IDE_PHPUNIT_PHPUNIT_INCLUDE", newPhpInclude);
envStr+=strlen(envStr)+1;
}
envStr[0]=0; // Terminte block;
argv[0] = PHP_EXECUTABLE;
char cmd[MAX_CMD];
cmd[0]=0;
for(int i=0; i<argc; i++) {
strcat(cmd, "\"");
strcat(cmd, argv[i]);
strcat(cmd, "\"");
if(i<argc-1) strcat(cmd, " ");
}
printf("Command %s\n",cmd);
char *buffer = malloc(BUFFER_SIZE);
int rc = run_piped(cmd, environmentBlock, buffer);
printf("%s", convertOutputPaths(buffer));
//printf("%s", buffer);
return rc;
}
@MatteoOreficeIT
Copy link

MatteoOreficeIT commented Mar 23, 2017

I wrote a couple of scripts to solve similar problem around calling cygwin's git.exe version from PHPStorm , it basically rewrite arguments which contain an absolute windows path like c:.... e:.... etc in the mixed mode c:/../.... with cygpath

git-wrapper.bat

We need a batch script to be placed in phpstorm git configuration pane

set PATH=%USERPROFILE%\cygwin64\bin;%USERPROFILE%\bin;%PATH%
set CYGWIN_BINDIR=%USERPROFILE%\cygwin64\bin
REM see http://conemu.github.io/en/CygwinStartDir.html for CHERE_INVOKING
%CYGWIN_BINDIR%\env CHERE_INVOKING=1 /bin/bash -cl "$HOME/bin/git-wrapper.sh ""$@"" " git %*

git-wrapper.sh

This is the real script which rewrite arguments passin through git.exe

#!/usr/bin/env bash
args=( "$@" )
INDEX=0
for param in "$@" ; do 
	if [[ "$param" =~ ^[a-zA-Z]: ]] ; 
		then 
			args[$INDEX]=$(cygpath -m "$param"); 
	fi ;
	INDEX=$(( INDEX + 1 ))
done;
set -- "${args[@]}"
git "$@"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment