summaryrefslogtreecommitdiffstats
path: root/private/sdktools/doctor
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/sdktools/doctor
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/sdktools/doctor')
-rw-r--r--private/sdktools/doctor/c2rtf.c691
-rw-r--r--private/sdktools/doctor/doctor.c184
-rw-r--r--private/sdktools/doctor/doctor.h202
-rw-r--r--private/sdktools/doctor/makefile6
-rw-r--r--private/sdktools/doctor/readtxt.c1425
-rw-r--r--private/sdktools/doctor/sources17
-rw-r--r--private/sdktools/doctor/strings.c113
-rw-r--r--private/sdktools/doctor/strings.h24
-rw-r--r--private/sdktools/doctor/symbol.c489
-rw-r--r--private/sdktools/doctor/symbol.h53
-rw-r--r--private/sdktools/doctor/writertf.c251
11 files changed, 3455 insertions, 0 deletions
diff --git a/private/sdktools/doctor/c2rtf.c b/private/sdktools/doctor/c2rtf.c
new file mode 100644
index 000000000..5e80fbf75
--- /dev/null
+++ b/private/sdktools/doctor/c2rtf.c
@@ -0,0 +1,691 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#define IN
+#define OUT
+#define MAX_COMMENT_SIZE 10000
+#define isalpha(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
+#define isnum(c) (c >= '0' && c <= '9')
+#define ISWHITESPACE(c) (c == ' ' || c == '\t')
+
+char *Header[] = {
+"{\\rtf1\\pc {\\info{\\revtim\\mo07\\dy31\\yr1989}{\\creatim\\mo07\\dy31\\yr1989}",
+"{\\nofchars9564}}\\deff0{\\fonttbl{\\f0\\fmodern pica;}",
+"{\\f1\\fmodern Courier;}{\\f2\\fmodern elite;}{\\f3\\fmodern prestige;}",
+"{\\f4\\fmodern lettergothic;}{\\f5\\fmodern gothicPS;}",
+"{\\f6\\fmodern cubicPS;}{\\f7\\fmodern lineprinter;}",
+"{\\f8\\fswiss Helvetica;}{\\f9\\fmodern avantegarde;}",
+"{\\f10\\fmodern spartan;}{\\f11\\fmodern metro;}",
+"{\\f12\\fmodern presentation;}{\\f13\\fmodern APL;}{\\f14\\fmodern OCRA;}",
+"{\\f15\\fmodern OCRB;}{\\f16\\froman boldPS;}{\\f17\\froman emperorPS;}",
+"{\\f18\\froman madaleine;}{\\f19\\froman zapf humanist;}",
+"{\\f20\\froman classic;}{\\f21\\froman roman f;}{\\f22\\froman roman g;}",
+"{\\f23\\froman roman h;}{\\f24\\froman timesroman;}{\\f25\\froman century;}",
+"{\\f26\\froman palantino;}{\\f27\\froman souvenir;}{\\f28\\froman garamond;}",
+"{\\f29\\froman caledonia;}{\\f30\\froman bodini;}{\\f31\\froman university;}",
+"{\\f32\\fscript script;}{\\f33\\fscript scriptPS;}{\\f34\\fscript script c;}",
+"{\\f35\\fscript script d;}{\\f36\\fscript commercial script;}",
+"{\\f37\\fscript park avenue;}{\\f38\\fscript coronet;}",
+"{\\f39\\fscript script h;}{\\f40\\fscript greek;}{\\f41\\froman kana;}",
+"{\\f42\\froman hebrew;}{\\f43\\froman roman s;}{\\f44\\froman russian;}",
+"{\\f45\\froman roman u;}{\\f46\\froman roman v;}{\\f47\\froman roman w;}",
+"{\\f48\\fdecor narrator;}{\\f49\\fdecor emphasis;}",
+"{\\f50\\fdecor zapf chancery;}{\\f51\\fdecor decor d;}",
+"{\\f52\\fdecor old english;}{\\f53\\fdecor decor f;}{\\f54\\fdecor decor g;}",
+"{\\f55\\fdecor cooper black;}{\\f56\\ftech Symbol;}{\\f57\\ftech linedraw;}",
+"{\\f58\\ftech math7;}{\\f59\\ftech math8;}{\\f60\\ftech bar3of9;}",
+"{\\f61\\ftech EAN;}{\\f62\\ftech pcline;}{\\f63\\ftech tech h;}}",
+"{\\stylesheet {\\*\\cs1\\b\\f16 CT;}{\\*\\cs2\\b\\f16 CP;}{\\*\\cs3\\b\\f16 CD;}",
+"{\\*\\cs4\\i\\f16 CI;}{\\*\\cs5\\f16\\ul CR;}{\\*\\s30\\sl-240\\sa240 \\f16",
+"Normal;}{\\*\\s31\\li720\\fi-720\\sl-240\\sa240\\tqr\\tx432\\tx720 \\f16 L1;}",
+"{\\*\\s32\\li1440\\fi-1440\\sl-240\\sa240\\tqr\\tx1152\\tx1440 \\f16 L2;}{\\*\\s33",
+"\\li1152\\sl-240\\sa240 \\b\\f16\\ul P3;}{\\*\\s34\\li1728\\fi-576\\sl-240\\sa240",
+"\\f16 P4;}{\\*\\s35\\li720\\sl-240\\sa240 \\f16 S1;}{\\*\\s36",
+"\\li1440\\sl-240\\sa240 \\f16 S2;}{\\*\\s42\\ri576\\li576\\sl-240\\sa240 \\i\\f16",
+"N1;}{\\*\\s43\\ri576\\li1296\\sl-240\\sa240 \\i\\f16 N2;}{\\*\\s44",
+"\\li1152\\fi-576\\sl-240 \\f16 NL;}{\\*\\s52\\sl-240\\tx576\\tx1152\\tx1728",
+"\\f16 PP;}{\\*\\s53\\li1152\\fi-576\\sl-240\\sa240 \\f16 PL;}{\\*\\s54",
+"\\li1152\\sl-240\\sa240 \\f16 P2;}{\\*\\s62\\sl-240\\tqr\\tx9936 \\b\\f16 RH;}",
+"{\\*\\s63\\qc\\sl-240 \\b\\f16 RF;}{\\*\\s64\\sl-240\\sa240 \\b\\f16 TN;}{\\*\\s65",
+"\\sl-240\\sa240 \\i\\f16 TA;}{\\*\\s66\\sl-240 \\i\\f16 TR;}{\\*\\s72",
+"\\li576\\fi-576\\sl-240\\sa240 \\f16 PT;}{\\*\\s73",
+"\\li576\\sl-240\\tx1152\\tx1728\\tx2304\\tx2880\\tx3456\\tx4032\\tx4608\\tx5184\\tx5760\\tx6336\\tx6912",
+"\\f7\\fs17 PC;}{\\*\\s74\\keep\\sl-240 \\f1 PD;}{\\*\\s88\\keepn\\sl-240\\sa240",
+"\\b\\f16 heading 1;}{\\*\\s89\\keepn\\sl-240\\sa240 \\b\\f16 heading 2;}{\\*\\s90",
+"\\keepn\\sl-240\\sa240 \\b\\f16 heading 3;}{\\*\\s91\\keepn\\sl-240\\sa240",
+"\\b\\f16 heading 4;}{\\*\\s99",
+"\\li288\\fi-288\\sl-240\\sb240\\tldot\\tx8064\\tqr\\tx8640 \\f16 toc 1;}",
+"{\\*\\s100\\li576\\fi-288\\sl-240\\tldot\\tx8064\\tqr\\tx8640 \\f16 toc 2;}",
+"{\\*\\s101\\li864\\fi-288\\sl-240\\tldot\\tx8064\\tqr\\tx8640 \\f16 toc 3;}",
+"{\\*\\s102\\li1152\\fi-288\\sl-240\\tldot\\tx8064\\tqr\\tx8640 \\f16 toc 4;}",
+"{\\*\\ds105\\linex576\\endnhere\\pgnrestart standard division;}{\\*\\ds106",
+"\\pgnlcrm\\linex576\\endnhere\\pgnrestart DT;}}",
+"\0"
+};
+
+FILE *InputFile;
+char FileName[50],Function[50];
+char GetWord();
+void DoFormat(),GlobalFormat();
+int GetComment(),strpos();
+char Comment[MAX_COMMENT_SIZE];
+char *cp; /* pointer to current value in Comment */
+
+int
+_CRTAPI1
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int i,nummods;
+ char *modules[255];
+
+
+ nummods = 0;
+ if(argc != 3 && argc != 1) {
+ fprintf(stderr,"Usage: c2rtf [program function]\n");
+ exit(1);
+ }
+
+ i = 0;
+ while(*Header[i] != '\0') {
+ printf("%s\n",Header[i++]);
+ }
+ printf("\\ftnbj\\ftnrestart\\widowctrl \\sectd \\linex576\\endnhere");
+ printf(" \\pard \\sl-240\n");
+
+ if(argc == 3) {
+ InputFile = fopen(argv[1],"r");
+ if(InputFile == NULL) {
+ fprintf(stderr,"c2rtf: Error opening file %s.\n",argv[1]);
+ exit(2);
+ }
+
+ strcpy(Function,argv[2]);
+ strcpy(FileName,argv[1]);
+ DoFormat();
+
+ fclose(InputFile);
+ } else {
+ if(scanf("%s",FileName) == EOF) {
+ exit(1);
+ }
+ InputFile = fopen(FileName,"r");
+ if(InputFile == NULL) {
+ fprintf(stderr,"c2rtf: Error opening file %s.\n",FileName);
+ } else {
+ modules[nummods] = (char *)malloc((strlen(FileName) + 1) * sizeof(char));
+ strcpy(modules[nummods++],FileName);
+ GlobalFormat();
+ }
+ fclose(InputFile);
+ while(scanf("%s",Function) != EOF) {
+ if(!strncmp(strchr(Function,'\0')-2,".c",2) ||
+ !strncmp(strchr(Function,'\0')-2,".s",2) ||
+ !strncmp(strchr(Function,'\0')-2,".h",2)) {
+ strcpy(FileName,Function);
+ InputFile = fopen(FileName,"r");
+ if(InputFile == NULL) {
+ fprintf(stderr,"c2rtf: Error opening file %s.\n",FileName);
+ continue;
+ }
+ for(i = 0; i < nummods; i++) {
+ if(!strcmp(modules[i],FileName)) {
+ break;
+ }
+ }
+ if(i == nummods) {
+ modules[nummods] = (char *)malloc((strlen(FileName) + 1) * sizeof(char));
+ strcpy(modules[nummods++],FileName);
+ GlobalFormat();
+ }
+ fclose(InputFile);
+ if(scanf("%s",Function) == EOF) {
+ exit(0);
+ }
+ }
+ InputFile = fopen(FileName,"r");
+ if(InputFile == NULL) {
+ fprintf(stderr,"c2rtf: Error opening file %s for %s.\n",FileName,Function);
+ continue;
+ }
+
+ DoFormat();
+
+ fclose(InputFile);
+ }
+ }
+
+ printf("}\n");
+ return 0;
+}
+
+int
+KillWhiteSpace(
+ char *killchars
+ )
+/*++
+
+Routine Description:
+
+ Removes white space from InputFile until non-whitespace character
+ is reached.
+
+Arguments:
+
+ killchars - characters to be removed; generally some of ' ', '\t', '\n'.
+
+Return Value:
+
+ Number of characters removed.
+
+--*/
+
+{
+ int i = 0;
+ char c;
+
+ c = getc(InputFile);
+ while(strpos(killchars,c) != -1) {
+ i++;
+ c = getc(InputFile);
+ }
+ ungetc(c,InputFile);
+ return(i);
+}
+
+char
+GetWord(
+ OUT char *word,
+ IN char todo
+ )
+/*++
+
+Routine Description:
+
+ Finds the next string of alphabetic characters in InputFile.
+ Only letters are used.
+
+Arguments:
+
+ word - pointer to space where the string is placed
+
+ todo - a character that determines whether to get the next word
+ from the input or the previous word (stored in the static last).
+
+Return value:
+
+ EOF if the end of file is reached before a word is found, 0 otherwise.
+
+--*/
+
+{
+ char c;
+ char *w;
+ static char last[50];
+
+ /* if todo is 'l' then return the previous word instead of next */
+ if(todo == 'l') {
+ strcpy(word,last);
+ return(1);
+ }
+
+ strcpy(last,word);
+ w = word;
+ c = getc(InputFile);
+ while(c != EOF && !(isalpha(c) || c == '_')) {
+ c = getc(InputFile);
+ }
+ if(c != EOF) {
+ *w++ = c;
+ }
+ while((c = getc(InputFile)) != EOF && (isalpha(c) || c == '_' || isnum(c))) {
+ *w++ = c;
+ }
+ ungetc(c,InputFile);
+ *w = '\0';
+ if(strlen(word) == 0)
+ return(EOF);
+ else
+ return(0);
+}
+
+void
+DoFormat(
+ )
+/*++
+
+Routine Description:
+
+ Performs actual parsing and output formating.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ char word[50],c;
+ int isfuncdef;
+
+ isfuncdef = 0;
+ do {
+ do {
+ if(GetWord(word,'c') == EOF) {
+ fprintf(stderr,"c2rtf: Function %s not found in %s.\n",Function,FileName);
+ return;
+ }
+ }
+ while(strcmp(word,Function));
+ KillWhiteSpace("\n\t ");
+ if(getc(InputFile) == '(') {
+ KillWhiteSpace("\t /");
+ c = getc(InputFile);
+ if(c == '\n') {
+ isfuncdef = 1;
+ }
+ if(c == ')') {
+ KillWhiteSpace(" \t\n");
+ c = getc(InputFile);
+ if(c != ';') {
+ ungetc(c,InputFile);
+ isfuncdef = 2;
+ }
+ }
+ }
+ }
+ while(!isfuncdef);
+
+ printf("\\s89\\keepn\\sl-240\\sa240 \\plain \\b\\f16 %s\\par\n",Function);
+
+ GetWord(word,'l');
+ printf("\\pard \\s30\\sl-240\\sa0 \\plain \\b\\f16 %s\\par\n",word);
+ if(isfuncdef == 1) {
+ printf("%s(\\par\n",Function);
+ do {
+ printf("\\tab ");
+ do {
+ GetWord(word,'c');
+ printf("%s ",word);
+ }
+ while(!strcmp(word,"IN") || !strcmp(word,"OUT"));
+ GetWord(word,'c');
+ printf("\\plain \\i\\f16 %s\\plain \\b\\f16 ",word);
+ KillWhiteSpace("\t ");
+ while((c = getc(InputFile)) != ',' && c != '\n') {
+ ungetc(c,InputFile);
+ GetWord(word,'c');
+ printf(" %s",word);
+ KillWhiteSpace("\t ");
+ }
+ if(c == '\n') {
+ printf("\\par\n\\tab )\\par");
+ } else {
+ printf(",\\par\n");
+ }
+ }
+ while(c != '\n');
+ } else {
+ printf("%s()\\par\n",Function);
+ }
+
+ if(GetComment()) {
+ printf("\\par \\pard\n");
+ return;
+ }
+
+ while(strncmp("Routine Description:",cp,20)) {
+ cp++;
+ if(*cp == '\0') {
+ fprintf(stderr,"c2rtf: Function %s in %s has no routine description.\n",Function,FileName);
+ printf("\\pard\n");
+ return;
+ }
+ }
+
+ printf("\\par\n");
+ printf("\\plain \\f16\\ul Routine Description:\\plain \\f16 \\par \\par\n");
+ printf("\\pard \\s53\\li576\\fi0\\sl-240\\sa240 ");
+ for(cp += 22; strchr(" \t\n/",*cp) != NULL; cp++);
+
+ while(strncmp("Arguments:",cp,10)) {
+ if(*cp == '\n') {
+ if(*(cp + 1) == '\n' || !strncmp(cp + 1, "//\n",3)) {
+ printf("\\par\n");
+ for(cp++; strchr(" \t\n/",*cp) != NULL; cp++);
+ continue;
+ } else {
+ putchar(' ');
+ for(cp++; strchr(" \t/",*cp) != NULL; cp++);
+ continue;
+ }
+ }
+ putchar(*cp);
+ cp++;
+
+ if(*cp == '\0') {
+ fprintf(stderr,"c2rtf: Function %s in %s lacks 'Arguments:'.\n",Function,FileName);
+ printf("\\pard\n");
+ return;
+ }
+ }
+
+ printf("\\pard \\plain \\f16\\ul Parameters:\\plain \\f16 \\par \\par\n");
+ printf("\\pard \\s53\\li1152\\fi-576\\sl-240\\sa240 ");
+ for(cp += 11; strchr(" \t\n/",*cp) != NULL; cp++);
+ printf("\\plain \\i\\f16 ");
+ do {
+ putchar(*cp++);
+ }
+ while(isalpha(*cp));
+ printf("\\plain \\f16 ");
+
+ while(strncmp("Return Value",cp,12)) {
+ if(*cp == '\n') {
+ for(cp++; strchr(" \t/",*cp) != NULL; cp++);
+ if(*cp == '\n') {
+ while(strchr(" \t\n/",*cp) != NULL) {
+ cp++;
+ }
+ if(!strncmp("Return Value",cp,12)) {
+ continue;
+ }
+ printf("\\par\n");
+ printf("\\plain \\i\\f16 ");
+ do {
+ putchar(*cp++);
+ }
+ while(isalpha(*cp));
+ printf("\\plain \\f16 ");
+ continue;
+ } else {
+ while(strchr(" \t\n/",*cp) != NULL) {
+ cp++;
+ }
+ putchar(' ');
+ putchar(*cp);
+ }
+ } else {
+ putchar(*cp);
+ }
+ cp++;
+ if(*cp == '\0') {
+ fprintf(stderr,"c2rtf: Function %s in %s lacks 'Return Value'.\n",Function,FileName);
+ printf("\\pard\n");
+ return;
+ }
+
+ }
+
+ printf("\\par \\pard\n");
+ printf("\\plain \\f16\\ul Return Value:\\plain \\f16 \\par \\par\n");
+ printf("\\pard \\s53\\li576\\fi0\\sl-240\\sa240 ");
+ for(cp += 14; strchr(" \t\n/",*cp) != NULL; cp++);
+
+ while(*cp != '\0' && strncmp(cp,"Environment",11)) {
+ if(*cp == '\n') {
+ for(cp++; strchr(" \t/",*cp) != NULL; cp++);
+ if(*cp == '\n') {
+ printf("\\par\n");
+ for(cp++; strchr(" \n\t/",*cp) != NULL && *cp != EOF; cp++) {
+ if(*cp == '\0') {
+ break;
+ }
+ }
+ continue;
+ } else {
+ putchar(' ');
+ continue;
+ }
+ }
+ putchar(*cp);
+ cp++;
+ }
+
+ if(*cp == '\0') {
+ printf("\\pard \\plain\n");
+ return;
+ }
+
+ printf("\\pard\n");
+ printf("\\plain \\f16\\ul Environment:\\plain \\f16 \\par \\par\n");
+ printf("\\pard \\s53\\li576\\fi0\\sl-240\\sa240 ");
+ for(cp += 14; strchr(" \t\n/",*cp) != NULL; cp++);
+
+ while(*cp != '\0') {
+ if(*cp == '\n') {
+ for(cp++; strchr(" \t/",*cp) != NULL; cp++);
+ if(*cp == '\n') {
+ printf("\\par\n");
+ for(cp++; strchr(" \n\t/",*cp) != NULL && *cp != EOF; cp++) {
+ if(*cp == '\0') {
+ break;
+ }
+ }
+ continue;
+ } else {
+ putchar(' ');
+ continue;
+ }
+ }
+ putchar(*cp);
+ cp++;
+ }
+ printf("\\pard \\plain\n");
+}
+
+int
+GetComment(
+ )
+/*++
+
+Routine Description:
+
+ This routine loads the next comment in the input, defined in the normal C
+ manner with / *++ and --* / (no spaces in there) into the Comment[]
+ array.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ 0 if successful
+ 1 if { precedes the next comment
+ 2 if the comment is not ended
+ 3 if comment size is larger than MAX_COMMENT_SIZE
+
+--*/
+{
+ int index,i;
+ char temp[5];
+
+
+ for(i = 0; i<4; i++) {
+ if((temp[i] = getc(InputFile)) == EOF) {
+ fprintf(stderr,"No comment found.\n");
+ return(1);
+ }
+ }
+ temp[4] = '\0';
+
+ while(strcmp(temp,"/*++") && strcmp(temp + 2,"//")) {
+ temp[0] = temp[1];
+ temp[1] = temp[2];
+ temp[2] = temp[3];
+ temp[3] = getc(InputFile);
+ if(temp[3] == EOF || temp[3] == '{') {
+ fprintf(stderr,"c2rtf: No comment found in %s of %s.\n",Function,FileName);
+ return(1);
+ }
+ }
+
+ for(i = 0; i<4; i++) {
+ if((temp[i] = getc(InputFile)) == EOF) {
+ fprintf(stderr,"c2rtf: Comment not ended in %s of %s.\n",Function,FileName);
+ return(1);
+ }
+ }
+ temp[4] = '\0';
+
+ index = 0;
+ while(strcmp(temp,"--*/") && strcmp(temp,"//--")) {
+ if(temp[0] == '\t') {
+ for(i=0; i<8; i++) {
+ Comment[index++] = ' ';
+ }
+ } else {
+ Comment[index++] = temp[0];
+ }
+ temp[0] = temp[1];
+ temp[1] = temp[2];
+ temp[2] = temp[3];
+ temp[3] = getc(InputFile);
+ if(temp[3] == EOF) {
+ fprintf(stderr,"c2rtf: Comment not ended in %s of %s.\n",Function,FileName);
+ return(2);
+ }
+ if(index >= MAX_COMMENT_SIZE) {
+ fprintf(stderr,"c2rtf: Comment too large in %s of %s.\n",Function,FileName);
+ return(3);
+ }
+ }
+
+ Comment[index] = '\0';
+ cp = Comment;
+ return(0);
+}
+
+int
+strpos(
+ char *s,
+ char c
+ )
+
+/*++
+
+Routine Description:
+
+ Finds the location of the character c in the string s. See section
+ 15.5 of _C: A Reference Manual_, page 300, for complete description.
+
+Parameters:
+
+ s - "haystack" of characters to search for.
+
+ c - character to search for.
+
+Return Value:
+
+ The position of c in s or -1 if c is not in s.
+
+--*/
+
+{
+ int i;
+
+ for(i = 0; *s != '\0'; s++,i++) {
+ if(c == *s) {
+ return(i);
+ }
+ }
+ return(-1);
+}
+
+void GlobalFormat(
+ )
+
+/*++
+
+Routine Description:
+
+ Formats the abstract of a module into RTF format.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ char c,word[50],basename[75],*s;
+ int i;
+
+ do {
+ if(GetWord(word,'c') == EOF) {
+ fprintf(stderr,"Module %s lacks an abstract.\n");
+ return;
+ }
+ }
+ while(strcmp("Abstract",word));
+
+ while((c = getchar()) == ' ' || c == '\t' || c == '\n') {
+ i++;
+ }
+
+ i = 0;
+ if(c == '\"') {
+ while((c = getchar()) != '\"') {
+ basename[i++] = c;
+ }
+ basename[i] = '\0';
+ } else {
+ ungetc(c,stdin);
+ for(s = FileName; *s != '\0'; s++) {
+ if(*s == '\\') {
+ i = 0;
+ } else {
+ basename[i++] = *s;
+ }
+ }
+ basename[i] = '\0';
+ }
+
+ if(!strcmp("continue",basename)) {
+ return;
+ }
+
+ printf("\\page\n");
+ printf("\\pard \\s88\\keepn\\sl-240\\sa240 \\plain \\b\\f16 %s\\par",basename);
+ printf("\\pard \\li576\\sl-240\\sa240 \\plain \\f16\n");
+
+ strcpy(word,"\0");
+ KillWhiteSpace(" \t\n/:");
+ do {
+ c = getc(InputFile);
+ if(c == '\n') {
+ putchar(' ');
+ KillWhiteSpace(" \t/");
+ c = getc(InputFile);
+ if(c == '\n') {
+ printf("\\par\n");
+ KillWhiteSpace(" \t\n/");
+ GetWord(word,'c');
+ if(strcmp(word,"Author")) {
+ printf("%s",word);
+ }
+ } else {
+ putchar(c);
+ }
+ } else {
+ putchar(c);
+ }
+ }
+ while(strcmp(word,"Author"));
+
+ printf("\\pard\n");
+
+ return;
+
+}
diff --git a/private/sdktools/doctor/doctor.c b/private/sdktools/doctor/doctor.c
new file mode 100644
index 000000000..6edafc473
--- /dev/null
+++ b/private/sdktools/doctor/doctor.c
@@ -0,0 +1,184 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ doctor.c
+
+Abstract:
+
+ Main source file for the doctor program. This program reads plain
+ text source files, with limited markups to describe formatting. It
+ output .RTF files, which can then be read into WORD to convert to
+ .DOC files. Hopefully, we can run the RTF_OS2.EXE conversion program
+ directly.
+
+Author:
+
+ Steve Wood (stevewo) 02-Mar-1989
+
+
+Revision History:
+
+--*/
+
+#include "doctor.h"
+
+//
+// Variables maintained by doctor.c
+//
+
+int DoctorReturnCode = 0;
+
+BOOLEAN VerboseOutput = FALSE;
+BOOLEAN KeepIntermediateFile = FALSE;
+BOOLEAN OutputQuickHelp = FALSE; // -h switch specified
+BOOLEAN OutputRichTextFormat = TRUE; // -r switch NOT specified
+
+BOOLEAN
+ConstructFileNames( PSZ FileNameArgument );
+
+char TxtFileName[ MAXPATHLEN ]; // Full path spec of text input file
+char RtfFileName[ MAXPATHLEN ]; // Full path spec of RTF output file
+char DocFileName[ MAXPATHLEN ]; // Full path spec of RTF output file
+char HlpFileName[ MAXPATHLEN ]; // Full path spec of QH output file
+
+#define RTF2DOC_PROGRAM "RTF_OS2.EXE"
+char ProgramName[ MAXPATHLEN ]; // Full path name for RTF_OS2.EXE
+char Arguments[ 4+2*MAXPATHLEN ]; // Command line arguments for RTF_OS2.EXE
+
+void
+PrintUsage( void )
+{
+ fprintf( stderr, "usage: DOCTOR [-?] [-v] [-k] {.TXT filename}\n" );
+}
+
+
+int
+_CRTAPI1
+main(
+ int argc,
+ char *argv[]
+ )
+{
+ register char *s, c;
+ BOOLEAN result;
+ PROCESS_INFORMATION ProcessInformation;
+ STARTUPINFO StartupInfo;
+
+ if (argc < 2) {
+ PrintUsage();
+ exit( 1 );
+ }
+
+ while (--argc) {
+ s = *++argv;
+ if (*s == '-' || *s == '/') {
+ while (c = *++s) {
+ switch( tolower( c ) ) {
+ case '?': PrintUsage();
+ exit( 1 );
+ break;
+
+ case 'h': OutputQuickHelp = TRUE;
+ break;
+
+ case 'k': KeepIntermediateFile = TRUE;
+ break;
+
+ case 'v': VerboseOutput = TRUE;
+ break;
+
+ default:
+ fprintf( stderr, "Invalid switch: %c\n", (USHORT)c );
+ break;
+ }
+ }
+ }
+ else
+ if (ConstructFileNames( s )) {
+ fprintf( stderr, "Reading %s", TxtFileName );
+ if (InitTxtFileReader( TxtFileName )) {
+ fprintf( stderr, "\n" );
+ if (OutputRichTextFormat) {
+ if (!OpenRtfFile( RtfFileName )) {
+ fprintf( stderr,
+ "Unable to open intermediate file - %s\n",
+ RtfFileName );
+ exit(1);
+ }
+ }
+
+ if (OutputRichTextFormat || OutputQuickHelp) {
+ result = ProcessTxtFile();
+
+ if (OutputRichTextFormat)
+ CloseRtfFile();
+ if (OutputQuickHelp)
+ ;
+ }
+
+ TermTxtFileReader();
+ }
+ else {
+ fprintf( stderr, " - unable to open\n" );
+ DoctorReturnCode = 1;
+ }
+ }
+ }
+
+ return( DoctorReturnCode );
+}
+
+BOOLEAN
+ConstructFileNames( PSZ FileNameArgument )
+{
+ register char *s;
+
+ RtfFileName[ 0 ] = '\0';
+ DocFileName[ 0 ] = '\0';
+ HlpFileName[ 0 ] = '\0';
+
+ rootpath( FileNameArgument, TxtFileName );
+ while (!(s = strchr( TxtFileName, '.' ))) {
+ strcat( TxtFileName, ".txt" );
+ }
+
+ *s = '\0';
+ strcpy( RtfFileName, TxtFileName );
+ strcpy( DocFileName, TxtFileName );
+ *s = '.';
+ strcat( RtfFileName, ".rtf" );
+ strcat( DocFileName, ".doc" );
+
+ return( TRUE );
+}
+
+
+PVOID
+AllocateMemory(
+ IN ULONG NumberBytes
+ )
+{
+ register PVOID Memory = (PVOID)calloc( NumberBytes, 1 );
+
+ if (!Memory)
+ fprintf( stderr, "*** Out of memory, need %d bytes\n", NumberBytes );
+
+ return( Memory );
+}
+
+
+PVOID
+FreeMemory(
+ IN PVOID Memory
+ )
+{
+ if (Memory) {
+ free( (char *)Memory );
+ Memory = (PVOID)NULL;
+ }
+
+ return( NULL );
+}
diff --git a/private/sdktools/doctor/doctor.h b/private/sdktools/doctor/doctor.h
new file mode 100644
index 000000000..edcee231c
--- /dev/null
+++ b/private/sdktools/doctor/doctor.h
@@ -0,0 +1,202 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ doctor.h
+
+Abstract:
+
+ Top level include file for doctor program
+
+Author:
+
+ Steve Wood (stevewo) 02-Mar-1989
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+#include <tools.h>
+
+#include "strings.h"
+#include "symbol.h"
+
+typedef struct _RESULTCODES { /* resc */
+ USHORT codeTerminate;
+ USHORT codeResult;
+} RESULTCODES;
+typedef RESULTCODES far *PRESULTCODES;
+
+typedef USHORT SEL, far *PSEL;
+
+#define MAKEP(sel, off) ((PVOID)MAKEULONG(off, sel))
+#define MAKEULONG(l, h) ((ULONG)(((USHORT)(l)) | ((ULONG)((USHORT)(h))) << 16))
+
+USHORT pascal far DosAllocSeg( USHORT, PSEL, USHORT );
+USHORT pascal far DosReallocSeg(USHORT, SEL);
+USHORT pascal far DosFreeSeg( SEL );
+
+USHORT pascal far DosExecPgm(char far *, SHORT, USHORT, char far *, char far *, PRESULTCODES, char far *);
+USHORT pascal far DosSearchPath(USHORT, char far *, char far *, char far *, USHORT);
+
+/* DosExecPgm functions */
+
+#define EXEC_SYNC 0
+#define EXEC_ASYNC 1
+#define EXEC_ASYNCRESULT 2
+#define EXEC_TRACE 3
+#define EXEC_BACKGROUND 4
+#define EXEC_LOAD 5
+
+#define SEARCH_CUR_DIRECTORY 0x01
+#define SEARCH_ENVIRONMENT 0x02
+#define SEARCH_PATH 0x00
+
+//
+// Entry points in doctor.c
+//
+PVOID
+AllocateMemory(
+ IN ULONG NumberBytes
+ );
+
+PVOID
+FreeMemory(
+ IN PVOID Memory
+ );
+
+//
+// Entry points in readtxt.c
+//
+VOID
+ErrorMessage(
+ IN PSZ FormatString,
+ IN PSZ InsertString
+ );
+
+BOOLEAN
+InitTxtFileReader(
+ IN PSZ TxtFileName
+ );
+
+BOOLEAN
+TermTxtFileReader( VOID );
+
+#define MAXLINELENGTH 1024
+#define DOCTORCOMMANDCHAR '.'
+#define DOCTORLINECONTCHAR '\\'
+
+BOOLEAN
+ProcessTxtFile( VOID );
+
+
+//
+// Entry points in writertf.c
+//
+BOOLEAN
+OpenRtfFile(
+ IN PSZ RtfFileName
+ );
+
+
+BOOLEAN
+CloseRtfFile( VOID );
+
+BOOLEAN
+RtfTitlePage(
+ IN PSZ Title,
+ IN PSZ Author,
+ IN PSZ Revision,
+ IN PSZ Creation
+ );
+
+BOOLEAN
+RtfHeading(
+ ULONG HeadingLevel,
+ PSZ HeadingNumber,
+ PSZ HeadingTitle
+ );
+
+BOOLEAN
+RtfParagraph(
+ PSZ ParagraphStyle,
+ PSZ CharStyle,
+ PSZ ParagraphBullet,
+ PSZ ParagraphText
+ );
+
+BOOLEAN
+RtfOpenPara(
+ PSZ ParagraphStyle,
+ PSZ LeadingText
+ );
+
+BOOLEAN
+RtfClosePara(
+ PSZ TrailingText
+ );
+
+BOOLEAN
+RtfWord(
+ PSZ CharStyle,
+ PSZ LeadingText,
+ PSZ WordText
+ );
+
+#define EMDASH "\\f1 \\plain "
+
+#define CS_NORMAL "\\plain "
+#define CS_CP "\\cs2\\b\\f16 "
+#define CS_CD "\\cs3\\b\\f16 "
+#define CS_CT "\\cs1\\b\\f16 "
+#define CS_CI "\\cs4\\i\\f16 "
+#define CS_CR "\\cs5\\f16\\ul "
+
+#define PS_PSKEEP "\\pard \\s48\\keepn\\sl-240\\sa240 \\plain \\f16 "
+#define PS_PS "\\pard \\s30\\sl-240\\sa240 \\plain \\f16 "
+#define PS_L1 "\\pard \\s31\\li720\\fi-720\\sl-240\\sa240\\tqr\\tx432\\tx720 \\plain \\f16 "
+#define PS_L2 "\\pard \\s32\\li1152\\fi-1152\\sl-240\\sa240\\tqr\\tx864\\tx1152 \\plain \\f16 "
+#define PS_L3 "\\pard \\s45\\li1584\\fi-1584\\sl-240\\sa240\\tqr\\tx1296\\tx1584 \\plain \\f16 "
+#define PS_L4 "\\pard \\s46\\li2016\\fi-2016\\sl-240\\sa240\\tqr\\tx1728\\tx2016 \\plain \\f16 "
+#define PS_T5 "\\pard \\s47\\li1440\\fi-288\\sl-240\\tldot\\tx8064\\tqr\\tx8640 \\plain \\f16 "
+#define PS_S1 "\\pard \\s35\\li432\\sl-240\\sa240 \\plain \\f16 "
+#define PS_S2 "\\pard \\s36\\li1152\\sl-240\\sa240 \\plain \\f16 "
+#define PS_PT "\\pard \\s72\\li576\\fi-576\\sl-240\\sa240 \\plain \\f16 "
+#define PS_PP "\\pard \\s52\\keep\\keepn\\sl-240\\tx576\\tx1152\\tx1728 \\plain \\f16 "
+#define PS_PL "\\pard \\s53\\li1152\\fi-576\\sl-240\\sa240 \\plain \\f16 "
+#define PS_P2 "\\pard \\s54\\li1152\\sl-240\\sa240 \\plain \\f16 "
+#define PS_PV "\\pard \\s55\\li576\\sl-240\\sa240 \\plain \\f16 "
+#define PS_P3 "\\pard \\s33\\li1152\\sl-240\\sa240 \\plain \\b\\f16\\ul "
+#define PS_P4 "\\pard \\s34\\li1728\\fi-576\\sl-240\\sa240 \\plain \\f16 "
+#define PS_P5 "\\pard \\s37\\li1728\\sl-240\\sa240 \\plain \\b\\f16\\ul "
+#define PS_P6 "\\pard \\s38\\li2304\\fi-576\\sl-240\\sa240 \\plain \\f16 "
+#define PS_P7 "\\pard \\s40\\li2304\\sl-240\\sa240 \\plain \\b\\f16\\ul "
+#define PS_P8 "\\pard \\s41\\li2880\\fi-576\\sl-240\\sa240 \\plain \\f16 "
+#define PS_N1 "\\pard \\s42\\ri576\\li576\\sl-240\\sa240 \\plain \\i\\f16 "
+#define PS_N2 "\\pard \\s43\\ri576\\li1296\\sl-240\\sa240 \\plain \\i\\f16 "
+#define PS_NL "\\pard \\s44\\li1152\\fi-576\\sl-240 \\plain \\f16 "
+#define PS_RH "\\pard \\s62\\sl-240\\tqr\\tx9936 \\plain \\b\\f16 "
+#define PS_RF "\\pard \\s63\\qc\\sl-240 \\plain \\b\\f16 "
+#define PS_PC "\\pard \\s73\\li576\\sl-240\\tx1152\\tx1728\\tx2304\\tx2880\\tx3456\\tx4032\\tx4608\\tx5184\\tx5760\\tx6336\\tx6912 \\f7\\fs17 "
+#define PS_PD "\\pard \\s74\\keep\\keepn\\sl-240 \\f1 "
+#define PS_H1 "\\pard \\s88\\keepn\\sl-240\\sa240 \\plain \\b\\f16 "
+#define PS_H2 "\\pard \\s89\\keepn\\sl-240\\sa240 \\plain \\b\\f16 "
+#define PS_H3 "\\pard \\s90\\keepn\\sl-240\\sa240 \\plain \\b\\f16 "
+#define PS_H4 "\\pard \\s91\\keepn\\sl-240\\sa240 \\plain \\b\\f16 "
+#define PS_H5 "\\pard \\s92\\keepn\\sl-240\\sa240 \\plain \\b\\f16 "
+#define PS_HN "\\pard \\keepn\\sl-240\\sa240 \\plain \\b\\f16 "
diff --git a/private/sdktools/doctor/makefile b/private/sdktools/doctor/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/sdktools/doctor/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/sdktools/doctor/readtxt.c b/private/sdktools/doctor/readtxt.c
new file mode 100644
index 000000000..f7617c69c
--- /dev/null
+++ b/private/sdktools/doctor/readtxt.c
@@ -0,0 +1,1425 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ readtext.c
+
+Abstract:
+
+ This module contains the code to read the text input format supported
+ by the doctor program.
+
+Author:
+
+ Steve Wood (stevewo) 02-Mar-1989
+
+Revision History:
+
+--*/
+
+#include "doctor.h"
+
+extern BOOLEAN VerboseOutput;
+
+BOOLEAN PreviousParagraphHeading;
+
+BOOLEAN
+PushTxtFile(
+ IN PSZ TxtFileName,
+ IN ULONG TxtFileEof
+ );
+
+BOOLEAN
+PopTxtFile(
+ VOID
+ );
+
+BOOLEAN
+ReadTxtPara(
+ BOOLEAN LineBreaksPara
+ );
+
+typedef struct _PARAINFO {
+ ULONG Type;
+ ULONG Level;
+ ULONG Lines;
+ BOOLEAN Bullet;
+ BOOLEAN FunctionPrototype;
+ BOOLEAN TrailingColon;
+ ULONG CountOfTokensBeforeEmDash;
+ PSZ EmDash;
+ PSZ Text;
+ PSZ NextWord;
+} PARAINFO, *PPARAINFO;
+
+PARAINFO TxtFilePara;
+
+#define TXT_PARA_BUFFER_LENGTH 4096
+char TxtParaBuffer[ TXT_PARA_BUFFER_LENGTH ];
+char TxtWordBuffer[ TXT_PARA_BUFFER_LENGTH/8 ];
+
+#define PARA_EOF 0
+#define PARA_CMD 1
+#define PARA_TXT 2
+
+PSZ
+GetParaWord(
+ BOOLEAN BlankDelimitted
+ );
+
+BOOLEAN
+ProcessTxtCommand(
+ VOID
+ );
+
+#define MAX_TXTFILESTACK_DEPTH 16
+#define MAX_PARAMTABLESTACK_DEPTH 8
+#define MAX_HEADING_LEVEL 8
+
+#define TFS_PARAGRAPH 0
+#define TFS_RETURN_TYPE 1
+#define TFS_FUNCTION_NAME 2
+#define TFS_PARAMETER_DECL 3
+#define TFS_END_FUNCTION 4
+#define TFS_FUNCTION_LIST 5
+
+#define TXT_FILE 0
+#define SRC_FILE_MODULE_HEADER 1
+#define SRC_FILE_FUNCTION_HEADER 2
+
+typedef struct _TXTFILE {
+ ULONG TxtFileState;
+ ULONG TxtFileEof;
+ PSTRING TxtFileName;
+ ULONG TxtLineNumber;
+ FILE *TxtFileHandle;
+} TXTFILE, *PTXTFILE;
+
+TXTFILE TxtFileStack[ MAX_TXTFILESTACK_DEPTH ];
+ULONG TxtFileStackDepth = MAX_TXTFILESTACK_DEPTH;
+PTXTFILE CurrentTxtFile;
+BOOLEAN TitlePageWritten = FALSE;
+ULONG LinesPerInch;
+BOOLEAN InLiteralText = FALSE;
+BOOLEAN LiteralFixedPitchFont = FALSE;
+BOOLEAN GlobalHighlight = FALSE;
+
+PSTRING TitleString;
+PSTRING AuthorName;
+PSTRING CreationDate;
+PSTRING RevisionNumber;
+
+SYMBOLTABLEHANDLE HighLightTable;
+
+SYMBOLTABLEHANDLE ParamTableStack[ MAX_PARAMTABLESTACK_DEPTH ];
+ULONG ParamTableStackDepth = MAX_PARAMTABLESTACK_DEPTH;
+ULONG HeadingLevels[ MAX_HEADING_LEVEL ];
+
+BOOLEAN ProcessHeadingCmd( PSZ CmdLine );
+BOOLEAN ProcessBeginCmd( PSZ CmdLine );
+BOOLEAN CheckForEndCmd( PSZ CmdLine );
+BOOLEAN ProcessBulletedList( VOID );
+BOOLEAN ProcessSimpleList( VOID );
+BOOLEAN ProcessFunctionList( VOID );
+BOOLEAN ProcessFunction( VOID );
+BOOLEAN ProcessFunctionPrototype( PULONG FuncType );
+
+#define FUNC_TYPE_VOID_RETURN 0x1
+#define FUNC_TYPE_VOID_PARMS 0x2
+
+BOOLEAN ProcessFunctionParameters( VOID );
+BOOLEAN ProcessStructure( VOID );
+BOOLEAN ProcessFunctionNames( VOID );
+BOOLEAN ProcessFieldNames( VOID );
+BOOLEAN ProcessLiteralText( VOID );
+BOOLEAN ProcessTextParagraph( VOID );
+
+BOOLEAN OutputParagraph(
+ PSZ ParaStyle,
+ PSZ Bullet,
+ ULONG ParaType
+ );
+
+#define OUTPUT_PARA_TEXT 0
+#define OUTPUT_PARA_FUNCLIST 1
+#define OUTPUT_PARA_FUNCPROTO 2
+
+VOID
+SetTxtFileState(
+ ULONG NewState
+ );
+
+PSZ
+GetNextWord(
+ PSZ *String,
+ ULONG *HighLight
+ );
+
+BOOLEAN
+GetIdentifier(
+ register PSZ DstString,
+ PSZ *SrcString
+ );
+
+PSZ
+AddFuncName(
+ PSZ FuncString
+ );
+
+PSZ
+AddParmName(
+ PSZ ParmString
+ );
+
+PSZ
+AddTypeName(
+ PSZ FuncString
+ );
+
+PSZ
+SkipSpaces(
+ IN PSZ String
+ );
+
+PSZ
+MarkToken(
+ IN PSZ String
+ );
+
+BOOLEAN
+InitTxtFileReader(
+ IN PSZ TxtFileName
+ )
+{
+ ULONG i;
+
+ if (!(HighLightTable = CreateSymbolTable( 37, TRUE ))) {
+ return( FALSE );
+ }
+
+ ParamTableStackDepth = MAX_PARAMTABLESTACK_DEPTH;
+
+ TitleString = MakeString( "*** .title ***" );
+ AuthorName = MakeString( "*** .author ***" );
+ CreationDate = MakeString( "*** .created ***" );
+ RevisionNumber = MakeString( "*** .revision ***" );
+
+ for (i=0; i<MAX_HEADING_LEVEL; i++) {
+ HeadingLevels[ i ] = 0;
+ }
+
+ TxtFileStackDepth = MAX_TXTFILESTACK_DEPTH;
+ CurrentTxtFile = NULL;
+ return( PushTxtFile( TxtFileName, TXT_FILE ) );
+}
+
+
+BOOLEAN
+TermTxtFileReader( VOID )
+{
+ HighLightTable = DestroySymbolTable( HighLightTable );
+
+ while (PopTxtFile())
+ ;
+
+ return( TRUE );
+}
+
+
+VOID
+ErrorMessage(
+ IN PSZ FormatString,
+ IN PSZ InsertString
+ )
+{
+ if (CurrentTxtFile) {
+ fprintf( stderr, "%s(%d) : ", CurrentTxtFile->TxtFileName->Buffer,
+ CurrentTxtFile->TxtLineNumber );
+ }
+
+ fprintf( stderr, FormatString, InsertString );
+ fprintf( stderr, "\n" );
+}
+
+
+BOOLEAN
+PushTxtFile(
+ IN PSZ TxtFileName,
+ IN ULONG TxtFileEof
+ )
+{
+ FILE *TxtFileHandle;
+ PSZ s;
+
+ if (TxtFileStackDepth &&
+ (TxtFileHandle = fopen( TxtFileName, "r" ))) {
+
+ s = TxtFileName;
+ while (*s) {
+ switch (*s++) {
+ case ':':
+ case '/':
+ case '\\':
+ TxtFileName = s;
+ }
+ }
+
+ CurrentTxtFile = &TxtFileStack[ --TxtFileStackDepth ];
+ CurrentTxtFile->TxtFileName = MakeString( TxtFileName );
+ CurrentTxtFile->TxtFileHandle = TxtFileHandle;
+ CurrentTxtFile->TxtLineNumber = 0;
+ CurrentTxtFile->TxtFileEof = TxtFileEof;
+ CurrentTxtFile->TxtFileState = TFS_PARAGRAPH;
+ return( TRUE );
+ }
+ else
+ return( FALSE );
+}
+
+
+BOOLEAN
+PopTxtFile(
+ VOID
+ )
+{
+ if (CurrentTxtFile && (CurrentTxtFile->TxtFileHandle != NULL)) {
+ fclose( CurrentTxtFile->TxtFileHandle );
+ CurrentTxtFile->TxtFileHandle = NULL;
+ }
+
+ if (TxtFileStackDepth < MAX_TXTFILESTACK_DEPTH)
+ CurrentTxtFile = &TxtFileStack[ ++TxtFileStackDepth ];
+ else
+ CurrentTxtFile = NULL;
+
+ return( (BOOLEAN)(CurrentTxtFile != NULL) );
+}
+
+
+BOOLEAN
+ReadTxtPara(
+ BOOLEAN LineBreaksPara
+ )
+{
+ PSZ s, s1;
+ ULONG n, cb;
+ int c;
+
+ s = TxtParaBuffer;
+ n = TXT_PARA_BUFFER_LENGTH;
+ *s = '\0';
+
+ TxtFilePara.Type = PARA_EOF;
+ TxtFilePara.Text = "*** END OF FILE ***";
+ TxtFilePara.NextWord = NULL;
+ TxtFilePara.FunctionPrototype = FALSE;
+ TxtFilePara.TrailingColon = FALSE;
+ TxtFilePara.Lines = 0;
+ while (TRUE) {
+ s1 = s;
+ while ((c = fgetc( CurrentTxtFile->TxtFileHandle )) != EOF) {
+ if (c == '\n') {
+ *s1 = '\0';
+ break;
+ }
+
+ if (c == '\\') {
+ *s1++ = (char)c;
+ }
+
+ *s1++ = (char)c;
+ }
+
+ if (c == EOF) {
+ break;
+ }
+
+ CurrentTxtFile->TxtLineNumber++;
+ cb = s1 - s;
+
+ if (!cb) {
+ if (!TxtFilePara.Lines) {
+ continue;
+ }
+
+ break;
+ }
+
+ TxtFilePara.Lines++;
+ s1 = s;
+ while (*s1 == ' ') {
+ s1++;
+ }
+
+ if (*s1 == DOCTORCOMMANDCHAR) {
+ if (s != s1) {
+ ErrorMessage( "Illegal command indentation - %s", s );
+ break;
+ }
+
+ if (TxtFilePara.Lines > 1) {
+ fseek( CurrentTxtFile->TxtFileHandle, -(long)cb, SEEK_CUR );
+ }
+ else {
+ TxtFilePara.Type = PARA_CMD;
+ }
+ break;
+ }
+
+ TxtFilePara.Type = PARA_TXT;
+ if (LineBreaksPara) {
+ break;
+ }
+
+ if (TxtFilePara.Lines > 1) {
+ cb -= (s1 - s);
+ strcpy( s, s1 );
+ }
+
+ s += cb;
+ *s++ = ' ';
+ *s = '\0';
+ n -= cb+1;
+ }
+
+ while (*--s == ' ') {
+ *s = '\0';
+ }
+
+ if (TxtFilePara.Lines == 1) {
+ if (*s == ':') {
+ TxtFilePara.TrailingColon = TRUE;
+ }
+ }
+ else {
+ if (!strcmp( s-1, " )" ) ||
+ !strcmp( s-2, " );" ) ||
+ !strcmp( s-6, " VOID )" ) ||
+ !strcmp( s-7, " VOID );" )
+ ) {
+ TxtFilePara.FunctionPrototype = TRUE;
+ }
+ }
+
+ s = TxtParaBuffer;
+ cb = 0;
+ while (*s == ' ') {
+ cb++;
+ s++;
+ }
+
+ TxtFilePara.Bullet = FALSE;
+ if (!LineBreaksPara && cb && !TxtFilePara.FunctionPrototype &&
+ (TxtFilePara.Type == PARA_TXT)
+ ) {
+ if (cb % 4) {
+ if (s[1] == ' ' && (s[0] == 'o' || s[0] == '-')) {
+ cb += 2;
+ *s++ = ' ';
+ if (*++s != ' ') {
+ TxtFilePara.Bullet = TRUE;
+ }
+ else {
+ ErrorMessage( "Illegal bulleted text - %s", TxtParaBuffer );
+ return( FALSE );
+ }
+ }
+ else {
+ ErrorMessage( "Illegal indentation - %s", TxtParaBuffer );
+ return( FALSE );
+ }
+ }
+
+ TxtFilePara.Level = cb/4;
+ }
+ else {
+ TxtFilePara.Level = 0;
+ }
+
+ TxtFilePara.CountOfTokensBeforeEmDash = 0;
+ TxtFilePara.EmDash = NULL;
+ TxtFilePara.Text = s;
+ TxtFilePara.NextWord = s;
+
+ if (!TxtFilePara.FunctionPrototype) {
+ while (*s) {
+ if (*s == ' ') {
+ s++;
+ if (*s == ' ') {
+ break;
+ }
+
+ if (TxtFilePara.CountOfTokensBeforeEmDash++ >= 2) {
+ break;
+ }
+
+ if (*s == '-' && *++s == ' ' && *++s != ' ') {
+ TxtFilePara.EmDash = s - 2;
+ break;
+ }
+ }
+ else {
+ s++;
+ }
+ }
+ }
+
+ if (!TxtFilePara.EmDash) {
+ TxtFilePara.CountOfTokensBeforeEmDash = 0;
+ }
+
+#if 0
+ fprintf( stderr,
+ "\n\nReadTxtPara: Type: %d \"%s\"\n",
+ TxtFilePara.Type,
+ TxtFilePara.Text
+ );
+
+ fprintf( stderr,
+ "Level: %d Bullet: %d Func: %d Lines: %d Colon: %d EmDash: (%d)%.8s\n\n",
+ TxtFilePara.Level,
+ TxtFilePara.Bullet,
+ TxtFilePara.FunctionPrototype,
+ TxtFilePara.Lines,
+ TxtFilePara.TrailingColon,
+ TxtFilePara.CountOfTokensBeforeEmDash,
+ TxtFilePara.EmDash ? TxtFilePara.EmDash : ""
+ );
+#endif
+
+ return( (BOOLEAN)(TxtFilePara.Type != PARA_EOF) );
+}
+
+PSZ
+GetParaWord(
+ BOOLEAN BlankDelimitted
+ )
+{
+ PSZ s, dst;
+
+ s = TxtFilePara.NextWord;
+ if (!s) {
+ return( NULL );
+ }
+
+ while (*s == ' ') {
+ s++;
+ }
+
+ dst = TxtWordBuffer;
+ *dst = '\0';
+ if (BlankDelimitted) {
+ while (*s && *s > ' ') {
+ *dst++ = *s++;
+ }
+
+ }
+ else {
+ if (iscsymf( *s )) {
+ while (iscsym( *s )) {
+ *dst++ = *s++;
+ }
+ }
+ else {
+ while (*s && !iscsymf( *s )) {
+ *dst++ = *s++;
+ }
+
+ if (dst != TxtWordBuffer) {
+ while (dst[-1] == ' ') {
+ dst--;
+ }
+ }
+ }
+ }
+
+ if (TxtWordBuffer[ 0 ]) {
+ TxtFilePara.NextWord = s;
+
+ *dst = '\0';
+ if (dst != TxtWordBuffer) {
+ return( TxtWordBuffer );
+ }
+ }
+
+ TxtFilePara.NextWord = NULL;
+ return( NULL );
+}
+
+
+BOOLEAN
+ProcessTxtFile( VOID )
+{
+ while (ReadTxtPara( FALSE )) {
+ if (TxtFilePara.Type == PARA_CMD) {
+ if (!ProcessTxtCommand()) {
+ return( FALSE );
+ }
+ }
+ else
+ if (TxtFilePara.Type == PARA_TXT) {
+ ProcessTextParagraph();
+ PreviousParagraphHeading = FALSE;
+ }
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+ProcessTxtCommand( VOID )
+{
+ PSZ Cmd = TxtFilePara.Text;
+ register PSZ s;
+
+ s = Cmd;
+ while (*s > ' ')
+ s++;
+
+ *s++ = '\0';
+
+ if (!_stricmp( Cmd, ".title" )) {
+ TitleString = MakeString( s );
+ return( (BOOLEAN)(TitleString != NULL) );
+ }
+ else
+ if (!_stricmp( Cmd, ".author" )) {
+ AuthorName = MakeString( s );
+ return( (BOOLEAN)(AuthorName != NULL) );
+ }
+ else
+ if (!_stricmp( Cmd, ".revision" )) {
+ RevisionNumber = MakeString( s );
+ return( (BOOLEAN)(RevisionNumber != NULL) );
+ }
+ else
+ if (!_stricmp( Cmd, ".created" )) {
+ CreationDate = MakeString( s );
+ return( (BOOLEAN)(CreationDate != NULL) );
+ }
+ else
+ if (!_stricmp( Cmd, ".heading" )) {
+ if (!TitlePageWritten) {
+ RtfTitlePage( TitleString->Buffer,
+ AuthorName->Buffer,
+ RevisionNumber->Buffer,
+ CreationDate->Buffer );
+ TitlePageWritten = TRUE;
+ }
+
+ return( ProcessHeadingCmd( s ) );
+ }
+ else
+ if (!_stricmp( Cmd, ".begin" )) {
+ return( ProcessBeginCmd( s ) );
+ }
+ else
+ if (!_stricmp( Cmd, ".end" )) {
+ ErrorMessage( ".end command without .begin command", NULL );
+ return( FALSE );
+ }
+ else {
+ ErrorMessage( "Unknown command - %s", Cmd );
+ return( FALSE );
+ }
+}
+
+BOOLEAN
+ProcessHeadingCmd(
+ PSZ CmdLine
+ )
+{
+ ULONG HeadingLevel, i;
+ PSZ HeadingString, s;
+ char HeadingBuffer[ 32 ];
+
+ CmdLine = SkipSpaces( CmdLine );
+ HeadingLevel = (ULONG)atoi( CmdLine );
+ if (HeadingLevel >= MAX_HEADING_LEVEL ) {
+ ErrorMessage( "Invalid heading level - %s", CmdLine );
+ return( FALSE );
+ }
+ else {
+ HeadingString = MarkToken( CmdLine );
+ HeadingLevels[ HeadingLevel ] += 1;
+ s = HeadingBuffer;
+ for (i=0; i<=HeadingLevel; i++) {
+ sprintf( s, "%d", HeadingLevels[ i ] );
+ s += strlen( s );
+ if (!HeadingLevel || i<HeadingLevel) {
+ *s++ = '.';
+ }
+ *s = '\0';
+ }
+ for (i=HeadingLevel+1; i<MAX_HEADING_LEVEL; i++) {
+ HeadingLevels[ i ] = 0;
+ }
+
+ RtfHeading( HeadingLevel, HeadingBuffer, HeadingString );
+ PreviousParagraphHeading = TRUE;
+ return( TRUE );
+ }
+}
+
+BOOLEAN
+ProcessBeginCmd(
+ PSZ CmdLine
+ )
+{
+ CmdLine = SkipSpaces( CmdLine );
+
+ if (!_stricmp( CmdLine, "simple" )) {
+ return( ProcessSimpleList() );
+ }
+ else
+ if (!_stricmp( CmdLine, "funclist" )) {
+ return( ProcessFunctionList() );
+ }
+ else
+ if (!_stricmp( CmdLine, "literal" )) {
+ return( ProcessLiteralText() );
+ }
+ else
+ if (!_stricmp( CmdLine, "funcnames" )) {
+ return( ProcessFunctionNames() );
+ }
+ else
+ if (!_stricmp( CmdLine, "fieldnames" )) {
+ return( ProcessFieldNames() );
+ }
+ else {
+ ErrorMessage( "Unknown .begin argument - %s", CmdLine );
+ return( FALSE );
+ }
+}
+
+BOOLEAN
+CheckForEndCmd(
+ PSZ CmdLine
+ )
+{
+ if (!_stricmp( CmdLine, ".end" )) {
+ return( TRUE );
+ }
+ else {
+ return( FALSE );
+ }
+}
+
+
+BOOLEAN ProcessBulletedList( VOID )
+{
+ PSZ Bullet;
+ PSZ ParaStyle;
+ ULONG StartingLevel = TxtFilePara.Level;
+
+ do {
+ if (TxtFilePara.Type == PARA_CMD) {
+ return( ProcessTxtCommand() );
+ }
+
+ if (TxtFilePara.Level < StartingLevel) {
+ break;
+ }
+
+ if (TxtFilePara.Level == 1) {
+ ParaStyle = PS_L1;
+ }
+ else
+ if (TxtFilePara.Level == 2) {
+ ParaStyle = PS_L2;
+ }
+ else {
+ ErrorMessage( "Illegal nesting of bulleted list - %s",
+ TxtFilePara.Text
+ );
+
+ return( FALSE );
+ }
+
+ if (TxtFilePara.Bullet) {
+ Bullet = "\to\t";
+ }
+ else {
+ Bullet = "\t\t";
+ }
+
+ OutputParagraph( ParaStyle, Bullet, OUTPUT_PARA_TEXT );
+ }
+ while (ReadTxtPara( FALSE ));
+
+ return( TRUE );
+}
+
+
+BOOLEAN ProcessSimpleList( VOID )
+{
+ PSZ ParaStyle;
+
+ while (ReadTxtPara( FALSE )) {
+ if (TxtFilePara.Type == PARA_CMD) {
+ break;
+ }
+
+ if (TxtFilePara.Level == 1) {
+ ParaStyle = PS_S1;
+ }
+ else
+ if (TxtFilePara.Level == 2) {
+ ParaStyle = PS_S2;
+ }
+ else {
+ ErrorMessage( "Illegal nesting of simple list - %s",
+ TxtFilePara.Text
+ );
+
+ return( FALSE );
+ }
+
+ OutputParagraph( ParaStyle, "", OUTPUT_PARA_TEXT );
+ }
+
+ return( CheckForEndCmd( TxtFilePara.Text ) );
+}
+
+
+BOOLEAN ProcessFunctionList( VOID )
+{
+ while (ReadTxtPara( FALSE )) {
+ if (TxtFilePara.Type == PARA_CMD) {
+ break;
+ }
+
+ OutputParagraph( PS_NL, "", OUTPUT_PARA_FUNCLIST );
+ }
+
+ RtfParagraph( PS_NL, "", "", "" );
+ return( CheckForEndCmd( TxtFilePara.Text ) );
+}
+
+BOOLEAN ProcessFunction( VOID )
+{
+ ULONG VoidFunction;
+
+ if (!ProcessFunctionPrototype( &VoidFunction )) {
+ return( FALSE );
+ }
+
+ ReadTxtPara( FALSE );
+ if (TxtFilePara.Type != PARA_TXT ||
+ TxtFilePara.Lines != 1 ||
+ _stricmp( TxtFilePara.Text, "Parameters:" )
+ ) {
+ if (!(VoidFunction & FUNC_TYPE_VOID_PARMS)) {
+ ErrorMessage( "Missing Parameters: line - %s", TxtFilePara.Text );
+ return( FALSE );
+ }
+ else {
+ RtfParagraph( PS_PP, "", "", "" );
+ }
+ }
+ else {
+ if (VoidFunction & FUNC_TYPE_VOID_PARMS) {
+ ErrorMessage( "VOID Function cant have parameters - %s", TxtFilePara.Text );
+ return( FALSE );
+ }
+
+ RtfParagraph( PS_PP, "", "", "" );
+ RtfParagraph( PS_PP, CS_CR, "", TxtFilePara.Text );
+ RtfParagraph( PS_PP, "", "", "" );
+
+ }
+
+ if (!(VoidFunction & FUNC_TYPE_VOID_PARMS)) {
+ if (!ProcessFunctionParameters()) {
+ return( FALSE );
+ }
+ }
+
+ if (TxtFilePara.Type != PARA_TXT ||
+ _stricmp( TxtFilePara.Text, "Return Value:" )
+ ) {
+ if (!(VoidFunction & FUNC_TYPE_VOID_RETURN)) {
+ ErrorMessage( "Return Value: line missing - %s", TxtFilePara.Text );
+ return( FALSE );
+ }
+ }
+ else {
+ if (VoidFunction & FUNC_TYPE_VOID_RETURN) {
+ ErrorMessage( "Return Value: line on VOID - %s", TxtFilePara.Text );
+ return( FALSE );
+ }
+ else {
+ RtfParagraph( PS_PP, CS_CR, "", TxtFilePara.Text );
+ RtfParagraph( PS_PP, "", "", "" );
+ while (ReadTxtPara( FALSE )) {
+ if (TxtFilePara.Type == PARA_CMD) {
+ return( ProcessTxtCommand() );
+ }
+ else
+ if (TxtFilePara.Type == PARA_TXT) {
+ if (TxtFilePara.Level > 0) {
+ OutputParagraph( PS_PV, "", OUTPUT_PARA_TEXT );
+ }
+ else
+ return( ProcessTextParagraph() );
+ }
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+#define FUNCPROTO_STATE_RETURN_TYPE 1
+#define FUNCPROTO_STATE_NAME1 2
+#define FUNCPROTO_STATE_NAME2 3
+#define FUNCPROTO_STATE_PARM1 4
+#define FUNCPROTO_STATE_PARM2 5
+#define FUNCPROTO_STATE_PARM3 6
+#define FUNCPROTO_STATE_DONE 7
+
+BOOLEAN ProcessFunctionPrototype(
+ PULONG VoidFunction
+ )
+{
+ BOOLEAN FirstParmToken, PrevAsterisk;
+ ULONG State;
+ PSZ s;
+
+ *VoidFunction = 0;
+ PrevAsterisk = FALSE;
+ State = FUNCPROTO_STATE_RETURN_TYPE;
+ while (s = GetParaWord( FALSE )) {
+donextword:
+ switch (State) {
+ case FUNCPROTO_STATE_RETURN_TYPE:
+ RtfParagraph( PS_PP, CS_CT, "", s );
+ if (!strcmp( s, "VOID" )) {
+ *VoidFunction |= FUNC_TYPE_VOID_RETURN;
+ }
+
+ RtfOpenPara( PS_PP, "" );
+ State = FUNCPROTO_STATE_NAME1;
+ break;
+
+ case FUNCPROTO_STATE_NAME1:
+ if (!strcmp( s, "typedef" )) {
+ RtfClosePara( s );
+ RtfOpenPara( PS_PP, "" );
+ }
+ else
+ if (!strcmp( s, "(*" )) {
+ RtfWord( NULL, "", "(" );
+ RtfWord( CS_CT, "", "*" );
+ }
+ else {
+ if (VerboseOutput) {
+ printf( "%s\n", s );
+ }
+ RtfWord( AddFuncName( s ), "", s );
+ State = FUNCPROTO_STATE_NAME2;
+ }
+ break;
+
+ case FUNCPROTO_STATE_NAME2:
+ if (!strcmp( s, ")(" ) || !strcmp( s, "(" )) {
+ RtfWord( NULL, "", s );
+ s = GetParaWord( FALSE );
+ if (!strcmp( s, "VOID" )) {
+ RtfWord( CS_CT, " ", s );
+ State = FUNCPROTO_STATE_PARM3;
+ *VoidFunction |= FUNC_TYPE_VOID_PARMS;
+ }
+ else {
+ RtfClosePara( "" );
+ RtfOpenPara( PS_PP, "\t" );
+ State = FUNCPROTO_STATE_PARM1;
+ FirstParmToken = TRUE;
+ goto donextword;
+ }
+ }
+ else {
+ return( FALSE );
+ }
+
+ break;
+
+ case FUNCPROTO_STATE_PARM1:
+ if (strcmp( s, "IN" ) && strcmp( s, "OUT" )) {
+ State = FUNCPROTO_STATE_PARM2;
+ }
+ RtfWord( CS_CT, FirstParmToken ? "" : " ", s );
+ FirstParmToken = FALSE;
+ break;
+
+ case FUNCPROTO_STATE_PARM2:
+ if (!strcmp( s, "*" ) || !strcmp( s, "OPTIONAL" )) {
+ PrevAsterisk = (BOOLEAN)(*s == '*');
+ RtfWord( CS_CT, " ", s );
+ }
+ else
+ if (!strcmp( s, "," ) || !strcmp( s, "[]," )) {
+ RtfClosePara( s );
+ RtfOpenPara( PS_PP, "\t" );
+ State = FUNCPROTO_STATE_PARM1;
+ FirstParmToken = TRUE;
+ }
+ else
+ if (!strcmp( s, ")" ) || !strcmp( s, ");" ) || !strcmp( s, "[]" )) {
+ RtfClosePara( "" );
+ RtfOpenPara( PS_PP, "\t" );
+ RtfClosePara( s );
+ State = FUNCPROTO_STATE_DONE;
+ }
+ else {
+ RtfWord( AddParmName( s ), PrevAsterisk ? "" : " ", s );
+ PrevAsterisk = FALSE;
+ }
+
+ break;
+
+ case FUNCPROTO_STATE_PARM3:
+ if (!strcmp( s, ")" ) || !strcmp( s, ");" )) {
+ RtfClosePara( " )" );
+ State = FUNCPROTO_STATE_DONE;
+ }
+ else {
+ return( FALSE );
+ }
+ break;
+
+ case FUNCPROTO_STATE_DONE:
+ if (strlen( s )) {
+ return( FALSE );
+ }
+
+ break;
+
+ default:
+ return( FALSE );
+ }
+ }
+
+ return( TRUE );
+}
+
+BOOLEAN ProcessFunctionParameters( VOID )
+{
+ PSZ PrevStyle;
+
+ while (ReadTxtPara( FALSE )) {
+ if (TxtFilePara.Level == 0) {
+ return( TRUE );
+ }
+
+ if (TxtFilePara.Level == 1) {
+ OutputParagraph( PrevStyle = PS_PL, "", OUTPUT_PARA_FUNCPROTO );
+ }
+ else
+ if (TxtFilePara.TrailingColon) {
+ if (TxtFilePara.Level == 2) {
+ RtfParagraph( PrevStyle = PS_P3, "", "", TxtFilePara.Text );
+ }
+ else
+ if (TxtFilePara.Level == 3) {
+ RtfParagraph( PrevStyle = PS_P5, "", "", TxtFilePara.Text );
+ }
+ else
+ if (TxtFilePara.Level == 4) {
+ RtfParagraph( PrevStyle = PS_P7, "", "", TxtFilePara.Text );
+ }
+ else {
+ ErrorMessage( "Value/Flags/Class/Structure: at wrong level - %s",
+ TxtFilePara.Text
+ );
+ }
+ }
+ else
+ if (TxtFilePara.Level == 2) {
+ if (PrevStyle == PS_PL || PrevStyle == PS_P2) {
+ OutputParagraph( PrevStyle = PS_P2, "", OUTPUT_PARA_FUNCPROTO );
+ }
+ else {
+ OutputParagraph( PrevStyle = PS_P4, "", OUTPUT_PARA_FUNCPROTO );
+ }
+ }
+ else
+ if (TxtFilePara.Level == 3) {
+ OutputParagraph( PrevStyle = PS_P6, "", OUTPUT_PARA_FUNCPROTO );
+ }
+ else
+ if (TxtFilePara.Level == 4) {
+ OutputParagraph( PrevStyle = PS_P8, "", OUTPUT_PARA_FUNCPROTO );
+ }
+ else {
+ ErrorMessage( "Text at wrong level - %s", TxtFilePara.Text );
+ }
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN ProcessStructure( VOID )
+{
+ BOOLEAN PrevAsterisk;
+ BOOLEAN PrevStruct;
+ PSZ s, sEnd;
+ ULONG i;
+
+ s = GetParaWord( FALSE );
+ RtfOpenPara( PS_PP, s ); // typedef
+ s = GetParaWord( FALSE );
+ RtfWord( NULL, " ", s ); // struct
+ s = GetParaWord( FALSE );
+ RtfWord( CS_CT, " ", s ); // TypeName
+ s = GetParaWord( FALSE );
+ RtfClosePara( " \\{" ); // {
+ RtfOpenPara( PS_PP, "" );
+
+ i = 0;
+ PrevAsterisk = FALSE;
+ PrevStruct = FALSE;
+ while (TRUE) {
+ s = GetParaWord( FALSE );
+ if (!s) {
+ return( FALSE );
+ }
+
+ if (i == 0) {
+ if (!strcmp( s, "struct" )) {
+ RtfWord( CS_CT, "\t", s ); // TypeName
+ PrevStruct = TRUE;
+ }
+ else {
+ RtfWord( CS_CT, PrevStruct ? "" : "\t", s ); // TypeName
+ PrevStruct = FALSE;
+ i++;
+ }
+ }
+ else
+ if (i == 1) {
+ if (!strcmp( s, "*" )) {
+ RtfWord( CS_CT, " ", s ); // TypeName
+ PrevAsterisk = TRUE;
+ }
+ else { // FieldName
+
+ RtfWord( AddParmName( s ), PrevAsterisk ? "" : " ", s );
+ PrevAsterisk = FALSE;
+ i++;
+ }
+ }
+ else {
+ sEnd = s + strlen( s ) - 1;
+ if (*sEnd == '}') {
+ *sEnd = '\0';
+ RtfClosePara( s );
+ RtfOpenPara( PS_PP, "\\}" );
+ break;
+ }
+
+ RtfWord( NULL, "", s ); // [: 2] ;
+ if (*sEnd == ';' ) {
+ RtfClosePara( "" );
+ RtfOpenPara( PS_PP, "" );
+ i = 0;
+ }
+ }
+ }
+
+ s = GetParaWord( FALSE );
+ RtfWord( CS_CT, " ", s ); // TypeName
+ if (VerboseOutput) {
+ printf( "%s\n", s );
+ }
+ s = GetParaWord( FALSE );
+ RtfWord( NULL, "", "," ); // ,
+ RtfWord( CS_CT, " ", "*" ); // *
+ s = GetParaWord( FALSE );
+ RtfWord( CS_CT, "", s ); // PTypeName
+ s = GetParaWord( FALSE );
+ RtfClosePara( s ); // ;
+
+ ReadTxtPara( FALSE );
+ if (TxtFilePara.Type != PARA_TXT ||
+ !TxtFilePara.TrailingColon
+ ) {
+ ErrorMessage( "Missing Structure: line - %s", TxtFilePara.Text );
+ }
+
+ RtfParagraph( PS_PP, "", "", "" );
+ RtfParagraph( PS_PP, CS_CR, "", TxtFilePara.Text );
+ RtfParagraph( PS_PP, "", "", "" );
+
+ if (!ProcessFunctionParameters()) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN ProcessFunctionNames( VOID )
+{
+ PSZ s;
+
+ while (ReadTxtPara( TRUE )) {
+ if (TxtFilePara.Type == PARA_CMD) {
+ break;
+ }
+
+ while (s = GetParaWord( TRUE )) {
+ AddFuncName( s );
+ }
+ }
+
+ return( CheckForEndCmd( TxtFilePara.Text ) );
+}
+
+
+BOOLEAN ProcessFieldNames( VOID )
+{
+ PSZ s;
+
+ while (ReadTxtPara( TRUE )) {
+ if (TxtFilePara.Type == PARA_CMD) {
+ break;
+ }
+
+ while (s = GetParaWord( TRUE )) {
+ AddParmName( s );
+ }
+ }
+
+ return( CheckForEndCmd( TxtFilePara.Text ) );
+}
+
+
+BOOLEAN ProcessLiteralText( VOID )
+{
+ while (ReadTxtPara( TRUE )) {
+ if (TxtFilePara.Type == PARA_CMD) {
+ break;
+ }
+
+ RtfParagraph( PS_PC, "", "", TxtFilePara.Text );
+ }
+
+ RtfParagraph( PS_PC, "", "", "" );
+ return( CheckForEndCmd( TxtFilePara.Text ) );
+}
+
+
+BOOLEAN ProcessTextParagraph( VOID )
+{
+ if (TxtFilePara.Bullet) {
+ ProcessBulletedList();
+ }
+ else
+ if (TxtFilePara.FunctionPrototype) {
+ if (!ProcessFunction()) {
+ ErrorMessage( "Invalid function prototype", NULL );
+ return( FALSE );
+ }
+ }
+ else
+ if (!strncmp( TxtFilePara.Text, "typedef struct _", 16 )) {
+ if (!ProcessStructure()) {
+ ErrorMessage( "Invalid structure prototype", NULL );
+ return( FALSE );
+ }
+ }
+ else {
+ if (PreviousParagraphHeading && TxtFilePara.Lines < 4) {
+ OutputParagraph( PS_PSKEEP, "", OUTPUT_PARA_TEXT );
+ }
+ else {
+ OutputParagraph( PS_PS, "", OUTPUT_PARA_TEXT );
+ }
+ }
+
+ PreviousParagraphHeading = FALSE;
+ return( TRUE );
+}
+
+
+BOOLEAN OutputParagraph(
+ PSZ ParaStyle,
+ PSZ Bullet,
+ ULONG ParaType
+ )
+{
+ ULONG WordCount;
+ CHAR c;
+ PSZ CharStyle;
+ PSZ s, s1, Separator;
+ SYMBOLTABLEVALUE Value;
+ BOOLEAN EmDash;
+
+ RtfOpenPara( ParaStyle, Bullet );
+ EmDash = FALSE;
+ WordCount = 0;
+ Separator = "";
+ while (s = GetParaWord( TRUE )) {
+ WordCount++;
+ CharStyle = NULL;
+ if (TxtFilePara.EmDash && WordCount <= 3) {
+ if (TxtFilePara.CountOfTokensBeforeEmDash == (WordCount-1) &&
+ !strcmp( s, "-" )
+ ) {
+ s = EMDASH;
+ EmDash = TRUE;
+ }
+ else
+ if (ParaType != OUTPUT_PARA_TEXT) {
+ if (TxtFilePara.CountOfTokensBeforeEmDash == WordCount) {
+ if (ParaType == OUTPUT_PARA_FUNCPROTO) {
+ CharStyle = AddParmName( s );
+ }
+ else {
+ CharStyle = AddFuncName( s );
+ }
+ }
+ else
+ if (TxtFilePara.CountOfTokensBeforeEmDash == (WordCount+1)) {
+ if (ParaType == OUTPUT_PARA_FUNCPROTO) {
+ CharStyle = AddTypeName( s );
+ }
+ else {
+ ErrorMessage( "Illegal function list syntax - %s",
+ TxtFilePara.Text
+ );
+ }
+ }
+ }
+ }
+ else {
+ if (iscsymf( *s )) {
+ s1 = s;
+ while (iscsym( *s1 )) {
+ s1++;
+ }
+
+ c = *s1;
+ *s1 = '\0';
+ if (AccessSymbolTable( HighLightTable,
+ s,
+ &Value,
+ LookupAccess )
+ ) {
+ CharStyle = (PSZ)Value;
+ if (c) {
+ RtfWord( CharStyle, Separator, s );
+ CharStyle = NULL;
+ Separator = "";
+ *s1 = c;
+ s = s1;
+ }
+ }
+ else {
+ *s1 = c;
+ }
+ }
+ }
+
+ RtfWord( CharStyle, Separator, s );
+ if (EmDash) {
+ EmDash = FALSE;
+ Separator = "";
+ }
+ else
+ if (s[strlen( s )-1] == '.') {
+ Separator = " ";
+ }
+ else {
+ Separator = " ";
+ }
+ }
+
+ RtfClosePara( "" );
+ return( TRUE );
+}
+
+
+PSZ
+AddFuncName(
+ PSZ FuncString
+ )
+{
+ PSZ HighLighting = CS_CP;
+
+ AccessSymbolTable( HighLightTable,
+ FuncString,
+ (SYMBOLTABLEVALUE *)&HighLighting,
+ InsertAccess );
+
+ return( HighLighting );
+}
+
+
+PSZ
+AddParmName(
+ PSZ ParmString
+ )
+{
+ PSZ HighLighting = CS_CI;
+
+ AccessSymbolTable( HighLightTable,
+ ParmString,
+ (SYMBOLTABLEVALUE *)&HighLighting,
+ InsertAccess );
+
+ return( HighLighting );
+}
+
+PSZ
+AddTypeName(
+ PSZ FuncString
+ )
+{
+ PSZ HighLighting = CS_CT;
+
+ AccessSymbolTable( HighLightTable,
+ FuncString,
+ (SYMBOLTABLEVALUE *)&HighLighting,
+ InsertAccess );
+
+ return( HighLighting );
+}
+
+
+PSZ
+SkipSpaces(
+ IN PSZ String
+ )
+{
+ while (*String == ' ') {
+ String++;
+ }
+
+ if (*String)
+ return( String );
+ else
+ return( NULL );
+}
+
+
+PSZ
+MarkToken(
+ IN PSZ String
+ )
+{
+ while (*String && *String != ' ') {
+ String++;
+ }
+
+ if (*String)
+ *String++ ='\0';
+
+ return( SkipSpaces( String ) );
+}
diff --git a/private/sdktools/doctor/sources b/private/sdktools/doctor/sources
new file mode 100644
index 000000000..9b177eae3
--- /dev/null
+++ b/private/sdktools/doctor/sources
@@ -0,0 +1,17 @@
+MAJORCOMP=tools
+MINORCOMP=doctor
+
+TARGETNAME=doctor
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\ztools\inc
+
+SOURCES=readtxt.c \
+ writertf.c \
+ strings.c \
+ symbol.c
+
+UMAPPL=doctor*c2rtf
+UMTYPE=console
+UMLIBS=obj\*\doctor.lib ..\ztools\src\obj\*\ztools.lib
diff --git a/private/sdktools/doctor/strings.c b/private/sdktools/doctor/strings.c
new file mode 100644
index 000000000..4d8b0d909
--- /dev/null
+++ b/private/sdktools/doctor/strings.c
@@ -0,0 +1,113 @@
+
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ strings.c
+
+Abstract:
+
+ This module defines functions for manipulating counted strings.
+
+Author:
+
+ Steve Wood (stevewo) 14-Mar-1989
+
+Revision History:
+
+--*/
+
+#include "doctor.h"
+
+PSTRING
+MakeString(
+ IN PSZ AscizString OPTIONAL
+ )
+{
+ register PSTRING ResultString;
+ ULONG cb;
+
+ cb = AscizString ? strlen( AscizString ) : 0;
+ if (ResultString = AllocateMemory( sizeof(STRING) )) {
+ ResultString->Length = (USHORT)cb;
+ if (cb) {
+ ResultString->MaximumLength = (USHORT)(cb+1);
+ ResultString->Buffer = (PSZ)AllocateMemory( cb+1 );
+ strcpy( ResultString->Buffer, AscizString );
+ }
+ else {
+ ResultString->Buffer = NULL;
+ ResultString->MaximumLength = 0;
+ }
+ }
+
+ return( ResultString );
+}
+
+
+PSTRING
+FreeString(
+ IN PSTRING String
+ )
+{
+ if (String) {
+ if (String->Buffer) {
+ FreeMemory( String->Buffer );
+ }
+ FreeMemory( String );
+ String = NULL;
+ }
+
+ return( String );
+}
+
+
+PSTRING
+EraseString(
+ IN OUT PSTRING String
+ )
+{
+ if (String) {
+ if (String->Buffer)
+ FreeMemory( String->Buffer );
+ String->Length = 0;
+ String->MaximumLength = 0;
+ String->Buffer = NULL;
+ }
+
+ return( String );
+}
+
+
+PSTRING
+CopyString(
+ OUT PSTRING DestString OPTIONAL,
+ IN PSTRING SourceString
+ )
+{
+ PSZ StringCopy;
+
+ if (!(StringCopy = (PSZ)AllocateMemory( (ULONG)
+ (SourceString->MaximumLength) )))
+ return( NULL );
+
+ if (!DestString)
+ DestString = MakeString( NULL );
+ else
+ EraseString( DestString );
+
+ if (DestString) {
+ strncpy( DestString->Buffer = StringCopy,
+ SourceString->Buffer,
+ (DestString->Length = SourceString->Length)
+ );
+ DestString->MaximumLength = SourceString->MaximumLength;
+ }
+ else {
+ FreeMemory( StringCopy );
+ }
+
+ return( DestString );
+}
diff --git a/private/sdktools/doctor/strings.h b/private/sdktools/doctor/strings.h
new file mode 100644
index 000000000..2a13123e0
--- /dev/null
+++ b/private/sdktools/doctor/strings.h
@@ -0,0 +1,24 @@
+//
+// Entry points in strings.c
+//
+
+PSTRING
+MakeString(
+ IN PSZ AscizString OPTIONAL
+ );
+
+PSTRING
+FreeString(
+ IN PSTRING String
+ );
+
+PSTRING
+EraseString(
+ IN OUT PSTRING String
+ );
+
+PSTRING
+CopyString(
+ OUT PSTRING DestString OPTIONAL,
+ IN PSTRING SourceString
+ );
diff --git a/private/sdktools/doctor/symbol.c b/private/sdktools/doctor/symbol.c
new file mode 100644
index 000000000..ace4033f9
--- /dev/null
+++ b/private/sdktools/doctor/symbol.c
@@ -0,0 +1,489 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ symbol.c
+
+Abstract:
+
+ This module implements a general symbol table package. A symbol
+ table uses a fixed size hash table, with chaining used to resolve
+ collisions. The hash function is the sum of the characters, except
+ that the char. bits are rotated in order to distribute the bits
+ across the hash function. Characters are converted to upper case
+ in the hash function so that case insensitive lookup can be supported,
+ while preserving the original case that the symbol has when inserted.
+
+ This module supports multiple symbol tables, so that clients, can
+ implement a primitive scoping mechanism.
+
+Author:
+
+ Steve Wood (stevewo) 02-Mar-1989
+
+
+Revision History:
+
+--*/
+
+#include "doctor.h"
+
+//
+// Data definitions private to this module.
+//
+
+typedef struct _SYMBOLTABLEENTRY {
+ struct _SYMBOLTABLEENTRY *ChainLink;
+ SYMBOLTABLEVALUE Value;
+ ULONG NameLength;
+ CHAR Name[1];
+} SYMBOLTABLEENTRY, *PSYMBOLTABLEENTRY;
+
+typedef LONG (_cdecl *SYMBOLTABLESTRCMP)(
+ IN PSZ String1,
+ IN PSZ String2,
+ IN ULONG String1Length
+ );
+
+typedef struct _SYMBOLTABLE {
+ ULONG Size;
+ ULONG Id;
+ SYMBOLTABLESTRCMP StrCmp;
+ ULONG CountSymbols;
+ ULONG CountHashBuckets;
+ PSYMBOLTABLEENTRY HashBuckets[1];
+} SYMBOLTABLE, *PSYMBOLTABLE;
+
+#define SYMBOLTABLEID 1234
+
+
+//
+// Function prototypes for procedures private to this module
+//
+
+PSYMBOLTABLE
+MapHandleToTable(
+ IN SYMBOLTABLEHANDLE SymbolTableHandle
+ );
+
+//
+// This function allocates memory for a symbol table. The first parameter
+// specifies the number of hash buckets to use. The second parameter
+// specifies whether symbol lookup for this table is case sensitive or not.
+//
+SYMBOLTABLEHANDLE
+CreateSymbolTable(
+ IN ULONG CountHashBuckets,
+ IN BOOLEAN IsCaseSensitive
+ )
+{
+ PSYMBOLTABLE SymbolTable;
+ ULONG i;
+
+ i = sizeof(SYMBOLTABLE) + (CountHashBuckets * sizeof(PSYMBOLTABLEENTRY));
+ SymbolTable = AllocateMemory( i );
+ if (SymbolTable) {
+ SymbolTable->Size = i;
+ SymbolTable->Id = SYMBOLTABLEID;
+ SymbolTable->StrCmp = (SYMBOLTABLESTRCMP)(IsCaseSensitive ?
+ strncmp : _strnicmp);
+ SymbolTable->CountSymbols = 0;
+ SymbolTable->CountHashBuckets = CountHashBuckets;
+ for (i=0; i<CountHashBuckets; i++) {
+ SymbolTable->HashBuckets[ i ] = (PSYMBOLTABLEENTRY)NULL;
+ }
+ }
+
+ return( (SYMBOLTABLEHANDLE)SymbolTable );
+}
+
+
+//
+// This function frees the memory associated with the passed symbol table.
+// Returns NULL if successful. Otherwise returns its parameter.
+//
+SYMBOLTABLEHANDLE
+DestroySymbolTable(
+ SYMBOLTABLEHANDLE SymbolTableHandle
+ )
+{
+ PSYMBOLTABLE SymbolTable = MapHandleToTable( SymbolTableHandle );
+ PSYMBOLTABLEENTRY TableEntry;
+ PSYMBOLTABLEENTRY NextTableEntry;
+ ULONG i;
+
+ if (!SymbolTable)
+ return( SymbolTableHandle );
+
+ //
+ // Make the symbol table invalid
+ //
+ SymbolTable->Id = 0;
+
+ //
+ // Enumerate each non-null entry, free the memory associated with it.
+ // Zero the hash buckets as we go.
+ //
+ for (i=0; i<SymbolTable->CountHashBuckets; i++) {
+ TableEntry = SymbolTable->HashBuckets[ i ];
+ SymbolTable->HashBuckets[ i ] = NULL;
+ while (TableEntry) {
+ NextTableEntry = TableEntry->ChainLink;
+ FreeMemory( TableEntry );
+ TableEntry = NextTableEntry;
+ }
+ }
+ SymbolTable->CountSymbols = 0;
+ SymbolTable->CountHashBuckets = 0;
+
+ //
+ // Free the memory associated with the symbol table header.
+
+ FreeMemory( SymbolTable );
+ return( NULL );
+}
+
+
+//
+// Function to enumerate the entries in a symbol table. No order is implied
+// other than random order. The passed enumeration function is called once
+// for each entry and is passed the two values that were passed to the
+// InsertSymbol call that created the entry. It is also allow to pass in
+// one ULONG argument that will be passed uninterpreted to the enumeration
+// function.
+//
+// The enumeration function should return TRUE if it wants to stop the
+// enumeration. Otherwise it should return FALSE to continue the enumeration.
+//
+// This function return TRUE if the enumeration was stopped by the
+// enumeration function returning TRUE. Otherwise this function returns
+// FALSE if an invalid symbol table was passed in, or if all the entries
+// in the table were enumerated without the enumeration function returning
+// TRUE.
+//
+
+
+BOOLEAN
+EnumerateSymbolTable(
+ IN SYMBOLTABLEHANDLE SymbolTableHandle,
+ IN SYMBOLTABLEENUMERATIONFUNCTION EnumerationFunction,
+ IN ULONG EnumerationArgument
+ )
+{
+ PSYMBOLTABLE SymbolTable = MapHandleToTable( SymbolTableHandle );
+ PSYMBOLTABLEENTRY TableEntry;
+ PSYMBOLTABLEENTRY NextTableEntry;
+ BOOLEAN StopEnumeration = FALSE;
+ ULONG i;
+
+ //
+ // Do nothing and return FALSE if invalid string table or null enumeration
+ // function passed.
+ //
+ if (!SymbolTable || !EnumerationFunction) {
+ return( FALSE );
+ }
+
+ //
+ // Enumerate each non-null entry until either the enumeration function
+ // stops the enumeration by returning TRUE or the end of the table is
+ // reached.
+ //
+ for (i=0; !StopEnumeration && i<SymbolTable->CountHashBuckets; i++) {
+ TableEntry = SymbolTable->HashBuckets[ i ];
+ while (!StopEnumeration && TableEntry) {
+ NextTableEntry = TableEntry->ChainLink;
+ StopEnumeration = (*EnumerationFunction)( EnumerationArgument,
+ TableEntry->Name,
+ TableEntry->Value );
+ TableEntry = NextTableEntry;
+ }
+ }
+
+ //
+ // Return TRUE if enumeration function terminated the enumeration, and
+ // FALSE otherwise.
+ //
+ return( StopEnumeration );
+}
+
+
+//
+// This functions allows a client to maniputate the contents of a symbol
+// table. It supports four operations:
+//
+// Lookup, Modify, Insert and Delete
+//
+// The Lookup, Modify and Delete operations succeed only if the passed
+// name matches an entry in the symbol table. If a match is found and
+// and the Value parameter is specified, then it will receive the value
+// associated with the symbol found. In the case of Modify, the old and
+// new values are exchanged.
+//
+// If the passed name is NOT found in the symbol table then all but the
+// Insert operation will return FALSE. The Insert operation returns
+// failure only if it is unable to allocate memory for the new entry.
+//
+
+BOOLEAN
+AccessSymbolTable(
+ SYMBOLTABLEHANDLE SymbolTableHandle,
+ IN PSZ Name,
+ IN OUT SYMBOLTABLEVALUE *Value OPTIONAL,
+ IN SYMBOLTABLEACCESS Access
+ )
+{
+ PSYMBOLTABLE SymbolTable = MapHandleToTable( SymbolTableHandle );
+ PSYMBOLTABLEENTRY *HeadTableEntry;
+ PSYMBOLTABLEENTRY TableEntry;
+ PSYMBOLTABLEENTRY NewTableEntry;
+ ULONG NameLength;
+ LONG ComparisonResult = -1;
+ SYMBOLTABLEVALUE NewValue = 0;
+ register PSZ s;
+ register ULONG h;
+ char c;
+
+ //
+ // Validate symbol table and name pointers. Zero length names
+ // invalid also.
+ //
+ ;
+ if (!SymbolTable || !(s = Name) && !*s)
+ return( FALSE );
+
+ //
+ // Dummy up a valid Value pointer if none supplied.
+ //
+ if (!ARGUMENT_PRESENT( Value ))
+ Value = &NewValue;
+
+
+ //
+ // Compute the address of the head of the bucket chain for this name.
+ //
+ h = 0;
+ while (c = *s++) {
+ h += (h << 1) + (h >> 1) + c;
+ if (islower( c ))
+ h += (ULONG)('A'-'a');
+ }
+
+ HeadTableEntry = &SymbolTable->HashBuckets[ h % SymbolTable->CountHashBuckets ];
+
+ //
+ // Walt the chain of symbol table entries for this hash bucket, looking
+ // for either a match, or the insertion point if no match in the chain.
+ //
+ NameLength = strlen( Name );
+ while (TableEntry = *HeadTableEntry) {
+ if (NameLength == TableEntry->NameLength) {
+ //
+ // Compare strings using appropriate function.
+ //
+ ComparisonResult =
+ (*SymbolTable->StrCmp)( Name, TableEntry->Name, NameLength );
+ //
+ // If name matches, then exit loop with TableEntry pointing to
+ // matching entry.
+ //
+ if (!ComparisonResult) {
+ break;
+ }
+
+ //
+ // If name less than name of current, then exit loop with
+ // TableEntry set to NULL and HeadTableEntry pointing to
+ // the insertion point if that is requested.
+ //
+ if (ComparisonResult < 0) {
+ TableEntry = NULL;
+ break;
+ }
+
+ //
+ // Otherwise, name greater than this name, so continue to next
+ // entry on chain.
+ //
+ }
+
+ HeadTableEntry = &TableEntry->ChainLink;
+ }
+
+ //
+ // At this point, there are two possiblilities:
+ //
+ // - we found an entry that matched and TableEntry points to that
+ // entry. HeadTableEntry points to the pointer value that points
+ // to the entry found. (i.e. *HeadTableEntry == TableEntry). This
+ // is so the delete function can unlink the entry from the chain.
+ //
+ // - we did not find an entry that matched and TableEntry is NULL.
+ // HeadTableEntry points to the pointer value that points to entry
+ // to insert a new entry before. This is so the insertion function
+ // can link the new entry into the chain.
+ //
+ if (TableEntry) {
+ if (Access == LookupAccess) {
+ //
+ // Lookup function - just return the value.
+ //
+ *Value = TableEntry->Value;
+ return( TRUE );
+ }
+
+ else
+ if (Access == DeleteAccess) {
+ //
+ // Delete function - unlink the entry from the chain and free
+ // the memory for the entry. Decrement the count of entries
+ // in the table.
+ //
+ *HeadTableEntry = TableEntry->ChainLink;
+ *Value = TableEntry->Value;
+ TableEntry->ChainLink = NULL;
+ FreeMemory( TableEntry );
+ SymbolTable->CountSymbols--;
+ return( TRUE );
+ }
+ else
+ if (Access == ModifyAccess) {
+ //
+ // Modify function - return old value and update entry with
+ // new value.
+ //
+ *Value = TableEntry->Value;
+ TableEntry->Value = NewValue;
+ return( TRUE );
+ }
+ else
+ //
+ // Insert function - return failure since it is already there
+ //
+ return( FALSE );
+ }
+ else
+ //
+ // No match found - return failure if not insert function
+ //
+ if (Access != InsertAccess)
+ return( FALSE );
+
+
+ //
+ // Insert function - allocate memory for a new entry. Fail if
+ // not enough memory.
+ //
+ NewTableEntry = (PSYMBOLTABLEENTRY)
+ AllocateMemory( sizeof( SYMBOLTABLEENTRY ) +
+ NameLength );
+
+ if (NewTableEntry) {
+ //
+ // Link the new entry into the chain at the insertion point.
+ //
+ NewTableEntry->ChainLink = *HeadTableEntry;
+ *HeadTableEntry = NewTableEntry;
+
+ //
+ // Store the value, name length and name string in the entry.
+ // The name string will have a terminating null byte just for
+ // convenience.
+ //
+ NewTableEntry->Value = *Value;
+ NewTableEntry->NameLength = NameLength;
+ strncpy( NewTableEntry->Name, Name, NameLength+1 );
+
+ //
+ // Increment the count of entries in the symbol table and return
+ // success.
+ //
+ SymbolTable->CountSymbols++;
+ return( TRUE );
+ }
+ else {
+ return( FALSE );
+ }
+}
+
+
+//
+// Function to map a string table handle to a pointer to string table.
+// Assumes the handle is just the pointer, and validates that it really
+// points to a string table.
+//
+PSYMBOLTABLE
+MapHandleToTable(
+ IN SYMBOLTABLEHANDLE SymbolTableHandle
+ )
+{
+ PSYMBOLTABLE SymbolTable = (PSYMBOLTABLE)SymbolTableHandle;
+
+ //
+ // If non-null handle, and it points to valid string table Id then
+ // return the pointer. Otherwise return NULL.
+ //
+ if (SymbolTable && SymbolTable->Id == SYMBOLTABLEID) {
+ return( SymbolTable );
+ }
+ else {
+ return( (PSYMBOLTABLE)NULL );
+ }
+}
+
+
+#if DBG
+
+VOID
+PrintSymbolTable(
+ IN SYMBOLTABLEHANDLE SymbolTableHandle,
+ IN FILE *PrintFileHandle OPTIONAL
+ )
+{
+ PSYMBOLTABLE SymbolTable = MapHandleToTable( SymbolTableHandle );
+ PSYMBOLTABLEENTRY TableEntry;
+ ULONG i;
+
+ if (!ARGUMENT_PRESENT( PrintFileHandle ))
+ PrintFileHandle = stdout;
+
+ fprintf( PrintFileHandle,
+ "Symbol Table Handle = %p\n", SymbolTableHandle );
+ fprintf( PrintFileHandle,
+ "Size = %d\n", SymbolTable->Size );
+ fprintf( PrintFileHandle,
+ "Id = %d\n", SymbolTable->Id );
+ fprintf( PrintFileHandle,
+ "Case Sensitive: %s\n",
+ SymbolTable->StrCmp == (SYMBOLTABLESTRCMP)strncmp ? "Yes" : "No" );
+ fprintf( PrintFileHandle,
+ "Count of Symbols = %d\n", SymbolTable->CountSymbols );
+ fprintf( PrintFileHandle,
+ "Count of Hash Buckets: %d\n", SymbolTable->CountHashBuckets );
+
+ //
+ // Enumerate each non-null entry until either the enumeration function
+ // stops the enumeration by returning TRUE or the end of the table is
+ // reached.
+ //
+ for (i=0; i<SymbolTable->CountHashBuckets; i++) {
+ if (TableEntry = SymbolTable->HashBuckets[ i ])
+ fprintf( PrintFileHandle, "chain[%2d]: ", i );
+ while (TableEntry) {
+ fprintf( PrintFileHandle, "%4x (%2d) %-32s = %p\n",
+ TableEntry,
+ TableEntry->NameLength,
+ TableEntry->Name,
+ TableEntry->Value );
+
+ if (TableEntry = TableEntry->ChainLink)
+ fprintf( PrintFileHandle, " " );
+ }
+ }
+
+ fprintf( PrintFileHandle, "\n" );
+}
+
+#endif //DBG
diff --git a/private/sdktools/doctor/symbol.h b/private/sdktools/doctor/symbol.h
new file mode 100644
index 000000000..7f803a5f0
--- /dev/null
+++ b/private/sdktools/doctor/symbol.h
@@ -0,0 +1,53 @@
+//
+// Entry points in symbol.c
+//
+typedef HANDLE SYMBOLTABLEHANDLE;
+typedef ULONG SYMBOLTABLEVALUE;
+
+SYMBOLTABLEHANDLE
+CreateSymbolTable(
+ IN ULONG CountHashBuckets,
+ IN BOOLEAN IsCaseSensitive
+ );
+
+SYMBOLTABLEHANDLE
+DestroySymbolTable(
+ SYMBOLTABLEHANDLE SymbolTableHandle
+ );
+
+typedef enum _SYMBOLTABLEACCESS {
+ LookupAccess,
+ InsertAccess,
+ DeleteAccess,
+ ModifyAccess
+} SYMBOLTABLEACCESS;
+
+BOOLEAN
+AccessSymbolTable(
+ SYMBOLTABLEHANDLE SymbolTableHandle,
+ IN PSZ Name,
+ IN OUT SYMBOLTABLEVALUE *Value,
+ IN SYMBOLTABLEACCESS Access
+ );
+
+typedef BOOLEAN (*SYMBOLTABLEENUMERATIONFUNCTION)(
+ IN ULONG EnumerationArgument,
+ IN PSZ Name,
+ IN SYMBOLTABLEVALUE Value
+ );
+
+BOOLEAN
+EnumerateSymbolTable(
+ IN SYMBOLTABLEHANDLE SymbolTableHandle,
+ IN SYMBOLTABLEENUMERATIONFUNCTION EnumerationFunction,
+ IN ULONG EnumerationArgument
+ );
+
+
+#if DBG
+VOID
+PrintSymbolTable(
+ IN SYMBOLTABLEHANDLE SymbolTableHandle,
+ IN FILE *PrintFileHandle OPTIONAL
+ );
+#endif
diff --git a/private/sdktools/doctor/writertf.c b/private/sdktools/doctor/writertf.c
new file mode 100644
index 000000000..2c5f33fe5
--- /dev/null
+++ b/private/sdktools/doctor/writertf.c
@@ -0,0 +1,251 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ writertf.c
+
+Abstract:
+
+ This module contains the code to output in Rich Text Format (RTF)
+
+Author:
+
+ Steve Wood (stevewo) 02-Mar-1989
+
+Revision History:
+
+--*/
+
+#include "doctor.h"
+
+#define RTF_TEMPLATE_FILE "DOCTOR.RTF"
+
+char RtfTemplateFileName[ 256 ];
+FILE *RtfTemplateFileHandle; // File handle of RTF template file
+
+FILE *RtfFileHandle; // File handle of RTF output file
+
+#define RtfOut fprintf( RtfFileHandle,
+
+BOOLEAN
+OpenRtfFile(
+ IN PSZ RtfFileName
+ )
+{
+ PSZ FilePart;
+
+ if (!SearchPath( getenv( "PATH" ),
+ RTF_TEMPLATE_FILE,
+ NULL,
+ sizeof( RtfTemplateFileName ),
+ RtfTemplateFileName,
+ &FilePart
+ )
+ ) {
+ fprintf( stderr,
+ "DOCTOR: Unable to find %s template file\n",
+ RTF_TEMPLATE_FILE
+ );
+
+ exit( 1 );
+ }
+
+ if (!(RtfTemplateFileHandle = fopen( RtfTemplateFileName, "r" ))) {
+ fprintf( stderr,
+ "DOCTOR: Unable to open %s template file\n",
+ RtfTemplateFileName
+ );
+
+ exit( 1 );
+ }
+
+#if 0
+ RtfFileHandle = stderr;
+ return( TRUE );
+#else
+ if (RtfFileHandle = fopen( RtfFileName, "w" )) {
+ return( TRUE );
+ }
+ else
+ return( FALSE );
+#endif
+}
+
+
+BOOLEAN
+CloseRtfFile( VOID )
+{
+ int c;
+
+ if (RtfTemplateFileHandle) {
+ if (RtfFileHandle) {
+ while ((c = fgetc( RtfTemplateFileHandle )) != EOF) {
+ fputc( c, RtfFileHandle );
+ }
+ }
+
+ if (!fclose( RtfTemplateFileHandle )) {
+ RtfTemplateFileHandle = NULL;
+ }
+ }
+
+ if (RtfFileHandle) {
+ if (!fclose( RtfFileHandle )) {
+ RtfFileHandle = NULL;
+ return( TRUE );
+ }
+ }
+
+ return( FALSE );
+}
+
+
+char *MonthNames[] = {
+ NULL,
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+};
+
+BOOLEAN
+RtfTitlePage(
+ IN PSZ Title,
+ IN PSZ Author,
+ IN PSZ Revision,
+ IN PSZ Creation
+ )
+{
+ int c;
+ SYSTEMTIME date;
+
+ GetSystemTime( &date );
+
+ while ((c = fgetc( RtfTemplateFileHandle )) != EOF) {
+ if (c != '%') {
+ fputc( c, RtfFileHandle );
+ }
+ else
+ switch (fgetc( RtfTemplateFileHandle )) {
+ case 'D': // Day
+ RtfOut "%02d", date.wDay );
+ break;
+
+ case 'M': // Month
+ RtfOut "%02d", date.wMonth );
+ break;
+
+ case 'Y': // Year
+ RtfOut "%02d", date.wYear );
+ break;
+
+ case 'N': // Document Name or Title
+ RtfOut "%s", Title );
+ break;
+
+ case 'A': // Author
+ RtfOut "%s", Author );
+ break;
+
+ case 'C': // Creation
+ RtfOut "%s", Creation );
+ break;
+
+ case 'V': // Version
+ RtfOut "%s", Revision );
+ break;
+
+ case 'R': // Revision
+ RtfOut "%s, %s %d, %d",
+ Revision,
+ MonthNames[ date.wMonth ],
+ date.wDay,
+ date.wYear );
+ break;
+
+ case 'T': // Text of document
+ return TRUE;
+
+ default:
+ fprintf( stderr, "DOCTOR: %s file is invalid\n",
+ RtfTemplateFileName
+ );
+ return FALSE;
+ }
+ }
+
+ return( FALSE );
+}
+
+
+BOOLEAN
+RtfHeading(
+ ULONG HeadingLevel,
+ PSZ HeadingNumber,
+ PSZ HeadingTitle
+ )
+{
+ switch( HeadingLevel ) {
+ case 0: RtfOut "%s%s %s\\par\n", PS_H1, HeadingNumber, HeadingTitle ); break;
+ case 1: RtfOut "%s%s %s\\par\n", PS_H2, HeadingNumber, HeadingTitle ); break;
+ case 2: RtfOut "%s%s %s\\par\n", PS_H3, HeadingNumber, HeadingTitle ); break;
+ case 3: RtfOut "%s%s %s\\par\n", PS_H4, HeadingNumber, HeadingTitle ); break;
+ case 4: RtfOut "%s%s %s\\par\n", PS_H5, HeadingNumber, HeadingTitle ); break;
+ default:RtfOut "%s%s %s\\par\n", PS_HN, HeadingNumber, HeadingTitle ); break;
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+RtfParagraph(
+ PSZ ParagraphStyle,
+ PSZ CharStyle,
+ PSZ ParagraphBullet,
+ PSZ ParagraphText
+ )
+{
+ RtfOut "%s%s%s%s\\par\n",
+ ParagraphStyle,
+ CharStyle,
+ ParagraphBullet,
+ ParagraphText
+ );
+ return( TRUE );
+}
+
+BOOLEAN
+RtfOpenPara(
+ PSZ ParagraphStyle,
+ PSZ LeadingText
+ )
+{
+ RtfOut "%s%s", ParagraphStyle, LeadingText );
+ return( TRUE );
+}
+
+BOOLEAN
+RtfClosePara(
+ PSZ TrailingText
+ )
+{
+ RtfOut "\\plain %s\\par\n", TrailingText );
+ return( TRUE );
+}
+
+BOOLEAN
+RtfWord(
+ PSZ CharStyle,
+ PSZ LeadingText,
+ PSZ WordText
+ )
+{
+ if (CharStyle == NULL) {
+ RtfOut "%s%s", LeadingText, WordText );
+ }
+ else {
+ RtfOut "%s%s%s\\plain ", LeadingText, CharStyle, WordText );
+ }
+
+ return( TRUE );
+}