mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
650 lines
13 KiB
650 lines
13 KiB
/* srmep.c - extension for Z that interfaces with SYMREF
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#include <lm.h>
|
|
|
|
#include "ext.h"
|
|
|
|
#include "symmsg.h"
|
|
|
|
#define strpre(s1,s2) (_strnicmp ((s1), (s2), strlen (s1)) == 0)
|
|
|
|
void fnErr (PSZ psz, int erc);
|
|
flagType fnFileSave (EVTargs far *pevt);
|
|
|
|
#define SKIPSPACE(p) while (*(p) == ' ' || *(p) == '\t') (p)++
|
|
#define FINDSPACE(p) while (*(p) != 0 && *(p) != ' ' && *(p) != '\t') (p)++
|
|
|
|
/* name processing for symref
|
|
*
|
|
* These rely on the convention that symref/srmep is called upon to index
|
|
* only local files or UNC files. The local files stored on drive X must
|
|
* be globally available through a share ROOTX.
|
|
*
|
|
* The usage scenarios are:
|
|
*
|
|
* user wishes to index remote files
|
|
* remote must be running server
|
|
* daemon must be running wksta/server
|
|
* local names == global names == UNC names
|
|
*
|
|
* user wishes to index local files
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
* The name cases we have to handle are:
|
|
*
|
|
* Local name is X:\path
|
|
*
|
|
* if no local server then
|
|
* global name is X:\path
|
|
* else
|
|
* global name is \\wksta\rootX\path
|
|
*
|
|
* Global name is \\mach\share\path
|
|
* if mach == wksta and share is rootX
|
|
* local name is X:\path
|
|
* else
|
|
* local name is \\mach\share\path
|
|
*
|
|
* From the daemon standpoint, if a global name has UNC in it, then
|
|
* the daemon must be running the wksta and the remote system must be
|
|
* running a server.
|
|
*
|
|
* So the interesting cases are:
|
|
*
|
|
* daemon is shared by several people
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
BOOL fServerStarted = FALSE; // TRUE iff local server is started
|
|
char szServer[MAX_PATH]; // text of server machine name
|
|
char szWksta[MAX_PATH]; // text of local workstation name
|
|
|
|
/* InitName - initialize name translation
|
|
*
|
|
* pszServer machine name for symref daemon
|
|
*/
|
|
void InitName (IN PSZ pszServer)
|
|
{
|
|
PSERVICE_INFO_0 psi;
|
|
PWKSTA_INFO_100 pwi;
|
|
|
|
//
|
|
// Set up daemon server name
|
|
//
|
|
|
|
strcpy (szServer, pszServer);
|
|
|
|
//
|
|
// See if our own server is started
|
|
//
|
|
|
|
if (NetServiceGetInfo (NULL, "SERVER", 0, (LPBYTE *) &psi) == 0) {
|
|
fServerStarted = TRUE;
|
|
NetApiBufferFree (psi);
|
|
}
|
|
|
|
|
|
//
|
|
// Set up workstation name
|
|
//
|
|
|
|
NetWkstaGetInfo (NULL, 100, (LPBYTE *) &pwi);
|
|
|
|
strcpy (szWksta, pwi->wki100_computername);
|
|
|
|
NetApiBufferFree (pwi);
|
|
}
|
|
|
|
|
|
/* GetLocalName - get local version of symref-global name
|
|
*
|
|
* pszGlobal canonical global name for file
|
|
* pszLocal local name for file if possible, else global name
|
|
*/
|
|
|
|
void GetLocalName (IN PSZ pszGlobal, OUT PSZ pszLocal)
|
|
{
|
|
char *psz;
|
|
|
|
psz = pszGlobal;
|
|
|
|
//
|
|
// if the file name is UNC
|
|
//
|
|
if (strpre ("\\\\", psz)) {
|
|
|
|
psz += 2;
|
|
|
|
//
|
|
// if the wksta is the same as the UNC machine
|
|
//
|
|
|
|
if (strpre (szWksta, psz)) {
|
|
|
|
psz += strlen (szWksta);
|
|
|
|
//
|
|
// if the share is ROOTX
|
|
//
|
|
|
|
if (strpre ("\\ROOT", psz) && isalpha (psz[5]) && psz[6] == '\\') {
|
|
|
|
//
|
|
// convert \\WKSTA\ROOTX\PATH into X:\PATH
|
|
//
|
|
|
|
sprintf (pszLocal, "%c:%s", psz[5], psz + 6);
|
|
return;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// the name is not local to the current machine through our conventions
|
|
// just use it as-is
|
|
//
|
|
|
|
strcpy (pszLocal, pszGlobal);
|
|
}
|
|
|
|
|
|
/* GetGlobalName - get global version
|
|
*
|
|
* pszLocal canonical local name for file
|
|
* pszGlobal canonical global name for file if possible
|
|
*/
|
|
|
|
void GetGlobalName (IN PSZ pszLocal, OUT PSZ pszGlobal)
|
|
{
|
|
//
|
|
// if the wksta is not the same as server
|
|
//
|
|
|
|
if (_strcmpi (szWksta, szServer) &&
|
|
|
|
//
|
|
// if local server is started
|
|
//
|
|
|
|
fServerStarted &&
|
|
|
|
//
|
|
// if the name is local
|
|
//
|
|
|
|
pszLocal[1] == ':')
|
|
|
|
//
|
|
// convert X:\PATH into \\WKSTA\ROOTX\PATH
|
|
//
|
|
|
|
sprintf (pszGlobal, "\\\\%s\\root%c%s", szWksta, pszLocal[0], pszLocal + 2);
|
|
|
|
else
|
|
|
|
strcpy (pszGlobal, pszLocal);
|
|
}
|
|
|
|
|
|
char szServerPipe[MAX_PATH];
|
|
char szScope[MAX_PATH];
|
|
|
|
/* OpenDatabase - open pipe to database
|
|
*
|
|
* returns HANDLE to database pipe
|
|
*/
|
|
HANDLE OpenDatabase (PSZ pszServerPipe)
|
|
{
|
|
HANDLE h;
|
|
|
|
while (TRUE) {
|
|
h = CreateFile (pszServerPipe,
|
|
(GENERIC_READ | GENERIC_WRITE),
|
|
(FILE_SHARE_READ | FILE_SHARE_WRITE),
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (h != (HANDLE)-1)
|
|
break;
|
|
|
|
if (GetLastError () != ERROR_PIPE_BUSY) {
|
|
fnErr ("OpenDatabase returned ", GetLastError ());
|
|
break;
|
|
}
|
|
if (!Confirm ("Daemon is busy, wait (y/n)?", NULL))
|
|
break;
|
|
WaitNamedPipe (pszServerPipe, NMPWAIT_USE_DEFAULT_WAIT);
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
/* SendSz - send an asciiz string via a named pipe
|
|
*
|
|
* hPipe handle to server
|
|
* pszMsg message to send
|
|
*/
|
|
void SendSz (HANDLE hPipe, PSZ pszMsg)
|
|
{
|
|
int cbWritten;
|
|
|
|
if (!WriteFile (hPipe, pszMsg, strlen (pszMsg) + 1, &cbWritten, NULL))
|
|
fnErr ("SendSz returned", GetLastError ());
|
|
}
|
|
|
|
/* ReceiveSz - receive an asciiz string via named pipe
|
|
*
|
|
* hPipe handle to server
|
|
* pszMsg place to store message
|
|
*/
|
|
flagType ReceiveSz (HANDLE hPipe, PSZ pszMsg)
|
|
{
|
|
int cbRead;
|
|
|
|
if (!ReadFile (hPipe, pszMsg, CBMSG, &cbRead, NULL)) {
|
|
fnErr ("ReceiveSz returned", GetLastError ());
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* CloseDatabase - close database handle
|
|
*
|
|
* hPipe handle to database
|
|
*/
|
|
void CloseDatabase (HANDLE hPipe)
|
|
{
|
|
if (!CloseHandle (hPipe))
|
|
fnErr ("CloseDatabase returned", GetLastError ());
|
|
}
|
|
|
|
|
|
BOOL fInited = FALSE;
|
|
|
|
void LoadIni (BOOL fForce)
|
|
{
|
|
char szServer[MAX_PATH];
|
|
|
|
|
|
if (fForce || !fInited) {
|
|
|
|
//
|
|
// Get the server and scope parameters from the shared place
|
|
//
|
|
|
|
GetProfileString (PSZAPPNAME, PSZSCOPE, "", szScope, MAX_PATH);
|
|
GetProfileString (PSZAPPNAME, PSZSERVER, ".", szServer, MAX_PATH);
|
|
sprintf (szServerPipe, "\\\\%s\\pipe\\symref-daemon", szServer);
|
|
|
|
InitName (szServer);
|
|
|
|
fInited = TRUE;
|
|
}
|
|
}
|
|
|
|
struct smsgType {
|
|
struct smsgType *psmsgNext;
|
|
char *psz;
|
|
};
|
|
|
|
typedef struct smsgType SMSG;
|
|
|
|
SMSG *psmsgHead = NULL; /* head of message list */
|
|
SMSG *psmsgCur = NULL; /* current message being displayed */
|
|
|
|
char szSym[CBMSG]; // symbol of last search
|
|
|
|
int cchString = 0; /* length of search string */
|
|
char szStart[CBMSG];
|
|
COL colStart;
|
|
LINE linStart;
|
|
|
|
/* EVTFileSave is the event we use to look for file saves. When any save
|
|
* occurs, we send a re-index request off to the database.
|
|
*/
|
|
EVT EVTFileSave =
|
|
{ EVT_FILEWRITEEND, /* finished writing file */
|
|
fnFileSave, /* routine to handle event */
|
|
NULL, /* empty forward link */
|
|
0 /* no specific focus required */
|
|
};
|
|
|
|
/* FlushMsg - free up all pending messages
|
|
*/
|
|
void FlushMsg ()
|
|
{
|
|
while (psmsgHead != NULL) {
|
|
SMSG *psmsgTmp = psmsgHead->psmsgNext;
|
|
|
|
Free (psmsgHead->psz);
|
|
Free (psmsgHead);
|
|
psmsgHead = psmsgTmp;
|
|
}
|
|
psmsgCur = NULL;
|
|
}
|
|
|
|
/* ViewNext - display next message
|
|
*
|
|
* Advance psmsgCur to next message, displaying end and recycling.
|
|
*/
|
|
void ViewNext ()
|
|
{
|
|
char sz[CBMSG];
|
|
char szFile[MAX_PATH];
|
|
|
|
if (psmsgCur == NULL)
|
|
psmsgCur = psmsgHead;
|
|
else
|
|
psmsgCur = psmsgCur->psmsgNext;
|
|
|
|
if (psmsgCur == NULL) {
|
|
fChangeFile (FALSE, szStart);
|
|
MoveCur (colStart, linStart);
|
|
DoMessage ("No more references");
|
|
}
|
|
else
|
|
if (!strcmp (psmsgCur->psz, "Symbol not found")) {
|
|
sprintf (sz, "Symbol \"%s\" not found", szSym);
|
|
DoMessage (sz);
|
|
}
|
|
else {
|
|
PFILE pfile;
|
|
char *pszl, *pszc, *pszFile, *p;
|
|
LINE l;
|
|
COL c;
|
|
|
|
strcpy (sz, psmsgCur->psz);
|
|
|
|
//
|
|
// skip to beginning of file name
|
|
//
|
|
|
|
pszFile = sz;
|
|
SKIPSPACE (pszFile);
|
|
|
|
//
|
|
// find end of file name
|
|
//
|
|
|
|
pszl = pszFile;
|
|
|
|
FINDSPACE(pszl);
|
|
|
|
if (*pszl != '\0')
|
|
*pszl++ = '\0';
|
|
|
|
//
|
|
// find beginning of line number
|
|
//
|
|
|
|
SKIPSPACE (pszl);
|
|
|
|
//
|
|
// find end of line number
|
|
//
|
|
|
|
pszc = pszl;
|
|
|
|
FINDSPACE (pszc);
|
|
|
|
if (*pszc != '\0')
|
|
*pszc++ = '\0';
|
|
|
|
//
|
|
// find beginning of column
|
|
//
|
|
|
|
SKIPSPACE (pszc);
|
|
|
|
//
|
|
// find end of column
|
|
//
|
|
|
|
p = pszc;
|
|
|
|
FINDSPACE (p);
|
|
|
|
*p = 0;
|
|
|
|
//
|
|
// Make the file name local if possible
|
|
//
|
|
|
|
GetLocalName (pszFile, szFile);
|
|
|
|
if (fChangeFile (FALSE, szFile)) {
|
|
c = atoi (pszc);
|
|
l = atoi (pszl);
|
|
|
|
MoveCur (c-1, l-1);
|
|
if (cchString != 0) {
|
|
rn rn;
|
|
|
|
GetEditorObject (RQ_FILE_HANDLE, 0, &pfile);
|
|
rn.flFirst.lin = rn.flLast.lin = l - 1;
|
|
rn.flFirst.col = c-1;
|
|
rn.flLast.col = c - 1 + cchString - 1;
|
|
SetHiLite (pfile, rn, HGCOLOR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* fnErr - display an error message and error code
|
|
*
|
|
* psz prefix string for error
|
|
* erc error code
|
|
*/
|
|
void fnErr (PSZ psz, int erc)
|
|
{
|
|
char sz[CBMSG];
|
|
|
|
sprintf (sz, "%s %d", psz, erc);
|
|
DoMessage (sz);
|
|
}
|
|
|
|
/* fnFileSave - send an index-file request to server
|
|
*
|
|
* psz name of file to be indexed. This name is already rootpath'd by
|
|
* the editor.
|
|
*/
|
|
|
|
flagType fnFileSave (EVTargs far *pevt)
|
|
{
|
|
char sz[CBMSG];
|
|
char szFile[MAX_PATH];
|
|
HANDLE h;
|
|
|
|
GetGlobalName (pevt->arg.pfn, szFile);
|
|
|
|
sprintf (sz, "%s %s", CMD_MODIFY_FILE, szFile);
|
|
|
|
h = OpenDatabase (szServerPipe);
|
|
|
|
if (h != (HANDLE)-1) {
|
|
SendSz (h, sz);
|
|
CloseDatabase (h);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void SRSendSymLocate (PSZ psz)
|
|
{
|
|
char sz[CBMSG];
|
|
SMSG *psmsgTail, *psmsg;
|
|
HANDLE h;
|
|
|
|
if (strlen (szScope) != 0)
|
|
sprintf (sz, "Looking for %s under %s", psz, szScope);
|
|
else
|
|
sprintf (sz, "Looking for %s", psz);
|
|
|
|
DoMessage (sz);
|
|
|
|
sprintf (sz, "%s %s -a %s", CMD_LOCATE, psz, szScope);
|
|
|
|
h = OpenDatabase (szServerPipe);
|
|
|
|
SendSz (h, sz);
|
|
|
|
psmsgTail = NULL;
|
|
|
|
while (TRUE) {
|
|
if (!ReceiveSz (h, sz))
|
|
break;
|
|
else
|
|
if (!strcmp (RSP_EOD, sz))
|
|
break;
|
|
else {
|
|
psmsg = (SMSG *) Malloc (sizeof (SMSG) * 16);
|
|
psmsg->psz = Malloc ((strlen (sz) + 1) * 16);
|
|
strcpy (psmsg->psz, sz);
|
|
psmsg->psmsgNext = NULL;
|
|
if (psmsgTail == NULL)
|
|
psmsgTail = psmsgHead = psmsg;
|
|
else {
|
|
psmsgTail->psmsgNext = psmsg;
|
|
psmsgTail = psmsg;
|
|
}
|
|
}
|
|
}
|
|
CloseDatabase (h);
|
|
}
|
|
|
|
|
|
/* SRLocate - send a locate-symbol message to the server
|
|
*
|
|
* Create a mailslot, send request to server, display all responses until
|
|
* !EOM is seen.
|
|
*
|
|
* NOARG - advance to next symbol
|
|
* NULLARG - <arg> pick off symbol from text
|
|
* <arg><meta> refresh scope and server
|
|
* <arg><arg> force index of current file
|
|
* TEXTARG - <arg> text looks up symbol
|
|
* <arg><arg> text sends command
|
|
*/
|
|
flagType SRLocate (unsigned int argData, ARG far *pArg, flagType fMeta)
|
|
{
|
|
char sz[CBMSG], *p, *p1;
|
|
PFILE pfile;
|
|
|
|
switch (pArg->argType) {
|
|
case NOARG: /* advance to next symbol */
|
|
if (!fMeta)
|
|
ViewNext ();
|
|
else
|
|
BadArg ();
|
|
break;
|
|
|
|
case NULLARG: /* single arg, parse off symbol from text */
|
|
/* double arg, force index of current file */;
|
|
if (pArg->arg.nullarg.cArg == 1)
|
|
if (fMeta)
|
|
LoadIni (TRUE);
|
|
else {
|
|
GetEditorObject (RQ_FILE_HANDLE, 0, &pfile);
|
|
GetLine (pArg->arg.nullarg.y, sz, pfile);
|
|
if (strlen (sz) <= (unsigned int) pArg->arg.nullarg.x)
|
|
BadArg ();
|
|
else {
|
|
p = & sz[pArg->arg.nullarg.x];
|
|
if (!iscsymf (*p))
|
|
BadArg ();
|
|
else {
|
|
p1 = p + 1;
|
|
while (iscsym (*p1))
|
|
p1++;
|
|
*p1 = 0;
|
|
FlushMsg ();
|
|
GetEditorObject (RQ_FILE_NAME, 0, szStart);
|
|
GetTextCursor (&colStart, &linStart);
|
|
strcpy (szSym, p);
|
|
SRSendSymLocate (szSym);
|
|
cchString = strlen (p);
|
|
ViewNext ();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
BadArg ();
|
|
|
|
break;
|
|
case TEXTARG: /* single arg, look for symbol */
|
|
/* double arg, send command to daemon */
|
|
if (pArg->arg.textarg.cArg == 1 && !fMeta) {
|
|
FlushMsg ();
|
|
GetEditorObject (RQ_FILE_NAME, 0, szStart);
|
|
GetTextCursor (&colStart, &linStart);
|
|
strcpy (szSym, pArg->arg.textarg.pText);
|
|
SRSendSymLocate (szSym);
|
|
cchString = strlen (pArg->arg.textarg.pText);
|
|
ViewNext ();
|
|
}
|
|
else
|
|
if (pArg->arg.textarg.cArg == 2 && !fMeta) {
|
|
HANDLE h;
|
|
|
|
h = OpenDatabase (szServerPipe);
|
|
if (h != (HANDLE)-1) {
|
|
SendSz (h, pArg->arg.textarg.pText);
|
|
CloseDatabase (h);
|
|
}
|
|
}
|
|
else
|
|
BadArg ();
|
|
|
|
break;
|
|
default:
|
|
BadArg ();
|
|
}
|
|
return TRUE;
|
|
|
|
argData;
|
|
|
|
}
|
|
|
|
|
|
void WhenLoaded (void)
|
|
{
|
|
RegisterEvent (&EVTFileSave);
|
|
SetKey ("sr-locate", "alt+s");
|
|
|
|
LoadIni (FALSE);
|
|
|
|
}
|
|
|
|
struct swiDesc swiTable[] = {
|
|
{0, 0, 0}
|
|
};
|
|
|
|
struct cmdDesc cmdTable[] = {
|
|
{ "sr-locate", SRLocate, 0, NOARG | NULLARG | TEXTARG | BOXSTR },
|
|
{0, 0, 0}
|
|
};
|