This repository has been archived on 2024-01-04. You can view files and clone it, but cannot push or open issues or pull requests.
ncsa-mosaic/libhtmlw/HTMLlists.c

937 lines
18 KiB
C

/****************************************************************************
* NCSA Mosaic for the X Window System *
* Software Development Group *
* National Center for Supercomputing Applications *
* University of Illinois at Urbana-Champaign *
* 605 E. Springfield, Champaign IL 61820 *
* mosaic@ncsa.uiuc.edu *
* *
* Copyright (C) 1993, Board of Trustees of the University of Illinois *
* *
* NCSA Mosaic software, both binary and source (hereafter, Software) is *
* copyrighted by The Board of Trustees of the University of Illinois *
* (UI), and ownership remains with the UI. *
* *
* The UI grants you (hereafter, Licensee) a license to use the Software *
* for academic, research and internal business purposes only, without a *
* fee. Licensee may distribute the binary and source code (if released) *
* to third parties provided that the copyright notice and this statement *
* appears on all copies and that no charge is associated with such *
* copies. *
* *
* Licensee may make derivative works. However, if Licensee distributes *
* any derivative work based on or derived from the Software, then *
* Licensee will (1) notify NCSA regarding its distribution of the *
* derivative work, and (2) clearly notify users that such derivative *
* work is a modified version and not the original NCSA Mosaic *
* distributed by the UI. *
* *
* Any Licensee wishing to make commercial use of the Software should *
* contact the UI, c/o NCSA, to negotiate an appropriate license for such *
* commercial use. Commercial use includes (1) integration of all or *
* part of the source code into a product for sale or license by or on *
* behalf of Licensee to third parties, or (2) distribution of the binary *
* code or source code to third parties that need it to utilize a *
* commercial product sold or licensed by or on behalf of Licensee. *
* *
* UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
* ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
* WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
* USERS OF THIS SOFTWARE. *
* *
* By using or copying this Software, Licensee agrees to abide by the *
* copyright law and all other applicable laws of the U.S. including, but *
* not limited to, export control laws, and the terms of this license. *
* UI shall have the right to terminate this license immediately by *
* written notice upon Licensee's breach of, or non-compliance with, any *
* of its terms. Licensee may be held legally responsible for any *
* copyright infringement that is caused or encouraged by Licensee's *
* failure to abide by the terms of this license. *
* *
* Comments and questions are welcome and can be sent to *
* mosaic-x@ncsa.uiuc.edu. *
****************************************************************************/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include "HTML.h"
#ifndef DISABLE_TRACE
extern int htmlwTrace;
#endif
/*
* Code to manage a linked list of parsed HTML objects generated
* from a raw text file.
* Also code to manage a linked list of formatted elements that
* make up a page of a formatted document.
*/
/*
* Free up the passed linked list of parsed elements, freeing
* all memory associates with each element.
*/
void
FreeObjList(List)
struct mark_up *List;
{
struct mark_up *current;
struct mark_up *mptr;
current = List;
while (current != NULL)
{
mptr = current;
current = current->next;
mptr->next = NULL;
if (mptr->start != NULL)
{
free((char *)mptr->start);
}
if (mptr->text != NULL)
{
free((char *)mptr->text);
}
if (mptr->end != NULL)
{
free((char *)mptr->end);
}
free((char *)mptr);
}
}
/*
* Add an object to the parsed object list.
* return a pointer to the current (end) position in the list.
* If the object is a normal text object containing nothing but
* white space, throw it out, unless we have been told to keep
* white space.
*/
struct mark_up *
AddObj(listp, current, mark, keep_wsp)
struct mark_up **listp;
struct mark_up *current;
struct mark_up *mark;
int keep_wsp;
{
if (mark == NULL)
{
return(current);
}
/*
* Throw out normal text blocks that are only white space,
* unless keep_wsp is set.
*/
if ((mark->type == M_NONE)&&(!keep_wsp))
{
char *ptr;
ptr = mark->text;
if (ptr == NULL)
{
free((char *)mark);
return(current);
}
/*
* No longer throw out whitespace, it is important to keep
* white space between tags.
while ((*ptr == ' ')||(*ptr == '\t')||(*ptr == '\n'))
{
ptr++;
}
*
*/
if (*ptr == '\0')
{
free(mark->text);
free((char *)mark);
return(current);
}
}
/*
* Add object to either the head of the list for a new list,
* or at the end after the current pointer.
*/
if (*listp == NULL)
{
*listp = mark;
current = *listp;
}
else
{
current->next = mark;
current = current->next;
}
current->next = NULL;
return(current);
}
/*
* Convert type number to a printed string for debug
*/
void
PrintType(type)
int type;
{
#ifndef DISABLE_TRACE
if (htmlwTrace) {
switch(type)
{
case M_NONE:
fprintf(stderr,"M_NONE");
break;
case M_TITLE:
fprintf(stderr,"M_TITLE");
break;
case M_FIXED:
fprintf(stderr,"M_FIXED");
break;
case M_BOLD:
fprintf(stderr,"M_BOLD");
break;
case M_ITALIC:
fprintf(stderr,"M_ITALIC");
break;
case M_EMPHASIZED:
fprintf(stderr,"M_EMPHASIZED");
break;
case M_STRONG:
fprintf(stderr,"M_STRONG");
break;
case M_CODE:
fprintf(stderr,"M_CODE");
break;
case M_SAMPLE:
fprintf(stderr,"M_SAMPLE");
break;
case M_KEYBOARD:
fprintf(stderr,"M_KEYBOARD");
break;
case M_VARIABLE:
fprintf(stderr,"M_VARIABLE");
break;
case M_CITATION:
fprintf(stderr,"M_CITATION");
break;
case M_STRIKEOUT:
fprintf(stderr,"M_STRIKEOUT");
break;
case M_HEADER_1:
fprintf(stderr,"M_HEADER_1");
break;
case M_HEADER_2:
fprintf(stderr,"M_HEADER_2");
break;
case M_HEADER_3:
fprintf(stderr,"M_HEADER_3");
break;
case M_HEADER_4:
fprintf(stderr,"M_HEADER_4");
break;
case M_HEADER_5:
fprintf(stderr,"M_HEADER_5");
break;
case M_HEADER_6:
fprintf(stderr,"M_HEADER_6");
break;
case M_ANCHOR:
fprintf(stderr,"M_ANCHOR");
break;
case M_PARAGRAPH:
fprintf(stderr,"M_PARAGRAPH");
break;
case M_ADDRESS:
fprintf(stderr,"M_ADDRESS");
break;
case M_PLAIN_TEXT:
fprintf(stderr,"M_PLAIN_TEXT");
break;
case M_LISTING_TEXT:
fprintf(stderr,"M_LISTING_TEXT");
break;
case M_UNUM_LIST:
fprintf(stderr,"M_UNUM_LIST");
break;
case M_NUM_LIST:
fprintf(stderr,"M_NUM_LIST");
break;
case M_MENU:
fprintf(stderr,"M_MENU");
break;
case M_DIRECTORY:
fprintf(stderr,"M_DIRECTORY");
break;
case M_LIST_ITEM:
fprintf(stderr,"M_LIST_ITEM");
break;
case M_DESC_LIST:
fprintf(stderr,"M_DESC_LIST");
break;
case M_DESC_TITLE:
fprintf(stderr,"M_DESC_TITLE");
break;
case M_DESC_TEXT:
fprintf(stderr,"M_DESC_TEXT");
break;
case M_IMAGE:
fprintf(stderr,"M_IMAGE");
break;
case M_SELECT:
fprintf(stderr,"M_SELECT");
break;
case M_OPTION:
fprintf(stderr,"M_OPTION");
break;
case M_INPUT:
fprintf(stderr,"M_INPUT");
break;
case M_TEXTAREA:
fprintf(stderr,"M_TEXTAREA");
break;
case M_FORM:
fprintf(stderr,"M_FORM");
break;
case M_INDEX:
fprintf(stderr,"M_INDEX");
break;
case M_HRULE:
fprintf(stderr,"M_HRULE");
break;
case M_BASE:
fprintf(stderr,"M_BASE");
break;
case M_LINEBREAK:
fprintf(stderr,"M_LINEBREAK");
break;
case M_BLOCKQUOTE:
fprintf(stderr,"M_BLOCKQUOTE");
break;
default:
fprintf(stderr,"UNKNOWN %d", type);
break;
}
}
#endif
}
/*
* Print the contents of a parsed object list, for debug
*/
void
PrintList(list)
struct mark_up *list;
{
struct mark_up *mptr;
#ifndef DISABLE_TRACE
if (htmlwTrace) {
mptr = list;
while (mptr != NULL)
{
PrintType(mptr->type);
if (mptr->is_end)
{
fprintf(stderr," END");
}
else
{
fprintf(stderr," START");
}
if (mptr->text != NULL)
{
fprintf(stderr,"\n{\n\t");
fprintf(stderr,"%s", mptr->text);
fprintf(stderr,"}\n");
}
else
{
fprintf(stderr,"\n");
}
mptr = mptr->next;
}
}
#endif
}
/*
* Used to find the longest line (in characters) in a collection
* of text blocks. cnt is the running count of characters, and
* txt is the pointer to the current text block. Since we are
* finding line widths, a newline resets the width count.
*/
char *
MaxTextWidth(txt, cnt)
char *txt;
int *cnt;
{
char *start;
char *end;
int width;
if (txt == NULL)
{
return(NULL);
}
width = *cnt;
start = txt;
/*
* If this blocks starts with a newline, reset the width
* count, and skip the newline.
*/
if (*start == '\n')
{
width = 0;
start++;
}
end = start;
/*
* count characters, stoping either at a newline, or at the
* end of this text block. Expand tabs.
*/
while ((*end != '\0')&&(*end != '\n'))
{
if (*end == '\t')
{
width = ((width / 8) + 1) * 8;
}
else
{
width++;
}
end++;
}
*cnt = width;
return(end);
}
/*
* Free up the passed linked list of formatted elements, freeing
* all memory associates with each element.
*/
void
FreeLineList(list)
struct ele_rec *list;
{
struct ele_rec *current;
struct ele_rec *eptr;
current = list;
while (current != NULL)
{
eptr = current;
current = current->next;
eptr->next = NULL;
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
if (eptr->anchorHRef != NULL)
{
free((char *)eptr->anchorHRef);
}
if (eptr->anchorName != NULL)
{
free((char *)eptr->anchorName);
}
if (eptr->anchorSubject != NULL)
{
free((char *)eptr->anchorSubject);
}
free((char *)eptr);
}
}
/*
* Add an element to the linked list of formatted elements.
* return a pointer to the current (end) position in the list.
*/
struct ele_rec *
AddEle(elistp, current, eptr)
struct ele_rec **elistp;
struct ele_rec *current;
struct ele_rec *eptr;
{
if (eptr == NULL)
{
return(current);
}
/*
* Add object to either the head of the list for a new list,
* or at the end after the current pointer.
*/
if (*elistp == NULL)
{
*elistp = eptr;
(*elistp)->next = NULL;
(*elistp)->prev = NULL;
current = *elistp;
}
else
{
current->next = eptr;
eptr->prev = current;
current = current->next;
current->next = NULL;
}
return(current);
}
/*
* Contruct and return an array of pointers into the element list that
* indexes the elements by line number.
* Note, lines containing only while space will have NULL pointers
* into the element list.
*/
struct ele_rec **
MakeLineList(elist, max_line)
struct ele_rec *elist;
int max_line;
{
int i;
struct ele_rec *eptr;
struct ele_rec **ll;
/*
* malloc index array
*/
ll = (struct ele_rec **)malloc(sizeof(struct ele_rec *) * max_line);
if (ll == NULL)
{
fprintf(stderr, "cannot allocate space for line list\n");
exit(1);
}
/*
* zero the index array
*/
for (i=0; i<max_line; i++)
{
ll[i] = NULL;
}
/*
* fill in pointers to beginning of the lines
*/
eptr = elist;
while (eptr != NULL)
{
if (eptr->line_number > max_line)
{
break;
}
if (ll[eptr->line_number - 1] == NULL)
{
ll[eptr->line_number - 1] = eptr;
}
eptr = eptr->next;
}
return(ll);
}
/*
* Passed in 2 element pointers, and element positions.
* Function should return 1 if if start occurs before end.
* Otherwise return 0.
*/
int
ElementLessThan(start, end, start_pos, end_pos)
struct ele_rec *start;
struct ele_rec *end;
int start_pos, end_pos;
{
struct ele_rec *current;
/*
* Deal with start or end being NULL
*/
if ((start == NULL)&&(end == NULL))
{
return(0);
}
else if ((start == NULL)&&(end != NULL))
{
return(1);
}
else if ((start != NULL)&&(end == NULL))
{
return(0);
}
/*
* Deal with easy identical case
*/
if (start == end)
{
if (start_pos < end_pos)
{
return(1);
}
else
{
return(0);
}
}
/*
* We know element Ids are always equal or increasing within a
* list.
*/
if (start->ele_id < end->ele_id)
{
return(1);
}
else if (start->ele_id == end->ele_id)
{
current = start;
while (current != NULL)
{
if (current->ele_id != start->ele_id)
{
break;
}
else if (current == end)
{
break;
}
current = current->next;
}
if (current == end)
{
return(1);
}
else
{
return(0);
}
}
else
{
return(0);
}
}
/*
* Passed in 2 element pointers, and element positions.
* Function should return 1 if they need to be swapped in order for then
* to proceed left to right and top to bottom in the text.
* Otherwise return 0.
*/
int
SwapElements(start, end, start_pos, end_pos)
struct ele_rec *start;
struct ele_rec *end;
int start_pos, end_pos;
{
struct ele_rec *current;
/*
* Deal with start or end being NULL
*/
if ((start == NULL)&&(end == NULL))
{
return(0);
}
else if ((start == NULL)&&(end != NULL))
{
return(1);
}
else if ((start != NULL)&&(end == NULL))
{
return(0);
}
/*
* Deal with easy identical case
*/
if (start == end)
{
if (start_pos > end_pos)
{
return(1);
}
else
{
return(0);
}
}
/*
* We know element Ids are always equal or increasing within a
* list.
*/
if (start->ele_id < end->ele_id)
{
return(0);
}
else if (start->ele_id == end->ele_id)
{
current = start;
while (current != NULL)
{
if (current->ele_id != start->ele_id)
{
break;
}
else if (current == end)
{
break;
}
current = current->next;
}
if (current == end)
{
return(0);
}
else
{
return(1);
}
}
else
{
return(1);
}
}
/*
* Free up the allocated list of internal hrefs.
*/
void
FreeHRefs(list)
struct ref_rec *list;
{
struct ref_rec *hptr;
struct ref_rec *tptr;
hptr = list;
while (hptr != NULL)
{
tptr = hptr;
hptr = hptr->next;
if (tptr->anchorHRef != NULL)
{
free((char *)tptr->anchorHRef);
}
free((char *)tptr);
}
}
/*
* Find an element in the linked list of Internal HREFS.
* return a pointer to the element, or NULL if not found.
*/
struct ref_rec *
FindHRef(list, href)
struct ref_rec *list;
char *href;
{
struct ref_rec *hptr;
if (href == NULL)
{
return(NULL);
}
hptr = list;
while (hptr != NULL)
{
if (strcmp(hptr->anchorHRef, href) == 0)
{
break;
}
hptr = hptr->next;
}
return(hptr);
}
/*
* Add an element to the linked list of Internal HREFS we
* have visited before.
* return a pointer to the head of the new list.
*/
struct ref_rec *
AddHRef(list, href)
struct ref_rec *list;
char *href;
{
struct ref_rec *hptr;
if (href == NULL)
{
return(list);
}
hptr = FindHRef(list, href);
if (hptr == NULL)
{
hptr = (struct ref_rec *)malloc(sizeof(struct ref_rec));
if (hptr == NULL)
{
#ifndef DISABLE_TRACE
if (htmlwTrace) {
fprintf(stderr, "cannot extend internal href list\n");
}
#endif
return(list);
}
hptr->anchorHRef = (char *)malloc(strlen(href) + 1);
if (hptr->anchorHRef == NULL)
{
free((char *)hptr);
#ifndef DISABLE_TRACE
if (htmlwTrace) {
fprintf(stderr, "cannot extend internal href list\n");
}
#endif
return(list);
}
strcpy(hptr->anchorHRef, href);
hptr->next = list;
list = hptr;
}
return(list);
}
/*
* Free up the allocated list of visited delayed images
*/
void
FreeDelayedImages(list)
struct delay_rec *list;
{
struct delay_rec *iptr;
struct delay_rec *tptr;
iptr = list;
while (iptr != NULL)
{
tptr = iptr;
iptr = iptr->next;
if (tptr->src != NULL)
{
free((char *)tptr->src);
}
free((char *)tptr);
}
}
/*
* Find an element in the linked list of visited delayed images.
* return a pointer to the element, or NULL if not found.
*/
struct delay_rec *
FindDelayedImage(list, src)
struct delay_rec *list;
char *src;
{
struct delay_rec *iptr;
if (src == NULL)
{
return(NULL);
}
iptr = list;
while (iptr != NULL)
{
if (strcmp(iptr->src, src) == 0)
{
break;
}
iptr = iptr->next;
}
return(iptr);
}
/*
* Add an element to the linked list of visited delayed images.
* return a pointer to the head of the new list.
*/
struct delay_rec *
AddDelayedImage(list, src)
struct delay_rec *list;
char *src;
{
struct delay_rec *iptr;
if (src == NULL)
{
return(list);
}
iptr = FindDelayedImage(list, src);
if (iptr == NULL)
{
iptr = (struct delay_rec *)malloc(sizeof(struct delay_rec));
if (iptr == NULL)
{
#ifndef DISABLE_TRACE
if (htmlwTrace) {
fprintf(stderr, "cannot extend visited delayed images list\n");
}
#endif
return(list);
}
iptr->src = (char *)malloc(strlen(src) + 1);
if (iptr->src == NULL)
{
free((char *)iptr);
#ifndef DISABLE_TRACE
if (htmlwTrace) {
fprintf(stderr, "cannot extend visited delayed images list\n");
}
#endif
return(list);
}
strcpy(iptr->src, src);
iptr->next = list;
list = iptr;
}
return(list);
}