diff options
Diffstat (limited to 'gnu/usr.bin/cvs/windows-NT/SCC/scc.c')
-rw-r--r-- | gnu/usr.bin/cvs/windows-NT/SCC/scc.c | 486 |
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; +} |