gecko-dev/network/module/nsRelatedLinks.cpp
1998-07-16 18:22:23 +00:00

811 lines
21 KiB
C++

#include "nsIRelatedLinks.h"
#include "net.h"
#include "merrors.h"
#include "plstr.h"
#include "proto.h"
typedef uint8 RL_LOAD_STATUS;
char* relatedLinksProvider = NULL;
#define RL_STATUS_WAITING_TO_LOAD 1
#define RL_STATUS_LOADING 2
#define RL_STATUS_ABORTED 3
#define RL_STATUS_COMPLETED 4
#define RL_STATUS_NOT_AVAILABLE 5
#define RL_MAX_URL 300
#define RL_LINE_SIZE 1024
extern int XP_RL_FETCHING;
extern int XP_RL_UNAVAILABLE;
#define validRLItem(item) ((item->type == RL_CONTAINER) || (item->type == RL_SEPARATOR) || (item->type == RL_LINK) || (item->type == RL_LINK_NEW_WINDOW))
int32 gInitialDiff = 4;
int32 gMaxDiff = 4;
PRBool enableRelatedLinksp = 1;
struct _RL_Window {
char* url;
char* rlurl;
RL_LOAD_STATUS status;
uint8 parseStatus;
uint8 type;
char* holdOver;
char* line;
struct _RL_Item* items;
uint8 diff;
uint8 count;
void* fe_data;
struct _RL_Item* stack[3];
uint8 depth;
RLCallBackProc callBack;
URL_Struct *currentlyLoading;
struct _RL_Item* prevItems;
PRBool demoUrlp;
};
struct _RL_Item {
RL_ItemType type;
char* name;
char* convertedName;
char* url;
char* rurl;
struct _RL_Item* child;
struct _RL_Item* next;
};
typedef struct _RL_Get {
RL_Window win;
URL_Struct *url;
} *RL_Get;
typedef struct _RL_SpecialItems {
RL_Item loading;
RL_Item noData;
RL_Item disabled;
} *RL_SpecialItems;
typedef struct _RL_EquivBucket {
char* jumpPoint;
char* seenAt;
struct _RL_EquivBucket* next;
} *RL_EquivBucket;
RL_SpecialItems gRLSpecial = 0;
void RL_DestroyRLWindow(RL_Window win);
void RL_SetRLWindowURL(RL_Window win, char* url);
RL_Item RL_WindowItems (RL_Window win);
RL_Item RL_NextItem(RL_Item item);
RL_Item RL_ItemChild(RL_Item item);
uint8 RL_ItemCount(RL_Window win);
RL_ItemType RL_GetItemType(RL_Item item);
char* RL_ItemName(RL_Item item);
char* RL_ItemUrl(RL_Item item);
typedef void (*RLCallBackProc)(void* pdata, RL_Window win);
RL_Window RL_MakeRLWindowWithCallback(RLCallBackProc callBack, void* fedata);
void freeMem(void* x);
RL_Window RL_MakeRLWindow();
void RL_DestroyRLWindow(RL_Window win);
void RL_EnableRelatedLinks();
void RL_DisableRelatedLinks();
void RL_SetRLWindowURL(RL_Window win, char* url);
void RL_AddItem (RL_Window win, char* url, char* name, uint8 type);
RL_Item RL_WindowItems (RL_Window win);
RL_Item RL_NextItem(RL_Item item);
RL_ItemType RL_GetItemType(RL_Item item);
char* RL_ItemName(RL_Item item);
char* RL_ItemUrl(RL_Item item);
void GetRL (RL_Window win);
void cleanRLTree(RL_Item item);
MWContext* GetRLContext(RL_Window win);
void rl_GetUrlExitFunc (URL_Struct *urls, int status, MWContext *cx) ;
void TryLoadRLFromCache(RL_Window win) ;
void parseNextRDFXMLBlob (RL_Window f, char* blob, int32 size) ;
void parseNextRDFToken (RL_Window f, char* token) ;
void extractAttributes (char* attr, char** attlist) ;
PRBool tokenEquals(char* token, char* string, PRBool endp);
char* getAttributeValue(char** attlist, char* elName);
PUBLIC NET_StreamClass* RL_Converter(FO_Present_Types format_out, void
*data_object, URL_Struct *URL_s, MWContext *window_id) ;
int rl_write(void *obj, const char *str, int32 len) ;
unsigned int rl_write_ready(void *obj) ;
void rl_abort(void *obj, int status) ;
void rl_complete (void *obj) ;
PRBool startsWith (char* pattern, char* uuid) ;
PRBool rlStartsWith (char* pattern, char* uuid) ;
int16 charSearch (char c, char* data) ;
/*char* copyString (char* source) ; */
void parseNextRLBlob (RL_Window f, char* blob, int32 len) ;
void parseNextAlexaLine (RL_Window f, char* line) ;
static PRBool findNextDomain(const char *inDomains, size_t *ioBegin,
size_t *outEnd);
static PRBool nextDomain (char* dom, size_t *n, size_t maxLength);
static PRBool validateDomain(const char *inDomains, size_t inBegin,
size_t inEnd);
class nsRelatedLinks: public nsIRelatedLinks {
public:
nsRelatedLinks() {
NS_INIT_REFCNT();
}
NS_DECL_ISUPPORTS
void DestroyRLWindow (RL_Window win) {
RL_DestroyRLWindow (win);
}
void SetRLWindowURL (RL_Window win, char* url) {
RL_SetRLWindowURL (win, url);
}
RL_Item WindowItems (RL_Window win) {
return RL_WindowItems (win);
}
RL_Item NextItem (RL_Item item) {
return RL_NextItem (item);
}
RL_Item ItemChild (RL_Item item) {
return RL_ItemChild (item);
}
uint8 ItemCount (RL_Window win) {
return RL_ItemCount (win);
}
RL_ItemType GetItemType (RL_Item item) {
return RL_GetItemType (item);
}
char* ItemName (RL_Item item) {
return RL_ItemName (item);
}
char* ItemUrl (RL_Item item) {
return RL_ItemUrl (item);
}
RL_Window MakeRLWindowWithCallback(RLCallBackProc callBack, void*fedata) {
return RL_MakeRLWindowWithCallback(callBack,fedata);
}
};
NS_IMPL_ADDREF(nsRelatedLinks)
NS_IMPL_RELEASE(nsRelatedLinks)
NS_DEFINE_IID(kIRelatedLinksIID, NS_IRELATEDLINKS_IID);
nsresult nsRelatedLinks::QueryInterface(const nsIID &aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
if (aIID.Equals(kISupportsIID)) {
*aInstancePtr = (void*) ((nsISupports *)this);
AddRef();
return NS_OK;
}
if (aIID.Equals(kIRelatedLinksIID)) {
*aInstancePtr = (void*) ((nsIRelatedLinks *)this);
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
extern "C" nsIRelatedLinks * NS_NewRelatedLinks(void) {
nsRelatedLinks * pIObject= new nsRelatedLinks;
if (pIObject) {
pIObject->AddRef();
return (nsIRelatedLinks*)pIObject;
}
return nsnull;
}
#define copyString(x) PL_strdup(x)
PRBool startsWith (char* pattern, char* uuid) {
short l1 = strlen(pattern);
short l2 = strlen(uuid);
if (l2 < l1) return PR_FALSE;
return (strncmp(pattern, uuid, l1) == 0) ? PR_TRUE : PR_FALSE;
}
PRBool rlStartsWith (char* pattern, char* uuid) {
short l1 = strlen(pattern);
short l2 = strlen(uuid);
short index;
if (l2 < l1) return PR_FALSE;
for (index = 0; index < l1; index++) {
if ((index == l1-1) && (pattern[index] == '*')) return PR_TRUE;
if (pattern[index] != uuid[index]) return PR_FALSE;
}
return PR_TRUE;
}
int16 charSearch (char c, char* data) {
int32 l1 = strlen(data);
int16 index;
for (index = 0; index < l1; index++) {
if (data[index] == c) return index;
}
return -1;
}
char* getMem(size_t x) {
char* ans = (char *)calloc(1,(x));
if (ans != NULL) {
memset(ans, '\0', x);
} else {
ans = 0;
}
return ans;
}
RL_Item makeRLItem (char* name, char* url) {
RL_Item item = (RL_Item) getMem(sizeof(struct _RL_Item));
if (item) {
item->name = name;
item->url = url;
item->type = RL_LINK;
return item;
} else return NULL;
}
PRBool specialItemp (RL_Item item) {
return ((item == gRLSpecial->loading) ||
(item == gRLSpecial->noData) ||
(item == gRLSpecial->disabled)) ? PR_TRUE : PR_FALSE;
}
void readRLPrefs () {
int32 autoload = -1;
}
extern "C" void RL_Init () {
gRLSpecial = (RL_SpecialItems)getMem(sizeof(struct _RL_SpecialItems));
if (gRLSpecial == NULL) {
enableRelatedLinksp = 0;
}
gRLSpecial->loading = makeRLItem("Fetching ...", NULL);
gRLSpecial->noData = makeRLItem("No data available", NULL);
gRLSpecial->disabled = makeRLItem("Related Links Disabled", NULL);
if (gRLSpecial->loading == NULL || gRLSpecial->noData == NULL ||
gRLSpecial->disabled == NULL) {
enableRelatedLinksp = 0;
freeMem(gRLSpecial->loading);
freeMem(gRLSpecial->noData);
freeMem(gRLSpecial->disabled);
}
NET_RegisterContentTypeConverter( "*", FO_CACHE_AND_RDF, NULL,
NET_CacheConverter);
NET_RegisterContentTypeConverter( "*", FO_RDF, NULL, RL_Converter);
enableRelatedLinksp = 1;
gInitialDiff = gMaxDiff = 4;
relatedLinksProvider = copyString("http://www-rl.netscape.com/wtgn?");
}
void freeMem(void* x) {
if (x != NULL) free(x);
}
static RL_Window gRLWindow = 0;
RL_Window RL_MakeRLWindowWithCallback (RLCallBackProc callBack, void*
fe_data) {
RL_Window win = RL_MakeRLWindow();
if (win == NULL) return NULL;
win->callBack = callBack;
win->fe_data = fe_data;
gRLWindow = win;
return win;
}
RL_Window RL_MakeRLWindow() {
RL_Window ans = (RL_Window) getMem(sizeof(struct _RL_Window));
if (ans == NULL) return NULL;
ans->line = getMem(RL_LINE_SIZE);
if (ans->line == NULL) {
freeMem(ans);
return NULL;
}
ans->holdOver = getMem(RL_LINE_SIZE);
if (ans->holdOver == NULL) {
freeMem(ans->line);
freeMem(ans);
return NULL;
}
ans->rlurl = getMem(RL_MAX_URL);
if (ans->rlurl == NULL) {
freeMem(ans->line);
freeMem(ans->rlurl);
freeMem(ans);
return NULL;
}
ans->diff = gInitialDiff;
return ans;
}
void RL_DestroyRLWindow(RL_Window win) {
if (!win) return;
cleanRLTree(win->prevItems);
cleanRLTree(win->items);
if (win->currentlyLoading) {
win->currentlyLoading->fe_data = NULL; /* |fe_data| is really |win|
and will be */
/* disposed of below */
NET_InterruptStream (win->currentlyLoading);
}
freeMem(win->line);
freeMem(win->holdOver);
freeMem(win);
}
PRBool implicitDomainURL (char* url) {
uint16 n = 7;
uint16 size = strlen(url);
while (n < size) {
if (url[n] == '/') return PR_TRUE;
if (url[n] == '.') return PR_FALSE;
n++;
}
return PR_TRUE;
}
PRBool relatedLinksEnabledURL (char* url) {
if (url == NULL) return PR_FALSE;
if (strlen(url) > 300) return PR_FALSE;
if (!startsWith("http:", url)) {
return PR_FALSE;
} else if (implicitDomainURL(url)) {
return PR_FALSE;
} else return PR_TRUE;
}
PRBool getRLURL (RL_Window win, char* url) {
size_t n, m, l;
memset(win->rlurl, '\0', RL_MAX_URL);
if (!win->demoUrlp) {
if (!strstr(url, "http://")) return PR_FALSE;
}
if (strlen(url) > 370) return PR_FALSE;
sprintf(win->rlurl, "%s", relatedLinksProvider);
n = strlen(relatedLinksProvider) ;
m = (win->demoUrlp ? 25 : 7);
l = strlen(url);
while (m < l) {
if ((url[m] == '?') || (url[m] == '#') || (url[m] == '@')) {
win->rlurl[n++] = url[m++];
break;
}
win->rlurl[n++] = url[m++];
}
return PR_TRUE;
}
void RL_SetRLWindowURL(RL_Window win, char* url) {
if (!win || !relatedLinksProvider || !enableRelatedLinksp) return;
cleanRLTree(win->prevItems);
win->prevItems = win->items;
win->items = NULL;
freeMem(win->url);
win->url = NULL;
if (win->currentlyLoading != NULL) {
NET_InterruptStream (win->currentlyLoading);
win->currentlyLoading = NULL;
}
win->count = 0;
if (win->url && url && !strcmp(url,win->url)) return;
win->demoUrlp = startsWith("file:///c%7C/NS1998Demos", url);
if (!win->demoUrlp && !relatedLinksEnabledURL(url)) {
win->status = RL_STATUS_NOT_AVAILABLE;
return;
}
if (!getRLURL(win, url)) return;
win->url = copyString(url);
win->diff++;
if (win->diff < gMaxDiff) {
win->status = RL_STATUS_LOADING;
GetRL(win);
} else {
win->status = RL_STATUS_WAITING_TO_LOAD;
}
}
void cleanRLTree (RL_Item item) {
while (item) {
RL_Item old = item;
freeMem(item->name);
PL_strfree(item->convertedName);
freeMem(item->rurl);
item->name = item->url = NULL;
if (item->child) cleanRLTree(item->child);
item->child = NULL;
item = item->next;
freeMem(old);
}
}
void RL_AddItem (RL_Window win, char* nurl, char* name, uint8 type) {
if (win != NULL && (win->status == RL_STATUS_LOADING)) {
RL_Item item = (RL_Item)getMem(sizeof(struct _RL_Item));
PRBool zerop = (win->count == 0) ? PR_TRUE : PR_FALSE;
RL_Item existing;
char* url = NULL;
if (nurl) url = strstr(&nurl[7], "http://");
if (!url) url = nurl;
if (item == NULL) return;
item->rurl = nurl;
item->name = name;
item->url = url;
item->type = type;
win->count++;
existing = (win->depth == 0 ? win->items : win->stack[win->depth-1]->child);
if (!existing) {
if (win->depth == 0) {
win->items = item;
} else {
win->stack[win->depth-1]->child = item;
}
} else {
while (existing->next) {
if (existing->url && url && (strcmp(existing->url, url) == 0)) {
freeMem(item);
return;
}
existing = existing->next;
}
existing->next = item;
}
if (type == RL_CONTAINER) win->stack[win->depth++] = item;
}
}
RL_Item RL_WindowItems (RL_Window win) {
if ((win != NULL) && (win->rlurl[0] != '\0') && enableRelatedLinksp) {
win->diff = 0;
gInitialDiff = 0;
if (win->items) {
return win->items;
} else if (win->status == RL_STATUS_WAITING_TO_LOAD) {
win->status = RL_STATUS_LOADING;
GetRL(win);
if (win->items == NULL) return gRLSpecial->loading;
return win->items;
} else if (win->status == RL_STATUS_LOADING) {
return gRLSpecial->loading;
} else return gRLSpecial->noData;
} else if (!enableRelatedLinksp) {
return gRLSpecial->disabled;
} else return gRLSpecial->noData;
}
void RL_PossiblyLoad (RL_Window win) {
if ((win != NULL) && (win->diff < gMaxDiff) && enableRelatedLinksp &&
(win->status == RL_STATUS_WAITING_TO_LOAD)) {
win->status = RL_STATUS_LOADING;
GetRL(win);
}
}
RL_Item RL_NextItem(RL_Item item) {
if (!validRLItem(item)) return NULL;
return item->next;
}
RL_Item RL_ItemChild(RL_Item item) {
if (!validRLItem(item)) return NULL;
return item->child;
}
uint8 RL_ItemCount(RL_Window win) {
return (win->count ? win->count : 1);
}
RL_ItemType RL_GetItemType(RL_Item item) {
if (!validRLItem(item)) return NULL;
return item->type;
}
char* RL_ItemName(RL_Item item) {
if (!validRLItem(item)) return NULL;
return item->name;
}
char* RL_ItemUrl(RL_Item item) {
if (!validRLItem(item)) return NULL;
return item->url;
}
char* RL_WinReferer(RL_Window win) {
return win->rlurl;
}
void GetRL (RL_Window win) {
URL_Struct *urls;
if (!enableRelatedLinksp) return;
/* XP_Trace("\nFetching %s", win->rlurl); */
urls = NET_CreateURLStruct(win->rlurl, NET_DONT_RELOAD);
if (urls == NULL) return;
urls->load_background = TRUE;
urls->fe_data = win; /* hookup url_struct to RL_Window and vice
versa */
win->currentlyLoading = urls; /* so you can get one from the other */
win->status = RL_STATUS_LOADING;
MWContext * pContext = XP_FindContextOfType(0,MWContextBrowser);
NET_GetURL(urls, FO_CACHE_AND_RDF, pContext,
rl_GetUrlExitFunc);
}
void rl_GetUrlExitFunc (URL_Struct *urls, int status, MWContext *cx) {
if (urls != NULL) {
RL_Window win = (RL_Window)urls->fe_data;
if ( win != NULL ) {
win->status = RL_STATUS_ABORTED;
/* if (win->callBack) (*(win->callBack))(win->fe_data, win); */
NET_FreeURLStruct (urls);
}
}
}
PUBLIC NET_StreamClass *
RL_Converter(FO_Present_Types format_out, void *data_object,
URL_Struct *URL_s, MWContext *window_id) {
NET_StreamClass* stream;
RL_Window rl = (RL_Window) URL_s->fe_data;
RL_Get rg;
/* XP_Trace("\nSetting up display stream. Have URL: %s\n",
URL_s->address); */
if ((rl == NULL) || (rl->status != RL_STATUS_LOADING))
return NULL;
rg = (RL_Get) getMem(sizeof(struct _RL_Get));
memset(rl->line, '\0', RL_LINE_SIZE);
memset(rl->holdOver, '\0', RL_LINE_SIZE);
rg->win = rl;
rl->depth = 0;
rg->url = URL_s;
rl->currentlyLoading = URL_s;
stream = NET_NewStream("RL",
(MKStreamWriteFunc)rl_write,
(MKStreamCompleteFunc)rl_complete,
(MKStreamAbortFunc)rl_abort,
(MKStreamWriteReadyFunc)rl_write_ready,
rg, window_id);
return(stream);
}
int rl_write(void *obj, const char *str, int32 len) {
RL_Get rg = (RL_Get)obj;
RL_Window win;
if (obj == NULL || len < 0) {
return MK_INTERRUPTED;
}
win = gRLWindow;
/* if (rg->url != win->currentlyLoading) return len; */
parseNextRDFXMLBlob(win, (char *)str, len);
return(len);
}
unsigned int rl_write_ready(void *obj) {
return RL_LINE_SIZE;
}
void rl_abort(void *obj, int status) {
RL_Get rg = (RL_Get)obj;
RL_Window win ;
if (rg == NULL) return;
win = gRLWindow;
if (win->currentlyLoading == rg->url)
win->status = RL_STATUS_ABORTED;
if (win->callBack) (*(win->callBack))(win->fe_data, win);
freeMem(obj);
}
void rl_complete (void *obj) {
RL_Get rg = (RL_Get)obj;
RL_Window win;
if (rg == NULL) return;
win = gRLWindow;
if (win->currentlyLoading == rg->url) win->status =
RL_STATUS_COMPLETED;
win->currentlyLoading = NULL;
}
#define MAX_ATTRIBUTES 9
void parseNextRDFXMLBlob (RL_Window f, char* blob, int32 size) {
int32 n, last, m;
PRBool somethingseenp = PR_FALSE;
n = last = 0;
while (n < size) {
char c = blob[n];
m = 0;
somethingseenp = PR_FALSE;
memset(f->line, '\0', RL_LINE_SIZE);
if (f->holdOver[0] != '\0') {
memcpy(f->line, f->holdOver, strlen(f->holdOver));
m = strlen(f->holdOver);
somethingseenp = PR_TRUE;
memset(f->holdOver, '\0', RL_LINE_SIZE);
}
while ((m < 300) && (c != '<') && (c != '>')) {
f->line[m] = c;
m++;
somethingseenp = (somethingseenp || ((c != ' ') && (c != '\r') &&
(c != '\n'))) ? PR_TRUE : PR_FALSE;
n++;
if (n < size) c = blob[n];
else break;
}
if (c == '>') f->line[m] = c;
n++;
if (m > 0) {
if ((c == '<') || (c == '>')) {
last = n;
if (c == '<') f->holdOver[0] = '<';
if (somethingseenp == 1) parseNextRDFToken(f, f->line);
} else if (size > last) {
memcpy(f->holdOver, f->line, m);
}
} else if (c == '<') f->holdOver[0] = '<';
}
}
void parseRDFProcessingInstruction (RL_Window win, char* token) {
char* attlist[MAX_ATTRIBUTES+1];
char* newServer;
extractAttributes(token, attlist);
newServer = getAttributeValue(attlist, "relatedLinksServer");
if (newServer) {
freeMem(relatedLinksProvider);
relatedLinksProvider = getMem(strlen(newServer));
if (relatedLinksProvider)
memcpy(relatedLinksProvider, newServer, strlen(newServer));
}
}
char* getAttributeValue (char** attlist, char* elName) {
size_t n = 0;
while ((n < MAX_ATTRIBUTES) && (*(attlist + n) != NULL)) {
if (strcmp(*(attlist + n), elName) == 0) return *(attlist + n + 1);
n = n + 2;
}
return NULL;
}
PRBool tokenEquals (char* token, char* elName, PRBool endp) {
if (endp) {
return ((token[1] == '/') && (strncmp(elName, &token[2],
strlen(elName)) ==0)) ? PR_TRUE : PR_FALSE;
} else {
return (strncmp(elName, &token[1], strlen(elName)) ==0) ? PR_TRUE :
PR_FALSE;
}
}
void parseNextRDFToken (RL_Window f, char* token) {
if (token[0] != '<') {
return;
} else if (tokenEquals(token, "RelatedLinks", PR_TRUE)) {
(*f->callBack)(f->fe_data, f);
} else if (tokenEquals(token, "Topic", PR_TRUE)) {
if (f->depth > 0) f->depth--;
} else if (token[1] == '?') {
parseRDFProcessingInstruction(f, token);
} else {
char* attlist[MAX_ATTRIBUTES+1];
extractAttributes(token, attlist);
if (tokenEquals(token, "aboutPage", PR_FALSE)) {
} else if (tokenEquals(token, "child", PR_FALSE)) {
char* url = getAttributeValue(attlist, "href");
char* name = getAttributeValue(attlist, "name");
char* type = getAttributeValue(attlist, "instanceOf");
if (url && name) RL_AddItem(f, copyString(url), copyString(name),
RL_LINK);
if (type && (strcmp(type, "Separator"))) RL_AddItem(f, NULL, NULL,
RL_SEPARATOR);
} else if (tokenEquals(token, "Topic", PR_FALSE)) {
char* name = getAttributeValue(attlist, "name");
if (name) RL_AddItem(f, NULL, copyString(name), RL_CONTAINER);
}
}
}
void extractAttributes (char* attr, char** attlist) {
size_t n = 1;
size_t s = strlen(attr);
char c ;
size_t m = 0;
size_t atc = 0;
PRBool emptyTagp = (attr[s-2] == '/') ? PR_TRUE : PR_FALSE;
PRBool inAttrNamep = PR_TRUE;
c = attr[n++];
while (n < s) {
if ((c == ' ') || (c == '\n') || (c == '\r')) break;
c = attr[n++];
}
while (atc < MAX_ATTRIBUTES+1) {*(attlist + atc++) = NULL;}
atc = 0;
s = (emptyTagp ? s-2 : s-1);
while (n < s) {
PRBool attributeOpenStringSeenp = PR_FALSE;
m = 0;
c = attr[n++];
while ((n <= s) && (atc < MAX_ATTRIBUTES)) {
if (inAttrNamep && (m > 0) && ((c == ' ') || (c == '\n') || (c ==
'\r') || (c == '='))) {
attr[n-1] = '\0';
*(attlist + atc++) = &attr[n-m-1];
break;
}
if (!inAttrNamep && attributeOpenStringSeenp && (c == '"')) {
attr[n-1] = '\0';
*(attlist + atc++) = &attr[n-m-1];
break;
}
if (inAttrNamep) {
if ((m > 0) || (c != ' ')) m++;
} else {
if (c == '"') {
attributeOpenStringSeenp = PR_TRUE;
} else {
if ((m > 0) || (c != ' ')) m++;
}
}
c = attr[n++];
}
inAttrNamep = (inAttrNamep ? PR_FALSE : PR_TRUE);
}
}