/***************************************************************************** * * "__main()" Subroutine to "_main()" * ---------------------------------- * Copyright 1983 by Digital Research Inc. All rights reserved. * * Routine "__main()" is entered from the "_main()" routine to start a * C program. The command string from CP/M is parsed into * a UNIX-like "argc/argv" setup, including simple I/O redirection. * * This module can be compiled without wildcard parsing if the * symbol "NOWILD" (note upper case) is defined in the compile line. * * Edits: * 28-Feb-84 whf "_salloc()" goes to NOWILD region * 02-Feb-84 whf nowild -> NOWILD, removed write() * 01-Jan-84 whf add in handle for OPTION*.h * 08-Dec-83 whf handle PC-DOS diffs, add ">>" redirection * 11-Oct-83 whf converted to DRC from CPM68K * * Calling Sequence: * return = _main(command,length); * * Where: * command Is the address of the command line from CP/M * length Is the number of characters in the line, * excluding the termination character (CR/LF). * *****************************************************************************/ #include "portab.h" /* Include std definitions */ #include "osif.h" /* Include CP/M Definitions */ #include "ctype.h" /* char type definitions */ #define STDIN 0 /* file descriptors */ #define STDOUT 1 /* */ #define STDERR 2 /* */ #define ISWHITE(ch) ((ch)==NULL || isspace(ch)) /* */ #ifndef NOWILD EXTERN BYTE *_salloc(); /* Stack allocation routine */ #endif EXTERN BYTE *sbrk(); /* Incr break location */ EXTERN BYTE *strchr(); /* V7 "index" function */ EXTERN BYTE __pname[]; /* Default Program name */ MLOCAL WORD argc; /* Arg count */ MLOCAL BYTE *argv; /* -> array of pointers */ MLOCAL BYTE *argv2; /* Companion ptr to argv */ __main(com, len) /****************************/ BYTE *com; /* Command address */ WORD len; /* Command length */ { /****************************/ REG WORD i; /* Define a count var. */ REG BYTE *s; /* Temp byte pointer */ REG BYTE *p; /* Another "" */ REG BYTE c; /* Character temp */ FD *pfd; /* File Desc temp */ BYTE tmpbuf[30]; /* Filename temp */ BYTE *strchr(); /* V7 index() func */ /****************************/ argv2 = argv = sbrk(0); /* -> first free location */ argc = 0; /* No args yet */ addargv(__pname); /* */ for (s = com; *s; s += i) /* One arg at a time */ { /* */ while (*s && isspace(*s)) /* Skip leading spaces */ ++s; /* */ if (!*s) /* End of line? */ break; /* Yes, don't continue */ if(*s == '"' || *s == '\'') /* Quoted string */ { /* */ c = *s; /* c = quote character */ p = strchr(s+1,c); /* Find next */ if (p == NULLPTR) /* Any? */ _err(s,": unmatched quote");/* No, bitch. */ i = (WORD)p-s; /* Compute length */ s[i++] = '\0'; /* Nullify at end */ addargv(s+1); /* Add to arg list */ } /****************************/ else /* */ { /****************************/ for(i = 0; !ISWHITE(s[i]); ++i)/* How many characters? */ ; /* */ if (s[i]) /* If last is space, etc... */ s[i++] = '\0'; /* Make it a null for C */ switch(*s) /* Now do i/o scan */ { /****************************/ case '<': /* Redirecting input?? */ close(STDIN); /* Yes, close TTY */ if (opena(s + 1,READ) != STDIN) /* Open New */ _err("Cannot open ", s + 1) ;/* Can't ... */ break; /* Done with this one */ /****************************/ case '>': /* Redirecting output?? */ close(STDOUT); /* Close output */ if(s[1]=='>') { /* Appending? */ if(opena(s+2,WRITE)!=STDOUT /* Try to open old */ || -1 == lseek(STDOUT,0L,2) ) /* At EOF */ _err("Cannot append ",s+1); /* Can't */ } else { /*** */ if (creata(s+1,0)!=STDOUT) /* Try to open new */ _err("Cannot create ", s + 1); /* Can't */ } /* */ break; /****************************/ /* */ default: /* Just a regular arg */ /****************************/ #ifndef NOWILD /********************************************************/ /********************************************************/ if(strchr(s,'?') || /* Wild */ strchr(s,'*')) /* Cards? */ { /****************************/ pfd = _getccb(STDERR+1); /* Use unused channel */ __OSIF(SETDMA,pfd->buffer);/* Use buffer for DMA */ c=__open(STDERR+1,s,SEARCHF); /* Do the search */ if(c == 0xff) /* Failed ... */ _err(s,": No match"); /* Complain */ while(c != 0xff) /* Do search next's */ { /****************************/ _toasc(pfd,c,tmpbuf); /* Convert file to ascii */ p = _salloc(strlen(tmpbuf)+1);/* Allocate area */ strcpy(p,tmpbuf); /* Move in filename */ addargv(p); /* Add this file to argv */ c=__open(STDERR+1,s,SEARCHN); /* Search next */ } /****************************/ } else /* */ /********************************************************/ #endif /********************************************************/ addargv(s); /* save in argv */ } /* */ } /* */ } /****************************/ addargv(NULLPTR); /* Insure terminator */ argc--; /* Back off by 1 */ if( brk(argv2)==FAILURE) /* Allocate the pointers */ _err("Stack Overflow",""); /* Call "Stack Overflow" rtn*/ exit(main(argc,argv,NULLPTR)); /* Invoke C program (No Env)*/ } /* */ MLOCAL _err(s1,s2) /* Error routine */ char *s1; /* Message text */ char *s2; /* Filename */ { /****************************/ char buf[128]; /* place to build message */ /* */ strcpy(buf,s1); /* Output error message */ strcat(buf,s2); /* And filename */ strcat(buf,"\r\n$"); /* + Newline */ __OSIF(C_WRITESTR,buf); /* output directly to CON: */ exit(-1); /* And fail hard */ } /****************************/ /* * Addargv function -- adds a pointer to the argv array, getting the * space from the heap. */ MLOCAL addargv(ptr) /****************************/ REG BYTE *ptr; /* -> Argument string to add*/ { /* */ *((BYTE **)argv2) = ptr; /* Load pointer */ argv2 += sizeof(char *); /* More room from heap */ argc++; /* Increment arg count */ } /****************************/ /*****************************************************************************/ /*****************************************************************************/ #ifndef NOWILD /* * Toasc routine -- combines the FCB name in the DMA and the user number * / drive field to produce an ascii file name for SEARCHes. * */ MLOCAL _toasc(p,c,buf) /*****************************/ REG FD *p; /* -> Data area */ REG BYTE c; /* 0 .. 3 search code */ REG BYTE *buf; /* Output buffer area */ { /*****************************/ REG BYTE *f; /* -> Fcb in DMA buffer */ WORD i; /* Temp. */ /* */ *buf = NULL; /* Nullify at first */ i = FALSE; /*****************************/ f = p->buffer; /* Pnt to results of search */ #if CPM /*================================================================*/ f += c*32; /* c == directory search code*/ if( p->user ) /* User # not default? */ { /* Yes */ i = (p->user) -1; /* Cvt to real user # */ if( i>=10 ) *buf++ = '1'; /* Assume user # <15 */ *buf++ = '0' + (i % 10); /* now for digits */ *buf++ = ':'; /* finish off with this */ i = TRUE; /* remember */ }; /*****************************/ #endif /*================================================================*/ if(p->fcb.drive) /* Drive specified? */ { /* Yes */ if(i) /* User #? */ buf--; /* Yes, back up over ':' */ *buf++ = p->fcb.drive - 1 + 'a'; /* Put in drive code */ *buf++ = ':'; /* And delimiter */ } /* */ for(i=1;i<9;i++) /* Move the filename */ { /*****************************/ if(f[i] != ' ') /* Non-blank? */ *buf++ = tolower((f[i]&0x7f)); /* Yes, move it in */ } /*****************************/ *buf++ = '.'; /* Put in delimiter */ for(i=9; i<12; i++) /* Move in extension */ { /* */ if(f[i] != ' ') /* Non-blank? */ *buf++ = tolower((f[i]&0x7f)); /* Yes, move it in */ } /*****************************/ *buf++ = NULL; /* Null at end */ } /*****************************/ #else nowildcards() /* stubroutine for OPTION*.h package */ { } #endif /*****************************************************************************/ /*****************************************************************************/ ************************************************************/ ************************************************************/