home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-03-03 | 52.7 KB | 1,452 lines |
- /* > c.1stMake - (c) Paul Witheridge - Version 2.01 - 03 Mar 1993 */
-
- /*===================================================================*/
- /* */
- /* 1stMake - converts text files to 1stWord+ files */
- /* ------- */
- /* */
- /* This utility converts plain text files to 1stWord+ files in an */
- /* intelligent manner, so that (hopefully) the resulting file can */
- /* be re-formatted using 1stWord+ without losing indents, hanging */
- /* indents, etc. */
- /* */
- /*-------------------------------------------------------------------*/
- /* */
- /* COPYRIGHT NOTICE */
- /* */
- /* 1stMake is subject to Copyright. */
- /* */
- /* Permission is granted by the author to any recipient of this */
- /* material to use and make/disseminate copies of the application */
- /* provided that no charges are made for doing so (other than to */
- /* cover any cost of media or postage) and that this notice is */
- /* included with all copies. */
- /* */
- /*===================================================================*/
-
- #include "kernel.h" /* ARC specifics */
- #include <ctype.h> /* Character handling */
- #include <limits.h> /* Implementation limits */
- #include <stddef.h> /* Standard definitions */
- #include <stdio.h> /* Input/output */
- #include <stdlib.h> /* General utilities */
- #include <string.h> /* String handling */
- #include "Beep.h" /* Beep header */
- #include "GetDirs.h" /* GetDirs header */
- #include "ArgFuncs.h" /* Arg functions etc */
- #include "Useful.h" /* Useful definitions */
-
- /*-------------------------------------------------------------------*/
- /* Global data declarations and definitions. */
- /*-------------------------------------------------------------------*/
-
- static unsigned char flags = '\0' ; /* Processing flags */
- #define flgfnd 0x01 /* Found file to process */
- #define flglfo 0x02 /* List file is open */
- #define flglst 0x10 /* List mode */
- #define flgovr 0x20 /* Overwrite mode */
- #define flgrcs 0x40 /* Recursive mode */
- #define flgtst 0x80 /* Test mode */
-
- static int filecount = 0 ; /* Count of files processed. */
-
- static const char *argptr = NULL ; /* Pointer to file spec. */
- static const char *pfxptr = "_" ; /* Pointer to output prefix */
- static const char *lstptr = NULL ; /* Pointer to list file spec */
- static FILE *listfile = NULL ; /* Pointer to list file */
-
- /*-------------------------------------------------------------------*/
- /* Define settings for line flags. */
- /*-------------------------------------------------------------------*/
-
- #define brkflg 0x01 /* Break at end of this line */
- #define hinflg 0x02 /* Hanging indent */
- #define itmflg 0x04 /* List item */
- #define pinflg 0x08 /* Paragraph indent flag */
- #define hrdflg 0x10 /* Hard spaces flag */
-
- /*-------------------------------------------------------------------*/
- /* Define 1stWord+ standard file header. */
- /*-------------------------------------------------------------------*/
-
- static const char docheader[] =
- {
- 0x1F, 0x30, /* File Start */
- 0x36, 0x36, /* Form length */
- 0x30, 0x31, /* Top of form margin */
- 0x30, 0x33, /* Header Margin */
- 0x30, 0x33, /* Footer Margin */
- 0x30, 0x35, /* Bottom of form margin */
- 0x38, 0x30, 0x30,
- 0x0A, /* End of first line */
-
- 0x1F, 0x31, /* Left hdg text would go here */
- 0x1F, /* Centre hdg text would go here */
- 0x1F, /* Right hdg text would go here */
- 0x0A, /* End of hdg line */
-
- 0x1F, 0x32, /* Left ftg text would go here */
- 0x1F, /* Centre ftg text would go here */
- 0x1F, /* Right ftg text would go here */
- 0x0A, /* End of ftg line */
-
- 0x1F, 0x46, 0x30, /* Start of footnote line */
- 0x31, /* Lines before footnote */
- 0x31, /* Lines after footnote */
- 0x30, 0x30,
- 0x33, 0x30, /* Length of separator line */
- 0x0A, /* End of footnote line */
-
- 0x1F, 0x39, /* Start of default ruler */
- 0x5B, /* Start of TABS definition */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 1st TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 2nd TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 3rd TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 4th TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 5th TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 6th TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 7th TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 8th TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 9th TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 10th TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 11th TAB */
- 0x2E, 0x2E, 0x2E, 0x2E, 0x7F, /* 12th TAB */
- 0x2E, 0x2E, 0x2E,
- 0x5D, /* End of tabs */
- 0x30, /* Pitch Pica/Elite/Cndnsd/Expnded */
- 0x30, /* Justification off/on */
- 0x31, /* Line spacing */
- 0x0A, /* End of ruler line */
- 0x1B, 0x80
- } ;
-
- /*-------------------------------------------------------------------*/
- /* Declare functions local in scope to this file. */
- /*-------------------------------------------------------------------*/
-
- static enum boolean cnvtfunc( /* Convert function */
- const char *path,
- direntry *ptr) ;
-
- static int leadblanks( /* Count leading blanks */
- const char *lineptr) ;
-
- static enum boolean isitem( /* Tests for list item */
- const char *lineptr,
- const int indent) ;
-
- static enum boolean isnumbered( /* Test for 1-2 digit number */
- const char *p,
- const int l) ;
-
- static enum boolean isroman( /* Test for roman numeral */
- const char *p,
- const int l) ;
-
- static enum boolean isterm( /* Tests for definition term */
- const char *lineptr,
- int len,
- int indent,
- int nextindent) ;
-
- static enum boolean istag( /* Test for certain GML tags */
- const char *lineptr) ;
-
- static enum boolean isshort( /* Test for short line */
- const char *lineptr,
- const int len,
- const int brklen) ;
-
- static void sethangingindent( /* Set hanging indent */
- int line,
- int nlines,
- int nextindent,
- char *(*lineptrs)[],
- char (*lineflgs)[]) ;
-
- static void putdup( /* Repeat character to file */
- const int c,
- const int n,
- FILE *fileptr) ;
-
- /*===================================================================*/
- /* */
- /* Main program */
- /* ------------ */
- /* */
- /* Analyse arguments. Then call the "GetDirentrys" function to */
- /* read all the file-names in the specified directory. Provide */
- /* pointer to function to process the specified files. */
- /* */
- /*===================================================================*/
-
- int main(
- const int argc, /* Number of arguments */
- const char *argv[]) /* Array of pointers to args */
- {
- /*-----------------------------------------------------------------*/
- /* Local definitions. */
- /*-----------------------------------------------------------------*/
-
- int returncode ;
-
- static const char **posval[] = /* Ptrs to ptrs to posit'nal values */
- {
- &argptr
- } ;
- static const char **(*posargs)[] = &posval ; /* Ptr to array */
-
- static const char options[] = /* Used to match option argument */
- {
- 'L', /* List mode */
- 'O', /* Overwrite mode */
- 'P', /* Output prefix */
- 'R', /* Recursive mode */
- 'T', /* Test mode */
- '0' /* Null byte terminator */
- } ;
-
- static const unsigned char optflags[] = /* Used to set option flgs */
- {
- flglst, /* List mode */
- flgovr, /* Overwrite mode */
- 0, /* Output prefix */
- flgrcs, /* Recursive mode */
- flgtst, /* Test mode */
- } ;
-
- static const char **optval[] = /* Ptrs to ptrs to option values */
- {
- &lstptr, /* Optional list file name */
- NULL, /* No value allowed */
- &pfxptr, /* Output file prefix */
- NULL, /* No value allowed */
- NULL, /* No value allowed */
- } ;
-
- static const char helpdata[] = /* Help text to be displayed */
-
- "1stMake converts plain ASCII text files into 1stWord+ "
- "documents. It attempts to insert the correct 1stWord+ "
- "format control characters for hanging indents and lists "
- "so that they can be reflowed correctly when reformatting "
- " with 1stWord+.\x1f"
- "\x1f"
- "WARNING:\x01" "This utility converts files IN-PLACE if the "
- "'-o' option is used to replace the input text file with "
- "the output 1stWord+ document.\x1f"
- "\x1f"
- "Syntax:\x01" "*1stMake [path.]object [options]\x1f"
- "\x1f"
- "object:\x01" "Specifies one of the following:\x1f"
- "\x01" "(a) a single non-wildcarded file name\x1f"
- "\x01" "(b) a single non-wildcarded directory name\x1f"
- "\x01" "(c) a wildcarded name.\x1f"
- "\x1f"
- "\x01" "In case (a) the file is converted provided that "
- "it has a file-type of TEXT.\x1f"
- "\x1f"
- "\x01" "In case (b) all TEXT files in the specified directory "
- "are converted. If the RECURSION option is specified all TEXT "
- "files in all subdirectories are also converted.\x1f"
- "\x1f"
- "\x01" "In case (c) all matching TEXT files are converted. "
- "If no matching files are found, then the first matching "
- "directory name is taken and all TEXT files therein are "
- "converted. If the RECURSION option is specified, all "
- "matching TEXT files are converted, plus all TEXT files "
- "in all subdirectories.\x1f"
- "\x1f"
- "\x01" "In all cases, only files which have a filetype of "
- "TEXT (hex FFF) will be converted.\x1f"
- "\x1f"
- "path:\x01" "Specifies the directory to be searched for the "
- "object file/directory. If omitted the current directory "
- "is searched.\x1f"
- "\x1f"
- "options:\x01" "Specifies processing options which can be "
- "one or more of the following:\x1f"
- "\x1f"
- "\x01" "-l xxx\x02" "-\x03" "LIST mode; the input file "
- "contents are listed to file 'xxx', each line prefixed by "
- "flags showing the conversion action for that line; if 'xxx' "
- "is omitted the list is written to the standard output "
- "stream.\x1f"
- "\x1f"
- "\x01" "-o\x02" "-\x03" "OVERWRITE mode; output file will "
- "have same name and will replace input file.\x1f"
- "\x1f"
- "\x01" "-p xxx\x02" "-\x03" "specify PREFIX which will be "
- "used to create name for output file if '-o' is not specified; "
- "'xxx' can be one or more characters including directory "
- "specification (e.g. 'txtdir.'); if not specified a default "
- "of '_' is used.\x1f"
- "\x1f"
- "\x01" "-r\x02" "-\x03" "RECURSION mode which causes all eligible "
- "files in all subdirectories to be converted.\x1f"
- "\x1f"
- "\x01" "-t\x02" "-\x03" "TEST mode; a list of files to be "
- "converted is displayed but no output is actually written; "
- "useful for checking when specifying a directory or wildcarded "
- "filename.\x1f"
- "\x1f"
- "If option '-l' (list mode) is specified, the input file contents "
- "are listed with each line prefixed by flag characters indicating "
- "how 1stMake will convert that line. The flag possible flag "
- "characters are as follows:\x1f"
- "\x1f"
- "\x04" "B\x05" "-\x06" "line assumed to be 'break' in formatting "
- "(end of paragraph) and no space will be inserted before new "
- "line character at end of line.\x1f"
- "\x1f"
- "\x04" "P\x05" "-\x06" "line assumed to be start of paragraph "
- "and will be indented with fixed spaces (as produced by TAB or "
- "FIXED SPACE key).\x1f"
- "\x1f"
- "\x04" "L\x05" "-\x06" "line assumed to be the start of an item "
- "in a list and the initial item identification (e.g. paragraph "
- "number) will be followed by an 'indent' space plus 'stretch' "
- "spaces (as produced by INDENT key)\x1f"
- "\x1f"
- "\x04" "I\x05" "-\x06" "line will be indented with an 'indent' "
- "space plus 'stretch' spaces (as produced by INDENT key)\x1f"
- "\x1f"
- "\x04" "A\x05" "-\x06" "line is assumed to be non-formattable "
- "('as is') and all spaces will be converted to fixed spaces.\x1f"
- "\x1f"
- "1stMake - copyright Paul Witheridge, 1993\x1f"
- "\x1f" ;
-
- static const unsigned char helptabs[] = /* Help text tab settings */
- {
- 1,10,17,19,2,4,6
- } ;
-
- /*-----------------------------------------------------------------*/
- /* Executable statements */
- /* */
- /* First display sign-on message with version/date ids. */
- /*-----------------------------------------------------------------*/
-
- puts("\n1stMake Version 2.01 - 03 March 1993\n") ;
-
- /*-----------------------------------------------------------------*/
- /* Analyse arguments for file-name and option flags. */
- /*-----------------------------------------------------------------*/
-
- analargs(argc,argv,1,&posargs,options,&flags,optflags,optval) ;
-
- /*-----------------------------------------------------------------*/
- /* Set paged scrolling mode */
- /*-----------------------------------------------------------------*/
-
- _kernel_oswrch(12) ;
- _kernel_oswrch(14) ;
-
- puts(" PRESS SHIFT KEY TO ALLOW WINDOW TO SCROLL\n") ;
-
- /*-----------------------------------------------------------------*/
- /* If no file name operand just display help text. */
- /*-----------------------------------------------------------------*/
-
- if ( argptr == NULL )
- {
- displaytext(helpdata,helptabs) ;
- _kernel_oswrch(15) ;
- return 0 ;
- }
-
- /*-----------------------------------------------------------------*/
- /* If TEST MODE issue message. */
- /*-----------------------------------------------------------------*/
-
- if ( flags & flgtst )
- {
- puts("TEST MODE (files will be identified, not converted).\n") ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Invoke GetDirs function to read the directory entry(s) of the */
- /* file(s) to be processed. Pass it a pointer of a processing */
- /* function to be called. */
- /*-----------------------------------------------------------------*/
-
- returncode = 4 ;
-
- if ( getdirentrys(argptr,
- ( flags & flgrcs ? RECURSE_ALWAYS : RECURSE_ONCE ),cnvtfunc) )
- {
- if ( flags & flgfnd )
- {
- printf("\n%d text file(s) ",filecount) ;
- if ( flags & flgtst )
- {
- printf("would be ") ;
- }
- puts("converted.\n") ;
- returncode = 0 ;
- }
- else
- {
- printf("No text files found matching '%s'\n",argptr) ;
- beep() ;
- }
- }
-
- /*-----------------------------------------------------------------*/
- /* Close list file if open. */
- /*-----------------------------------------------------------------*/
-
- if ( flags & flglfo )
- {
- fclose(listfile) ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Return to caller. All done. */
- /*-----------------------------------------------------------------*/
-
- _kernel_oswrch(15) ;
- return returncode ;
- }
-
- /*===================================================================*/
- /* */
- /* cnvtfunc - perform actual file conversion */
- /* -------- */
- /* */
- /* This function is called by the "getdirentrys" function for each */
- /* file-name that it encounters. */
- /* */
- /* Only files which have a filetype of "text" (0xFFF) will be */
- /* processed. */
- /* */
- /*===================================================================*/
-
- static enum boolean cnvtfunc(
- const char *path, /* Pointer to path name. */
- direntry *ptr) /* Pointer to direntry info. */
- {
- /*-----------------------------------------------------------------*/
- /* Local definitions. */
- /*-----------------------------------------------------------------*/
-
- char *infile ; /* Ptr to path + leafname */
- char *oufile ; /* Ptr tp path + leafname */
- int result ; /* Result from OS-File SWI */
- char *workarea ; /* Ptr to start of work area */
- char *workend ; /* Ptr to end of work area */
- char *iptr ; /* Working pointer */
- char *optr ; /* Working pointer */
- _kernel_osfile_block osfileblk ; /* OS_File parameter block */
- char *(*lineptrs)[] ; /* Ptr to line ptr array */
- char *lineptr ; /* Ptr to current line */
- char (*lineflgs)[] ; /* Ptr to line flags array */
- int lineflg ; /* Copy of current line flags */
- int len ; /* Length of current line */
- int maxlen ; /* Maximum length of any line */
- int brklen ; /* Short line threshold */
- int line ; /* Current line number */
- int nlines ; /* Number of lines */
- int nblanks ; /* Working blanks counter */
- int indent ; /* Indent of current line */
- int nextindent ; /* Indent of next line */
- int minindent ; /* Minimum indent of any line */
- FILE *fileptr ; /* Output file pointer */
- FILE *lstfptr ; /* List file pointer */
- int i,j,k ; /* Working integers */
- int c ; /* Working character */
- char flagprnt[8] ; /* Flag display work area */
-
- static const char toomanylines[] =
- "'%s' contains too many lines to process" ;
-
- /*-----------------------------------------------------------------*/
- /* Executable statements */
- /* */
- /* Return immediatley if not a text file. */
- /*-----------------------------------------------------------------*/
-
- if ( ptr->type != 0xfff )
- {
- return TRUE ;
- }
-
- /*-----------------------------------------------------------------*/
- /* If test mode without "-l" option, just list file name. */
- /*-----------------------------------------------------------------*/
-
- if ( (flags & (flgtst | flglst)) == flgtst )
- {
- if ( !(flags & flgfnd) )
- {
- flags |= flgfnd ;
- puts("The following files would be converted "
- "to 1stWord+ documents:\n") ;
- }
- printf("%s%s\n",path,ptr->name) ;
- filecount++ ;
- return TRUE ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Create input and output filespecs */
- /*-----------------------------------------------------------------*/
-
- if ( ( infile = malloc(2 * (strlen(path) + strlen(ptr->name) + 1)
- + strlen(pfxptr) ) ) == NULL )
- {
- puts("Out of memory") ;
- return FALSE ;
- }
-
- oufile = infile + sprintf(infile,"%s%s",path,ptr->name) + 1 ;
- sprintf(oufile,"%s%s%s",path,flags & flgovr ? "" : pfxptr,ptr->name) ;
-
- /*-----------------------------------------------------------------*/
- /* Check input file has non-zero length. */
- /*-----------------------------------------------------------------*/
-
- if ( ptr->length == 0 )
- {
- printf("'%s' is empty\n",infile) ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Allocate memory for file and load it. */
- /*-----------------------------------------------------------------*/
-
- if ( (workarea = malloc((ptr->length)+1)) == NULL )
- {
- printf("'%s' too large to load",infile) ;
- goto error4 ;
- }
-
- workend = workarea + ptr->length ;
-
- osfileblk.load = (int)workarea ;
- osfileblk.exec = 0 ;
- result = _kernel_osfile(255,infile,&osfileblk) ;
-
- if ( result == _kernel_ERROR )
- {
- printf("'%s' load failed - %s\n",infile,
- _kernel_last_oserror()->errmess) ;
- goto error3 ;
- }
-
- /*-----------------------------------------------------------------*/
- /* If missing new-line at end of file, add one (provided that */
- /* file is non-zero length). */
- /*-----------------------------------------------------------------*/
-
- if ( workend > workarea && *(workend-1) != '\n' )
- {
- *(workend++) = '\n' ;
- printf("No newline character at end of '%s' - inserted\n",infile) ;
- beep() ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Count number of newline characters in file. Substitute null */
- /* bytes for the newline characters. Also determine the minimum */
- /* indentation of any line. */
- /*-----------------------------------------------------------------*/
-
- indent = minindent = INT_MAX ;
- nblanks = nlines = 0 ;
-
- for ( iptr = workarea ;iptr < workend ; iptr++ )
- {
- switch (*iptr)
- {
- /*-------------------------------------------------------------*/
- /* Process newline character. */
- /*-------------------------------------------------------------*/
-
- case '\n' :
-
- *iptr = '\0' ;
- nlines++ ;
- if ( indent < minindent )
- {
- minindent = indent ;
- }
- nblanks = 0 ;
- indent = INT_MAX ;
- break ;
-
- /*-------------------------------------------------------------*/
- /* Process blank. */
- /*-------------------------------------------------------------*/
-
- case ' ' :
-
- nblanks++ ;
- break ;
-
- /*-------------------------------------------------------------*/
- /* Process other characters */
- /*-------------------------------------------------------------*/
-
- default :
- if ( indent == INT_MAX )
- {
- indent = nblanks ;
- }
- }
- }
-
- /*-----------------------------------------------------------------*/
- /* Allocate storage for pointer array. Perform second pass */
- /* through loaded file setting up pointers, shifting each line */
- /* left by minimum indentation amount, truncating any trailing */
- /* blanks and computing maximum line length. */
- /*-----------------------------------------------------------------*/
-
- if ( (lineptrs = malloc((nlines+2) * sizeof(char *))) == NULL )
- {
- printf(toomanylines,infile) ;
- goto error3 ;
- }
-
- iptr = optr = workarea ;
- maxlen = 0 ;
- (*lineptrs)[0] = (*lineptrs)[nlines+1] = "" ;
-
- for ( line = 1 ; line <= nlines ; line++ )
- {
- (*lineptrs)[line] = lineptr = optr ;
- len = strlen(iptr) ;
- if ( len < minindent )
- {
- iptr += len + 1 ;
- }
- else
- {
- iptr += minindent ;
- for ( ; (*optr = *(iptr++)) != '\0' ; optr++ ) ;
- while ( optr > lineptr )
- {
- if ( *(--optr) != ' ' )
- {
- optr++ ;
- break ;
- }
- }
- if ( (len = optr - lineptr) > maxlen )
- {
- maxlen = len ;
- }
- }
- *(optr++) = '\0' ;
-
- }
-
- brklen = 2 * maxlen / 3 ;
-
- /*-----------------------------------------------------------------*/
- /* Allocate storage for line flag array */
- /*-----------------------------------------------------------------*/
-
- if ( (lineflgs = malloc(nlines+2)) == NULL )
- {
- printf(toomanylines,infile) ;
- goto error2 ;
- }
- memset(lineflgs,0,nlines+2) ;
-
- /*-----------------------------------------------------------------*/
- /* Perform pass through file setting flags to indicate how the */
- /* line should be converted. */
- /*-----------------------------------------------------------------*/
-
- nextindent = leadblanks((*lineptrs)[1]) ;
-
- for ( line = 1 ; line <= nlines ; line++ )
- {
- lineptr = (*lineptrs)[line] ;
- lineflg = (*lineflgs)[line] ;
- len = strlen(lineptr) ;
- indent = nextindent ;
- nextindent = leadblanks((*lineptrs)[line+1]) ;
-
- /*---------------------------------------------------------------*/
- /* If null line encountered or if this line starts with a */
- /* period (i.e. is SCRIPT/VS control word) set break flag on */
- /* this and on previous line. */
- /*---------------------------------------------------------------*/
-
- if ( *lineptr == '\0' || *lineptr == '.' )
- {
- (*lineflgs)[line-1] |= brkflg ;
- lineflg |= brkflg ;
- }
-
- /*---------------------------------------------------------------*/
- /* If not a null line then it must be analysed to determine */
- /* any special formatting requirements. */
- /*---------------------------------------------------------------*/
-
- else
- {
- /*-------------------------------------------------------------*/
- /* If line begins with a colon (i.e. is a SCRIPT/VS GML */
- /* tag) then set break flag on previous line (provided */
- /* that it is not one of the GML tags that I prefer NOT */
- /* to be treated as a break). */
- /*-------------------------------------------------------------*/
-
- if ( *lineptr == ':' && !istag(lineptr) )
- {
- (*lineflgs)[line-1] |= brkflg ;
- }
-
- /*-------------------------------------------------------------*/
- /* Count number of punctuation characters in line. If */
- /* they make up more than two thirds of the non-blank */
- /* characters on the line, treat it as an 'asis' line. */
- /*-------------------------------------------------------------*/
-
- for ( i = j = k = 0 ; i < len ; i++ )
- {
- c = lineptr[i] ;
- if ( ispunct(c) )
- {
- j++ ;
- }
- else if ( c == ' ' )
- {
- k++ ;
- }
- }
-
- if ( j > 2 * (len - k) / 3 )
- {
- (*lineflgs)[line-1] |= brkflg ;
- lineflg |= brkflg | hrdflg ;
- }
-
- /*-------------------------------------------------------------*/
- /* Current line indented more than next line. */
- /* */
- /* If current line is part of hanging indent, assume end */
- /* of list item, so set break flag on current line. */
- /* If line starts with bullet-like format assume a one */
- /* line list item and set break flag on current line and */
- /* on previous line. Otherwise assume start of new */
- /* paragraph. */
- /*-------------------------------------------------------------*/
-
- else if ( indent > nextindent )
- {
- if ( lineflg & hinflg )
- {
- lineflg |= brkflg ;
- if ( isitem(lineptr,indent) )
- {
- (*lineflgs)[line-1] |= brkflg ;
- lineflg |= itmflg ;
- }
- }
- else
- {
- (*lineflgs)[line-1] |= brkflg ;
- if( isitem(lineptr,indent) )
- {
- lineflg |= brkflg | itmflg ;
- }
- else
- {
- lineflg |= pinflg ;
- if ( isshort(lineptr,len,brklen) )
- {
- lineflg |= brkflg ;
- }
- }
- }
- }
-
- /*-------------------------------------------------------------*/
- /* Current line at same indentation as next. */
- /* */
- /* Set break flag if short line. If line starts with */
- /* bullet-like format assume one line list item. */
- /*-------------------------------------------------------------*/
-
- else if ( indent == nextindent )
- {
- if ( isshort(lineptr,len,brklen) )
- {
- lineflg |= brkflg ;
- }
- if ( isitem(lineptr,indent) )
- {
- (*lineflgs)[line-1] |= brkflg ;
- lineflg |= itmflg | brkflg ;
- }
- if ( !(lineflg & hinflg) )
- {
- if ( indent > 0 )
- {
- (*lineflgs)[line-1] |= brkflg ;
- lineflg |= hinflg ;
- sethangingindent(line,nlines,nextindent,
- lineptrs,lineflgs) ;
- }
- }
- }
-
- /*-------------------------------------------------------------*/
- /* Current line is less indented than next line. */
- /* */
- /* Assume start of hanging indent. Set item flag if line */
- /* appears to start with bullet-like format or list term. */
- /* */
- /* Set hanging indent flag on all following lines of same */
- /* or greater indent than next line. */
- /*-------------------------------------------------------------*/
-
- else
- {
- if ( isitem(lineptr,indent) ||
- isterm(lineptr,len,indent,nextindent) )
- {
- (*lineflgs)[line-1] |= brkflg ;
- lineflg |= itmflg ;
- }
- if ( isshort(lineptr,len,brklen) )
- {
- lineflg |= brkflg ;
- }
- sethangingindent(line,nlines,nextindent,lineptrs,lineflgs) ;
- }
- }
- (*lineflgs)[line] = lineflg ;
- }
-
- /*-----------------------------------------------------------------*/
- /* For debug purposes list document showing flag settings. */
- /*-----------------------------------------------------------------*/
-
- if ( flags & flglst )
- {
- if ( !(flags & flglfo) )
- {
- if ( lstptr != NULL )
- {
- if ( (listfile = fopen(lstptr,"w")) == NULL )
- {
- printf("Cannot open list file '%s'\n"
- "Listing will be written to "
- "standard output stream\n",lstptr) ;
- }
- }
- flags |= flglfo ;
- }
- lstfptr = ( listfile == NULL ) ? stdout : listfile ;
-
- putdup('*',70,lstfptr) ;
- fprintf(lstfptr,"\nConversion listing for file: %s\n",infile) ;
- putdup('*',70,lstfptr) ;
- fputc('\n',lstfptr) ;
-
- for ( line = 1 ; line <= nlines ; line++ )
- {
- lineflg = (*lineflgs)[line] ;
- strcpy(flagprnt,"..... ") ;
- if ( lineflg & brkflg )
- {
- flagprnt[0] = 'B' ;
- }
- if ( lineflg & pinflg )
- {
- flagprnt[1] = 'P' ;
- }
- if ( lineflg & itmflg )
- {
- flagprnt[2] = 'L' ;
- }
- if ( lineflg & hinflg )
- {
- flagprnt[3] = 'I' ;
- }
- if ( lineflg & hrdflg )
- {
- flagprnt[4] = 'A' ;
- }
- fprintf(lstfptr,"%s%s\n",flagprnt,(*lineptrs)[line]) ;
- }
- putdup('*',70,lstfptr) ;
- fputs("\n\n",lstfptr) ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Unless test mode convert document and replace original file. */
- /*-----------------------------------------------------------------*/
-
- if ( !(flags & flgtst) )
- {
- /*---------------------------------------------------------------*/
- /* Open target file for output. */
- /*---------------------------------------------------------------*/
-
- if ( (fileptr = fopen(oufile,"w")) == NULL )
- {
- printf("Cannot open file '%s' - %s\n",oufile,
- _kernel_last_oserror()->errmess) ;
- goto error1 ;
- }
-
- /*---------------------------------------------------------------*/
- /* Copy 1stWord+ header to output file. */
- /*---------------------------------------------------------------*/
-
- for ( i = 0 ; i < sizeof(docheader) ; i++ )
- {
- fputc(docheader[i],fileptr) ;
- }
-
- /*---------------------------------------------------------------*/
- /* Copy document to output file. */
- /*---------------------------------------------------------------*/
-
- nextindent = leadblanks((*lineptrs)[1]) ;
-
- for ( line = 1 ; line <= nlines ; line++ )
- {
- lineptr = (*lineptrs)[line] ;
- lineflg = (*lineflgs)[line] ;
- len = strlen(lineptr) ;
- indent = nextindent ;
- nextindent = leadblanks((*lineptrs)[line+1]) ;
-
- i = 0 ;
-
- /*-------------------------------------------------------------*/
- /* If 'asis' line copy to output file asis. */
- /*-------------------------------------------------------------*/
-
- if ( lineflg & hrdflg )
- {
- for ( ; (c = lineptr[i]) != '\0' ; i++ )
- {
- fputc(c,fileptr) ;
- }
- }
-
- /*-------------------------------------------------------------*/
- /* If 'paragraph' indent, indent with hard spaces. */
- /*-------------------------------------------------------------*/
-
- else if ( lineflg & pinflg )
- {
- putdup(' ',indent,fileptr) ;
- i = indent ;
- }
-
- /*-------------------------------------------------------------*/
- /* If hanging indent, indent with indent spaces. */
- /*-------------------------------------------------------------*/
-
- else if ( lineflg & hinflg )
- {
- fputc(0x1d,fileptr) ;
- putdup(0x1c,indent-1,fileptr) ;
- i = indent ;
- }
-
- /*-------------------------------------------------------------*/
- /* If start of list item indent with indent spaces. */
- /*-------------------------------------------------------------*/
-
- if ( lineflg & itmflg )
- {
- j = 0 ;
- c = lineptr[i] ;
- while ( (i < nextindent || j < 2) && c != '\0' )
- {
- if (c == ' ')
- {
- fputc(0x1d,fileptr) ;
- i++ ;
- while ( (i < nextindent || j < 2) &&
- (c = lineptr[i]) == ' ' )
- {
- fputc(0x1c,fileptr) ;
- i++ ;
- }
- }
- else
- {
- j++ ;
- while ( (c = lineptr[i]) != ' ' && c != '\0' )
- {
- fputc(c,fileptr) ;
- i++ ;
- }
- }
- }
- }
-
- /*-------------------------------------------------------------*/
- /* Copy rest of line to output, converting blanks to */
- /* 'soft' blanks. */
- /*-------------------------------------------------------------*/
-
- for ( ; (c = lineptr[i]) != '\0' ; i++ )
- {
- if ( c == ' ' )
- {
- c = 0x1e ;
- }
- fputc(c,fileptr) ;
- }
-
- /*-------------------------------------------------------------*/
- /* Unless break expected, add a final soft blank to the */
- /* end of the line. */
- /*-------------------------------------------------------------*/
-
- if ( !(lineflg & brkflg) )
- {
- fputc(0x1e,fileptr) ;
- }
-
- /*-------------------------------------------------------------*/
- /* Finish off with newline character. */
- /*-------------------------------------------------------------*/
-
- fputc('\n',fileptr) ;
- }
-
- /*---------------------------------------------------------------*/
- /* Close file. */
- /*---------------------------------------------------------------*/
-
- fclose(fileptr) ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Free work area, line pointers, etc. */
- /*-----------------------------------------------------------------*/
-
- free(lineflgs) ;
- free(lineptrs) ;
- free(workarea) ;
-
- /*-----------------------------------------------------------------*/
- /* Set record type to that for 1stWord+ Document. */
- /*-----------------------------------------------------------------*/
-
- if ( !(flags & flgtst) )
- {
- osfileblk.load = 0xaf8 ;
- result = _kernel_osfile(18,oufile,&osfileblk) ;
-
- if ( result == _kernel_ERROR )
- {
- printf("'%s' SETTYPE failed - %s\n",oufile,
- _kernel_last_oserror()->errmess) ;
- goto error4 ;
- }
-
- printf("'%s' converted",infile) ;
- if ( !(flags & flgovr) )
- {
- printf(" to '%s'",oufile) ;
- }
- putchar('\n') ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Return to caller with RC=TRUE. */
- /*-----------------------------------------------------------------*/
-
- free(infile) ;
- flags |= flgfnd ;
- filecount++ ;
- return TRUE ;
-
- /*-----------------------------------------------------------------*/
- /* Error exits. */
- /*-----------------------------------------------------------------*/
-
- error1: free(lineflgs) ;
- error2: free(lineptrs) ;
- error3: free(workarea) ;
- error4: free(infile) ;
- beep() ;
-
- return FALSE ;
- }
-
- /*===================================================================*/
- /* */
- /* leadblanks - count number of leading blanks in line */
- /* ---------- */
- /* */
- /* This function determines the indent of the line passed as an */
- /* argument. */
- /* */
- /*===================================================================*/
-
- static int leadblanks(
- const char *lineptr) /* Ptr to line text */
- {
- int i = 0 ;
- while ( lineptr[i] == ' ' )
- {
- i++ ;
- }
- return i ;
- }
-
- /*===================================================================*/
- /* */
- /* isitem - test for list item format */
- /* ------ */
- /* */
- /* Check for line staring with: */
- /* */
- /* - a bullet ("*", "-", or "o") */
- /* - an alphabetic id in form "(x)" or "x)" */
- /* - a numeric id in form "(n)", "(nn)", "n)", "nn)", "n.", "nn." */
- /* - a roman numeral in form "(r)", "r)", "r." or "r" */
- /* */
- /*===================================================================*/
-
- static enum boolean isitem(
- const char *lineptr, /* Ptr to line text */
- const int indent) /* Count of leading blanks */
- {
- const char *p ;
- int l ;
-
- lineptr += indent ;
-
- if ( (p = strchr(lineptr,' ')) == NULL )
- {
- return FALSE ;
- }
-
- if ( (l = p - lineptr) == 1 )
- {
- if ( strchr("*-o",*lineptr) != NULL )
- {
- return TRUE ;
- }
- }
- else
- {
- p-- ;
-
- if ( *lineptr == '(' && *p == ')' )
- {
- lineptr++ ;
- l -= 2 ;
- if ( l == 1 && isalpha(*lineptr) )
- {
- return TRUE ;
- }
- return (isnumbered(lineptr,l) | isroman(lineptr,l)) ;
- }
-
- if ( *p == ')' )
- {
- l-- ;
- if ( l == 1 && isalpha(*lineptr) )
- {
- return TRUE ;
- }
- return (isnumbered(lineptr,l) | isroman(lineptr,l)) ;
- }
-
- if ( *p == '.' )
- {
- l-- ;
- return (isnumbered(lineptr,l) | isroman(lineptr,l)) ;
- }
- }
-
- return isroman(lineptr,l) ;
- }
-
- /*===================================================================*/
- /* */
- /* isnumbered - check for one or two digit number */
- /* ---------- */
- /* */
- /* This function checks that the argument passed is either a one */
- /* or two digit number. */
- /* */
- /*===================================================================*/
-
- static enum boolean isnumbered(
- const char *p, /* Ptr to item number */
- const int l) /* Length of item number */
- {
- if ( l == 1 )
- {
- if ( isdigit(*p) )
- {
- return TRUE ;
- }
- }
- else if ( l == 2 )
- {
- if ( isdigit(*p) && isdigit(*(p+1)) )
- {
- return TRUE ;
- }
- }
- return FALSE ;
- }
-
- /*===================================================================*/
- /* */
- /* isroman - check for roman numeral */
- /* ------- */
- /* */
- /* This function checks that the argument passed is a roman numeral */
- /* in the range one to twenty (i - xx). */
- /* */
- /*===================================================================*/
-
- static enum boolean isroman(
- const char *p, /* Ptr to item number */
- const int l) /* Length of item number */
- {
- static const char *const roman[] =
- {
- "i",
- "v",
- "x",
- "ii",
- "iv",
- "vi",
- "ix",
- "xi",
- "xv",
- "xx",
- "vii",
- "iii",
- "xii",
- "xiv",
- "xvi",
- "xix",
- "viii",
- "xiii",
- "xvii",
- "xviii"
- } ;
-
- static const char lroman[] =
- {
- 1, /* i */
- 1, /* v */
- 1, /* x */
- 2, /* ii */
- 2, /* iv */
- 2, /* vi */
- 2, /* ix */
- 2, /* xi */
- 2, /* xv */
- 2, /* xx */
- 3, /* vii */
- 3, /* iii */
- 3, /* xii */
- 3, /* xiv */
- 3, /* xvi */
- 3, /* xix */
- 4, /* viii */
- 4, /* xiii */
- 4, /* xvii */
- 5, /* xviii */
- 99 /* end of list */
- } ;
-
- int i,j ;
-
- if ( strspn(p,"ivx") != l || l > 5 )
- {
- return FALSE ;
- }
-
- for ( i = 0 ; l > lroman[i] ; i++ ) ;
-
- for ( ; l == lroman[i] ; i++ )
- {
- j = 0 ;
- while ( p[j] == roman[i][j] )
- {
- j++ ;
- if ( j == l )
- {
- return TRUE ;
- }
- }
- }
- return FALSE ;
- }
-
- /*===================================================================*/
- /* */
- /* isterm - test for definition list item */
- /* ------ */
- /* */
- /* Assume a line starts with a definition term if: */
- /* */
- /* - line is indented less than following line */
- /* - line extends beyond ident of following line */
- /* - indent of following line matches start of a word on this line */
- /* */
- /*===================================================================*/
-
- static enum boolean isterm(
- const char *lineptr, /* Ptr to line text */
- int len, /* Length of line */
- int indent, /* Indent of this line */
- int nextindent) /* Indent of next line */
- {
- if ( indent < nextindent &&
- len > nextindent &&
- lineptr[nextindent] != ' ' &&
- lineptr[nextindent-1] == ' ' )
- {
- return TRUE ;
- }
- return FALSE ;
- }
-
- /*===================================================================*/
- /* */
- /* istag - test for list of non-break GML tags */
- /* ----- */
- /* */
- /* This function tests the start of the line for the presence of */
- /* GML tags which are not required to start on a separate line. */
- /* */
- /*===================================================================*/
-
- static enum boolean istag(
- const char *lineptr) /* Ptr to line text */
- {
- static const char *const tags[] =
- {
- "HP", /* :hp and :ehp */
- "CIT", /* :cit and :ecit */
- "Q", /* :q and :eq */
- "FNREF", /* :fnref and :efnref */
- "HDREF" /* :hdref and :ehdref */
- } ;
- #define ntags (sizeof(tags)/sizeof(char *))
-
- int i,j,c ;
- const char *tag ;
-
- lineptr++ ;
-
- if ( toupper(*lineptr) == 'E' )
- {
- lineptr++ ;
- }
-
- for ( i = 0 ; i < ntags ; i++ )
- {
- tag = tags[i] ;
- c = tag[0] ;
- j = 0 ;
- while ( c == toupper(lineptr[j]) )
- {
- j++ ;
- if ( (c = tag[j]) == '\0' )
- {
- return TRUE ;
- }
- }
- }
- return FALSE ;
- }
-
- /*===================================================================*/
- /* */
- /* isshort - check for short line */
- /* ------- */
- /* */
- /* This function checks for a short line ending with a punctuation */
- /* character (i.e. a 'break' line). */
- /* */
- /*===================================================================*/
-
- static enum boolean isshort(
- const char *lineptr, /* Ptr to line text */
- const int len, /* Length of line */
- const int brklen) /* Max length of short line */
- {
- if ( len > brklen || strchr(".:!?",lineptr[len-1]) == NULL )
- {
- return FALSE ;
- }
- return TRUE ;
- }
-
- /*===================================================================*/
- /* */
- /* sethangingindent - scan forward setting hanging indent flag */
- /* ---------------- */
- /* */
- /* This function scans forward from the current line setting the */
- /* hanging-indent flag on all lines which have the same or greater */
- /* indent than the line following the current line. Null lines */
- /* are ignored. */
- /* */
- /*===================================================================*/
-
- static void sethangingindent(
- int line, /* Current line number */
- int nlines, /* Number of lines */
- int nextindent, /* Indent of next line */
- char *(*lineptrs)[], /* Ptr to line ptr array */
- char (*lineflgs)[]) /* Ptr to line flags array */
- {
- char *p ;
-
- for ( ++line ;
- line <= nlines &&
- (*(p = (*lineptrs)[line]) == '\0' ||
- (leadblanks(p) >= nextindent)) ;
- line++ )
- {
- if ( *p != '\0' )
- {
- (*lineflgs)[line] |= hinflg ;
- }
- }
- }
-
- /*===================================================================*/
- /* */
- /* putdup - write 'n' duplicate characters to output file */
- /* ------ */
- /* */
- /* This function writes a single character repeatedly to the */
- /* 1stWord+ document output file. */
- /* */
- /*===================================================================*/
-
- static void putdup(
- const int c, /* Character to be repeated */
- const int n, /* Duplication count */
- FILE *fileptr) /* File pointer */
- {
- int i ;
-
- for ( i = 0 ; i < n ; i++ )
- {
- fputc(c,fileptr) ;
- }
- }
-
- /*===================================================================*/
-