/* TODD-DRAW */ /* */ /* The poor man's paint program */ /* (no graphics adapter or printer needed) */ /* */ /* Andrew D. Todd */ /* */ /* v. 1.078 */ /* draft of jun 22, 1991, w. bug fixes to jun 1, 1994 */ /* */ /*$LIST*/ #include #include #include #include #include #include /*------------------------------------------------------------------------*/ /* START OF THE GENERAL PURPOSE PACKAGE ADTODD */ /*------------------------------------------------------------------------*/ /*-------------- Definitions for my package --------------*/ #define LF_ARW_KEY '\113' #define HOME_KEY '\107' #define UP_ARW_KEY '\110' #define PG_UP_KEY '\111' #define RT_ARW_KEY '\115' #define PG_DN_KEY '\121' #define DN_ARW_KEY '\120' #define END_KEY '\117' #define INS_KEY '\122' #define DEL_KEY '\123' #define ESC '\x1b' #define PF1_KEY '\73' #define PF2_KEY '\74' #define PF3_KEY '\75' #define PF4_KEY '\76' #define PF5_KEY '\77' #define PF6_KEY '\100' #define PF7_KEY '\101' #define PF8_KEY '\102' #define PF9_KEY '\103' #define PF10_KEY '\104' #define NULL_BYTE '\0' #define LG_YES 1 #define LG_NO 0 #define TRUE LG_YES #define FALSE LG_NO #define N_ERR LG_NO #define R_ERR -1 /*------------------ Character Attributes --------------------------*/ #define NORMAL '\7' #define HIGHLITE '\x70' #define BLINKBIT '\x80' #pragma trace- /*--------- BEGINING OF THE GENERAL PURPOSE FUNCTIONS ---------------------*/ clamp(val, lval, uval) int val, lval, uval; { if (val < lval) return lval; else {if (val > uval) return uval; else return val;}; } /* makes sure that val is not out of range */ /*used nowhere else */ /*--------------------------------------------------------------------------*/ /*---------------*/ char *chtostr( char *str, char al ) { str[0]=al; str[1]='\0'; return(str); } int imin( int a, int b ) { if(a < b) return(a); else return(b); } int imax( int a, int b ) { if(a > b) return(a); else return(b); } /*------------------------ Scrnputs ---------------------------------*/ /* A routine that puts the string S on the screen in a slot of */ /* specified LENGTH starting at ROW, ICOL, with attribute ATTRIB */ /* and fill character FILL. */ /* If RESTORE = LG_YES (1) it leaves the cursor where it found it. */ /*-------------------------------------------------------------------*/ scrnputs(int row, int icol, char *s, char fill, char attrib, int length, int restore ) { int col, trow, tcol; if(restore == LG_YES) { tcol=curscol(); trow=cursrow(); /* save cursor position */ } poscurs(row,icol); for( col = icol; col < icol+length; col++) { if( s[(col-icol)] != NULL_BYTE ) { poscurs(row, col); writechs(s[(col-icol)],attrib,1); } else break; } if( col < (icol+length)) { poscurs(row, col); writechs(fill, attrib, (icol+length-col)); } if(restore == LG_YES) poscurs(trow,tcol); /* restore cursor position */ } /*-------------------------------------------------------------------------*/ w_roll(int min_row, int max_row, /* maximum and minimum rows */ int min_col, int max_col, /* ditto columns */ int scroll, /* rows downward to scroll */ char attrib) /* to fill with */ { union REGS regs; regs.h.ch=min_row; regs.h.cl=min_col; regs.h.dh=max_row; regs.h.dl=max_col; regs.h.bh=attrib; if(scroll > 0 ) { regs.h.ah=7; regs.h.al=scroll; int86(0x10, ®s, ®s); } if(scroll < 0 ) { regs.h.ah=6; regs.h.al=-scroll; int86(0x10, ®s, ®s); } } /*--------------------------------------------------------------------------*/ inrange(int val, char mintest, int min, char maxtest, int max ) { if( (val < min) || ( (val == min) && mintest != '=')) return(FALSE); else if( (val > max) || ( (val == max) && maxtest != '=')) return(FALSE); else return(TRUE); } /*----------------------------------------------------------------------*/ /* PACKAGE FOR 2-DIM CHARACTER ARRAYS */ /*----------------------------------------------------------------------*/ /*------------------------- Carrmve ------------------------------------*/ /* A General Purpose Function For Moving Rectangular Areas Within */ /* Character Arrays */ /*--------------------------- */ carrmve(char *array, /* is the array acted upon */ int dim1, int dim2, /* are the dimensions */ int m1, int m2, /* are the displacements moved */ int low1, int high1, /* maximum and minimum values for index 1 */ int low2, int high2, /* for index 2 */ char fill /* character that fills the vacated region */ ) /*-----------------------------------------*/ { int srt1, srt2, not1, not2, inc1, inc2; unsigned int x1,x2; if(m1 >= 0){ srt1= high1; not1= low1-1; inc1= -1;} else { srt1= low1; not1= high1+1; inc1= 1; } if(m2 >= 0){ srt2= high2; not2= low2-1; inc2= -1;} else { srt2= low2; not2= high2+1; inc2= 1; } for(x1= srt1; x1 != not1 ; x1=x1+inc1) for(x2= srt2; x2 != not2 ; x2=x2+inc2) { array[(x1+m1)*dim2+(x2+m2)] = array[x1*dim2+x2]; array[x1*dim2+x2] = fill; } } /*------------------------------------------------------------------------*/ /* reduce the next three routines into one when you have */ /* the time */ /*----------------------- Carrmsk ----------------------------------------*/ /*----------------------- */ carrmsk( char *mask, /* if a given position of this array is */ char cond, /* equal (cond = '=') or unequal (cond != '=') */ char match, /* to this character */ char *dest, /* the corresponding position of this array */ int dim1, int dim2, /* (of these dimensions) */ char fill) /* is set to this character */ /*-----------------------------------------*/ { unsigned int i, j; j=dim1*dim2; if(cond == '=') for( i=0 ; i < j ; i++){ if(mask[i] == match) dest[i] = fill; } else for( i=0 ; i < j ; i++){ if(mask[i] != match) dest[i] = fill; } } /*------------------------- Carrmcpy --------------------------------------*/ carrmcpy( char *mask, char cond, char match, char *sorc, char *dest, int dim1, int dim2 ) { unsigned int i, j; j=dim1*dim2; if(cond == '=') for( i=0 ; i < j ; i++){ if(mask[i] == match) dest[i] = sorc[i]; } else for( i=0 ; i < j ; i++){ if(mask[i] != match) dest[i] = sorc[i]; } } /*---------------------- Carrcpy ------------------------------------------*/ carrcpy( char *sorc, /* copies this array to */ char *dest, /* this one */ int dim1, /* */ int dim2 /* where these are the dimensions */ ) /*------------------------------------------*/ { unsigned int i, j; j=dim1*dim2; for( i=0 ; i < j ; i++) dest[i] = sorc[i]; } /*---------------------- Carrset --------------------------------------*/ carrset(char *array, /* sets all the positions of this array */ int dim1, /* */ int dim2, /* of these dimensions */ char fill /* to this character */ ) /*-----------------------------------------*/ { unsigned int i, j; j=dim1*dim2; for( i=0 ; i < j ; i++) array[i] = fill; } /*-------------------------- Carrcbnd -------------------------------------*/ /* finds the maximum and minimum indices of the minimum rectangular */ /* region within which all those values lie which: */ /* a) do not equal MATCH (COND = '!') */ /* or */ /* b) do equal MATCH (COND = '=') */ /* */ /*-------------------------------------------------------------------------*/ carrcbnd( char *array, int fdim1, int fdim2, int *fldim1, int *fhdim1, int *fldim2, int *fhdim2, char cond, char match ) { int d1, d2, ld1, hd1, ld2, hd2; hd1=0; hd2=0; ld1=fdim1; ld2=fdim2; if(cond == '=') for( d1=0 ; d1 < fdim1 ; d1++) for( d2=0 ; d2 < fdim2 ; d2++) { if( array[d1*fdim2+d2] == match) { if( d1 > hd1) hd1 = d1; if( d1 < ld1) ld1 = d1; if( d2 > hd2) hd2 = d2; if( d2 < ld2) ld2 = d2; } } else for( d1=0 ; d1 < fdim1 ; d1++) for( d2=0 ; d2 < fdim2 ; d2++) { if( array[d1*fdim2+d2] != match) { if( d1 > hd1) hd1 = d1; if( d1 < ld1) ld1 = d1; if( d2 > hd2) hd2 = d2; if( d2 < ld2) ld2 = d2; } } *fldim1 =ld1; *fhdim1=hd1; *fldim2=ld2; *fhdim2=hd2; } #pragma trace /*---------------------- Carrlts --------------------------------------*/ carrlts( char *array, char *str, int lnum, int dim2, fill ) { unsigned int first_pos, last_pos, null_pos, i, k; first_pos=dim2*lnum; last_pos=first_pos+dim2-1; for( i=last_pos; i >= first_pos; i--) if( array[i] != fill) break; null_pos=i+1; for(k=first_pos; k < null_pos; k++) str[k-first_pos]=array[k]; str[k-first_pos]=NULL_BYTE; } #pragma trace- /*-------------------- Carrstl -----------------------------------------*/ carrstl( char *str, char *array, int lnum, int dim2, char fill ) { unsigned int first_pos, last_pos, i,j; first_pos=dim2*lnum; last_pos=first_pos+dim2-1; for(i=first_pos; i <= last_pos; i++) { if(str[i-first_pos] != NULL_BYTE) array[i]=str[i-first_pos]; else break; } for(j=i;j <= last_pos; j++) array[j]=fill; } /*------------------------------------------------------------------------*/ /*------------------- Carrfldf -------------------------------------------*/ /*----------------------------- Does a Flood Fill on a two dimesional */ carrfldf( /* charcter array. */ char *arr, /* array acted on */ int ival1, /* starting position */ int ival2, /* */ int d1, /* array dimensions */ int d2, /* */ char bnd /* fill char that also forms perimeter */ ) /*-----------------------------------------*/ { int k1, k2, k1p, x2, mx2, mn2, stakndx, i, j, l; short unsigned stak1[512], stak2[512]; arr[ival1*d2+ival2]=~bnd; stak1[0]=ival1; stak2[0]=ival2; stakndx=1; while(stakndx >= 1) { stakndx--; k1=stak1[stakndx]; k2=stak2[stakndx]; i=k1*d2; l=d2-1; arr[i+k2]=bnd; for(mx2=k2; (arr[i+mx2+1] != bnd) && (mx2 < l); mx2++) arr[i+mx2+1]=bnd; for(mn2=k2; (arr[i+mn2-1] != bnd) && (mn2 > 0); mn2--) arr[i+mn2-1]=bnd; for(k1p=k1-1; k1p <= k1+1;k1p+=2) /*for k1p=k-1 and k1p=k+1 */ { if((k1p < 0) || (k1p >= d1)) continue; i=k1p*d2; for(x2=mx2; x2 >= mn2; x2--) { j=i+x2; if( (arr[j] != bnd) && ((arr[j+1] == bnd) || (x2 == mx2)) && (stakndx < 512) ) { stak1[stakndx]=k1p; stak2[stakndx]=x2; stakndx++; } } } } } /* After: James D. Foley and Andries Van Dam, Fundumentals of */ /* Interactive Computer Graphics, Addison-Wesley Systems Programing */ /* Series, Addison-Wesley Publishing Co., 1983, orig. pub. 1982, pg 446-450 */ /* My thanks to Steve Van Devender, University of Oregon, */ /* for calling this work to my attention */ /*--------------------------------------------------------------------------*/ /* END OF THE GENERAL PURPOSE FUNCTION PACKAGE ADTODD */ /*-------------------------------------------------------------------------*/ #pragma trace /*-------------------------------------------------------------------------*/ /*--- BEGINING OF THE PROGRAM PROPER --------------------------------------*/ /*---------------- Definitions -----------------------*/ #define C_DIM_ROW 66 #define C_DIM_COL 80 #define SCRN_COL_N 80 #define S_MROW 24 #define LBULL '\x11' #define RBULL '\x10' #define BORDER '\xcd' #define MIDDLE_C 440 #define NIL 0 #define ADD_SCROLL 1 #define NO_PIV 1 #define OFF_EDGE 2 #define HIDBK 0 #define DELBK 1 #define CLRC 2 #define FARC 3 /*-------------------------------------------------------------------*/ enum dirty_bit {db_cln, db_drt}; /*------------------- The Canvas Type --------------------------------*/ struct canvas { char charbuf [C_DIM_ROW][C_DIM_COL]; char attrbuf[C_DIM_ROW][C_DIM_COL]; /*-----------------------------------------------------------*/ char fname[40]; /* The name of the file associated */ /* with the canvas */ FILE *fhandle; /*and the handle */ /*-----------------------------------------------------------*/ char wname; /* The one character name which has been */ /* temporarily given to this canvas, */ /* in order to distinguish it from */ /* the other one. */ /*-----------------------------------------------------------*/ int c_row, c_col; int updt_row, updt_col; /*-----------------------------------------------------------*/ int voffst; /* The row of the canvas referenced by the 0th */ /* row of the window that canvas */ /* is displayed in */ /*-----------------------------------------------------------*/ int pivon; int pivrow, pivcol; int file_has_contents_q; enum {ce_yes, ce_no} cv_exist; /* Does canvas exist? */ enum dirty_bit cv_drt_bt; /* Has canvas been altered? */ } canv1, canv2, canv3, *forg, *bakg, *temp; /*--------------------- Global Variables -----------------------------*/ /*------------------- The Screen Type --------------------------------*/ struct scrn_tp { int rulerln; int partln; int titleln; int statln; int t_forg_win; int b_forg_win; int t_bakg_win; int b_bakg_win; int s_split_q; } scrn_map; int fill; enum dirty_bit s_drt_bt; int l_marg = NIL; int r_marg = C_DIM_COL-1; enum {ms_yes, ms_no} marg_set = ms_no; char *errmess = "____________"; enum {er_is, er_not} error_bt; /*---------- Delete and Penup Toggles --------------------------------*/ enum toggle_flg {tg_yes, tg_no}; enum toggle_flg wipeout_q = tg_no; char *wipeout_q_indic[2] = {"Wip", " "}; enum toggle_flg pen_up_q = tg_no; char *pen_up_q_indic[2] = {"p_up", " "}; /*------------------------------------------------------------*/ enum {line_c, fill_c, mark_b} mode = line_c; char *mode_indic[3] = {"DrwLin", "Fill ", "MkBlk"}; /*----------------- The Main Routine ----------------------------------*/ main(int argc, char *argv[]) { int charin; forg=&canv1; bakg=&canv2; temp=&canv3; initial(argc, argv, &forg, &bakg, scrn_map); for(;;) { supdate(forg, bakg, scrn_map); charin=getch(); strcpy( errmess, "____________"); switch(charin){ case NULL_BYTE : charin=getch(); switch(charin){ case LF_ARW_KEY: slide( 0,-1,'-', forg); break; /* < */ case HOME_KEY: slide(-1,-1,'\\', forg); break; /* <^ */ case UP_ARW_KEY: slide(-1, 0,'|', forg); break; /* ^ */ case PG_UP_KEY: slide(-1, 1,'/', forg); break; /* ^> */ case RT_ARW_KEY: slide( 0, 1,'-', forg); break; /* > */ case PG_DN_KEY: slide( 1, 1,'\\', forg); break; /* v> */ case DN_ARW_KEY: slide( 1, 0,'|', forg); break; /* v */ case END_KEY: slide( 1,-1,'/', forg); break; /* voffst; if(forg->c_row < forg->voffst) new_voffst = imax(forg->c_row-ADD_SCROLL, 0); /*--- scroll up if it would go off top of window ---*/ else if( forg->c_row > forg->voffst + scrn_map->b_forg_win-scrn_map->t_forg_win ) new_voffst = imin( forg->c_row+ADD_SCROLL, C_DIM_ROW-1 ) -scrn_map->b_forg_win +scrn_map->t_forg_win; /*--- or down if it would go off the bottom ---*/ } /*-----------------------------------------------*/ /* 2. Choose an Updating Action */ if(s_drt_bt != db_cln) { forg->voffst = new_voffst; refresh(forg, bakg, scrn_map); } /* full screen update */ else if(new_voffst != forg->voffst) canv_roll(forg, scrn_map, new_voffst); /* window roll */ /* always */ /*-----------------------------------------------*/ /* 3. Set Up the Status Line */ strcpy(&s4, pen_up_q_indic[pen_up_q] ); /* pen up indicator */ strcat(&s4, " R: " ); /* row */ strcat(&s4, itoa(forg->c_row, &s2, 10) ); strcat(&s4, " C: " ); /* col */ strcat(&s4, itoa(forg->c_col, &s2, 10) ); strcat(&s4, " " ); strcat(&s4, wipeout_q_indic[wipeout_q] ); /* delete indicator */ strcat(&s4, mode_indic[mode] ); /* mode indicator */ if(mode == fill_c) strcat(&s4, chtostr(&s2, fill) ); /* fill character */ strcat(&s4, " " ); strcat(&s4, errmess ); /* error message */ strcat(&s4, " " ); strcat(&s4, chtostr(&s2, forg->wname) ); /* window name */ strcat(&s4, " " ); strcat(&s4, forg->fname ); /* file name */ scrnputs(scrn_map->statln, NIL, &s4, ' ', HIGHLITE, SCRN_COL_N, LG_YES); /*-----------------------------------------------*/ /* 4. Set Up the Ruler Line */ poscurs(scrn_map->rulerln, NIL); writechs(' ', HIGHLITE, SCRN_COL_N); if(marg_set == ms_yes) { if(l_marg >= 1) { poscurs(scrn_map->rulerln, l_marg-1); writechs(LBULL, HIGHLITE, 1); } if(r_marg <= SCRN_COL_N-2) { poscurs(scrn_map->rulerln, r_marg+1); writechs(RBULL, HIGHLITE, 1); } poscurs(scrn_map->rulerln, forg->c_col); writechs('M', HIGHLITE, 1); } else { poscurs(scrn_map->rulerln, forg->c_col); writechs('!', HIGHLITE, 1); } /*-----------------------------------------------*/ /* 5. Alter a Screen Position to Conform to Canvas */ if(inrange( forg->updt_row, '=', forg->voffst, '=',(forg->voffst+scrn_map->b_forg_win-scrn_map->t_forg_win) )) { poscurs( (forg->updt_row)-(forg->voffst) +(scrn_map->t_forg_win), forg->updt_col ); if( (forg->pivon == LG_YES) && (forg->updt_row == forg->pivrow) && (forg->updt_col == forg->pivcol) ) tempattr = BLINKBIT; /* if this is the pivot, make it blink */ else tempattr = NULL_BYTE; writechs( forg->charbuf[forg->updt_row][forg->updt_col], (forg->attrbuf[forg->updt_row][forg->updt_col] | tempattr), 1 ); } /*-----------------------------------------------*/ /* 6. Revise the update location counters */ forg->updt_row=forg->c_row; forg->updt_col=forg->c_col; /*-----------------------------------------------*/ /* 7. Positions the Screen Cursor */ poscurs( (forg->c_row -forg->voffst +scrn_map->t_forg_win ), forg->c_col ); } /*----------------------------------------------------------------------*/ /* these three routines are shot through with bugs */ /* create a generic routine to handle n lines from a specified canvas */ canv_roll( struct canvas *forg, struct scrn_tp *scrn_map, int new_voffst /* new offset */ ) { int i, roll; roll=-(new_voffst-forg->voffst); w_roll(scrn_map->t_forg_win, scrn_map->b_forg_win, NIL, SCRN_COL_N-1, roll, NORMAL); forg->voffst=new_voffst; if(roll > 0) putrow( forg, scrn_map->t_forg_win, (scrn_map->t_forg_win)+roll, scrn_map->t_forg_win ); if(roll < 0) putrow( forg, (scrn_map->b_forg_win)+roll, scrn_map->b_forg_win, scrn_map->t_forg_win ); } /*--------------------------------------------------------------------*/ /*------------------------------ Refresh ---------------------------------*/ /* Screen Refresh */ /* replaces window on canvas from memory and clears the dirty bit */ /*------------------------------------------------------------------------*/ refresh( struct canvas *forg, /* canvas to copy from forground from */ struct canvas *bakg, /* " " " " background " */ struct scrn_tp *scrn_map ) { int row; scrnputs(scrn_map->titleln, NIL, " = HELP TODD-DRAW = MENU", ' ', HIGHLITE, SCRN_COL_N, LG_NO); putrow( forg, scrn_map->t_forg_win, scrn_map->b_forg_win, scrn_map->t_forg_win ); if(scrn_map->s_split_q == tg_yes) { poscurs(scrn_map->partln, NIL); writechs(BORDER, HIGHLITE, SCRN_COL_N); putrow( bakg, scrn_map->t_bakg_win, scrn_map->b_bakg_win, scrn_map->t_bakg_win ); } s_drt_bt = db_cln; men_bottom(LG_YES, LG_NO, 0); } /*-------------------------------------------------------*/ putrow(struct canvas *forg, /* canvas to copy from */ first_row, /* of the screen to be copied from the canvas */ last_row, /* ditto */ w_voffst) /* the row of the screen which is the 0th row */ /* of the window */ { int row, col, t_c_row, scrn_to_canv_off; scrn_to_canv_off=(forg->voffst)-w_voffst; for(row=first_row; row <= last_row; row++) for( col=NIL ; col < C_DIM_COL ; col++) { t_c_row=row+scrn_to_canv_off; poscurs(row, col); writechs(forg->charbuf[t_c_row][col], forg->attrbuf[t_c_row][col],1); } /* if the pivot point exists and is in this range... */ if( (forg->pivon == LG_YES) && inrange( forg->pivrow, '=', first_row+scrn_to_canv_off, '=', last_row+scrn_to_canv_off ) ) { poscurs( ((forg->pivrow)-scrn_to_canv_off), forg->pivcol ); writechs(forg->charbuf[forg->pivrow][forg->pivcol], (forg->attrbuf[forg->pivrow][forg->pivcol] | BLINKBIT), 1); } /* mark the pivot */ } setsplit( struct canvas *forg, struct canvas *bakg, struct scrn_tp *scrn_map, int tosplit_q ) { if(tosplit_q == LG_YES) { if(bakg->cv_exist == ce_no) return(R_ERR); scrn_map->titleln = 0; scrn_map->t_forg_win = 1; scrn_map->b_forg_win =12; scrn_map->rulerln = 13; scrn_map->statln = 14; scrn_map->partln = 15; scrn_map->t_bakg_win = 16; scrn_map->b_bakg_win = S_MROW; scrn_map->s_split_q = tg_yes; } else { scrn_map->titleln = 0; scrn_map->t_forg_win = 1; scrn_map->b_forg_win = S_MROW-2; scrn_map->rulerln = S_MROW-1; scrn_map->statln = S_MROW; scrn_map->s_split_q = tg_no; } } help_scrn() { char *help_msg[] = { " MOVEMENT AND MODES: (Num Lock must be off ) OTHER: ", /*00*/ "-------------------------------------------- Help Screen ", /*01*/ "| < 7 Home > | < 8 UP > | < 9 PgUp > | Main Menu ", /*02*/ "| (up, left) | (up) | (up, right) | Set l. margin ", /*03*/ "|------------------------------------------| Set r. margin", /*04*/ "| < 4 LEFT > | < 5 > | < 6 RIGHT > | ", /*05*/ "| (left) | | (right) | ", /*06*/ "|------------------------------------------| ", /*07*/ "| < 1 End > | <2 DOWN > | < 3 PgDn > | ", /*08*/ "| (down, left) | (down) | (down,right) | ", /*09*/ "|------------------------------------------| ", /*10*/ "| < 0 Ins > (mode|toggles) < . Del > | ", /*11*/ "| (pen up--down)|(draw--undraw ) | ", /*12*/ "|------------------------------------------| ", /*13*/ " ", /*14*/ " To do block operations, you must first paint out the extent ", /*15*/ " of the block in MARK mode (you can use the BLOCK-INCLUDE ", /*16*/ " command to save time), set the pivot point (BLOCK-PIVOT) ", /*17*/ " and move to the destination corresponding to it if ", /*18*/ " appropriate, and then perform the operation. ", /*19*/ " ", /*20*/ " ", /*21*/ " ", /*22*/ " ", /*23*/ " Hit any key to resume " /*24*/ }; ask_prompt(help_msg, 25, LG_NO); s_drt_bt =db_drt; } /*------------- THE BASIC MOVEMENT ROUTINES ----------------------------*/ /*--------------------------- Slide ------------------------------------*/ /* Handles Cursor Key Input */ /*----------------------------------------------------------------------*/ slide(int irow, int icol, int al, struct canvas *forg) { int nrow, ncol; /* 1. would the move take it off side, top, or bottom of canvas? */ nrow = forg->c_row + irow; ncol = forg->c_col + icol; if( inrange(nrow, '=',NIL, '<',C_DIM_ROW) && inrange(ncol, '=',NIL, '<',C_DIM_COL) ) { /* 2. disable the typing margins */ marg_off(); /*--- 3. write to the current position ---*/ if(pen_up_q == tg_no) { if(mode == mark_b) { if(wipeout_q == tg_yes) forg->attrbuf[forg->c_row][forg->c_col] = NORMAL; else forg->attrbuf[forg->c_row][forg->c_col] = HIGHLITE; } else { forg->cv_drt_bt=db_drt; if(wipeout_q == tg_yes) forg->charbuf[forg->c_row][forg->c_col] = ' '; else if(mode == line_c) forg->charbuf[forg->c_row][forg->c_col] = al; else forg->charbuf[forg->c_row][forg->c_col] = fill; } } /*--- 4. now move the cursor ---*/ forg->c_row = nrow; forg->c_col = ncol; } } /*--------------------------- Type ------------------------------------*/ /* Handles Printable Character Input */ /*---------------------------------------------------------------------*/ type(int al, struct canvas *forg) { int trow, tcol, icol, i; switch(al) { case '\b': if( forg->c_col > NIL ) { forg->c_col--; forg->charbuf[forg->c_row][forg->c_col]=' '; forg->updt_col=forg->c_col; ver_marg(forg->c_col); } break; /* logic for back space */ case '\t': marg_set = ms_yes; l_marg = forg->c_col; /* set margins for note */ break; case '\r': ver_marg(forg->c_col); car_ret(LG_NO, forg); /* logic for car ret */ break; default: if(isprint(al)) /* if printable */ { ver_marg(forg->c_col); forg->cv_drt_bt=db_drt; forg->charbuf[forg->c_row][forg->c_col] = al; /* change array*/ if(forg->c_col < r_marg) forg->c_col++; else car_ret(LG_YES, forg); } } } /* sends an ordinary character ( or backspace) to the screen */ /* both operate on the principle of write and then move COMPLETE*/ /*-------------------------------------------------------------------------*/ ver_marg(int n_l_marg) { if(marg_set == ms_no) { l_marg = n_l_marg; marg_set = ms_yes; } else if((l_marg > n_l_marg) && (n_l_marg >= NIL)) l_marg = n_l_marg; } marg_off() { l_marg = NIL; r_marg = C_DIM_COL-1; marg_set = ms_no; } car_ret(int wrapflg, struct canvas *forg) { int s_w_col; if(forg->c_row >= (C_DIM_ROW-1) ) { sound(MIDDLE_C,10); return(R_ERR);} r_marg = forg->c_col; /* now wrap if appropriate, and move the cursor */ if(wrapflg == LG_YES) { for(s_w_col = r_marg; s_w_col > l_marg; s_w_col--) if(forg->charbuf[forg->c_row][s_w_col] == ' ') break; /*loc 1st spac*/ if( s_w_col > l_marg) /*if it is to the right of the left margin */ { s_drt_bt = db_drt; forg->cv_drt_bt = db_drt; carrmve(forg->charbuf, C_DIM_ROW, C_DIM_COL, 1, (l_marg-s_w_col-1), forg->c_row, forg->c_row, (s_w_col+1), r_marg, ' '); forg->c_col=l_marg+r_marg-s_w_col; } else forg->c_col=l_marg; } else forg->c_col=l_marg; forg->c_row++; } /*----------------------------------------------------------------------*/ toggle(enum toggle_flg *var) { if(*var == tg_no) *var = tg_yes; else *var = tg_no; } /*--------------------------- Initial ----------------------------------*/ /* The initialization routine */ /*----------------------------------------------------------------------*/ initial( int argc, char *argv[], int **pforg, int **pbakg, struct scrn_tp *scrn_map ) { int lflag=LG_NO; struct canvas *forg, *bakg; forg = *pforg; bakg = *pbakg; clrscrn(); forg->cv_exist=ce_no; bakg->cv_exist=ce_no; if( argc >= 2) { strcpy( forg->fname, argv[1]); lflag = LG_YES; } if(loadfil(lflag, forg) == N_ERR) { forg->wname=' '; setsplit(forg, bakg, scrn_map, LG_NO); s_drt_bt = db_drt; } else { clrscrn(); exit(3); } } #pragma trace /*---------------------------- Menu1 -----------------------------------*/ /* The Main Menu, invoked by F10 */ /*----------------------------------------------------------------------*/ menu1( int **pforg, int **pbakg, int **ptemp, struct scrn_tp *scrn_map ) { struct canvas *forg, *bakg, *temp; int charin; char *menu_msg[] = { "The options are: ", /*00*/ "FILE: quit done change save ", /*01*/ "BLOCK: move copy hide del pivot fill other_canvas include ", /*02*/ "PEN fill line mark_block ", /*03*/ "OTHER: clear_canvas print_canvas split_screen unsplit_screen ", /*04*/ "(F,B,P,C) " /*05*/ }; char *blok_men_msg[] = { "block operations: ",/*00*/ " COPY the block, moving pivot point to cursor",/*01*/ " MOVE \" \" ",/*02*/ " DELete the block ",/*03*/ " HIDE \" \" ",/*04*/ " mark the PIVOT point ",/*05*/ " FILL the block with a specified character ",/*06*/ " INCLUDE the interior of the block ",/*07*/ " REFLECT the block across the cursor ",/*08*/ " from the OTHER canvas: ",/*09*/ "(C,M,D,H,P,F,I,R,O) " /*10*/ }; char *blok_smen1_msg[] = {" reflect the block HORIZONTALY or VERTICALY (H,V) "}; /*00*/ char *blok_smen2_msg[] = {" COPY or MOVE from other canvas (C,M) "}; /*00*/ char *file_men_msg[] = { "file operations: ",/*00*/ " QUIT this canvas without saving ",/*01*/ "all DONE with this canvas, save and exit or go to the other one ",/*02*/ " CHANGE to the other canvas ",/*03*/ " SAVE this canvas and go on editing ",/*04*/ "(Q,D,C,S) " /*05*/ }; char *pen_men_msg[] = {"pen: Fill Line Mark_block "}; /*00*/ char *other_men_msg[] = { "Other functions: ",/*00*/ "CLEAR the canvas ",/*01*/ "PRINT the canvas ",/*02*/ "SPLIT the screen ",/*03*/ "UNSPLIT the screen ",/*04*/ "(C,P,S,U) " /*05*/ }; forg = *pforg; bakg = *pbakg; temp = *ptemp; marg_off(); s_drt_bt = db_drt; charin=ask_prompt(menu_msg, 6, LG_NO); switch(charin) { case 'f': charin=ask_prompt(file_men_msg, 6, LG_YES); switch(charin) { case 'q': savedone(LG_NO, LG_YES, pforg, pbakg, scrn_map); break; case 'd': savedone(LG_YES,LG_YES, pforg, pbakg, scrn_map); break; case 'c': change(pforg, pbakg, scrn_map); break; case 's': savedone(LG_YES,LG_NO, pforg, pbakg, scrn_map); break; default : break; }; break; case 'b': charin=ask_prompt(blok_men_msg, 11, LG_YES); switch(charin) { case 'c': copymove(HIDBK, forg, bakg, temp); break; case 'm': copymove(DELBK, forg, bakg, temp); break; case 'd': pixmanip(DELBK, forg); break; case 'h': pixmanip(HIDBK, forg); break; case 'p': setpiv(forg, LG_YES, forg->c_row, forg->c_col); break; case 'i': enclose(forg); break; case 'f': overfill(forg); break; case 'r': charin=ask_prompt(blok_smen1_msg, 1, LG_YES); switch(charin) { case 'h': reflect(LG_YES, forg); break; case 'v': reflect(LG_NO, forg); break; default : break; }break; case 'o': charin=ask_prompt(blok_smen2_msg, 1, LG_YES); switch(charin) { case 'c': copymove(HIDBK+FARC, forg, bakg, temp); break; case 'm': copymove(DELBK+FARC, forg, bakg, temp); break; default : break; }break; default : break; } break; case 'p': charin=ask_prompt(pen_men_msg, 1, LG_NO); switch(charin) { case 'f': pen_fill(); break; case 'l': mode = line_c; break; case 'm': mode = mark_b; break; default : break; } break; case 'o': charin=ask_prompt(other_men_msg, 6, LG_YES); switch(charin) { case 'c': pixmanip(CLRC, forg); break; case 'p': prntcanv(forg); break; case 's': setsplit(forg, bakg, scrn_map, LG_YES); break; case 'u': setsplit(forg, bakg, scrn_map, LG_NO); break; default : break; }; break; default : break; }; } #pragma trace- /*--------------*/ pen_fill() { int charin; if( (charin =askchar( "other: enter any character to be the new fill") ) != R_ERR) { mode = fill_c; fill = charin; } } /*-------------------------------------------------------*/ askchar(char *s) { int charin; pulldown(LG_YES, s); charin=getch(); if(isprint(charin)) return(charin); else { strcpy( errmess, "unprintabl"); return(R_ERR); } } /*-------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/ /* routines to export to and from files */ /* to be rewritten to deal with the array */ /*------------------------------------------------------------------------*/ prntcanv(struct canvas *canv) { put_canv(canv, stdprn); /* print the canvas */ putc( '\f', stdprn); /* and then issue a */ } /* sends screen to the printer */ /*think about commonizing this with the savefile */ /*----------------------------- Pixmanip ----------------------------------*/ /* applies an action specified by blnkflag (hide or delete block, */ /* clear canvas) to all positions in the canvas targ_canv */ /*-------------------------------------------------------------------------*/ pixmanip( int blnkflag, struct canvas *targ_canv ) { switch(blnkflag) { case DELBK: carrmsk(targ_canv->attrbuf, '!', NORMAL, targ_canv->charbuf, C_DIM_ROW, C_DIM_COL, ' '); targ_canv->cv_drt_bt = db_drt; case HIDBK: carrset(targ_canv->attrbuf, C_DIM_ROW, C_DIM_COL, NORMAL); break; case CLRC: carrset(targ_canv->attrbuf, C_DIM_ROW, C_DIM_COL, NORMAL); carrset(targ_canv->charbuf, C_DIM_ROW, C_DIM_COL, ' '); targ_canv->voffst = NIL; targ_canv->c_row = NIL; targ_canv->c_col = NIL; targ_canv->cv_drt_bt = db_drt; } setpiv(targ_canv, LG_NO, NIL, NIL); } /*------------------------------ Collect ----------------------------------*/ /* copies the block of src_canv into dest_canv, which is blanked, with a */ /* displacement so that the pivot is at the location (newrow, newcol). */ /* All the other positions are filled with spaces of normal attribute. */ /* - returns 0 if correct, 1 if no pivot, 2 if the move would take */ /* the block over the edge */ /*-------------------------------------------------------------------------*/ collect( struct canvas *src_canv, struct canvas *dest_canv, int newrow, int newcol ) { int row, col, mrow, mcol, lrow, hrow, lcol, hcol; if( src_canv->pivon == LG_NO) return(NO_PIV); mrow = newrow-src_canv->pivrow; mcol = newcol-src_canv->pivcol; carrset(dest_canv->attrbuf, C_DIM_ROW, C_DIM_COL, NORMAL); carrset(dest_canv->charbuf, C_DIM_ROW, C_DIM_COL, NORMAL); carrmcpy(src_canv->attrbuf, '!', NORMAL, src_canv->attrbuf, dest_canv->attrbuf, C_DIM_ROW, C_DIM_COL); carrmcpy(src_canv->attrbuf, '!', NORMAL, src_canv->charbuf, dest_canv->charbuf, C_DIM_ROW, C_DIM_COL); carrcbnd(src_canv->attrbuf, C_DIM_ROW,C_DIM_COL, &lrow, &hrow, &lcol, &hcol, '!', NORMAL ); dest_canv->cv_drt_bt = db_drt; if( (mrow+lrow < NIL) || (mrow+hrow >= C_DIM_ROW) || (mcol+lcol < NIL) || (mcol+hcol >= C_DIM_COL) ) return(OFF_EDGE); else { /* move in the array */ carrmve(dest_canv->charbuf, C_DIM_ROW,C_DIM_COL,mrow,mcol,lrow,hrow,lcol,hcol, ' '); carrmve(dest_canv->attrbuf, C_DIM_ROW,C_DIM_COL,mrow,mcol,lrow,hrow,lcol,hcol, NORMAL); return(N_ERR); } } /*---------------------------------------------------------------*/ copymove( int copyflag, struct canvas *forg, struct canvas *bakg, struct canvas *temp ) { int x, tc_row, tc_col; if(copyflag >= FARC) { tc_row=forg->c_row; tc_col=forg->c_col; x=collect(bakg, temp, tc_row, tc_col); copyflag-=FARC; } else x=collect(forg, temp, forg->c_row, forg->c_col); /* collect it */ switch(x){ case N_ERR : pixmanip(copyflag, forg); /* hide or delete on curent canvas */ replace(temp, forg); /* copy block back to current canvas */ break; case NO_PIV : strcpy( errmess, "no pivot pnt"); break; case OFF_EDGE : strcpy( errmess, "off the edge"); break; default : strcpy( errmess, "gone wombly "); break; } } /* copy (HIDBK), move(DELBK), farcopy(HIDBK+FARC), or farmove(DELBK+FARC) */ replace( struct canvas *src_canv, struct canvas *dest_canv ) { int row, col, trow, tcol; carrmcpy(src_canv->attrbuf, '!', NORMAL, src_canv->charbuf, dest_canv->charbuf, C_DIM_ROW, C_DIM_COL); carrmcpy(src_canv->attrbuf, '!', NORMAL, src_canv->attrbuf, dest_canv->attrbuf, C_DIM_ROW, C_DIM_COL); setpiv(dest_canv, LG_YES, dest_canv->c_row, dest_canv->c_col); dest_canv->cv_drt_bt = db_drt; } /* copies back the block from the buffer into the picture */ /*---------------------------*/ setpiv(struct canvas *targ_canv, int state, int row, int col) { targ_canv->pivon = state; targ_canv->pivrow = row; targ_canv->pivcol = col; } /*------------------------*/ enclose(struct canvas *targ_canv) { carrfldf(targ_canv->attrbuf, targ_canv->c_row, targ_canv->c_col, C_DIM_ROW, C_DIM_COL, HIGHLITE); } /* the auto block mark function */ /*--------------------------------------------------------------------------*/ overfill(struct canvas *targ_canv) { int tfill; if( (tfill=askchar( "what character to overwrite the whole block with? Use ESC to escape.") ) == R_ERR ) return(R_ERR); else { carrmsk(targ_canv->attrbuf, '=', HIGHLITE, targ_canv->charbuf, C_DIM_ROW, C_DIM_COL, tfill); return(N_ERR); } } /*-------------------------------------------------------------------------*/ reflect(int is_horizontal_q, struct canvas canv) { } /*-----------------------------------------------------------------------*/ /* WINDOW AND FILE MANIPULATION */ /* */ /* The Open and Input Section */ /*------------------------- Change --------------------------------------*/ /* Brings in (and if necesary opens) the other canvas */ /*-----------------------------------------------------------------------*/ change( int **pforg_canv, int **pbakg_canv, struct scrn_tp *scrn_map ) { struct canvas *forg_canv, *bakg_canv; forg_canv = *pforg_canv; bakg_canv = *pbakg_canv; if(bakg_canv->cv_exist != ce_yes) /*if not open */ { if(loadfil(LG_NO, bakg_canv) == N_ERR)/* open the canvas in background*/ { forg_canv->wname='X'; bakg_canv->wname='Y'; pswap(pforg_canv, pbakg_canv); setsplit(forg, bakg, scrn_map, LG_YES); } } else /* if already open */ { pswap(pforg_canv, pbakg_canv); } } /* routine to swap foreground and background canvases */ /*------------------------------------------ ------------------------- */ loadfil( int f_nm_pres_q, /* file name already present in canvas */ struct canvas *canv /* canvas to load into */ ) { int row; int dhandle; char *sptr; char str[84]; fpos_t locat; /* debugging code */ if( ( dhandle= getfile(f_nm_pres_q, LG_YES, "this is where it would ask for the file name", "this is where it would ask for the correct file name", canv->fname ) ) != R_ERR ) { /* read the file */ close(dhandle); canv->fhandle=fopen(canv->fname, "r"); pixmanip(2, canv); rewind(canv->fhandle); fgetpos(canv->fhandle, &locat); /* debugging code */ for( row=NIL ; row < C_DIM_ROW ; row++) { if( fgets(str,83,canv->fhandle) != NULL) /*read a line */ { sptr=strchr(str, '\n'); /* cut off the newline */ *sptr=NULL_BYTE; carrstl(str, canv->charbuf, row, C_DIM_COL, ' '); } /* and put the line in the array */ else break; /* until there are no more */ } if(row == NIL) canv->file_has_contents_q = LG_NO; else canv->file_has_contents_q = LG_YES; canv->cv_exist=ce_yes; canv->cv_drt_bt=db_cln; return(N_ERR); } else return(R_ERR); } /*---------------------------------------------------------------------*/ getfile( int f_nm_pres_q, /* file name already present */ int prmpt_cre_q, /* prompt for permission to create a file? */ char *iprompt, /* the initial prompt */ char *fprompt, /* prompt in the event of an invalid name */ char *filename /* holds the filename, and is altered or not */ ) /* returns file descriptor of opened file if sucessful */ /* or R_ERR (-1) if not */ { int name_ready_q = LG_NO; int dhandle; char *cprompt; if(f_nm_pres_q == LG_YES) name_ready_q=LG_YES; cprompt = iprompt; do { if(name_ready_q == LG_NO) { if(getname(fprompt, filename) != N_ERR) return(R_ERR); name_ready_q= LG_YES; } /* prompt for a filename if required */ if( (dhandle=open(filename, O_RDWR|O_CREAT|O_TEXT, S_IREAD|S_IWRITE) ) != R_ERR ) return(dhandle); /*return if good */ else { name_ready_q = LG_NO; cprompt = fprompt; /* or keep going until it is */ } } while(1); } /* Prompt for filename. If you get a valid filename, */ /* create it if necessary. Prompt again until the getname fails */ /* or a valid file is generated */ /* return handle for sucess, R_ERR if invalid file name */ /*-----------------------------------------------------------------------*/ /* The Close and Output Section */ /*------------------- Savedone ------------------------------------------*/ savedone( int save_f, /* LG_YES or LG_NO save */ int done_f, /* " done */ int **pcur_canv, int **palt_canv, struct scrn_tp *scrn_map ) { struct canvas *cur_canv, *alt_canv; int charin; cur_canv = *pcur_canv; alt_canv = *palt_canv; if(save_f == LG_YES) { if( savefile(cur_canv) != N_ERR) return(R_ERR); } else if(done_f == LG_YES) /* go through the quit verify routine */ { if(cur_canv->cv_drt_bt == db_drt) { pulldown(LG_YES, "Changes have been made. Do you really want to abandon? y/n"); charin=getch(); if( (charin != 'Y') && (charin != 'y') ) { strcpy( errmess, "abort"); return(R_ERR); } else strcpy( errmess, "abandon"); } else strcpy( errmess, "quit"); } /*--------------*/ if(done_f == LG_YES) { fclose(cur_canv->fhandle); cur_canv->cv_exist=ce_no; alt_canv->wname=' '; if(alt_canv->cv_exist == ce_yes) { pswap(palt_canv, pcur_canv); setsplit(alt_canv, cur_canv, scrn_map, LG_NO); } else { clrscrn(); exit(N_ERR); } } } /* save or don't save, then exit or don't exit that canvas */ /* if the other one is open, go into it, else exit the program */ /*--------------------------------------------------------------------------*/ #pragma trace savefile(struct canvas *canv) { int tflags; char tpath[MAXPATH], tdrive[MAXDRIVE], tdir[MAXDIR], tfile[MAXFILE], texten[MAXEXT]; /*get the backup name using fnmerge*/ tflags=fnsplit(canv->fname,tdrive,tdir,tfile,texten); strcpy(texten, ".gbk"); fnmerge(tpath,tdrive,tdir,tfile,texten); if((unlink(tpath) != N_ERR ) && ( errno != ENOENT)) { strcpy(errmess, "backup file locked"); return(R_ERR); } else { /*if the backup file doesnt exist, or can be deleted */ fclose(canv->fhandle); if(canv->file_has_contents_q == LG_YES) rename(canv->fname, tpath); /*close main file, rename to backup, */ canv->fhandle=fopen(canv->fname, "w"); /* reopen in write mode */ rewind(canv->fhandle); if(put_canv(canv, canv->fhandle) == R_ERR) { strcpy(errmess, "could not write to file"); return(R_ERR); } else { canv->file_has_contents_q = LG_YES; canv->cv_drt_bt=db_cln; strcpy( errmess, "Saved"); return(N_ERR); } } } /*saves and resets the canvas dirty bit, returns N_ERR if sucessful */ /* does its own sucess or error posting via errmess */ /*--------------------------------------------------------------------------*/ /* Put_canv writes the character array field of the CANVAS to an open */ /* high-level file, with file pointer THANDLE, but does not set any */ /* status flags */ put_canv(struct canvas *canv, FILE *thandle) { char str[84], str2[4]; int row, dummy, lastline; carrcbnd(canv->charbuf, C_DIM_ROW, C_DIM_COL, &dummy, &lastline, &dummy, &dummy, '!', ' '); for( row=NIL ; row <= lastline ; row++) { carrlts(canv->charbuf, str, row, C_DIM_COL, ' '); /* convert each line */ strcat(str,chtostr(str2,'\n')); /* into a string, add newline */ if(fputs(str, thandle) != N_ERR) return(R_ERR); /* and write it, reporting error */ } return(N_ERR); } #pragma trace- /*-------------------------------------------------------------------------*/ pswap(int **pt1, int **pt2) { int **t_ptr; t_ptr=*pt1; *pt1=*pt2; *pt2=t_ptr; } /*--------------------------------------------------------------------------*/ /* PROMPTING ROUTINES */ /* */ /*------------------------ Pulldown ----------------------------------------*/ /* the menu contruction routine: */ /* clears line lnum and writes in the string pointed to by s */ /* fills line lnum + 1 with '<'s, line lnum + 2 with '>'s */ /*--------------------------------------------------------------------------*/ pulldown(int new_box_q, char *s) { int line; line=men_bottom(LG_NO, new_box_q, 1); scrnputs(line, NIL, s, ' ', HIGHLITE, SCRN_COL_N, LG_NO); } /*--------------------------------------*/ ask_prompt(char *messages[], int n_lines, int towait) { int charin, i, s_line; s_line=men_bottom(LG_NO, LG_YES, n_lines); for(i = s_line ; i < s_line+n_lines ; i++ ) scrnputs(i, NIL, messages[i-s_line], ' ', HIGHLITE, SCRN_COL_N, LG_NO); if((charin=getch()) == NULL_BYTE) { charin=' '; getch(); } charin=tolower(charin); if(towait == LG_YES) { pulldown(LG_YES, "WAIT"); } return(charin); } /*--------------------------------------*/ getname( char *promptstr, char *dest ) { int col, scol, al, i, s_line; /* create the prompt screen */ s_line=men_bottom(LG_NO, LG_YES, 5); scrnputs(s_line, NIL, promptstr, ' ', HIGHLITE, SCRN_COL_N, LG_NO); poscurs((s_line+1),NIL); writechs('-',HIGHLITE,SCRN_COL_N); scrnputs(s_line+2, NIL, "Hit to accept, to correct, to quit", ' ', HIGHLITE, SCRN_COL_N, LG_NO); poscurs((s_line+3),NIL); writechs('-',HIGHLITE,SCRN_COL_N); scrnputs(s_line+4, NIL, "File? :", ' ', HIGHLITE, 8, LG_NO); poscurs(s_line+4, 8+40); writechs( ' ',HIGHLITE, SCRN_COL_N-8-40); scrnputs(s_line+4, 8, dest, ' ', NORMAL, 40, LG_NO); scol=col = curscol(); /* build the name on the screen */ for(;;) { al=getch(); switch(al) { case '\r': for(i=8; i < col; i++) { poscurs(s_line+4,i); dest[i-8]=readch(); } dest[col] = NULL_BYTE; return(N_ERR); case '\b': if(col > 8) { col--; poscurs(s_line+4, col); writech(' '); } break; case NULL_BYTE: getch(); case ESC : return(R_ERR); default : writech(al); if(col < 8+40-1) { col++; poscurs( s_line+4, col); } } } } /*----------------------------------------*/ men_bottom( int reset_q, /* to reset, yes or no */ int newbox_q, /* to start a new box, yes or no */ int n_lines /* number of lines of text there is to be room for */ ) { static int men_nxt_ln; /* the first line that could be used if no new box */ static int men_cln_ln; /* the first line that is undisturbed so far */ int i, start_of_txt, l_incr; /* cover the special cases and exceptions first */ if(n_lines > S_MROW+1) return(R_ERR); if(reset_q == LG_YES) { men_nxt_ln=NIL; men_cln_ln=NIL; return(0); } else { if(newbox_q == LG_NO) l_incr=0; else l_incr=1; } /* but assuming no special cases, lay out the region for the text */ if(men_nxt_ln+n_lines+l_incr <= S_MROW+1) /* if space to put it on bottom */ { start_of_txt=men_nxt_ln+l_incr; } else /* start over at the top */ { start_of_txt=0; } men_nxt_ln=start_of_txt+n_lines; if( men_cln_ln < men_nxt_ln) men_cln_ln=men_nxt_ln; /* now work out the border below it */ /* work out the bottom, that is, the begining of the undisturbed region */ if(men_cln_ln < men_nxt_ln+2) men_cln_ln = men_nxt_ln+2; /*make sure the border is as initially least two rows wide */ if(men_cln_ln > S_MROW) men_cln_ln = S_MROW+1; /* but it must not go off the screen */ /* now fill in from men_nxt_ln to just before men_cln_ln */ for( i=men_nxt_ln ; i < men_cln_ln-1; i++) { poscurs(i,NIL); writechs('>',HIGHLITE,SCRN_COL_N); } if(men_cln_ln > men_nxt_ln) /* the region is more than 0 high */ { poscurs(men_cln_ln-1,NIL); writechs('<',HIGHLITE,SCRN_COL_N); } return(start_of_txt); }