#define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x0400 #include <fcntl.h> #include <io.h> #include <stdio.h> #include <stdlib.h> #include <windows.h> static const char *p4user, *p4port, *p4client; /* * Extension list pulled shamelessly from * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sccvs70/html/vetskAddingSourceControlFileExtensions.asp * This must be NULL terminated because I'm too lazy to calculate how long the array is. */ static const char *extensions[] = {"*.sln", "*.vbproj", "*.vbdproj", "*.vbp", "*.csproj", "*.csdproj", "*.vjsproj", "*.vcproj", "*.dsp", "*.mdp", "*.mak", "*.vfpproj", "*.vdp", "*.vdproj", "*.dbp", "*.vsmproj", "*.vsmacros", "*.hwproj", "*.etp", "*.etpproxy", "*.actproj", "*.atp", "*.dmp", "*.mdmp", "*.dsw", NULL}; size_t stripchars = 1; static int scandir(const char *dirpath); static int scanfiles(const char *dirpath); static char *striptail(char *path); static void usage(); static int writeinfo(const char *port, const char *user, const char *client, const char *file, const char *dir); static void usage() { fprintf(stderr, "Usage: p4bindgen <port> <user> <client> [directory ...]\n"); fprintf(stderr, "\tport = P4PORT\n"); fprintf(stderr, "\tuser = P4USER\n"); fprintf(stderr, "\tclient = P4CLIENT\n"); fprintf(stderr, "\tThis utility generates MSSCCPRJ.SCC files suitable for Visual Studio.\n"); fprintf(stderr, "\tUnless a list of directories is passed in on the commandline, the utility\n"); fprintf(stderr, "\tsearches for project files rooted in the current directory.\n"); exit(1); } /* Recursive function to scan the named path and all subdirectories. */ static int scandir(const char *dirpath) { char *dir = NULL; // need a fresh pointer on each call to recurse... static char *searchpattern = NULL; WIN32_FIND_DATA dirdata; HANDLE findhandle; memset(&dirdata, 0, sizeof(WIN32_FIND_DATA)); if (searchpattern == NULL) { searchpattern = (char *)malloc(2048); if (searchpattern == NULL) return FALSE; } if (dir == NULL) { dir = (char *)malloc(2048); if (dir == NULL) return FALSE; } // Scan all of the files in this directory. scanfiles(dirpath); // Start the recursive scan. sprintf(searchpattern, "%s\\*", dirpath); findhandle = FindFirstFileEx(searchpattern, FindExInfoStandard, &dirdata, FindExSearchLimitToDirectories, NULL, 0); if (findhandle != INVALID_HANDLE_VALUE) { do { // We have to explicitly check the FILE_ATTRIBUTE_DIRECTORY since // the FindExSearchLimitToDirectories param to FindFirstFileEx is // only advisory. Go Microsoft! if ((dirdata.cFileName[0] != '.') && (dirdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { sprintf(dir, "%s\\%s", dirpath, dirdata.cFileName); scandir(dir); } } while (FindNextFile(findhandle, &dirdata)); FindClose(findhandle); } free(dir); // free the pointer return TRUE; } /* Function to scan for the named extensions. */ static int scanfiles(const char *dirpath) { static char *searchpattern = NULL; WIN32_FIND_DATA filedata; HANDLE findhandle; int i; memset(&filedata, 0, sizeof(WIN32_FIND_DATA)); if (searchpattern == NULL) { searchpattern = (char *)malloc(2048); if (searchpattern == NULL) return FALSE; } for(i = 0; extensions[i] != NULL; i++) { sprintf(searchpattern, "%s\\%s", dirpath, extensions[i]); findhandle = FindFirstFile(searchpattern, &filedata); if (findhandle != INVALID_HANDLE_VALUE) { do { writeinfo(p4port, p4user, p4client, filedata.cFileName, dirpath); } while (FindNextFile(findhandle, &filedata)); FindClose(findhandle); } } return TRUE; } static char * striptail(char *path) { size_t end; end = strlen(path); // Strip off CRLF if it is around. if ((end > 2) && (path[end-2] == (char)13) && (path[end-1] == (char)10)) path[end-2] = '\0'; end = strlen(path); // Grotty way to strip \... from the end of the directory path. // Perforce likes to add it occasionally. Also strip trailing \ if ((end > 4) && (path[end-4] == '\\') && (path[end-3] == '.') && (path[end-2] == '.') && (path[end-1] == '.')) path[end-4] = '\0'; else if ((end > 1) && (path[end-1] == '\\')) path[end-1] = '\0'; return path; } /* * Write the appropriate entries into the MSSCCPRJ.SCC file. Create the * MSSCCPRJ.SCC file with the appropriate header if it doesn't already exist. */ static int writeinfo(const char *port, const char *user, const char *client, const char *file, const char *dir) { FILE *fd; static char *auxpath = NULL; static char *outputfile = NULL; static char *header = "SCC = This is a source code control file\n\n"; if (outputfile == NULL) { outputfile = (char*)malloc(2048); if (outputfile == NULL) return FALSE; } sprintf(outputfile, "%s\\MSSCCPRJ.SCC", dir); if (auxpath == NULL) { auxpath = (char*)malloc(1024); if (auxpath == NULL) return FALSE; sprintf(auxpath, "\"P4SCC#%s##%s##%s\"", port, user, client); } fd = fopen(outputfile, "r"); if (fd == NULL) { // If the file doesn't exist, create it and add the appropriate header. printf("Creating new binding file: .%s\n", outputfile + stripchars); fd = fopen(outputfile, "w"); fwrite(header, sizeof(char), strlen(header), fd); fclose(fd); } else { // Header should already exist. fclose(fd); } printf("Writing binding for: .%s\\%s\n", dir + stripchars, file); WritePrivateProfileString(file, "SCC_Aux_Path", auxpath, outputfile); WritePrivateProfileString(file, "SCC_Project_Name", "Perforce Project", outputfile); return TRUE; } int main(int argc, char* argv[]) { int i, fd; FILE *file; size_t len; PROCESS_INFORMATION procinfo; STARTUPINFO startinfo; SECURITY_ATTRIBUTES attr; HANDLE mystdout, childstdout, temphandle, myread; char buf[1024]; char *buffer; char *process; if (argc < 4) usage(); p4port = argv[1]; p4user = argv[2]; p4client = argv[3]; // If we don't have a named directory, just look in the current one. if (argc == 4) scandir("."); else { // See how long the string will be, space separated (meaning +1). for(i = 4, len = 0; i < argc; i++) { if (argv[i][0] == '/' && argv[i][1] == '/') len += strlen(argv[i]) + 1; else { buffer = striptail(argv[i]); stripchars = strlen(buffer); scandir(buffer); } } // Skip everything else if we don't have any perforce depot paths. if (len == 0) return 0; process = (char *)malloc(8 + len + 1); sprintf(process, "p4 where "); for(i = 4; i < argc; i++) if (argv[i][0] == '/' && argv[i][1] == '/') sprintf(process, "%s %s", process, argv[i]); // Goo for using CreateProcess ZeroMemory(&procinfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&startinfo, sizeof(STARTUPINFO)); startinfo.cb = sizeof(STARTUPINFO); // Goo for using CreatePipe attr.nLength = sizeof(SECURITY_ATTRIBUTES); attr.bInheritHandle = TRUE; attr.lpSecurityDescriptor = NULL; // Basically we set my stdout to a pipe. That way when we fork a // child, he inherits our stdout. We restore our stdout and use // the other half of the pipe to get what the child is outputting. mystdout = GetStdHandle(STD_OUTPUT_HANDLE); CreatePipe(&temphandle, &childstdout, &attr, 0); SetStdHandle(STD_OUTPUT_HANDLE, childstdout); DuplicateHandle(GetCurrentProcess(), temphandle, GetCurrentProcess(), &myread, 0, FALSE, DUPLICATE_SAME_ACCESS); CloseHandle(temphandle); CreateProcess(NULL, process, NULL, NULL, TRUE, 0, NULL, NULL, &startinfo, &procinfo); CloseHandle(procinfo.hProcess); CloseHandle(procinfo.hThread); SetStdHandle(STD_OUTPUT_HANDLE, mystdout); // If we don't close the childstdout, when we try to read, it will // block since there is an open reference. CloseHandle(childstdout); // Convert from a Windows handle into a C standard descriptor and // finally into a stream. fd = _open_osfhandle((intptr_t)myread, _O_RDONLY); file = _fdopen(fd, "r"); while(fgets(buf, sizeof(buf), file)) { // Skip exclusionary mappings that start with '-' if (buf[0] == '-') continue; // Skip the first 2 tokens, we are interested in the last. (void)strtok(buf, " "); (void)strtok(NULL, " "); buffer = strtok(NULL, " "); buffer = striptail(buffer); stripchars = strlen(buffer); scandir(buffer); } // Clean up our handle. fclose(file); } return 0; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#3 | 6108 | Reed Snellenberger | Updated to VS 2005; creates a single MSSCCPRJ.SCC file at the solution root rather than scattering them around... | ||
#2 | 6066 | Reed Snellenberger |
make dir non-static so that the recursion algorithm works correctly. If you don't do this, it only follows takes the first branch in each high-level directory... |
||
#1 | 6063 | Reed Snellenberger | Integrate the p4bindgen project to add changes/fixes etc | ||
//guest/gordon_tetlow/p4bindgen/src/p4bindgen.cpp | |||||
#1 | 5319 | Gordon Tetlow | Move the source files into a src directory. | ||
//guest/gordon_tetlow/p4bindgen/p4bindgen.cpp | |||||
#1 | 4957 | Gordon Tetlow |
Add my first version of p4bindgen. This tool is meant to be used in the tools menu of P4Win. You point P4Win at a tree and run this and it will generate the MSSCCPRJ.SCC files for any of the files that need binding information. |