summaryrefslogtreecommitdiffstats
path: root/private/sdktools/rslm/rslm.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/sdktools/rslm/rslm.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/sdktools/rslm/rslm.c')
-rw-r--r--private/sdktools/rslm/rslm.c1111
1 files changed, 1111 insertions, 0 deletions
diff --git a/private/sdktools/rslm/rslm.c b/private/sdktools/rslm/rslm.c
new file mode 100644
index 000000000..7872bea60
--- /dev/null
+++ b/private/sdktools/rslm/rslm.c
@@ -0,0 +1,1111 @@
+//
+// RSLM.C
+//
+// rslm - a huge multi-project tool
+//
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <process.h>
+#include <io.h>
+#include <stdio.h>
+#include <string.h>
+#include <direct.h>
+#include <windows.h>
+
+/*
+ * Globals
+ */
+char szParentProject[32] = "";
+char szParentServer[MAX_PATH] = "";
+char szInfoFileName[MAX_PATH] = "rslm.ini";
+char szDefInfoFileName[] = "rslm.ini";
+char szSlmFileName[] = "slm.ini";
+char szNoLock[] = "NoLock";
+char szLocalMetaRoot[MAX_PATH] = "";
+BOOL fAsync = FALSE;
+BOOL fRecurse = FALSE;
+BOOL fBuildFiles = FALSE;
+BOOL fDebug = FALSE;
+BOOL fBatch = FALSE;
+BOOL fKeep = FALSE;
+BOOL fMinimized = FALSE;
+BOOL fValidate = FALSE;
+int iOutputFile = 0;
+WIN32_FIND_DATA wfd;
+
+/*
+ * Prototypes
+ */
+BOOL SpawnEnlistCmd(char **argv, char *pszServer, char *pszProject);
+BOOL SpawnSlmckCmd( char **argv, char *pszServer, char *pszProject);
+BOOL SpawnOtherCmd( char **argv, char *pszServer, char *pszProject);
+BOOL Noop( char **argv, char *pszServer, char *pszProject);
+BOOL GrabReadLock( char **argv, char *pszServer, char *pszProject);
+BOOL GrabWriteLock( char **argv, char *pszServer, char *pszProject);
+BOOL ReleaseLock( char **argv, char *pszServer, char *pszProject);
+BOOL CallRslm( char **argv, char *pszServer, char *pszProject);
+
+/*
+ * structures
+ */
+typedef struct tagSPAWNINFO {
+ char *pszCmd;
+ BOOL (*pfnSpawn)(char **, char*, char*);
+} SPAWNINFO, *PSPAWNINFO;
+
+SPAWNINFO aLockCmdData[] = {
+ { "ssync", GrabReadLock },
+ { "in", GrabWriteLock },
+ { NULL, Noop }
+};
+
+SPAWNINFO aPreCmdData[] = {
+ { "enlist", SpawnEnlistCmd },
+ { "slmck", SpawnSlmckCmd },
+ { "defect", Noop },
+ { "sadmin", SpawnSlmckCmd },
+ { NULL, SpawnOtherCmd }
+};
+
+SPAWNINFO aPostCmdData[] = {
+ { "defect", SpawnOtherCmd },
+ { NULL, Noop }
+};
+
+SPAWNINFO aUnlockCmdData[] = {
+ { "ssync", ReleaseLock },
+ { "in", ReleaseLock },
+ { NULL, Noop }
+};
+
+
+LPSTR *ParseCmdLine(
+LPSTR *parg)
+{
+ LPSTR arg;
+
+ ++parg; // skip name of us
+
+nextArg:
+
+ arg = *parg;
+
+ if (arg == NULL || (*arg != '-' && *arg != '/')) {
+ return(parg); // last arg
+ }
+
+ parg++; // parg points to next arg
+
+ while (TRUE) {
+ arg++; // skip switch char
+ switch (toupper(*arg)) {
+ case '\0':
+ case ' ':
+ goto nextArg;
+
+ case 'A':
+ fAsync = TRUE;
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -a\n");
+ }
+ break;
+
+ case 'B':
+ fBuildFiles = TRUE;
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -b\n");
+ }
+ break;
+
+ case 'C':
+ fBatch = TRUE;
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -c\n");
+ }
+ break;
+
+ case 'D':
+ fDebug = TRUE;
+ fprintf(stderr, "PARAM: -d\n");
+ break;
+
+ case 'F':
+ if (*parg == NULL) {
+ goto usage;
+ }
+ strcpy(szInfoFileName, *parg++);
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -f %s\n", szInfoFileName);
+ }
+ goto nextArg;
+
+ case 'K':
+ fKeep = TRUE;
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -k\n");
+ }
+ break;
+
+ case 'L':
+ if (*parg == NULL) {
+ goto usage;
+ }
+ strcpy(szLocalMetaRoot, *parg++);
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -l %s\n", szLocalMetaRoot);
+ }
+ goto nextArg;
+
+ case 'M':
+ fMinimized = TRUE;
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -m\n");
+ }
+ break;
+
+ case 'P':
+ if (*parg == NULL) {
+ goto usage;
+ }
+ strcpy(szParentProject, *parg++);
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -p %s\n", szParentProject);
+ }
+ goto nextArg;
+
+ case 'R':
+ fRecurse = TRUE;
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -r\n");
+ }
+ break;
+
+ case 'S':
+ if (*parg == NULL) {
+ goto usage;
+ }
+ strcpy(szParentServer, *parg++);
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -s %s\n", szParentServer);
+ }
+ goto nextArg;
+
+ case 'V':
+ fValidate = TRUE;
+ if (fDebug) {
+ fprintf(stderr, "PARAM: -v\n");
+ }
+ break;
+
+ default:
+usage:
+ fprintf(stderr, "usage: rslm [options] <command line>\n");
+ fprintf(stderr, " -a (async spawn)\n");
+ fprintf(stderr, " -b (build infofiles)\n");
+ fprintf(stderr, " -c (emit batch file to std out - no spawn)\n");
+ fprintf(stderr, " -d (debug mode)\n");
+ fprintf(stderr, " -f rslmfile (default=\"rslm.ini\")\n");
+ fprintf(stderr, " -k (keep async spawn windows around)\n");
+ fprintf(stderr, " -l lockdir (\"NoLock\" turns off meta locking)\n");
+ fprintf(stderr, " -m (async spawn windows minmimzed)\n");
+ fprintf(stderr, " -p project (defaults to slm.ini project)\n");
+ fprintf(stderr, " -r (do command on all dirs w/infofile.)\n");
+ fprintf(stderr, " -s slm_server (defaults to slm.ini server root)\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "set RSLM_OPTS environent variable for new defaults.\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "<command line> may contain the following substitute patterns:\n");
+ fprintf(stderr, " %%CUR_PATH%% => full path of Current Directory at spawn time.\n");
+ fprintf(stderr, " %%CUR_DIR%% => name of current directory at spawn time.\n");
+ _exit(1);
+ }
+ }
+
+ return(parg);
+}
+
+
+
+VOID mystrrpl(
+char *psz,
+char cFind,
+char cReplace)
+{
+ while (*psz != '\0') {
+ if (*psz == cFind) {
+ *psz = cReplace;
+ }
+ psz++;
+ }
+}
+
+
+/*
+ * Open file named pszSlmFileName and fill pszProject and pszServer from
+ * that file. (buffers are assumed large enough) Returns fSuccess.
+ */
+BOOL ExtractSlmIniInfo(
+char *pszSlmFileName,
+char *pszProject,
+char *pszServer)
+{
+ static char szProjectKey[] = "project = ";
+ static char szServerKey[] = "slm root = ";
+ static char szSlmFileLine[MAX_PATH];
+ FILE *hFile;
+ char *psz, *psz2;
+
+ hFile = fopen(pszSlmFileName, "r");
+ if (hFile == NULL) {
+ return(FALSE);
+ }
+ fgets(szSlmFileLine, MAX_PATH, hFile); // line 1
+
+ psz = strstr(szSlmFileLine, szProjectKey);
+ if (psz == NULL) {
+ fclose(hFile);
+ return(FALSE);
+ }
+ strcpy(pszProject, psz + strlen(szProjectKey));
+ pszProject[strlen(pszProject) - 1] = '\0'; // remove \n
+
+ fgets(szSlmFileLine, MAX_PATH, hFile); // line 2
+
+ psz = strstr(szSlmFileLine, szServerKey);
+ if (psz == NULL) {
+ fclose(hFile);
+ return(FALSE);
+ }
+ psz += strlen(szServerKey);
+ if (psz[3] == ':') {
+ // Its a local slm project, clean up the string
+ psz += 2; // skip '//'
+ psz2 = strchr(psz, '/');
+ *--psz2 = ':';
+ *--psz2 = *psz;
+ psz = psz2;
+ }
+ strcpy(pszServer, psz);
+ pszServer[strlen(pszServer) - 1] = '\0'; // remove \n
+ mystrrpl(pszServer, '/', '\\');
+
+ fclose(hFile);
+ return(TRUE);
+}
+
+
+/*
+ * Reads next line of hRslmFile and fills pszProject and pszServer with
+ * apropriate info from that line. Returns fSuccess.
+ */
+BOOL ExtractRslmLine(
+FILE *hRslmFile,
+LPSTR pszProject,
+LPSTR pszServer)
+{
+ char szBuf[100];
+ LPSTR psz;
+
+ if (fgets(szBuf, 100, hRslmFile) == NULL) {
+ return(FALSE);
+ }
+ psz = strchr(szBuf, ' ');
+ if (psz == NULL) {
+ return(FALSE);
+ }
+ *psz++ = '\0';
+ while (isspace(*psz)) {
+ psz++;
+ }
+ psz[strlen(psz) - 1] = '\0'; // remove \n
+ strcpy(pszServer, psz);
+ strcpy(pszProject, szBuf);
+ return(pszServer[0] && pszProject[0]);
+}
+
+
+/*
+ * Recurse from current directory depth first on all directories containing
+ * szSlmFileName files. Create szInfoFileName files at
+ * nodes where any descendant directories have projects differing from
+ * the parent directory's project.
+ *
+ * Returns fInfoFileCreated. Emits a message if directory structure is
+ * not ok. (ie, no rslm.ini file (except the root) should exist without
+ * its parent directory having an rslm.ini file too.
+ */
+BOOL BuildFiles(
+LPSTR pszCurProj)
+{
+ HANDLE hFF;
+ char szProject[32];
+ char szServer[MAX_PATH];
+ FILE *hInfoFile, *hFile;
+ char szCurPath[MAX_PATH];
+ BOOL fSlmOk;
+ BOOL fInfoFileCreated = FALSE;
+ BOOL fChildInfoFileCreated = FALSE;
+
+ GetCurrentDirectory(MAX_PATH, szCurPath);
+
+ //
+ // delete any existing rslm.ini file
+ //
+ hFile = fopen(szInfoFileName, "r");
+ if (hFile != NULL) {
+ fclose(hFile);
+ if (remove(szInfoFileName) == -1) {
+ fprintf(stderr, "RSLM: Could not delete %s\\%s\n", szCurPath,
+ szInfoFileName);
+ return(FALSE);
+ }
+ }
+
+ //
+ // for each subdirectory...
+ //
+ hFF = FindFirstFile("*.*", &wfd);
+ while (hFF) {
+ if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ goto nextFile;
+ }
+
+ if (!strcmp(wfd.cFileName, "..") || !strcmp(wfd.cFileName, ".")) {
+ goto nextFile;
+ }
+
+ if (!SetCurrentDirectory(wfd.cFileName)) {
+ goto nextFile;
+ }
+ /*
+ * if this sub-directory doesn't have an slm.ini file, skip it.
+ */
+ hFile = fopen(szSlmFileName, "r");
+ if (hFile == NULL) {
+ SetCurrentDirectory("..");
+ goto nextFile;
+ }
+ fclose(hFile);
+
+ fSlmOk = ExtractSlmIniInfo(szSlmFileName, szProject, szServer);
+
+ if (fSlmOk) {
+ fChildInfoFileCreated |= BuildFiles(szProject);
+ }
+
+ SetCurrentDirectory("..");
+
+ if (!fSlmOk) {
+ fprintf(stderr, "\nRSLM: Can't parse %s\\%s\\%s\n", szCurPath, wfd.cFileName, szSlmFileName);
+ } else {
+ /*
+ * Append child project info if its not part of the current proj.
+ */
+ if (_stricmp(szProject, pszCurProj)) {
+ hInfoFile = fopen(szInfoFileName, "a");
+ if (hInfoFile == NULL) {
+ fprintf(stderr, "RSLM: Couldn't append to %s.\n", szInfoFileName);
+ return(FALSE);
+ }
+ fprintf(hInfoFile, "%s %s\n", szProject, szServer);
+ fclose(hInfoFile);
+ fprintf(stdout, "%s\\%s << %s %s\n", szCurPath, szInfoFileName, szProject, szServer);
+ fInfoFileCreated = TRUE;
+ }
+ }
+
+nextFile:
+ if (!FindNextFile(hFF, &wfd)) {
+ FindClose(hFF);
+ break;
+ }
+ }
+ if (fDebug) {
+ fprintf(stderr, "RSLM: %d->%d at %s\n", fInfoFileCreated, fChildInfoFileCreated, szCurPath);
+ }
+ if (fChildInfoFileCreated && !fInfoFileCreated) {
+ fprintf(stderr, "RSLM: Invalid project structure at %s.\n", szCurPath);
+ }
+ return(fInfoFileCreated);
+}
+
+
+/*
+ * This routine validates an RSLM metaproject by ssyncing all rslm.ini files
+ * and making sure the directory structure reflects what the rslm.ini file
+ * says it should be.
+ *
+ * 1) reconcile szInfoFileName file (if not rslm.ini) to new rslm.ini file.
+ * a) If the new rslm.ini file contains a project that is not in the
+ * szInfoFIleName file, add it to the szInfoFIleName File.
+ * b) If the new rslm.ini file server is different from the
+ * szInforFIleName file server name, fix the szInfoFileName server
+ * name. Add an entry to the global changed file.
+ * c) If the new rslm.ini file does not contain projects that are in
+ * the szInfoFileName file, comment out entry from the szInfoFileName
+ * file.
+ *
+ * 2) for each subdirectory that has an slm.ini file with a project
+ * different from the current project name:
+ * a) if it is NOT in the szInfoFIleName file, add entry to global
+ * remove project file.
+ *
+ * 3) recurse on all directories with an rslm.ini file.
+ *
+ * 4) for each non-comment entry in the szInfoFileName file:
+ * a) if no directory exists with the project name:
+ * 1) if project exists in removed global list, mv removed project
+ * to current directory and remove entry from global removed list.
+ * 2) otherwise, enlist in the new project.
+ *
+ * 5) for each project in the global removed list, defect from that node.
+ *
+ * 6) for each project in the global changed list, slmck that node.
+ */
+BOOL Validate(
+LPSTR pszCurProj)
+{
+#if 0
+ char szCurDir[MAX_PATH];
+ FILE *hInfoFile;
+
+ static char *ssyncArgs[] = { "ssync", "rslm.ini", NULL };
+
+ if (fBatch) {
+ fprintf(stderr, "RSLM: Can't validate in batch mode.\n");
+ return(FALSE);
+ }
+
+ if (fAsync) {
+ fprintf(stderr, "RSLM: Can't validate in assync mode.\n");
+ return(FALSE);
+ }
+
+ if (fRecurse) {
+ fprintf(stderr, "RSLM: Can't validate in recurse mode.\n");
+ return(FALSE);
+ }
+
+ GetCurrentDirectory(MAX_PATH, szCurDir);
+
+ MySpawn(P_WAIT, ssyncArgs, NULL, 0);
+ if (_stricmp(szInfoFileName, szDefInfoFileName)) {
+ ReconcileInfoFile();
+ }
+
+ hInfoFile = fopen(szInfoFileName, "r");
+ if (hInfoFile == NULL) {
+ hInfoFile = fopen(szDefInfoFileName, "r");
+ if (hInfoFile == NULL) {
+ return(FALSE);
+ }
+ }
+
+ //
+ // for each subdirectory...
+ //
+ hFF = FindFirstFile("*.*", &wfd);
+ while (hFF) {
+ if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ goto nextFile;
+ }
+
+ if (!strcmp(wfd.cFileName, "..") || !strcmp(wfd.cFileName, ".")) {
+ goto nextFile;
+ }
+
+ if (!SetCurrentDirectory(wfd.cFileName)) {
+ goto nextFile;
+ }
+ /*
+ * if this sub-directory doesn't have an slm.ini file, skip it.
+ */
+ hFile = fopen(szSlmFileName, "r");
+ if (hFile == NULL) {
+ SetCurrentDirectory("..");
+ goto nextFile;
+ }
+ fclose(hFile);
+
+ fSlmOk = ExtractSlmIniInfo(szSlmFileName, szDirProject, szDirServer);
+
+ SetCurrentDirectory("..");
+
+ if (!fSlmOk) {
+ goto nextFile;
+ }
+
+ /*
+ * searsh rslm.ini file for szThisProject
+ */
+ rewind(hInfoFile);
+ while (ExtractRslmLine(hInfoFile, szThisProject, szThisServer)) {
+ if (!_stricmp(szThisProject, szDirProject) {
+ if (_stricmp(szThisServer, szDirServer)) {
+ goto nextFile; // cool, no problems
+ } else {
+ Append(pszChanged, szThisProject, szThisServer, szCurDir);
+ goto nextFile;
+ }
+ }
+ }
+ /*
+ * Getting here means we did not find an rslm.ini line to account
+ * for szThisProject. We need to remove it.
+ */
+ Append(pszRemoved, szThisProject, szThisServer, szCurDir);
+
+nextFile:
+ if (!FindNextFile(hFF, &wfd)) {
+ FindClose(hFF);
+ break;
+ }
+ }
+
+ fclose(hInfoFile);
+#endif
+ return(TRUE);
+}
+
+
+char *Substitute(
+char *pszIn)
+{
+ static char szCurDir[MAX_PATH];
+ char *pszOut, *pszOut2;
+
+ if (!_stricmp(pszIn, "%%CUR_PATH%%") ||
+ !strcmp(pszIn, "%%CUR_DIR%%")) {
+ GetCurrentDirectory(MAX_PATH, szCurDir);
+ pszOut = szCurDir;
+ if (!_stricmp(pszIn, "%%CUR_DIR%%")) {
+ pszOut = strrchr(szCurDir, '\\');
+ if (pszOut == NULL) {
+ pszOut = szCurDir;
+ } else {
+ pszOut++;
+ }
+ }
+ return(pszOut);
+ }
+ return(pszIn);
+}
+
+/*
+ * spawns the command in argv using the mode form. If argInsert is provided,
+ * those params are inserted into the argv params at param offset
+ * cCommandsBeforeInsert. If fRelease is set, the -r switch is propigated
+ * on spawns if "rslm" is an arguement.
+ *
+ * stdout is flushed after each spawn.
+ */
+int MySpawn(
+int mode,
+char *argv[],
+char *argInsert[],
+int cCommandsBeforeInsert)
+{
+ char *modarg[32];
+ int iMod, iRet, j, k, iArg, iAdded;
+ char szFullPath[MAX_PATH];
+ char szCurDir[MAX_PATH];
+ char *pszFilePart;
+ DWORD dw;
+
+ iMod = 0;
+ iArg = 0;
+ iAdded = 0;
+ if (fAsync) {
+ modarg[iMod++] = "start";
+ iAdded++;
+ if (fMinimized) {
+ modarg[iMod++] = "/MIN";
+ iAdded++;
+ }
+ if (fKeep) {
+ modarg[iMod++] = "cmd";
+ iAdded++;
+ modarg[iMod++] = "/K";
+ iAdded++;
+ }
+ }
+ while (iMod < cCommandsBeforeInsert + iAdded && argv[iArg] != NULL) {
+ modarg[iMod++] = Substitute(argv[iArg++]);
+ }
+ j = iMod;
+ while (argInsert != NULL && argInsert[iMod - j] != NULL) {
+ modarg[iMod] = Substitute(argInsert[iMod - j]);
+ iMod++;
+ }
+ while (argv[iArg] != NULL) {
+ modarg[iMod++] = Substitute(argv[iArg++]);
+ }
+ modarg[iMod] = NULL;
+
+searchIt:
+
+ if (!SearchPath(NULL, modarg[0], ".com", MAX_PATH, szFullPath, &pszFilePart))
+ if (!SearchPath(NULL, modarg[0], ".exe", MAX_PATH, szFullPath, &pszFilePart))
+ if (!SearchPath(NULL, modarg[0], ".cmd", MAX_PATH, szFullPath, &pszFilePart))
+ if (!SearchPath(NULL, modarg[0], ".bat", MAX_PATH, szFullPath, &pszFilePart)) {
+ /*
+ * assume its an internal command
+ */
+ for (iMod = 30; iMod; iMod--) {
+ modarg[iMod] = modarg[iMod - 2];
+ }
+ modarg[0] = "cmd";
+ modarg[1] = "/c";
+ goto searchIt;
+ }
+
+ if (fDebug) {
+ fprintf(stderr, "RSLM: spawning: ");
+ for (iMod = 0; modarg[iMod] != NULL; iMod++) {
+ fprintf(stderr, "%s ", modarg[iMod]);
+ }
+ fprintf(stderr, "\n");
+ }
+
+ if (fBatch) {
+ GetCurrentDirectory(MAX_PATH, szCurDir);
+ fprintf(stdout, "cd %s\n", szCurDir);
+ for (iMod = 0; modarg[iMod] != NULL; iMod++) {
+ fprintf(stdout, "%s ", modarg[iMod]);
+ }
+ fprintf(stdout, "\n");
+ iRet = 0;
+ } else {
+ modarg[0] = szFullPath;
+ iRet = spawnv(mode, modarg[0], modarg);
+ }
+ fflush(stdout);
+
+ return(iRet);
+}
+
+
+BOOL GrabReadLock(
+char **argv,
+char *pszParentServer,
+char *pszParentProject)
+{
+ static char *readlockargs[] = {
+ "cookie", "-r", "-c", "\"Autolock - (RSLM)\"", NULL
+ };
+ char szCurDir[MAX_PATH];
+ int iRet;
+
+ if (!_stricmp(szLocalMetaRoot, szNoLock)) {
+ return(TRUE); // skip locks
+ }
+
+ /*
+ * cd to local dir with meta-project locks
+ */
+ GetCurrentDirectory(MAX_PATH, szCurDir);
+ if (!SetCurrentDirectory(szLocalMetaRoot)) {
+ fprintf(stderr, "RSLM: Bad or unspecified rslm lock directory [%s].\n",
+ szLocalMetaRoot);
+ return(FALSE);
+ }
+ /*
+ * Get the cookie!
+ */
+ iRet = MySpawn(P_WAIT, readlockargs, NULL, 0);
+ if (fBatch) {
+ fprintf(stdout, "if ERRORLEVEL==1 goto end\n");
+ }
+ SetCurrentDirectory(szCurDir);
+ if (iRet) {
+ fprintf(stderr, "RSLM: Unable to obtain root lock.\n");
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+
+BOOL GrabWriteLock(
+char **argv,
+char *pszParentServer,
+char *pszParentProject)
+{
+ static char *readlockargs[] = {
+ "cookie", "-w", "-c", "\"Autolock - (RSLM)\"", NULL
+ };
+ char szCurDir[MAX_PATH];
+ int iRet;
+
+ if (!_stricmp(szLocalMetaRoot, szNoLock)) {
+ return(TRUE); // skip locks
+ }
+
+ /*
+ * cd to local dir with meta-project locks
+ */
+ GetCurrentDirectory(MAX_PATH, szCurDir);
+ if (!SetCurrentDirectory(szLocalMetaRoot)) {
+ fprintf(stderr, "RSLM: Bad or unspecified rslm lock directory [%s].\n",
+ szLocalMetaRoot);
+ return(FALSE);
+ }
+ /*
+ * Get the cookie!
+ */
+ iRet = MySpawn(P_WAIT, readlockargs, NULL, 0);
+ SetCurrentDirectory(szCurDir);
+ if (iRet) {
+ fprintf(stderr, "RSLM: Unable to obtain root lock.\n");
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+
+BOOL ReleaseLock(
+char **argv,
+char *pszParentServer,
+char *pszParentProject)
+{
+ static char *freelockargs[] = {
+ "cookie", "-f", NULL
+ };
+ char szCurDir[MAX_PATH];
+ int iRet;
+
+ if (!_stricmp(szLocalMetaRoot, szNoLock)) {
+ return(TRUE); // skip locks
+ }
+
+ /*
+ * cd to local dir with meta-project locks
+ */
+ GetCurrentDirectory(MAX_PATH, szCurDir);
+ if (!SetCurrentDirectory(szLocalMetaRoot)) {
+ fprintf(stderr, "RSLM: Bad or unspecified rslm lock directory.\n");
+ fprintf(stderr, "RSLM: Use -l parameter or set RSLM_LOCK_DIR variable.\n");
+ return(FALSE);
+ }
+ /*
+ * Release the cookie!
+ */
+ iRet = MySpawn(P_WAIT, freelockargs, NULL, 0);
+ if (fBatch) {
+ fprintf(stdout, ":end\n");
+ }
+ SetCurrentDirectory(szCurDir);
+ if (iRet) {
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+
+BOOL SpawnEnlistCmd(
+char **argv,
+char *pszParentServer,
+char *pszParentProject)
+{
+ int i;
+ static char*ssyncargs[] = {
+ "ssync", "-u", "rslm.ini", NULL
+ };
+ char *parentArgs[] = { "-s", pszParentServer, "-p", pszParentProject, NULL };
+
+ /*
+ * enlist requires p and s flags to be specified
+ */
+ if (!*pszParentProject || !*pszParentServer) {
+ fprintf(stderr, "RSLM: -p and/or -s parameter to rslm is missing.\n");
+ return(FALSE);
+ }
+ /*
+ * find out where to insert -p and -s parameters
+ */
+ for (i = 1; argv[i] != NULL && (*argv[i] == '-' || *argv[i] == '/'); i++) {
+ }
+ /*
+ * run enlist cmd
+ */
+ if (MySpawn(P_WAIT, argv, parentArgs, i)) {
+ return(FALSE);
+ }
+ /*
+ * ssync to rslm.ini file so we can continue recursing
+ */
+ if (MySpawn(P_WAIT, ssyncargs, NULL, 0)) {
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+
+
+BOOL SpawnSlmckCmd(
+char **argv,
+char *pszParentServer,
+char *pszParentProject)
+{
+ int i;
+ char *parentArgs[] = { "-s", pszParentServer, "-p", pszParentProject, NULL };
+
+ /*
+ * slmck requires p and s flags to be specified
+ */
+ if (!*pszParentProject || !*pszParentServer) {
+ fprintf(stderr, "RSLM: -p and/or -s parameter to rslm is missing.\n");
+ return(FALSE);
+ }
+ /*
+ * find out where to insert -p and -s parameters
+ */
+ for (i = 1; argv[i] != NULL && (*argv[i] == '-' || *argv[i] == '/'); i++) {
+ }
+ /*
+ * run slmck-like cmd
+ */
+ if (MySpawn(P_WAIT, argv, parentArgs, i)) {
+ return(FALSE);
+ }
+ /*
+ * correct project and server names if they are wrong or not supplied.
+ */
+ return(ExtractSlmIniInfo(szSlmFileName, pszParentProject, pszParentServer));
+}
+
+
+
+BOOL SpawnOtherCmd(
+char **argv,
+char *pszParentServer,
+char *pszParentProject)
+{
+ pszParentServer;
+ pszParentProject;
+
+ return(!MySpawn(P_WAIT, argv, NULL, 0));
+}
+
+
+BOOL Noop(
+char **argv,
+char *pszParentServer,
+char *pszParentProject)
+{
+ argv;
+ pszParentServer;
+ pszParentProject;
+
+ return(TRUE);
+}
+
+
+BOOL SpawnCommand(
+char **argv,
+char *pszParentServer,
+char *pszParentProject,
+PSPAWNINFO psi)
+{
+ int i;
+
+ for (i = 0; TRUE; i++) {
+ if (psi[i].pszCmd == NULL ||
+ !_stricmp(argv[0], psi[i].pszCmd)) {
+ return(psi[i].pfnSpawn(argv, pszParentServer, pszParentProject));
+ }
+ }
+}
+
+
+BOOL CallRslm(
+char **argv,
+char *pszParentServer,
+char *pszParentProject)
+{
+ static int cIndent = 0;
+ int i;
+ HANDLE hFF;
+ FILE *hOutputFile, *hInfoFile;
+ char szSpawnProject[32];
+ char szSpawnServer[MAX_PATH];
+
+ if (fDebug) {
+ for (i = 0; i < cIndent; i++) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "\\\n");
+ for (i = 0; i < cIndent; i++) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, " \\\n");
+ cIndent++;
+ }
+
+ SpawnCommand(argv, pszParentServer, pszParentProject, aPreCmdData);
+
+ /*
+ * Now spawn child projects as specified by the rslm.ini file.
+ *
+ * Spawn propigates proper -p and -s parameters to rslm.
+ */
+ hInfoFile = fopen(szInfoFileName, "r");
+ if (hInfoFile == NULL) {
+ /*
+ * szInfoFileName may be a custom file name, try for the default name
+ */
+ hInfoFile = fopen(szDefInfoFileName, "r");
+ }
+ if (hInfoFile != NULL) {
+ while (ExtractRslmLine(hInfoFile, szSpawnProject, szSpawnServer)) {
+ if (!SetCurrentDirectory(szSpawnProject)) {
+ fprintf(stderr, "RSLM: Creating %s directory\n", szSpawnProject);
+ _mkdir(szSpawnProject);
+ if (!SetCurrentDirectory(szSpawnProject)) {
+ fprintf(stderr, "RSLM: Could not create %s directory\n", szSpawnProject);
+ goto leave;
+ }
+ }
+
+ CallRslm(argv, szSpawnServer, szSpawnProject);
+
+ SetCurrentDirectory("..");
+ }
+ fclose(hInfoFile);
+ }
+
+ SpawnCommand(argv, pszParentServer, pszParentProject, aPostCmdData);
+
+ /*
+ * Now, if fRecurse is indicated, spawn all child directories w/o an
+ * rslm.ini file. This spawn propigates -p and -s parameters to rslm.
+ */
+ if (fRecurse) {
+ hFF = FindFirstFile("*.*", &wfd);
+ while (hFF) {
+ if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ goto nextFile;
+ }
+
+ if (!strcmp(wfd.cFileName, "..") || !strcmp(wfd.cFileName, ".")) {
+ goto nextFile;
+ }
+
+ if (!SetCurrentDirectory(wfd.cFileName)) {
+ goto nextFile;
+ }
+ if (!ExtractSlmIniInfo(szSlmFileName, szSpawnProject, szSpawnServer)) {
+ goto nextFile2;
+ }
+ /*
+ * If the project key in the slmini file != the parent project,
+ * skip this directory.
+ */
+ if (_stricmp(szSpawnProject, pszParentProject)) {
+ if (fDebug) {
+ fprintf(stderr, "RSLM: %s != %s\n", szSpawnProject, pszParentProject);
+ }
+ goto nextFile2;
+ }
+
+ CallRslm(argv, szSpawnServer, szSpawnProject);
+
+nextFile2:
+ SetCurrentDirectory("..");
+
+nextFile:
+ if (!FindNextFile(hFF, &wfd)) {
+ FindClose(hFF);
+ break;
+ }
+ }
+ }
+
+leave:
+
+ if (fDebug) {
+ cIndent--;
+ for (i = 0; i < cIndent; i++) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, " /\n");
+ for (i = 0; i < cIndent; i++) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "/\n");
+ }
+ return(0);
+}
+
+
+
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int defargc;
+ char *buf[25];
+ char **defargv = buf;
+ LPSTR psz;
+ char szDefParams[MAX_PATH] = "";
+ char szDefParamsEnv[] = "RSLM_OPTS";
+
+ /*
+ * First get default args from environment and parse them.
+ */
+ GetEnvironmentVariable(szDefParamsEnv, szDefParams, MAX_PATH);
+
+ psz = szDefParams;
+ defargv[0] = "";
+ defargc = 1;
+ while (*psz != '\0') {
+ while (*psz == ' ') { // scan to next token
+ *psz++;
+ }
+ if (*psz == '\0') { // quit if at NULL
+ break;
+ }
+ defargv[defargc++] = psz++; // mark start of token
+ while (*psz != ' ' && *psz != '\0') { // scan over token
+ *psz++;
+ }
+ if (*psz == ' ') { // terminate token
+ *psz++ = '\0';
+ }
+ }
+ defargv[defargc] = NULL;
+ ParseCmdLine(defargv);
+
+ /*
+ * Now parse the main command line.
+ */
+ argv = ParseCmdLine(argv);
+
+ if (fBuildFiles) {
+ char szCurProj[MAX_PATH];
+
+ GetCurrentDirectory(sizeof(szCurProj), szCurProj);
+ BuildFiles(strrchr(szCurProj, '\\') + 1);
+ fprintf(stderr, "RSLM: %s files are built.\n", szInfoFileName);
+ }
+
+ if (fValidate) {
+ char szCurProj[MAX_PATH];
+
+ GetCurrentDirectory(sizeof(szCurProj), szCurProj);
+ Validate(strrchr(szCurProj, '\\') + 1);
+ fprintf(stderr, "RSLM: metaproject is validated.\n", szInfoFileName);
+ }
+
+ if (*argv) {
+ if (!SpawnCommand(argv, szParentServer, szParentProject, aLockCmdData)) {
+ return(0);
+ }
+
+ CallRslm(argv, szParentServer, szParentProject);
+
+ SpawnCommand(argv, szParentServer, szParentProject, aUnlockCmdData);
+ }
+
+ return(0);
+}