amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (04/10/91)
Submitted-by: creubank@is.crl.sony.co.jp Posting-number: Volume 91, Issue 085 Archive-name: applications/quiz-1.0/part02 #!/bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 2 (of 2)." # Contents: parse.c quiz.c screen.c # Wrapped by tadguy@ab20 on Wed Apr 10 10:57:36 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'parse.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'parse.c'\" else echo shar: Extracting \"'parse.c'\" \(11191 characters\) sed "s/^X//" >'parse.c' <<'END_OF_FILE' X/*** X *** parse.c X *** X *** Curtis Eubanks X *** 3 November 1989 X *** X ***/ X X#include <stdio.h> X#include <string.h> X X#include <exec/types.h> /* only for def'n of 'node' */ X#include <exec/lists.h> /* needed in qstructs.h */ X X/*#ifndef EXEC_MEMORY_H X#include <exec/memory.h> X#endif X*/ X#define GLOBALVAR extern X#include "qstructs.h" Xextern char *mymalloc(); X Xvoid slistAdd(); Xstruct slist *Makeslist(); Xint slistSize(); Xvoid remwh(); Xchar *findfirstbrace(); Xchar *findlevel(); Xvoid deletebrackets(); Xchar *snarfbrackets(); Xvoid printslist(); Xstruct slist *FindOrs(); Xstruct slist *findors(); Xint checkbrackets(); Xstruct slist *joinslists(); Xchar *findmatchbrace(); Xstruct slist *expandslist(); Xstruct slist *expand(); X X/* Add a single string to slist sl. Does not copy */ Xvoid slistAdd(sl,s) struct slist *sl; char *s; X{ X while (sl->next) sl = sl->next; X sl->next = (struct slist *)mymalloc(sizeof(struct slist)); X (sl->next)->s = s; X (sl->next)->next = NULL; X} /* slistAdd */ X X/* returns the number of elems in sl */ Xint slistSize(sl) struct slist *sl; X{ X int rtn=0; X while (sl) rtn++, sl=sl->next; X return(rtn); X} /* slistSize */ X X/* allocate and return a new slist structure and fill it with 's' */ Xstruct slist *Makeslist(s) char *s; X{ X struct slist *rtn; X rtn = (struct slist *)mymalloc(sizeof(struct slist)); X rtn->s = s; X rtn->next = NULL; X return(rtn); X} /* Makeslist */ X X/* whitespace macro */ X#define iswhite(x) ((x == ' ')||(x == '\t')) X X/* modifies s by removing leading & trailing whitespace and replacing X any other whitespace with a single space */ Xvoid remwh(s) char *s; X{ X char *r; X r = s; /* start scanning at the beginning */ X if (!(*s)) return; /* a null string could mess us up */ X while (1) { X while ((*r) && iswhite(*r)) r++; X if (!(*r)) { X /* we may have to delete a single ' ' at the end */ X /* since we already check for a null string passed to remwh, */ X /* we know that *(s-1) is a valid address */ X if (iswhite(*(s-1))) *(s-1) = '\0'; X else *s = '\0'; X return; X } /* if !*r */ X /* now copy till next white */ X while ((*r) && (!(iswhite(*r)))) *s++ = *r++; X if (*r) *s++ = ' '; /* replace white with a space */ X } /* while (1) */ X} /* remwh */ X X/* returns the address of the first opening brace '{' in s. X If none found, returns NULL */ Xchar *findfirstbrace(s) X char *s; X{ X while (*s) { X if (*s == '{') return(s); X s++; X } /* while */ X return(NULL); X} /* findfirstbrace */ X X/* returns the address of first opening brace in s that is nested level X levels deep. Returns NULL if not found */ Xchar *findlevel(s, level) X char *s; X int level; X{ X int nest = 0; X X if (level == 0) return(s); X while (*s) { X if (*s == '{') { X nest++; X if (nest==level) return(s+1); X } /* if */ X else if (*s == '}') nest--; X s++; X } /* while */ Xreturn(NULL); X} /* findlevel */ X X/* Modifies s by deleting the first set of matching brackets in s. X Requires s has at least one set of balanced brackets. X deletebrackets("this {is {an} example} here") --> modifies s to --> X "this is {an} example here" */ Xvoid deletebrackets(s) char *s; X{ X int nest = 1; X char *t; X X while (*s != '{') s++; X t = s+1; X while (*t) { X if (*t == '{') nest++; X else if (*t == '}') { X nest--; X if (!nest) { t++; break; } /* found end brace */ X } /* else if */ X *s++ = *t++; X } /* while *t */ X while (*t) *s++ = *t++; /* copy the rest of the string */ X *s = '\0'; X} /* deletebrackets */ X X/* snarfbrackets is the same as deletebrackets except that it actually X deletes everything within and including the brackets. Returns a NEW X string. Doesn't modify s. Requires the brackets exist. X snarfbrackets("this {is {an} example} here") = "this here" */ Xchar *snarfbrackets(s) X char *s; X{ X char *first, *last, *rtn; X X rtn = mymalloc(strlen(s)+1); X (void)strcpy(rtn, s); X first = findfirstbrace(rtn); X if (!first) X FatalError("Aiigghh! Couldn't find first brace in %s\n",rtn); X last = findmatchbrace(first)+1; X if (!last) X FatalError("Aiigghh! Couldn't find matching brace in %s\n",first); X while (*last) *first++ = *last++; X *first = '\0'; X return(rtn); X} X X/* Prints out all the strings in an slist structure, each on a different X line. Used only for debugging */ Xvoid printslist(sl) struct slist *sl; X{ X printf("Slist is:\n"); X while (sl) { printf(" \"%s\"\n",sl->s); sl = sl->next; } X printf("\n"); X} X X/* FindOrs returns a list of outermost level strings of s that are X separated by '|'. Requires s have balanced brackets. If only one X string is found, NULL is returned. X FindOrs("one|{two|zwei|ni}|mikka") = X { "one", "{two|zwei|ni}", "mikka"} */ Xstruct slist *FindOrs(s) char *s; X{ X struct slist *rtn = NULL; X int tmpsize, numfound = 0, nest = 0; X char *lastword, *tmpstr; X X if (*s == '\0') return(rtn); X lastword = s; X while (*s) { X if (*s == '{') nest++; X else if (*s == '}') nest--; X if ((*s == '|')&&(!nest)) { X numfound++; X tmpsize = s-lastword+1; X tmpstr = mymalloc(tmpsize); X memcpy(tmpstr, lastword, tmpsize-1); X tmpstr[tmpsize-1] = '\0'; X if (!rtn) rtn = Makeslist(tmpstr); X else slistAdd(rtn, tmpstr); X lastword = s+1; X } /* if */ X s++; X } /* while */ X if (numfound == 0) return(NULL); X if (*lastword) { X numfound++; X tmpsize = s-lastword+1; X tmpstr = mymalloc(tmpsize); X memcpy(tmpstr, lastword, tmpsize-1); X tmpstr[tmpsize-1] = '\0'; X if (!rtn) rtn = Makeslist(tmpstr); X else slistAdd(rtn, tmpstr); X } /* if */ X return(rtn); X} /* FindOrs */ X X/* findors (probably not the best name) is similar to FindOrs, except X that it returns the '|'-separated strings between the first set of X balanced brackets. Requires at least one set of balanced braces. X findors("not in braces {a|b|{c|d}} not included") = X { "a", "b", "{c|d}" } X As with FindOrs, findors returns NULL if only a single string is X found or if s is an empty string or if no braces are found. This X was probably a bad idea. */ Xstruct slist *findors(s) char *s; X{ X struct slist *rtn = NULL; X int tmpsize, numfound = 0, nest = 1; X char *lastword, *tmpstr; X X if (*s == '\0') return(NULL); X X lastword = findfirstbrace(s); X if (!lastword) return(NULL); /* look ma, no braces */ X lastword++; /* point to actual string, not brace */ X s = lastword; X while (*s) { X if (*s=='{') nest++; X else if (*s=='}') { X nest--; X if (!nest) { X numfound++; X tmpsize = s-lastword+1; X tmpstr = mymalloc(tmpsize); X memcpy(tmpstr, lastword, tmpsize-1); X tmpstr[tmpsize-1] = '\0'; X if (!rtn) rtn = Makeslist(tmpstr); X else slistAdd(rtn, tmpstr); X break; X } /* if !nest */ X } /* if close bracket */ X else if ((*s == '|') && (nest==1)) { X numfound++; X tmpsize = s-lastword+1; X tmpstr = mymalloc(tmpsize); X memcpy(tmpstr, lastword, tmpsize-1); X tmpstr[tmpsize-1] = '\0'; X if (!rtn) rtn = Makeslist(tmpstr); X else slistAdd(rtn, tmpstr); X lastword = s+1; X } /* if */ X s++; X } /* while */ X if (numfound==1) return(NULL); X return(rtn); X } /* findors */ X X/* Returns deepest level of bracket nesting in a regular expression X string. Returns -1 if there is an error (unbalanced or unmatched X brackets. */ Xint checkbrackets(s) char *s; X{ X int nest = 0, maxlevel = 0; X X while (*s) { X if (*s == '{') { X nest++; X if (nest > maxlevel) maxlevel = nest; X } /* if open brace */ X else if (*s == '}') { X nest--; X if (nest < 0) return(-1); X } /* if close brace */ X s++; X } /* while */ X if (nest != 0) return(-1); X return(maxlevel); X} /* checkbrackets */ X X/* Joins two slists by adding sl2 to the end of sl1. Does not copy X sl2. Modifies sl1. There's really no reason to return sl1... */ Xstruct slist *joinslists(sl1, sl2) X struct slist *sl1, *sl2; X{ X struct slist *tmpslist; /* so we can return sl1 */ X X if (sl2) { X tmpslist = sl1; X while (tmpslist->next) tmpslist = tmpslist->next; X tmpslist->next = sl2; X } /* if sl2 */ X return(sl1); X} /* joinslists */ X X/* find and return pointer to a matching brace; requires such a X brace exists! Returns NULL if not found. */ Xchar *findmatchbrace(s) X char *s; X{ X int nest = 0; X X s = findfirstbrace(s); X while (*s) { X if (*s == '{') nest++; X else if (*s == '}') { X nest--; X if (nest==0) return(s); X } /* if close */ X s++; X } /* while */ X return(NULL); X} /* findmatchbrace */ X X/* expandslist expects a list of strings. Each string is considered to X be a simple regular expression of using '{', '}', and '|'. The X strings are expanded to all possibilities indicated by the regexp. X "a|b|c" --> "a", "b", "c" X "{x|y|z}-axis" --> "x-axis", "y-axis", "z-axis" X "this {option} is fun" --> "this option is fun", "this is fun" */ Xstruct slist *expandslist(sl) X struct slist *sl; X{ X struct slist *tmpslist, *rtn = NULL, workslist, *braceslist; X char *bptr, *eptr, *newstr; X int beforelength, afterlength; X X workslist.next = NULL; /* used with a single string for efficiency */ X while (sl) { /* repeat for each string in sl */ X tmpslist = FindOrs(sl->s); /* get top level disjunctions */ X if (!tmpslist) {tmpslist=&workslist;workslist.s=sl->s;} X while (tmpslist) { X if (bptr = findfirstbrace(tmpslist->s)) { /* there is a brace */ X braceslist = findors(bptr); /* or tmpslist->s */ X if (!braceslist) { /* "{degenerate case}" */ X /* we want "{x}" to map to "x" and "" */ X slistAdd(sl, snarfbrackets(tmpslist->s)); /* "" */ X deletebrackets(tmpslist->s); X slistAdd(sl, tmpslist->s); X tmpslist = tmpslist->next; X continue; X } /* if "{x}" */ X eptr = findmatchbrace(bptr) + 1; X beforelength = bptr - tmpslist->s; X afterlength = tmpslist->s + strlen(tmpslist->s) - eptr; X while (braceslist) { X newstr = mymalloc(beforelength+strlen(braceslist->s)+afterlength+1); X memcpy(newstr, tmpslist->s, beforelength); X strcat(newstr, braceslist->s); X strcat(newstr, eptr); X slistAdd(sl, newstr); X braceslist = braceslist->next; X } /* while */ X } /* if there is a brace */ X else { /* no brace, just add the string to return list */ X if (!rtn) rtn = Makeslist(tmpslist->s); X else slistAdd(rtn, tmpslist->s); X } /* else */ X tmpslist = tmpslist->next; /* iterate */ X } /* while tmpslist */ X sl = sl->next; /* iterate */ X } /* while sl */ X return(rtn); X} /* expandslist */ X X/* expand expands a single string by calling expandslist. */ X/* returns the expanded slist, or NULL if error */ Xstruct slist *expand(s) char *s; X{ X int level; X struct slist *rtn, *tmpslist; X X level = checkbrackets(s); X if (level<0) { X fprintf(stderr, "Unbalanced braces in \"%s\"\n", s); X return(NULL); X } /* if */ X rtn = expandslist(Makeslist(s)); X tmpslist = rtn; X while (tmpslist) { X remwh(tmpslist->s); X tmpslist = tmpslist->next; X } /* while */ X return(rtn); X} /* expand */ END_OF_FILE if test 11191 -ne `wc -c <'parse.c'`; then echo shar: \"'parse.c'\" unpacked with wrong size! fi # end of 'parse.c' fi if test -f 'quiz.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'quiz.c'\" else echo shar: Extracting \"'quiz.c'\" \(26723 characters\) sed "s/^X//" >'quiz.c' <<'END_OF_FILE' X/*** X *** quiz.c X *** a question-answer game similar to /usr/games/quiz. X *** X *** Curtis Eubanks X *** 19 October 1989 -- CLI only X *** 18 November 1989 -- graphics interface X *** X ***/ X X/* screen.c funcs */ Xextern void InitGraphics(), CloseGraphics(), redraw(), X UpdateMenuGraphState(); X X/* graph.c funcs */ Xextern void cleargraph(),drawgraph(), UpdateCurrentQ(); X X#include <exec/types.h> X#include <exec/lists.h> X#include <stdio.h> X#include <string.h> X#include <libraries/dos.h> X#include <libraries/dosextens.h> X#include <exec/memory.h> X#include <workbench/startup.h> X#include <stdlib.h> /* for srand & rand */ X#include <intuition/intuition.h> X Xextern struct FileHandle *Open(); Xextern long time(); X/*#include <time.h> for time() */ X X Xextern int bhandlemsg(); Xextern ULONG ehandlemsg(); Xextern struct NewWindow backnw; Xextern struct NewScreen ns; Xextern struct Window *backwindow; Xextern struct IntuiMessage *mes, *GetMsg(); Xextern char *qtext, *atext, *sbuff, *ubuff, *ctext; Xextern struct StringInfo sStringInfo; Xextern void DrawQText(); Xextern struct Gadget sgadget; X#define BEGINMENUNUM (SHIFTITEM(2)|SHIFTSUB(NOSUB)) X X/* type definitions */ X#define GLOBALVAR X#include "qstructs.h" X#include "parse.c.h" X#include "graph.h" X Xextern char *mymalloc(); /* in mymalloc.c */ X X/* in graph.c */ Xextern int readscore(); Xextern int *AddTrial(); Xextern void SetWorstQuestion(); X X/***** function defs ******/ Xvoid usage(); Xvoid parseargs(); Xstruct ResListItem *MakeNewItem(); Xvoid FreeResource(); Xvoid FreeAll(); Xvoid CleanUp(); Xchar *Allocate(); Xvoid FatalError(); Xvoid NonFatalError(); Xint readfile(); Xint countlines(); Xint isin(); Xchar *separate(); Xvoid ask(); Xvoid getinput(); Xvoid correct(); Xvoid wrong(); Xchar **extractlines(); Xvoid ilistAdd(); Xilist *Makeilist(); Xint ProcessQFile(); Xvoid doswap(); Xvoid stractivate(); Xvoid MajorSwap(); Xvoid quiz(); Xvoid writescore(); Xvoid main(); X X X X Xvoid usage(s) X char *s; X{ X printf("Usage: %s datafile [-switch] [-ignorecase] [-help]\n\n", s); X printf(" -switch: questions and answers are switched\n"); X printf(" -ignorecase: case doesn't matter\n"); X printf(" -help: print this message (duh...)\n\n"); X printf(" You can use just the first letter of each option as\n"); X printf(" well. datafile contains lines of the form\n"); X printf(" question:answer (one on each line)\n"); X exit(0); X} X X/* parses arguments and sets the appropriate qstate elements. */ X/* iff quiz was called with a filename, qstate.File is a non-empty */ X/* string. */ Xvoid parseargs(argc, argv) X int argc; X union { X char **args; X struct WBStartup *msg; X } *argv; X{ X if (argc==0) { /* Workbench startup */ X /*ns.DefaultTitle = argv->args[0];*/ X if (argv->msg->sm_NumArgs > 2) X NonFatalError("%s: only one quiz file can be selected!\n"); X if (argv->msg->sm_NumArgs >= 2) X strncpy(qstate.File, argv->msg->sm_ArgList[1].wa_Name,MAXFILENAME); X } X else { /* CLI startup */ X int i, gotfname=0; X for (i=1; i<argc; i++) { X X if ((!stricmp(argv->args[i], "-switch"))|| X (!stricmp(argv->args[i], "/switch"))|| X (!stricmp(argv->args[i], "-s"))) X qstate.Switch = 1; X X else if ((!stricmp(argv->args[i], "-help"))|| X (!stricmp(argv->args[i], "/help"))|| X (!stricmp(argv->args[i], "-h"))) X usage(argv->args[0]); /* exits */ X X else if ((!stricmp(argv->args[i], "-ignorecase"))|| X (!stricmp(argv->args[i], "/ignorecase"))|| X (!stricmp(argv->args[i], "-i"))) X qstate.CaseSensitive = 0; X X else if ((!stricmp(argv->args[i], "-dpen")) && (i+1 < argc)) X backnw.DetailPen = atoi(argv->args[++i]); X X else if ((!stricmp(argv->args[i], "-bpen")) && (i+1 < argc)) X backnw.BlockPen = atoi(argv->args[++i]); X X else if ((!stricmp(argv->args[i], "-sdpen")) && (i+1 < argc)) X ns.DetailPen = atoi(argv->args[++i]); X X else if ((!stricmp(argv->args[i], "-sbpen")) && (i+1 < argc)) X ns.BlockPen = atoi(argv->args[++i]); X X else if (gotfname) X NonFatalError("Quiz: unrecognized option: %s. Try -help\n",argv->args[i]); X else { X gotfname = 1; X strncpy(qstate.File, argv->args[i], MAXFILENAME); X } /* else */ X } /* for i */ X } /* CLI startup */ X} /* parseargs */ X Xstruct ResListItem *MakeNewItem(ptr, size, type) X char *ptr; X int size, type; X { X struct ResListItem *rtn; X extern char *AllocMem(); X rtn = (struct ResListItem *)AllocMem(sizeof(struct ResListItem), MEMF_CLEAR); X if (rtn==NULL) { X fprintf(stderr, "Ummm. Big trouble: couldn't allocate NewItem\n"); X CleanUp(DONE_MSG); X exit(-1); /* machine is really low on memory anyway */ X } /* if */ X rtn->ptr = ptr; X rtn->size = size; X rtn->type = type; X return(rtn); X} /* MakeNewItem */ X Xvoid FreeResource(Item) X struct ResListItem *Item; X{ Xswitch(Item->type) { X case ALLOC_TYPE: X if (Item->ptr) { X FreeMem(Item->ptr, Item->size); /* the real free */ X Item->ptr = NULL; X } /* if */ X break; X case LOCK_TYPE: X UnLock((struct FileLock *)Item->ptr); X break; X case LIB_TYPE: /* these should be the last items released! */ X if (Item->ptr) CloseLibrary(Item->ptr); /* cast it to what? */ X break; X case SCREEN_TYPE: /* should be 2nd to last item released! */ X if (Item->ptr) CloseScreen((struct Screen *)Item->ptr); X break; X case WINDOW_TYPE: /* must be closed AFTER screen! */ X if (Item->ptr) CloseWindow((struct Window *)Item->ptr); X break; X default: X NonFatalError("FreeResource: unknown resource type: %ld\n",Item->type); X break; X } /* switch */ X} /* FreeResource */ X X/* FreeAll will free all memory that has been allocated via Allocate() */ Xvoid FreeAll(ResListp) X struct List *ResListp; X{ X extern void ForgetMemory(); /* mymalloc.c */ X struct ResListItem *node; X struct List TmpList; X X /* Here's the deal: we want to free all memory resources. We will X copy all non-memory resources into a temporary list, freeing up X the memory resources as we go along. */ X X NewList(&TmpList); X X while (node = (struct ResListItem *)RemTail(ResListp)) { X if (node->type == ALLOC_TYPE) { X FreeResource(node); FreeMem(node, sizeof(struct ResListItem)); X } /* if Alloc type */ X else X AddTail(&TmpList, node); X } /* while */ X /* this yields the original order */ X NewList(ResListp); X while (node = (struct ResListItem *)RemTail(&TmpList)) X AddTail(ResListp, node); X X ForgetMemory(); /* must do this!!! This lets mymalloc know to start X allocating new memory and forget the old chunks */ X X} /* FreeAll */ X X/* CleanUp keeps track of all resource allocations and will clean up X when passed DONE_MSG. Must be passed INIT_MSG initally */ Xvoid CleanUp(msg, ptr, size) X int msg; X char *ptr; X int size; X{ X struct ResListItem *NewItem; X static struct List ResList; /* this is the resource list */ X struct ResListItem *node; X Xswitch (msg) { X case INIT_MSG: X NewList(&ResList); /* initialize resource list */ X break; X case ALLOC_MSG: X /* first we have to allocate space for the NewItem. If */ X /* this call fails, we're in big trouble. */ X NewItem = MakeNewItem(ptr, size, ALLOC_TYPE); X X /* and add it to the list */ X AddTail(&ResList, NewItem); X break; X X case LOCK_MSG: X /* lock resource type */ X NewItem = MakeNewItem(ptr, 0, LOCK_TYPE); /* size not used */ X AddTail(&ResList, &(NewItem->n)); X break; X X case LIB_MSG: X /* library opened */ X NewItem = MakeNewItem(ptr, 0, LIB_TYPE); X AddTail(&ResList, &(NewItem->n)); X break; X X case NEWSCREEN_MSG: X NewItem = MakeNewItem(ptr, 0, SCREEN_TYPE); X AddTail(&ResList, &(NewItem->n)); X break; X X case NEWWINDOW_MSG: X NewItem = MakeNewItem(ptr, 0, WINDOW_TYPE); X AddTail(&ResList, &(NewItem->n)); X break; X X case FREEONE_MSG: X NonFatalError("FREEONE not implemented yet! Bogosity, dude.\n"); X break; X X case FREEALL_MSG: X FreeAll(&ResList); X break; X X case DONE_MSG: /* this is really cleaning up */ X while (node = (struct ResListItem *)RemTail(&ResList)) { X /* this depends on the fact that &node = &NewItem->n */ X FreeResource(node); X if (node) { X FreeMem(node, sizeof(struct ResListItem)); /* overhead */ X node = NULL; X } /* if */ X } X break; X default: X NonFatalError("CleanUp: unknown message: %ld\n", msg); X break; X } /* switch */ X} /* CleanUp */ X Xchar *Allocate(size) X int size; X{ X char *ptr; X extern char *AllocMem(); X X/* ptr = AllocMem(size, MEMF_CLEAR);*/ X ptr = mymalloc(size); X if (ptr==NULL) X FatalError("Out of memory! Couldn't allocate %ld bytes\n", size); X/* already registered in mymalloc */ X#if 0 X else CleanUp(ALLOC_MSG, ptr, size); /* register the resource */ X#endif X return(ptr); X} X X/* NonFatalError */ Xvoid NonFatalError(s, a1, a2, a3, a4, a5) X char *s, *a1, *a2, *a3, *a4, *a5; X{ Xfprintf(stderr, s, a1, a2, a3, a4, a5); X} X X/* prints error message string s (w/optional format strings) , cleans X up and exits */ Xvoid FatalError(s, a1, a2, a3, a4, a5) X char *s, *a1, *a2, *a3, *a4, *a5; X{ X fprintf(stderr, s, a1 ,a2, a3, a4, a5); X CloseGraphics(); X CleanUp(DONE_MSG); X exit(10); X} X X/* read the file into one enormous buffer */ X/* returns 1 if successful, 0 if not */ X Xint readfile(name,thebuffer) X char *name, **thebuffer; X{ X struct FileInfoBlock *fib; X extern struct FileLock *Lock(); X struct FileLock *lock; X struct FileHandle *fh; X int filesize,success,bytesread; X X /* fib must be longword aligned!!! */ X fib = (struct FileInfoBlock *)Allocate(sizeof(struct FileInfoBlock)); X#ifdef DEBUG Xprintf("FileInfoBlock is at %d\n", fib); X#endif X lock = Lock(name, ACCESS_READ); X if (!lock) { X NonFatalError("%s not found!\n", name); X return 0; X } /* if */ X /* Normally, we could call X CleanUp(LOCK_MSG, (char *)lock, 0); X to register the resource; but we'll just unlock after we're X done so that the user can swap disks w/o trouble */ X success = Examine(lock, fib); X if (!success) { X NonFatalError("Couldn't examine %s!\n", name); X UnLock(lock); /* we're done with the lock */ X return 0; X } X X#ifdef DEBUG X/*---------------------------------------------------------------*/ Xprintf("Name: %s\n", fib->fib_FileName); Xprintf("[%d] ", fib->fib_DirEntryType); Xif (fib->fib_DirEntryType>0) printf("Directory.\n"); X else printf("Plain file.\n"); Xprintf("file size in bytes: %d\n", fib->fib_Size); Xprintf(" in blocks: %d\n", fib->fib_NumBlocks); Xprintf("file comment: %s\n", fib->fib_Comment); X/*printf("Last modified: \n"); ShowDate(&(fib->fib_Date));*/ X/*---------------------------------------------------------------*/ X#endif X X filesize = fib->fib_Size; /* file size */ X UnLock(lock); /* we're done with the lock */ X X *thebuffer=Allocate(filesize+1); /* add a '\0' to end */ X X fh = Open(name, MODE_OLDFILE); X if (!fh) { X NonFatalError("Couldn't open %s\n", name); X return 0; X } X bytesread = Read(fh, *thebuffer, filesize); X if (bytesread != filesize) { X FatalError("Couldn't read %ld bytes from %s\n",filesize,name); X Close(fh); X return 0; X } X (*thebuffer)[filesize] = '\0'; X Close(fh); X return 1; X} /* readfile */ X X/* count the number of lines that are separated by a newline in X buffer */ Xint countlines(buffer) X char *buffer; X{ X int count=0, i=0; X while (buffer[i]) if (buffer[i++]=='\n') count++; X if (buffer[i-1] != '\n') count++; /* printf("No terminating newline\n");*/ X /*else printf("Terminating newline\n");*/ X return(count); X} /* countlines */ X X/* returns 1 if s is in sl, 0 otherwise */ Xint isin(sl, s) X struct slist *sl; X char *s; X{ X if (qstate.CaseSensitive) X while(sl) { X if (!strcmp(sl->s, s)) return(1); X sl=sl->next; X } /* while */ X else X while(sl) { X if (!stricmp(sl->s, s)) return(1); X sl=sl->next; X } /* while */ X return(0); X} /* isin */ X X/* separate finds the ':' in a string "a:b" and replaces it with '\0' X then return a pointer to b. Modifies s. */ Xchar *separate(s) char *s; X{ X while (*s) { X if (*s==':') { *s = '\0'; return(s+1);} X s++; X } /* while */ X return(NULL); /* no ':' found */ X} /* separate */ X X/* q is the question string */ Xvoid ask(q, sofar, total) X char *q; X int sofar, total; X{ X X printf("[%ld/%ld] %s: ", sofar, total, q); } X X/* a is answer string */ Xvoid getinput(a) char *a; { X X gets(a); remwh(a); } X X/* if he gets it right */ Xvoid correct() { printf("Right!\n"); } X X/* if wrong */ Xvoid wrong(wrongi, right) X struct slist *right; X char *wrongi; X{ X int num; X X/* if user just pressed return be nice; at least he admits his ignorance */ Xif (*wrongi) printf("Wrong, dummy. "); X num = slistSize(right); X if (num == 1) printf("\"%s\"\n", right->s); X else { X printf("\n"); X while(right->next) printf(" \"%s\" or\n", right->s),right=right->next; X printf(" \"%s\"\n",right->s); X } /* else */ X} /* wrong */ X X/* extractlines finds n strings each separated by a '\n'. Creates and X fills an array that is the start address of each string. Replaces X '\n' with '\0' */ Xchar **extractlines(n,bigbuf) X int n; X char *bigbuf; X{ X char **rtn; X int i=0, j=0; X X rtn = (char **)Allocate(n * sizeof(char *)); X rtn[0]=bigbuf; X while (bigbuf[i]) { /* j is in case there's no terminating newline */ X if (bigbuf[i] == '\n') { X rtn[++j] = &(bigbuf[i])+1; X bigbuf[i] = '\0'; X } /* if */ X i++; X } /* while */ X X return(rtn); X} /* extractlines */ X X/* delete any blank lines in a buffer s */ Xvoid deleteblanklines(s) X char *s; X{ X char *t; X t = s; X /* get rid of any initial blank lines */ X while (*t == '\n') t++; X while (1) { X /* t now points to first char in a non-empty line */ X while (*t != '\n') { X if (*t == '\0') {*s = '\0'; return;} X *s++ = *t++; X } X while (*t == '\n') t++; X *s++='\n'; /* put one in */ X } /* while 1 */ X} /* deleteblanklines */ X X/* add an int to an ilist */ Xvoid ilistAdd(il, i) X ilist *il; X int i; X{ X while (il->next) il = il->next; X il->next = (ilist *)Allocate(sizeof(ilist)); X (il->next)->i = i; X (il->next)->next = NULL; X} /* ilistAdd */ X X/* create and return a new ilist */ Xilist *Makeilist(i) int i; X{ X ilist *rtn; X rtn = (ilist *)Allocate(sizeof(ilist)); X rtn->i = i; rtn->next = NULL; X return(rtn); X} /* Makeilist */ X X/*** X *** This function should be called after a quiz file has been read X *** in via readfile(). The file will be in buf at that time. X *** X *** ProcessQFile will delete blank lines, count lines, and parse X *** them. Note that all parameters are modified. Chotto abunai ne. X *** X *** *n is set to the number of lines. X *** *answers, *questions, *score, *origorder are all allocated. X *** A lot of other stuff will be allocated by subroutines. When X *** this quiz file is to be discarded, all allocated memory should X *** be free via FreeAll(). X *** X *** Answers and questions will be swapped if qstate.Switch. A X *** random order is calculated as well. X *** X *** Returns the number of questions. X *** X ***/ Xint ProcessQFile(answers, questions, score, origorder, preprocess, numq) X struct slist ***answers, ***questions; X short **score, **origorder; X int preprocess, numq; X{ X /*** X *** lines contains pointers to the beginning each line of X *** the quiz file. X *** tmpans is used in extracting the answer from each line. X *** X ***/ X char **lines,*tmpans; X int n,i; /* n is the number of questions */ X X /*** X *** tmpslist and tmpptr are used for swapping X ***/ X struct slist *tmpslist; X short tmpshort; X if (preprocess) { X deleteblanklines(buf); X n = countlines(buf); X X lines = extractlines(n,buf); X if (qstate.GraphType = readscore(n)) cleargraph(),drawgraph(); X UpdateMenuGraphState(); X *answers = (struct slist **)Allocate(n * sizeof(struct slist *)); X *questions = (struct slist **)Allocate(n * sizeof(struct slist *)); X *score = (short *)Allocate(n * sizeof(short)); /* initializes to 0 */ X *origorder = (short *)Allocate(n * sizeof(short)); X X history = *score; hindices = *origorder; X for (i=0; i<n; i++) { X (*origorder)[i]=(short)i; X /* now find the answer in "question:answer" line */ X tmpans = separate(lines[i]); /* modifies buf */ X X /* this error should really just abort this particular file X and not actually exit. Later... */ X if (!tmpans) X FatalError("Line \"%s\" is missing a colon\n", lines[i]); X X (*questions)[i] = expand(lines[i]); X (*answers)[i] = expand(tmpans); X X } /* for */ X X if (qstate.Switch) doswap(answers, questions); X X } /* if preprocess */ X else n = numq; /* if preprocess, n is passed in as last arg */ X X /* calculate a random order */ X srand((unsigned)time(NULL)); /* time is in seconds; where's utime? */ X for (i=0;i<n;i++) (*score)[i] = 0; /* can't be done in loop below */ X X for (i= 0; i<n; i++) { X int j, k; X /* swap questions j & k */ X j=rand() % n; k = rand() % n; X if (j != k) { X tmpslist = (*questions)[j]; X (*questions)[j] = (*questions)[k]; X (*questions)[k] = tmpslist; X X tmpslist = (*answers)[j]; X (*answers)[j] = (*answers)[k]; X (*answers)[k] = tmpslist; X X tmpshort = (*origorder)[j]; X (*origorder)[j] = (*origorder)[k]; X (*origorder)[k] = tmpshort; X } /* if */ X } /* for */ X return(n); X } /* ProcessQFile */ X X Xvoid doswap(a,q) X struct slist ***a, ***q; X{ X struct slist **tmpptr; X tmpptr=*a;*a=*q;*q=tmpptr; X} /* doswap */ X Xvoid stractivate() X{ X ActivateGadget(&sgadget, backwindow, NULL); X} /* stractivate */ X X/* swaps elements i and j of qs, as, ss, and os */ Xvoid MajorSwap(qs, as, ss, os, i, j) X short ss[], os[]; X struct slist *as[], *qs[]; X int i, j; X{ X short tmpshort; X struct slist *tmpslist; X X tmpslist = qs[i]; X qs[i] = qs[j]; X qs[j] = tmpslist; X X tmpslist = as[i]; X as[i] = as[j]; X as[j] = tmpslist; X X tmpshort = ss[i]; X ss[i] = ss[j]; X ss[j] = tmpshort; X X tmpshort = os[i]; X os[i] = os[j]; X os[j] = tmpshort; X} /* MajorSwap */ X Xvoid quiz() X { X /*** X *** answers is a list of valid answers X *** questions--a list of valid questions X *** X *** tmpslist is used for swapping X *** X ***/ X struct slist **answers, **questions; X X /*** X *** total is the total number of correct answers given. X *** n is the number of questions in the file. X *** gaveup = 1 if the user quits in the midde of this test. X *** if this is the case, a score file will NOT be written X *** X ***/ X int i=0,n=0,total=0,gaveup=0,j; X X /* score is an array of shorts--one for each question. Initially, X score[i] = 0. If the user answers a question right the first time, X score[i] = RIGHT. If he gets it wrong, score is decremented and X the question is asked again later. Each time he gets it wrong, X score[i] is decremented until score[i] == MAXWRONG. If the user X gets it right, score[i] = -score[i] and thus tells how many times it X took to get it right. */ X X /*** X *** origorder[n] is a list of shorts that gives the original index X *** of each quiz line. Remember, these get shuffled around since X *** a random order is selected, and missed questions get stuck at X *** the end. X *** X ***/ X short *score, *origorder; X ULONG val; X X /* initialize values */ X fileinit: X i=0,n=0,total=0,gaveup=0,val=IGNORE; X X strcpy(sStringInfo.Buffer, ""); X sStringInfo.BufferPos = 0; X sStringInfo.DispPos = 1; X X /* if we are in an asking state, process the question file */ X if (qstate.Asking) X n = ProcessQFile(&answers, &questions, &score, &origorder, 1, 0); X X X qtext = NULL; atext = NULL; ctext = NULL; X if (qstate.Asking) X { X qtext = questions[i]->s; X /* DrawQText(); necessary? we call redraw */ X } X X UpdateCurrentQ(0, (int)origorder[i]); X redraw(); X stractivate(); X X/* main loop */ Xquizloop: Xwhile ((i<n)||(!qstate.Asking)) { X WaitPort(backwindow->UserPort); /* be nice */ X while (mes = GetMsg(backwindow->UserPort)) val=bhandlemsg(mes); X X switch (val) { X case QUITNOW: X return; /* quit */ X X case ABORTNOW: X val = IGNORE; X OnMenu(backwindow, BEGINMENUNUM); X qstate.Asking = 0; X qstate.ShowingAns = 0; X qtext = NULL; X X strcpy(sStringInfo.Buffer, ""); X sStringInfo.BufferPos = 0; X sStringInfo.DispPos = 1; X redraw(); X stractivate(); X break; X /* abort */ X X case OPENNEWFILE: X val=IGNORE; X qstate.Asking=1; X OffMenu(backwindow, BEGINMENUNUM); X goto fileinit; /* filename already set */ X X case SWITCHEM: X doswap(&answers, &questions); X if (qstate.Asking) { X qtext = questions[i]->s; X DrawQText(); X } /* if */ X break; /* if switchem */ X X case STARTASKING: X if ((!qstate.Asking) && qstate.File[0]) { X qstate.Asking = 1; X i=0,total=0,gaveup=0,val=IGNORE; X OffMenu(backwindow, BEGINMENUNUM); X ProcessQFile(&answers, &questions, &score, &origorder, 0, n); X qtext = questions[i]->s; X UpdateCurrentQ(currentquestion, (int)origorder[i]); X DrawQText(); X if (qstate.GraphType) drawgraph(); X stractivate(); X } /* if */ X break; /* STARTASKING */ X X case NEWSTRING: X if (qstate.Asking) { X remwh(atext); X if (isin(answers[i], atext)) { X /* correct();*/ X if (score[i]==0) score[i] = RIGHT,total++; X else score[i] = -score[i]; X if (qstate.ShowingAns) { X qstate.ShowingAns = 0; X EraseCText(); X } /* if */ X } /* if isin */ X X else { /* got this one wrong */ X /* wrong(atext,answers[i]);*/ X score[i]--; X if (score[i] <= MAXWRONG) { X i++; X ctext = NULL; X qstate.ShowingAns = 0; X EraseCText(); X if (i>=n) break; X else X { /* do next question */ X qtext = questions[i]->s; X DrawQText(); X strcpy(sStringInfo.Buffer, ""); X sStringInfo.BufferPos = 0; X sStringInfo.DispPos = 1; X RefreshGadgets(&sgadget, backwindow, NULL); X stractivate(); X UpdateCurrentQ(currentquestion, (int)origorder[i]); X continue; X } /* else */ X X } /* give up on this question */ X else { X ctext = answers[i]->s; /* use the first legal answer I guess */ X qstate.ShowingAns = 1; X DrawCText(); X } /* else */ X X /* we want to ask again, so put the question back */ X /* swap with the last element */ X MajorSwap(questions, answers, score, origorder, i, n-1); X i--; X X } /* else wrong */ X X strcpy(sStringInfo.Buffer, ""); X sStringInfo.BufferPos = 0; X sStringInfo.DispPos = 1; X i++; X if (i>=n) break; X qtext = questions[i]->s; X DrawQText(); X UpdateCurrentQ(currentquestion, (int)origorder[i]); X X } /* if asking */ X break; /* if a new string */ X X case DISPLAYQ: X if (qstate.Asking) { X int theq=-1; X /* so we want to swap the current question with newquestion */ X /* newquestion refers to the original order, so we have to find */ X /* it first */ X for (j=0; j<n; j++) if (origorder[j]==newquestion) theq=j; X if (theq==-1) { X NonFatalError("Couldn't find that question out of %d!\n",n); X break; /* from switch */ X } /* if */ X X if (i== theq) break; X /* if theq<i, then we already asked this question and should decrement X i so that we don't lose any new questions */ X if (theq<i) i--; X MajorSwap(questions, answers, score, origorder, i, theq); X qtext = questions[i]->s; X X UpdateCurrentQ(currentquestion,(int)origorder[i]); X X strcpy(sStringInfo.Buffer, ""); X sStringInfo.BufferPos = 0; X sStringInfo.DispPos = 1; X X redraw(); X stractivate(); X X } /* if asking */ X break; /* DISPLAYQ */ X case IGNORE: X break; X default: X NonFatalError("quiz(): %d is an unknown message\n", val); X break; X } /* switch val */ X X stractivate(); X RefreshGadgets(&sgadget, backwindow, NULL); X X val=IGNORE; X} /* while i<=n */ X X qstate.Asking = 0; X qstate.ShowingAns = 0; X qtext = NULL; /* so it won't be redraw()n */ X OnMenu(backwindow, BEGINMENUNUM); X strcpy(sStringInfo.Buffer, ""); X sStringInfo.BufferPos = 0; X sStringInfo.DispPos = 1; X RefreshGadgets(&sgadget, backwindow, NULL); X stractivate(); X X if (total != n) { X printf("You missed:\n"); X for (i=0;i<n;i++) X /* score[i] is 0 if "quit" was selected */ X if ((score[i] != RIGHT)&&(score[i] != 0)) X printf(" %s: %s\n",questions[i]->s,answers[i]->s); X } /* if total != n */ X else printf("Congratulations!\n"); X printf("\nScore: %ld/%ld (%ld%%)\n", total, n, total * 100 / n); X if (gaveup==0){ X writescore(score, n, origorder, total); X if (qstate.GraphType==0) { X qstate.GraphType = BYQUESTION; X UpdateMenuGraphState(); X/* OffMenu(backwindow, (SHIFTMENU(1)|SHIFTITEM(4)|SHIFTSUB(NOSUB))); X OnMenu(backwindow, (SHIFTMENU(1)|SHIFTITEM(3)|SHIFTSUB(NOSUB)));*/ X } /* if */ X } /* if */ X if (qstate.GraphType) {cleargraph(); drawgraph();} X i = 0; X EraseQText(); EraseCText(); /* does nothing if they are empty */ X goto quizloop; X} /* quiz */ X X/* write the score to filename.sc, also updates graph data */ Xvoid writescore(score, n, value, total) X short *score, *value; X int n, total; X{ X char scorefile[MAXFILENAME+3]; /* ".sc" */ X FILE *fh; X int i, worstq; X strcpy(scorefile,qstate.File); strcat(scorefile,SCORE_FILE_EXT); X fh = fopen(scorefile,"a"); X if (fh==NULL) NonFatalError("Couldn't open score file %s\n",scorefile); X else { X int *intptr; X intptr = AddTrial(n-total,n); X X worstq = intptr[0]; X for (i=0;i<n;i++) { X/*printf("%d: orig=%d trialdata[%d]=%d worst=%d\n", X i,value[i],value[i],intptr[value[i]],worstq);*/ X if (score[i] != RIGHT) { X fprintf(fh, "%d ", value[i]); X intptr[value[i]]++; X } /* if */ X if (intptr[value[i]] > worstq) worstq = intptr[value[i]]; X } /* for */ X fprintf(fh, "\n"); X fclose(fh); X /* only set worst question if he actually missed something */ X if (n-total) SetWorstQuestion(worstq); X } /* else */ X X} /* writescore */ X Xvoid main(argc, argv) X int argc; X union { X char **args; X struct WBStartup *msg; X } argv; X{ X X CleanUp(INIT_MSG); /* initialize resource manager */ X X qstate.Switch = 0; X qstate.File[0] = '\0'; X qstate.ShowingAns = 0; X qstate.CaseSensitive = 1; X qstate.Asking = 0; X qstate.GraphType = 0; X X parseargs(argc, &argv); X X if (qstate.File[0]) { X if (readfile(qstate.File,&buf)) X qstate.Asking = 1; X else strcpy(qstate.File, ""); X } /* if */ X X InitGraphics(); X redraw(); X X quiz(); X CloseGraphics(); X CleanUp(DONE_MSG); X exit(0); X} /* main */ END_OF_FILE if test 26723 -ne `wc -c <'quiz.c'`; then echo shar: \"'quiz.c'\" unpacked with wrong size! fi # end of 'quiz.c' fi if test -f 'screen.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'screen.c'\" else echo shar: Extracting \"'screen.c'\" \(17829 characters\) sed "s/^X//" >'screen.c' <<'END_OF_FILE' X#include <stdio.h> X#include <string.h> /* strcpy */ X#include "screen.h" X Xvoid DrawRaisedText(); Xvoid EraseQText(), EraseCText(); Xvoid DrawQText(), DrawCText(); Xvoid colorwindow(); Xint OpenLibs(); Xvoid InitGraphics(); Xvoid UpdateMenuGraphState(); Xvoid CloseGraphics(); XULONG ehandlemsg(); Xint handlegadget(); Xint handlebuttons(); Xint bhandlemsg(); Xint handlemenu(); Xvoid main(); Xvoid redraw(); Xvoid about(), abort(); Xint load(); X Xextern void stractivate(); /* quiz.c */ X Xextern void drawgraph(), cleargraph(); /* graph.c */ Xextern int whichquestion(); /* graph.c */ X X X/* draw semi-3d-looking text */ Xvoid DrawRaisedText(rp,text,slen,x,y) X struct RastPort *rp; X char *text; X int slen, x, y; X { X /* draw it dark */ X SetAPen(rp, GREY2); X Move(rp, x+1,y); X Text(rp, text, slen); X X /* draw it light */ X SetAPen(rp, GREY11); X Move(rp, x-1,y); X Text(rp, text, slen); X X /* draw it just right */ X SetAPen(rp, GREY7); X Move(rp, x,y); X Text(rp, text, slen); X} /* DrawRaisedText */ X X/* clear qtext display area */ Xvoid EraseQText() { X if (qpb[0]) X { /* clear area */ X SetAPen(rp, GREY7); X SetDrMd(rp, JAM1); X RectFill(rp, qpt[2], qpt[3], qpb[2], qpb[3]); X qpb[0] = 0; X } /* if */ X} /* EraseQText */ X X#define QCOLOR GREY3 X/* draw the question */ Xvoid DrawQText() X{ X int slen,theight,textsize; X X /* delete old border */ X if (qpb[0]) /* don't delete if first time */ X { X /* clear the area */ X SetAPen(rp, GREY7); X SetDrMd(rp, JAM1); X RectFill(rp, qpt[2], qpt[3], qpb[2], qpb[3]); X } /* if */ X slen = strlen(qtext); X if (slen==0) return; X theight = rp->TxHeight; X textsize = slen * rp->TxWidth + 1; /* 1 pixel pad? */ X qpt[0] = QX-BORDWIDTH*2; X qpt[1] = QY+theight+BORDWIDTH*2; X qpt[2] = QX-BORDWIDTH*2; X qpt[3] = QY-BORDWIDTH*2; X qpt[4] = QX+textsize+BORDWIDTH*2; X qpt[5] = QY-BORDWIDTH*2; X X qpb[0] = QX-BORDWIDTH*2; X qpb[1] = QY+theight+BORDWIDTH*2; X qpb[2] = QX+textsize+BORDWIDTH*2; X qpb[3] = QY+theight+BORDWIDTH*2; X qpb[4] = QX+textsize+BORDWIDTH*2; X qpb[5] = QY-BORDWIDTH*2; X X if (slen <= maxqchars) { X /* set border */ X DrawBorder(rp,&qtop,0,0); X /* draw black box */ X SetAPen(rp, QCOLOR); X SetDrMd(rp, JAM1); X RectFill(rp, qpt[2]+BORDWIDTH, qpt[3]+BORDWIDTH, X qpb[2]-BORDWIDTH, qpb[3]-BORDWIDTH); X /* now draw text */ X DrawRaisedText(rp, qtext, slen, QX, QY+baseheight); X } /* if */ X else { /* must make bigger window */ X char *lastspace = NULL, *s, *r; X int done = 0, numlines = 0, maxlen = 0, i; X /* Have to copy strings and output them after breaking up */ X /* qtext. We must know maxlen's value in order to draw */ X /* the dark grey rectangle */ X char brokentext[MAXLINES][MAXQCHARS]; X int sizes[MAXLINES]; X r = qtext; X X do { X numlines++; X s = r; X while (s<r+maxqchars) { X if (*s == ' ') lastspace = s; X else if (*s == '\0') {done = 1; break;} X s++; X } /* while */ X /* this is gross */ X /* we found a line */ X if (lastspace) { X if (!done) *lastspace = '\0'; /* gulp */ X slen = strlen(r); if (slen>maxlen) maxlen = slen; X strncpy(brokentext[numlines-1],r,slen); X sizes[numlines-1] = slen; X /*DrawRaisedText(rp, r, slen, QX, QY+baseheight+theight*(numlines-1));*/ X if (!done) *lastspace = ' '; X r = lastspace + 1; X while (*r == ' ') r++; /* skip over any more spaces */ X if (!*r) done = 1; X lastspace = NULL; X } /* if lastspace */ X else if (done) /* reached the end in this iteration */ X { X slen = strlen(r); if (slen>maxlen) maxlen = slen; X strncpy(brokentext[numlines-1],r,slen); X sizes[numlines-1] = slen; X /*DrawRaisedText(rp, r, slen, QX, QY+baseheight+theight*(numlines-1));*/ X } X else { /* no breaks */ X strncpy(brokentext[numlines-1],r,maxqchars); X sizes[numlines-1] = maxqchars; X /*DrawRaisedText(rp, r, maxqchars, QX, QY+baseheight+theight*(numlines-1));*/ X r+=maxqchars; maxlen = maxqchars; X while (*r == ' ') r++; /* skip over any more spaces */ X if (!*r) done = 1; X } /* else */ X } while ((!done)&&(numlines<MAXLINES)); X /* set border -- only 3 must be changed*/ X textsize = maxlen * rp->TxWidth + 1; /* 1 pixel pad? */ X X qpt[4] = QX+textsize+BORDWIDTH; X qpb[2] = QX+textsize+BORDWIDTH; X qpb[4] = QX+textsize+BORDWIDTH; X X qpt[1] = QY+theight*numlines+BORDWIDTH; X qpb[1] = QY+theight*numlines+BORDWIDTH; X qpb[3] = QY+theight*numlines+BORDWIDTH; X X DrawBorder(rp,&qtop,0,0); X /* draw black box */ X SetAPen(rp, QCOLOR); X SetDrMd(rp, JAM1); X RectFill(rp, qpt[2]+BORDWIDTH, qpt[3]+BORDWIDTH, X qpb[2]-BORDWIDTH, qpb[3]-BORDWIDTH); X X /* now actually draw the text */ X for (i=0;i<numlines;i++) X DrawRaisedText(rp, brokentext[i], sizes[i], QX, QY+baseheight+theight*i); X } /* else */ X} /* DrawQText */ X X/* clear ctext display area */ Xvoid EraseCText() { X if (cpb[0]) X { /* clear area */ X SetAPen(rp, GREY7); X SetDrMd(rp, JAM1); X RectFill(rp, cpt[2], cpt[3], cpb[2], cpb[3]); X cpb[0] = 0; X } /* if */ X} /* EraseCText */ X X#define CCOLOR 15 /* ? */ X/* draw the correct answer */ Xvoid DrawCText() X{ X int slen, theight, textsize; X /* delete old border if existing */ X if (cpb[0]) X { /* clear area */ X SetAPen(rp, GREY7); X SetDrMd(rp, JAM1); X RectFill(rp, cpt[2], cpt[3], cpb[2], cpb[3]); X } /* if */ X if (ctext==NULL) return; X slen = strlen(ctext); X if (slen==0) return; X theight = rp->TxHeight; X textsize = slen * rp->TxWidth + 1; /* 1 pixel pad? */ X X cpt[0] = CX-BORDWIDTH*2; X cpt[1] = CY+theight+BORDWIDTH*2; X cpt[2] = CX-BORDWIDTH*2; X cpt[3] = CY-BORDWIDTH*2; X cpt[4] = CX+textsize+BORDWIDTH*2; X cpt[5] = CY-BORDWIDTH*2; X X cpb[0] = CX-BORDWIDTH*2; X cpb[1] = CY+theight+BORDWIDTH*2; X cpb[2] = CX+textsize+BORDWIDTH*2; X cpb[3] = CY+theight+BORDWIDTH*2; X cpb[4] = CX+textsize+BORDWIDTH*2; X cpb[5] = CY-BORDWIDTH*2; X X if (slen <= maxqchars) { X /* set border */ X DrawBorder(rp,&ctop,0,0); X /* draw black box */ X SetAPen(rp, CCOLOR); X SetDrMd(rp, JAM1); X RectFill(rp, cpt[2]+BORDWIDTH, cpt[3]+BORDWIDTH, X cpb[2]-BORDWIDTH, cpb[3]-BORDWIDTH); X /* now draw text */ X DrawRaisedText(rp, ctext, slen, CX, CY+baseheight); X } /* if */ X else { /* must make bigger window */ X char *lastspace = NULL, *s, *r; X int done = 0, numlines = 0, maxlen = 0, i; X /* Have to copy strings and output them after breaking up */ X /* ctext. We must know maxlen's value in order to draw */ X /* the dark grey rectangle */ X char brokentext[MAXLINES][MAXQCHARS]; X int sizes[MAXLINES]; X r = ctext; X X do { X numlines++; X s = r; X while (s<r+maxqchars) { X if (*s == ' ') lastspace = s; X else if (*s == '\0') {done = 1; break;} X s++; X } /* while */ X /* this is gross */ X /* we found a line */ X if (lastspace) { X if (!done) *lastspace = '\0'; /* gulp */ X slen = strlen(r); if (slen>maxlen) maxlen = slen; X strncpy(brokentext[numlines-1],r,slen); X sizes[numlines-1] = slen; X if (!done) *lastspace = ' '; X r = lastspace + 1; X while (*r == ' ') r++; /* skip over any more spaces */ X if (!*r) done = 1; X lastspace = NULL; X } /* if lastspace */ X else if (done) /* reached the end in this iteration */ X { X slen = strlen(r); if (slen>maxlen) maxlen = slen; X strncpy(brokentext[numlines-1],r,slen); X sizes[numlines-1] = slen; X } X else { /* no breaks */ X strncpy(brokentext[numlines-1],r,maxqchars); X sizes[numlines-1] = maxqchars; X r+=maxqchars; maxlen = maxqchars; X while (*r == ' ') r++; /* skip over any more spaces */ X if (!*r) done = 1; X } /* else */ X } while ((!done)&&(numlines<MAXLINES)); X /* set border -- only 3 must be changed*/ X textsize = maxlen * rp->TxWidth + 1; /* 1 pixel pad? */ X X cpt[4] = CX+textsize+BORDWIDTH; X cpb[2] = CX+textsize+BORDWIDTH; X cpb[4] = CX+textsize+BORDWIDTH; X X cpt[1] = CY+theight*numlines+BORDWIDTH; X cpb[1] = CY+theight*numlines+BORDWIDTH; X cpb[3] = CY+theight*numlines+BORDWIDTH; X X DrawBorder(rp,&ctop,0,0); X /* draw black box */ X SetAPen(rp, CCOLOR); X SetDrMd(rp, JAM1); X RectFill(rp, cpt[2]+BORDWIDTH, cpt[3]+BORDWIDTH, X cpb[2]-BORDWIDTH, cpb[3]-BORDWIDTH); X X /* now actually draw the text */ X for (i=0;i<numlines;i++) X DrawRaisedText(rp, brokentext[i], sizes[i], CX, CY+baseheight+theight*i); X } /* else */ X} /* DrawCText */ X X/* fills in an entire window with color c */ Xvoid colorwindow(w,c) X struct Window *w; X int c; X{ X SetDrMd(w->RPort, JAM1); X SetAPen(w->RPort, c); X RectFill(w->RPort, 0, 0, w->Width, w->Height); X} /* colorwindow*/ X X#if 0 Xvoid FatalError(s) char *s; X{ X printf("%s", s); X CloseGraphics(); X exit(1); X} /* FatalError */ X#endif X X/* Just opens intuition library. Returns 1 if successful, 0 if not */ Xint iopen=0, gopen=0; Xint OpenLibs() { X IntuitionBase = (struct IntuitionBase *) X OpenLibrary("intuition.library", 0); X if (IntuitionBase==NULL) return(0); X iopen = 1; X GfxBase = (struct GfxBase *) X OpenLibrary("graphics.library", 0); X if (GfxBase==NULL) return(0); X gopen=1; X return(1); X } /* OpenLibs */ X Xvoid InitGraphics() { X if (OpenLibs()==0) FatalError("Couldn't open libraries!\n"); X X if ((qscreen = OpenScreen(&ns)) == NULL) X FatalError("Couldn't open screen!\n"); X vp = &(qscreen->ViewPort); X X /* initialize colortable */ X LoadRGB4(vp, &mycmap[0], 32); X X/* errnw.Screen = qscreen;*/ X backnw.Screen = qscreen; X X backnw.FirstGadget = &sgadget; X if ((backwindow = OpenWindow(&backnw)) == NULL) X FatalError("Couldn't open backdrop window!\n"); X/* if ((ewindow = OpenWindow(&errnw)) == NULL) X FatalError("Couldn't open error window!\n");*/ X X menustrip[0] = &m1; X menustrip[1] = &m2; X menustrip[0]->NextMenu = menustrip[1]; X SetMenuStrip(backwindow,menustrip[0]); X X if (qstate.Asking || (!qstate.File[0])) X OffMenu(backwindow, BEGINMENUNUM); X if (qstate.GraphType==BYTRIAL) { X OffMenu(backwindow, TRIALMENUNUM); X OnMenu(backwindow, QUESTMENUNUM); X } /* if */ X else if (qstate.GraphType==BYQUESTION) X { X OffMenu(backwindow, QUESTMENUNUM); X OnMenu(backwindow, TRIALMENUNUM); X } /* if */ X ShowTitle(qscreen, FALSE); X rp = backwindow->RPort; X X /* calculate how many characters can fit in one line of text */ X /* note that this method doesn't account for variable-width fonts :-( */ X maxqchars = (MAXQX-QX)/rp->TxWidth; X baseheight = rp->TxBaseline; X } /* InitGraphics */ X X/* This is not very clean, but we need to be able to turn off/on the X correct menu items depending of the state of the graph */ Xvoid UpdateMenuGraphState() { X if (qstate.GraphType==BYTRIAL) { X OffMenu(backwindow, TRIALMENUNUM); X OnMenu(backwindow, QUESTMENUNUM); X } /* if */ X else if (qstate.GraphType == BYQUESTION) { X OffMenu(backwindow, QUESTMENUNUM); X OnMenu(backwindow, TRIALMENUNUM); X } /* if */ X} /* UpdateMenuGraphState */ X Xvoid CloseGraphics() X{ X if (backwindow) { X ClearMenuStrip(backwindow); X while (mes = GetMsg(backwindow->UserPort)) ReplyMsg(mes); X CloseWindow(backwindow); X } /* if backwindow */ X if (qscreen) CloseScreen(qscreen); X if (gopen) CloseLibrary(GfxBase); X if (iopen) CloseLibrary(IntuitionBase); X /*OpenWorkBench();*/ X /*WBenchToFront();*/ X} /* CloseGraphics */ X XULONG ehandlemsg(message) X struct IntuiMessage *message; X{ X struct IntuiMessage localms; X int i; X UBYTE *s, *d; X ULONG class,code; X X s = (UBYTE *)message; X d = (UBYTE *)&localms; X X for (i=0;i<sizeof(struct IntuiMessage);i++) *d++=*s++; X ReplyMsg(message); X X class = localms.Class; X code = localms.Code; X switch (class) X { X case CLOSEWINDOW: X break; X case REFRESHWINDOW: X case NEWSIZE: X redraw(); X default: X break; X } /* switch */ X return(class); X} /* ehandlemsg */ X Xint handlegadget(g) X struct Gadget *g; X{ X switch (g->GadgetID) { X case STRINGID: X atext = ((struct StringInfo *)(g->SpecialInfo))->Buffer; X /*DrawQText();*/ X return(NEWSTRING); X break; X case IMAGEID: X break; X default: X break; X } X return(IGNORE); X X} /* handle gadget */ X Xvoid about() { printf("Quiz by Curtis Eubanks\n"); } X X/* returns 1 if successful, 0 if not */ Xint load() { X if (*sStringInfo.Buffer) X { X strcpy(qstate.File, sStringInfo.Buffer); X history = hindices = (short *)NULL; X CleanUp(FREEALL_MSG); X if (readfile(qstate.File, &buf)) { X qstate.Asking = 1; X return 1; X } /* if */ X } /* if */ X return 0; X} /* load */ X Xvoid abort() { X } /* abort */ Xint handlemenu(code) X ULONG code; X{ X ULONG MenuNumber = MENUNUM(code), ItemNumber = ITEMNUM(code); X if ((code != MENUNULL) && (ItemNumber != NOITEM)) { X if (MenuNumber == PROJMENU) { X switch (ItemNumber) X { X case QUITNUM: X return(QUITNOW); X break; X case ABOUTNUM: X about(); X break; X case LOADNUM: X if (load()) return(OPENNEWFILE); else return(IGNORE); X break; X case BEGINNUM: X return(STARTASKING); X break; X default: X NonFatalError("Unknown Project Menu selection!\n"); X break; X } /* switch */ X } /* if project menu */ X else if (MenuNumber==OPTMENU) { X switch (ItemNumber) X { X case SWITCHNUM: X return(SWITCHEM); X break; X case IGNORENUM: X qstate.CaseSensitive = !qstate.CaseSensitive; X break; X case ABORTNUM: X abort(); X return(ABORTNOW); X break; X case MENUBYTRIAL: X if (qstate.GraphType != BYTRIAL && qstate.GraphType) { X qstate.GraphType = BYTRIAL; X OffMenu(backwindow, TRIALMENUNUM); X OnMenu(backwindow, QUESTMENUNUM); X cleargraph(); X drawgraph(); X stractivate(); X } X return IGNORE; X break; X case MENUBYQUESTION: X if (qstate.GraphType != BYQUESTION && qstate.GraphType) { X qstate.GraphType = BYQUESTION; X OffMenu(backwindow, QUESTMENUNUM); X OnMenu(backwindow, TRIALMENUNUM); X cleargraph(); X drawgraph(); X stractivate(); X } X return IGNORE; X break; X default: X NonFatalError("Unknown Option Menu selection!\n"); X break; X } /* switch itemnumber */ X } /* if option menu */ X } /* if non-null menu selection */ X return(IGNORE); X} /* handlemenu */ X X/* handle button presses */ Xint handlebuttons(code, mousex, mousey) X ULONG code; X SHORT mousex, mousey; X{ X if (code == SELECTDOWN) { X int q; X#ifdef DEBUG X printf("mouse at %d, %d\n", mousex, mousey); X#endif X if ((qstate.GraphType == BYQUESTION) && X ((q=whichquestion(mousex, mousey))!=-1)) X { /* in graph.c */ X newquestion = q; /* global, yucky */ X return DISPLAYQ; X } /* if q != -1 */ X } /* if code */ X return IGNORE; X} /* handlebuttons */ X X X Xint bhandlemsg(message) X struct IntuiMessage *message; X{ X struct IntuiMessage localms; X int i; X UBYTE *s, *d; X ULONG class,code; X X s = (UBYTE *)message; X bloop: X d = (UBYTE *)&localms; X X /* copy message */ X for (i=0;i<sizeof(struct IntuiMessage);i++) *d++=*s++; X ReplyMsg(message); X X class = localms.Class; X code = localms.Code; X switch (class) X { X case REFRESHWINDOW: /* ugh. this hurts */ X /* any more REFRESHWINDOW msgs waiting? */ X if (mes = GetMsg(backwindow->UserPort)) X { /* don't redraw if more than one REFRESHWINDOW in a row */ X/* printf("waiting: %d ",mes->Class); X if (mes->Class==REFRESHWINDOW) printf("(refresh)\n"); X else printf("(not refresh)\n");*/ X s = (UBYTE *)mes; message = mes; /* legal? */ X if (mes->Class==REFRESHWINDOW) goto bloop; X else { /* some other message. Redraw and process it */ X redraw(); X goto bloop; X } /* else */ X } /* if */ X else redraw(); X break; X case GADGETUP: X return(handlegadget((struct Gadget *)localms.IAddress)); X break; X case MENUPICK: X return(handlemenu(code)); X break; X case MOUSEBUTTONS: X return(handlebuttons(code, localms.MouseX, localms.MouseY)); X break; X default: X break; X } /* switch */ X return(IGNORE); X} /* bhandlemsg */ X X#if 0 Xvoid main(argc, argv) X int argc; X union { X char **args; X struct WBStartup *msg; X } argv; X{ X ULONG val=0; X if (argc>2) { X/* errnw.DetailPen = atoi(argv.args[1]); X errnw.BlockPen = atoi(argv.args[2]);*/ X } X if (argc>4) { X ns.DetailPen = atoi(argv.args[3]); X ns.BlockPen = atoi(argv.args[4]); X } X X InitGraphics(); X X redraw(); X /* WaitPort(ewindow->UserPort);*/ X while(1) { X while (mes = GetMsg(backwindow->UserPort)) val=bhandlemsg(mes); X if (val == QUITNUM) break; X/* while (mes = GetMsg(ewindow->UserPort)) val=ehandlemsg(mes);*/ X if (val == CLOSEWINDOW) break; X } X CloseGraphics(); X} /* main */ X#endif X#define BaseX 30 X#define BaseY 40 X#define Bsize 12 X Xvoid redraw() { X colorwindow(backwindow, GREY7); X SetDrMd(rp, JAM1); X X /* draw gadget's border */ X DrawBorder(rp,&ibt,0,0); X if (qtext) DrawQText(); X if (qstate.ShowingAns) DrawCText(); X if (qstate.GraphType) drawgraph(); X RefreshGadgets(&sgadget, backwindow, NULL); X } /* redraw */ END_OF_FILE if test 17829 -ne `wc -c <'screen.c'`; then echo shar: \"'screen.c'\" unpacked with wrong size! fi # end of 'screen.c' fi echo shar: End of archive 2 \(of 2\). cp /dev/null ark2isdone MISSING="" for I in 1 2 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked both archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Mail submissions (sources or binaries) to <amiga@uunet.uu.net>. Mail comments to the moderator at <amiga-request@uunet.uu.net>. Post requests for sources, and general discussion to comp.sys.amiga.misc.