home *** CD-ROM | disk | FTP | other *** search
- /*********************************************************/
- /* COPROC.C */
- /* Coroutinenmodul für Turbo C */
- /* (C) 1989 Guido Goldstein & TOOLBOX */
- /*********************************************************/
-
- #include <setjmp.h> /* Prototypen für nicht lokales goto */
- #include <alloc.h> /* Speicherverwaltung */
- #include <pointer.h> /* Makros für Arbeit mit Zeigern */
-
- /* Struktur für die Coprozess-Verwaltung */
- typedef struct {
- int from ; /* Caller der Routine */
- jmp_buf buffer ; /* Buffer für longjmp aus setjmp.h */
- char init ; /* Flag ob schon aktiv gewesen */
- void far (*fnc)(); /* Adresse der Funktion */
- char far *stack ; /* Zeiger auf den Stack */
- unsigned st_size ; /* Größe des Stacks (max. 64K) */
- } COPROCESS ;
-
- #define MAXCOPROC 62 /* Max. Anzahl an Coroutinen */
- #define MAINP (MAXCOPROC+1) /* Handle für das
- Hauptprogramm (main) */
-
- COPROCESS _coproc[MAXCOPROC+2] ;
-
- int HERE ; /* Aktueller Coprocess */
-
- /* Sprung zur angegebenen Coroutine */
- #define transfer(to) if (!setjmp(_coproc[HERE].buffer)) \
- callcoproc(to);
-
- /* Vereinfachter Rücksprung zum Caller */
- #define coreturn() if (!setjmp(_coproc[HERE].buffer)) \
- callcoproc(_coproc[HERE].from);
-
- /* Coprocess mit Nummer n aufrufen */
- /* Evtl. den Stack bereitstellen und initialisieren */
- void far callcoproc (int n)
- {
- if (n < MAINP && ((long)_coproc[n].fnc != 0L)) {
- /* Wenn gültige Prozess-Nr., den Process aufrufen */
- _coproc[n].from = HERE ;
- HERE = n ;
- if (_coproc[n].init)
- /* Process lief schon, weitermachen */
- longjmp (_coproc[n].buffer,1);
- else {
- /* Neustart, Prozess erst initialisieren */
- COPROCESS *cp ; /* Zeiger statt Index */
- cp = &_coproc[n] ;
- if ((long)cp->stack == 0L) {
- /* Wenn nötig, neuen Stack bereitstellen */
- cp->stack = farmalloc(cp->st_size);
- if ((long)cp->stack == 0L) /* Speicherfehler */
- return ;
- } /* end if */
- /* Initialisierungsflag setzen */
- cp->init = 1 ;
- /* Sprungpuffer einstellen */
- /* Zuerst die Adresse der Funktion
- (Coprozess) in den Puffer */
- cp->buffer->j_cs = FP_SEG(cp->fnc);
- cp->buffer->j_ip = FP_OFF(cp->fnc);
- /* Stackbereich in den Puffer */
- cp->buffer->j_ss = FP_SEG(cp->stack);
- /* Stackpointer auf Ende des Stackbereichs setzen */
- cp->buffer->j_sp = FP_OFF(cp->stack)+cp->st_size;
- /* Datensegment festlegen - siehe Text - */
- cp->buffer->j_ds = _DS ;
- /* Coprocess starten */
- longjmp (cp->buffer,1);
- } /* end else */
- } /* end if */
- else {
- if (n == MAINP) {
- /* Zurück in die aurufende Routine */
- _coproc[MAINP].from = HERE ;
- n = HERE = MAINP ;
- longjmp (_coproc[n].buffer,1);
- } /* end if */
- } /* end else */
- } /* end of callcoproc */
-
- /* Neue Coroutine aufnehmen, Handle zurückgeben */
- int far newcoproc (void far (*f)(), unsigned int st_size)
- {
- int i ;
-
- /* Freien Puffer suchen */
- for (i = 0;
- (i < MAXCOPROC) && ((long)_coproc[i].fnc != 0L) ;
- i++) ;
- if (i < MAXCOPROC) {
- /* Wenn gefunden, initialisieren */
- _coproc[i].fnc = f ;
- if ((long)_coproc[i].stack != 0L) {
- /* Falls Stack noch belegt, freigeben */
- farfree (_coproc[i].stack);
- _coproc[i].st_size = 0 ;
- _coproc[i].buffer->j_ss = _SS ;
- _coproc[i].buffer->j_sp = _SP ;
- } /* end if */
- _coproc[i].stack = 0L ;
- _coproc[i].st_size = st_size ;
- } /* end if */
- else /* Kein freier Puffer */
- return (-1); /* Fehler */
- return (i);
- } /* end of newcoproc */
-
- /* Freien Stackspeicher der Coroutine zurückgeben */
- unsigned far costackfree (void)
- {
- char huge *s1 ;
- char huge *s2 ;
-
- s1 = (char huge *) _coproc[HERE].stack ;
- s2 = (char huge *) MK_FP (_SS,_SP);
- return ((unsigned)((long)s2-(long)s1));
- } /* end of costackfree */
-
- /* Coroutine mit Nummer proc aus Puffer löschen */
- int far remcoproc (int proc)
- {
- if (proc < MAINP) {
- /* Wenn gültiger Processhandle, Process löschen */
- COPROCESS *cp ;
- cp = &_coproc[proc] ;
- cp->fnc = 0L ;
- cp->init = 0 ;
- if ((long)cp->stack != 0L) {
- /* Wenn nötig, Stack freigeben */
- farfree (cp->stack);
- cp->stack = 0L ;
- cp->st_size = 0 ;
- cp->buffer->j_ss = _SS ;
- cp->buffer->j_sp = _SP ;
- } /* end if */
- return (proc);
- } /* end if */
- return (-1);
- } /* end of remcoproc */
-
- /* Bestehenden Handle mit neuer Routine belegen */
- /* !!! Stack bleibt gleich !!! */
- int far changecoproc (int p, void far (*f)())
- {
- if (p < MAINP) {
- _coproc[p].init = 0 ;
- _coproc[p].fnc = f ;
- return (p);
- }
- return (-1);
- } /* end of changecoproc */
-
- /* Coprocess-Puffer initialisieren */
- void far initcoproc (void)
- {
- int i ;
-
- for (i = 0; i < (MAXCOPROC+1); i++) {
- _coproc[i].init = 0 ;
- _coproc[i].fnc = 0L ;
- _coproc[i].stack = 0L ;
- _coproc[i].st_size = 0 ;
- }
- _coproc[MAINP].init = 1 ;
- _coproc[MAINP].from = -1 ;
- HERE = MAINP ;
- } /* end of initcoproc */
-
- /* Coprocess richtig beenden */
- void far exitcoproc (void)
- {
- COPROCESS *cp ;
-
- cp = &_coproc[HERE] ;
- if (cp->from >= 0 && cp->from < MAINP) {
- /* Wenn möglich, zurück zum Caller */
- HERE = cp->from ;
- /* Routine löschen */
- cp->fnc = 0L ;
- cp->init = 0 ;
- cp = &_coproc[HERE] ;
- /* Sprung zum Caller */
- if ((long)cp->fnc != 0L)
- longjmp (cp->buffer,1);
- else
- /* Oder in das Hauptprogramm */
- longjmp (_coproc[MAINP].buffer,1);
- } /* end if */
- else
- /* Zurück ins Hauptprogramm */
- if (cp->from < 0 || cp->from >= MAINP) {
- cp->fnc = 0L ;
- HERE = MAINP ;
- longjmp (_coproc[MAINP].buffer,1);
- } /* end if */
- } /* end of exitcoproc */