summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/cvs/windows-NT/SCC/scc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/cvs/windows-NT/SCC/scc.c')
-rw-r--r--gnu/usr.bin/cvs/windows-NT/SCC/scc.c486
1 files changed, 486 insertions, 0 deletions
diff --git a/gnu/usr.bin/cvs/windows-NT/SCC/scc.c b/gnu/usr.bin/cvs/windows-NT/SCC/scc.c
new file mode 100644
index 00000000000..6815208f357
--- /dev/null
+++ b/gnu/usr.bin/cvs/windows-NT/SCC/scc.c
@@ -0,0 +1,486 @@
+/* This file was written by Jim Kingdon, and is hereby placed
+ in the public domain. */
+
+#include <Wtypes.h>
+#include <stdio.h>
+#include <direct.h> /* For chdir */
+
+
+/* Bits of the interface.
+ For paranoia's sake, I'm not using the same names as Microsoft.
+ I don't imagine copying a few names could be a credible copyright
+ case, but it seems safer to stick to only what is necessary for
+ the interface to work. */
+typedef long SCC_return;
+#define SCC_return_success 0
+#define SCC_return_unknown_project -2
+#define SCC_return_not_supported -14
+#define SCC_return_non_specific_error -15
+enum SCC_command
+{
+ SCC_command_get,
+ SCC_command_checkout,
+ SCC_command_checkin,
+ SCC_command_uncheckout,
+ SCC_command_add,
+ SCC_command_remove,
+ SCC_command_diff,
+ SCC_command_history,
+ SCC_command_rename,
+ SCC_command_properties,
+ SCC_command_options
+};
+
+/* Outproc codes, for second argument to outproc. */
+#define SCC_outproc_info 1
+#define SCC_outproc_warning 2
+#define SCC_outproc_error 3
+typedef long (*SCC_outproc) (char *, long);
+
+typedef BOOL (*SCC_popul_proc) (LPVOID callerdat, BOOL add_keep,
+ LONG status, LPCSTR file);
+
+/* Maximum sizes of various strings. These are arbitrary limits
+ which are imposed by the SCC. */
+/* Name argument to SccInitialize. */
+#define SCC_max_name 31
+/* Path argument to SccInitialize. */
+#define SCC_max_init_path 31
+/* Various paths many places in the interface. */
+#include <stdlib.h>
+#define SCC_max_path _MAX_PATH
+
+/* Bits to set in the caps used by SccInitialize. */
+#define SCC_cap_GetProjPath 0x200L
+#define SCC_cap_AddFromScc 0x400L
+#define SCC_cap_want_outproc 0x8000L
+
+/* Flags for SccGet. */
+#define SCC_RECURSE 2L
+/* This means to get all the files in a directory. */
+#define SCC_DIR 1L
+
+
+/* We get to put whatever we want here, and the caller will pass it
+ to us, so we don't need any global variables. */
+struct context {
+ FILE *debuglog;
+ /* Value of the CVSROOT we are currently working with (that is, the
+ "open project" in SCC terminology), malloc'd, or NULL if there is
+ no project currently open. */
+ char *root;
+ /* Local directory (working directory in CVS parlance). */
+ char *local;
+ SCC_outproc outproc;
+};
+
+#include <windows.h>
+
+/* Report a malloc error and return the SCC_return_* value which the
+ caller should return to the IDE. Probably this should be getting
+ the window argument too, but for the moment we don't need it.
+ Note that we only use this for errors which occur after the
+ context->outproc is set up. */
+SCC_return
+malloc_error (struct context *context)
+{
+ (*context->outproc) ("Out of memory\n", SCC_outproc_error);
+ return SCC_return_non_specific_error;
+}
+
+/* Return the version of the SCC spec, major version in the high word,
+ minor version in the low word. */
+LONG
+SccGetVersion ()
+{
+ /* We implement version 1.1 of the spec. */
+ return 0x10001;
+}
+
+SCC_return
+SccInitialize (void **contextp, HWND window, LPSTR caller, LPSTR name,
+ LPLONG caps, LPSTR path, LPDWORD co_comment_len,
+ LPDWORD comment_len)
+{
+ struct context *context;
+ FILE *fp;
+ fp = fopen ("d:\\debug.scc", "w");
+ if (fp == NULL)
+ /* Do what? Return some error value? */
+ abort ();
+ context = malloc (sizeof (struct context));
+ if (context == NULL)
+ {
+ fprintf (fp, "Out of memory\n");
+ fclose (fp);
+ /* Do what? Return some error? */
+ abort ();
+ }
+ context->debuglog = fp;
+ context->root = NULL;
+ *contextp = context;
+ fprintf (fp, "Made it into SccInitialize!\n");
+ *caps = (SCC_cap_GetProjPath
+ | SCC_cap_AddFromScc
+ | SCC_cap_want_outproc);
+
+ /* I think maybe this should have some more CVS-like
+ name, like "CVS Root", if we decide that is what
+ a SCC "project" is. */
+ strncpy (path, "CVS Project:", SCC_max_init_path);
+ fprintf (fp, "Caller name is %s\n", caller);
+ strncpy (name, "CVS", SCC_max_name);
+ /* CVS has no limit on comment length. But I suppose
+ we need to return a value which is small enough for
+ a caller to allocate a buffer this big. Not that I
+ would write a caller that way, but..... */
+ *co_comment_len = 8192;
+ *comment_len = 8192;
+ fflush (fp);
+ return SCC_return_success;
+}
+
+SCC_return
+SccUninitialize (void *context_arg)
+{
+ struct context *context = (struct context *)context_arg;
+ if (ferror (context->debuglog))
+ /* FIXME: return error value... */
+ if (fclose (context->debuglog) == EOF)
+ /* FIXME: return error value, I think. */
+ ;
+ free (context);
+ return SCC_return_success;
+}
+
+SCC_return
+SccOpenProject (void *context_arg, HWND window, LPSTR user,
+ LPSTR project, LPSTR local_proj, LPSTR aux_proj,
+ LPSTR comment, SCC_outproc outproc, LONG flags)
+{
+ struct context *context = (struct context *)context_arg;
+
+ /* This can happen if the IDE opens a project which is not under
+ CVS control. I'm not sure whether checking for aux_proj
+ being "" is the right way to detect this case, but it seems
+ it should work because I think that the source code control
+ system is what has control over the contents of aux_proj. */
+ if (aux_proj[0] == '\0')
+ return SCC_return_unknown_project;
+
+ context->root = malloc (strlen (aux_proj) + 5);
+ if (context->root == NULL)
+ return SCC_return_non_specific_error;
+ strcpy (context->root, aux_proj);
+ /* Since we don't yet support creating projects, we don't
+ do anything with flags. */
+
+ if (outproc == 0)
+ {
+ /* This supposedly can happen if the IDE chooses not to implement
+ the outproc feature. */
+ fprintf (context->debuglog, "Uh oh. outproc is a null pointer\n");
+ context->root = NULL;
+ fflush (context->debuglog);
+ return SCC_return_non_specific_error;
+ }
+ context->outproc = outproc;
+
+ fprintf (context->debuglog, "SccOpenProject (aux_proj=%s)\n", aux_proj);
+
+ context->local = malloc (strlen (local_proj) + 5);
+ if (context->local == NULL)
+ return malloc_error (context);
+ strcpy (context->local, local_proj);
+
+ fflush (context->debuglog);
+ return SCC_return_success;
+}
+
+SCC_return
+SccCloseProject (void *context_arg)
+{
+ struct context *context = (struct context *)context_arg;
+ fprintf (context->debuglog, "SccCloseProject\n");
+ fflush (context->debuglog);
+ if (context->root != NULL)
+ free (context->root);
+ context->root = NULL;
+ return SCC_return_success;
+}
+
+/* cvs get. */
+SCC_return
+SccGet (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names, LONG options, void *prov_options)
+{
+ struct context *context = (struct context *)context_arg;
+ int i;
+ char *fname;
+
+ fprintf (context->debuglog, "SccGet: %d; files:", num_files);
+#if 1
+ for (i = 0; i < num_files; ++i)
+ {
+ fprintf (context->debuglog, "%s ", file_names[i]);
+ }
+#endif
+ fprintf (context->debuglog, "\n");
+ if (options & SCC_DIR)
+ fprintf (context->debuglog, " Get all\n");
+ /* Should be using this flag to set -R vs. -l. */
+ if (options & SCC_RECURSE)
+ fprintf (context->debuglog, " recurse\n");
+
+ for (i = 0; i < num_files; ++i)
+ {
+ FILE *fp;
+
+ /* As with all file names passed to us by the SCC, these
+ file names are absolute pathnames. I think they will
+ tend to be paths within context->local, although I
+ don't know whether there are any exceptions to that. */
+ fname = file_names[i];
+ fprintf (context->debuglog, "%s ", fname);
+#if 0
+ fp = fopen (fname, "w");
+#endif
+ }
+ fprintf (context->debuglog, "\nExiting SccGet\n");
+ fflush (context->debuglog);
+ return SCC_return_success;
+}
+
+/* cvs edit. */
+SCC_return
+SccCheckout (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names, LPSTR comment, LONG options,
+ void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs ci. */
+SCC_return
+SccCheckin (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names, LPSTR comment, LONG options,
+ void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs unedit. */
+SCC_return
+SccUncheckout (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names, LONG options, void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs add + cvs ci, more or less, I think (but see also
+ the "keep checked out" flag in options). */
+SCC_return
+SccAdd (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names, LPSTR comment, LONG *options,
+ void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs rm -f + cvs ci, I think. Should barf if SCC_REMOVE_KEEP
+ (or maybe just put the file there, as if the user had removed
+ it and then done a "copy <saved-file> <filename>". */
+SCC_return
+SccRemove (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names, LPSTR comment, LONG options,
+ void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* mv, cvs add, cvs rm, and cvs ci, I think. */
+SCC_return
+SccRename (void *context_arg, HWND window, LPSTR old_name,
+ LPSTR new_name)
+{
+ return SCC_return_not_supported;
+}
+
+/* If "contents flag", then implement this ourself. For no
+ args or checksum (which we fall back to full compare) basically a
+ call to No_Diff or ? in the client case. For timestamp, just a
+ Classify_File. Now, if contents not set, then want to do a
+ cvs diff, and preferably start up WinDiff or something (to be
+ determined, for now perhaps could just shove in the text). */
+SCC_return
+SccDiff (void *context_arg, HWND window, LPSTR file_name,
+ LONG options, void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs log, I presume. If we want to get fancier we could bring
+ up a screen more analogous to the tkCVS log window, let the user
+ do "cvs update -r", etc. */
+SCC_return
+SccHistory (void *context_arg, HWND window, LONG num_files,
+ LPSTR file_names, LONG options, void *prov_options)
+{
+ return SCC_return_not_supported;
+}
+
+/* cvs status, presumably. */
+SCC_return
+SccProperties (void *context_arg, HWND window, LPSTR file_name)
+{
+ return SCC_return_not_supported;
+}
+
+/* Not sure what this should do. The most obvious thing is some
+ kind of front-end to "cvs admin" but I'm not actually sure that
+ is the most useful thing. */
+SCC_return
+SccRunScc (void *context_arg, HWND window, LONG num_files,
+ LPSTR *file_names)
+{
+ return SCC_return_not_supported;
+}
+
+/* Lots of things that we could do here. Options to get/update
+ such as -r -D -k etc. just for starters. */
+SCC_return
+SccGetCommandOptions (void *context_arg, HWND window,
+ enum SCC_command command,
+ void **prov_optionsp)
+{
+ return SCC_return_not_supported;
+}
+
+/* Not existing CVS functionality, I don't think.
+ Need to be able to tell user about what files
+ are out there without actually getting them. */
+SCC_return
+SccPopulateList (void *context_arg, enum SCC_command command,
+ LONG num_files,
+ LPSTR *file_names, SCC_popul_proc populate,
+ void *callerdat, LONG options)
+{
+ return SCC_return_success;
+}
+
+/* cvs status, sort of. */
+SCC_return
+SccQueryInfo (void *context_arg, LONG num_files, LPSTR *file_names,
+ LPLONG status)
+{
+ return SCC_return_not_supported;
+}
+
+SCC_return
+SccGetEvents (void *context_arg, LPSTR file_name, LPLONG status,
+ LPLONG events_remaining)
+{
+ /* They say this is supposed to only return cached status
+ information, not go to disk or anything. OK, although I
+ haven't really figured out what calls would cause us to
+ cache status without returning it then. */
+ return SCC_return_success;
+}
+
+/* This is where the user gives us the CVSROOT. */
+SCC_return
+SccGetProjPath (void *context_arg, HWND window, LPSTR user,
+ LPSTR proj_name, LPSTR local_proj, LPSTR aux_proj,
+ BOOL allow_change, BOOL *new)
+{
+ /* For now we just hardcode the CVSROOT. In the future we will
+ of course prompt the user for it (simple implementation would
+ have them supply a string; potentially better implementation
+ would have menus or something for access methods and so on,
+ although it might also have a way of bypassing that in case
+ CVS supports new features that the GUI code doesn't
+ understand). We probably will also at some point want a
+ "project" to encompass both a CVSROOT and a directory or
+ module name within that CVSROOT, but we don't try to handle
+ that yet either. We also will want to be able to use "user"
+ instead of having the username encoded in the aux_proj or
+ proj_name, probably. */
+
+ struct context *context = (struct context *)context_arg;
+ fprintf (context->debuglog, "SccGetProjPath called\n");
+
+ /* At least for now we leave the proj_name alone, and just use
+ the aux_proj. */
+ strncpy (proj_name, "zwork", SCC_max_path);
+ strncpy (aux_proj, ":server:harvey:/home/kingdon/zwork/cvsroot",
+ SCC_max_path);
+ if (local_proj[0] == '\0' && allow_change)
+ strncpy (local_proj, "d:\\sccwork", SCC_max_path);
+ /* I don't think I saw anything in the spec about this,
+ but let's see if it helps. */
+ if (_chdir (local_proj) < 0)
+ fprintf (context->debuglog, "Error in chdir: %s", strerror (errno));
+
+ if (*new)
+ /* It is OK for us to prompt the user for creating a new
+ project. */
+ /* We will say that the user said to create a new one. */
+ *new = 1;
+
+ fflush (context->debuglog);
+ return SCC_return_success;
+}
+
+/* Pretty much similar to SccPopulateList. */
+SCC_return
+SccAddFromScc (void *context_arg, HWND window, LONG *files,
+ char ***file_names)
+{
+ struct context *context = (struct context *)context_arg;
+
+ /* For now we have hardcoded the notion that there are two files,
+ foo.c and bar.c. */
+#define NUM_FILES 2
+ if (files == NULL)
+ {
+ char **p;
+
+ /* This means to free the memory that is allocated for
+ file_names. */
+ for (p = *file_names; *p != NULL; ++p)
+ {
+ fprintf (context->debuglog, "Freeing %s\n", *p);
+ free (*p);
+ }
+ }
+ else
+ {
+ *file_names = malloc ((NUM_FILES + 1) * sizeof (char **));
+ if (*file_names == NULL)
+ return malloc_error (context);
+ (*file_names)[0] = malloc (80);
+ if ((*file_names)[0] == NULL)
+ return malloc_error (context);
+ strcpy ((*file_names)[0], "foo.c");
+ (*file_names)[1] = malloc (80);
+ if ((*file_names)[1] == NULL)
+ return malloc_error (context);
+ strcpy ((*file_names)[1], "bar.c");
+ (*file_names)[2] = NULL;
+ *files = 2;
+
+ /* Are we supposed to also Get the files? Or is the IDE
+ next going to call SccGet on each one? The spec doesn't
+ say explicitly. */
+ }
+ fprintf (context->debuglog, "Success in SccAddFromScc\n");
+ fflush (context->debuglog);
+ return SCC_return_success;
+}
+
+/* This changes several aspects of how we interact with the IDE. */
+SCC_return
+SccSetOption (void *context_arg, LONG option, LONG val)
+{
+ return SCC_return_success;
+}