INLINE FILE_LOCAL ReturnCode stparmscan(struct Global *global, int delim) { /* * Normal string parameter scan. */ unsigned char *wp; int i; ReturnCode ret; wp = (unsigned char *)global->workp; /* Here's where it starts */ ret=scanstring(global, delim, save); if(ret) return(ret); /* Exit on scanstring error */ global->workp[-1] = EOS; /* Erase trailing quote */ wp++; /* -> first string content byte */ for (i = 0; i < global->nargs; i++) { if (streq(global->parlist[i], (char *)wp)) { *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ *wp++ = (i + MAC_PARM); /* Make a formal marker */ *wp = wp[-3]; /* Add on closing quote */ global->workp = (char *)wp + 1; /* Reset string end */ return(FPP_OK); } } global->workp[-1] = wp[-1]; /* Nope, reset end quote. */ return(FPP_OK); }
/* * Normal string parameter scan. */ void stparmscan(int delim) { char* wp; int i; wp = workp; /* Here's where it starts */ if (!scanstring(delim, save)) return; /* Exit on scanstring error */ workp[-1] = EOS; /* Erase trailing quote */ wp++; /* -> first string content byte */ for (i = 0; i < nargs; i++) { if (streq(parlist[i], wp)) { #ifdef SOLAR *wp++ = DEL; *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ *wp++ = (char)(i + MAC_PARM); /* Make a formal marker */ *wp = wp[-4]; /* Add on closing quote */ workp = wp + 1; /* Reset string end */ #else *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ *wp++ = (i + MAC_PARM); /* Make a formal marker */ *wp = wp[-3]; /* Add on closing quote */ workp = wp + 1; /* Reset string end */ #endif return; } } workp[-1] = wp[-1]; /* Nope, reset end quote. */ }
void lunascan::next() { if (CODESTACKSIZE<1) ERRORMSG(); clear(); scanspace(); if (CH!='\0') if (CH>='0' && CH<='9') scanvalue(); else if (CH=='-') scanminus(); else if (CH=='\'') scanchar(); else if (CH=='"') scanstring(); else if ((CH>='a' && CH<='z') || (CH>='A' && CH<='Z') || CH=='_') scanidentifier(); else scanspecial(); }
char *read_string(char *prompt, char *def) { short esito; static char stringa[EASYIO_MAX_STR_LEN]; for (int timeout = 0; timeout <= 5; timeout++) { fprintf(FPTR, "%s [%s] > ", prompt, def); esito = scanstring(stringa); switch (esito) { case EASYIO_DEFAULT: return (def); case EASYIO_OKAY: return (stringa); case EASYIO_ERROR: beep(); break; } } fprintf(FPTR, "\n FATAL ERROR: too many wrong attempts "); fprintf(FPTR, "in read_string() \n"); exit(-1); return (false); // not used: just to be nice with the compiler }
/* * Collect the actual parameters for this macro. TRUE if ok. */ FILE_LOCAL int expcollect() { int c; int paren; /* For embedded ()'s */ for (;;) { paren = 0; /* Collect next arg. */ while ((c = skipws()) == '\n') /* Skip over whitespace */ wrongline = TRUE; /* and newlines. */ if (c == ')') /* At end of all args? */ { /* * Note that there is a guard byte in parm[] * so we don't have to check for overflow here. */ *parmp = EOS; /* Make sure terminated */ break; /* Exit collection loop */ } else if (nargs >= LASTPARM) cfatal("Too many arguments in macro expansion", NULLST); parlist[nargs++] = parmp; /* At start of new arg */ for (;; c = cget()) /* Collect arg's bytes */ { if (c == EOF_CHAR) { cerror("end of file within macro argument", NULLST); return FALSE; /* Sorry. */ } else if (c == '\\') /* Quote next character */ { charput(c); /* Save the \ for later */ charput(cget()); /* Save the next char. */ continue; /* And go get another */ } else if (type[c] == QUO) /* Start of string? */ { scanstring(c, charput); /* Scan it off */ continue; /* Go get next char */ } else if (c == '(') /* Worry about balance */ paren++; /* To know about commas */ else if (c == ')') /* Other side too */ { if (paren == 0) /* At the end? */ { unget(); /* Look at it later */ break; /* Exit arg getter. */ } paren--; /* More to come. */ } else if (c == ',' && paren == 0) /* Comma delimits args */ break; else if (c == '\n') /* Newline inside arg? */ wrongline = TRUE; /* We'll need a #line */ charput(c); /* Store this one */ } /* Collect an argument */ charput(EOS); /* Terminate argument */ #if OSL_DEBUG_LEVEL > 1 if (debug) fprintf( pCppOut, "parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]); #endif } /* Collect all args. */ return TRUE; /* Normal return */ }
/* * Main process for cpp -- copies tokens from the current input * stream (main file, include file, or a macro) to the output * file. */ void cppmain() { int c; /* Current character */ int counter; /* newlines and spaces */ /* * Explicitly output a #line at the start of cpp output so * that lint (etc.) knows the name of the original source * file. If we don't do this explicitly, we may get * the name of the first #include file instead. * We also seem to need a blank line following that first #line. */ #ifdef EVALDEFS if ( !bIsInEval ) #endif { sharp(); PUTCHAR('\n'); } /* * This loop is started "from the top" at the beginning of each line * wrongline is set TRUE in many places if it is necessary to write * a #line record. (But we don't write them when expanding macros.) * * The counter variable has two different uses: at * the start of a line, it counts the number of blank lines that * have been skipped over. These are then either output via * #line records or by outputting explicit blank lines. * When expanding tokens within a line, the counter remembers * whether a blank/tab has been output. These are dropped * at the end of the line, and replaced by a single blank * within lines. */ for (;;) { counter = 0; /* Count empty lines */ for (;;) { /* For each line, ... */ while (type[(c = get())] == SPA) /* Skip leading blanks */ ; /* in this line. */ if (c == '\n') /* If line's all blank, */ ++counter; /* Do nothing now */ else if (c == '#') { /* Is 1st non-space '#' */ keepcomments = FALSE; /* Don't pass comments */ counter = control(counter); /* Yes, do a #command */ keepcomments = (cflag && compiling); } else if (c == EOF_CHAR) /* At end of file? */ { break; } else if (!compiling) { /* #ifdef false? */ skipnl(); /* Skip to newline */ counter++; /* Count it, too. */ } else { break; /* Actual token */ } } if (c == EOF_CHAR) /* Exit process at */ break; /* End of file */ /* * If the loop didn't terminate because of end of file, we * know there is a token to compile. First, clean up after * absorbing newlines. counter has the number we skipped. */ if ((wrongline && infile->fp != NULL) || counter > 4) sharp(); /* Output # line number */ else { /* If just a few, stuff */ while (--counter >= 0) /* them out ourselves */ PUTCHAR('\n'); } /* * Process each token on this line. */ unget(); /* Reread the char. */ for (;;) { /* For the whole line, */ do { /* Token concat. loop */ for (counter = 0; type[(c = get())] == SPA;) { #if COMMENT_INVISIBLE if (c != COM_SEP) #endif counter++; /* Skip over blanks */ } if (c == EOF_CHAR || c == '\n') goto end_line; /* Exit line loop */ else if (counter > 0) /* If we got any spaces */ PUTCHAR(' '); /* Output one space */ c = macroid(c); /* Grab the token */ } while (type[c] == LET && catenate()); if (c == EOF_CHAR || c == '\n') /* From macro exp error */ goto end_line; /* Exit line loop */ switch (type[c]) { case LET: fputs(token, pCppOut); /* Quite ordinary token */ #ifdef EVALDEFS { int len; if ( bIsInEval && nEvalOff + (len=strlen(token)) < NEVALBUF ) { strcpy( &EvalBuf[nEvalOff], token ); nEvalOff += len; } } #endif break; case DIG: /* Output a number */ case DOT: /* Dot may begin floats */ #ifdef EVALDEFS if ( bIsInEval ) scannumber(c, outputEval); else scannumber(c, output); #else scannumber(c, output); #endif break; case QUO: /* char or string const */ scanstring(c, output); /* Copy it to output */ break; default: /* Some other character */ cput(c); /* Just output it */ #ifdef EVALDEFS if ( bIsInEval && nEvalOff < NEVALBUF ) EvalBuf[nEvalOff++] = c; #endif break; } /* Switch ends */ } /* Line for loop */ end_line: if (c == '\n') { /* Compiling at EOL? */ PUTCHAR('\n'); /* Output newline, if */ if (infile->fp == NULL) /* Expanding a macro, */ wrongline = TRUE; /* Output # line later */ } } /* Continue until EOF */ #ifdef EVALDEFS if ( bIsInEval ) EvalBuf[nEvalOff++] = '\0'; #endif }
INLINE FILE_LOCAL ReturnCode expcollect(struct Global *global) { /* * Collect the actual parameters for this macro. */ int c; int paren; /* For embedded ()'s */ ReturnCode ret; for (;;) { paren = 0; /* Collect next arg. */ while ((c = skipws(global)) == '\n')/* Skip over whitespace */ global->wrongline = TRUE; /* and newlines. */ if (c == ')') { /* At end of all args? */ /* * Note that there is a guard byte in parm[] * so we don't have to check for overflow here. */ *global->parmp = EOS; /* Make sure terminated */ break; /* Exit collection loop */ } else if (global->nargs >= LASTPARM) { cfatal(global, FATAL_TOO_MANY_ARGUMENTS_EXPANSION); return(FPP_TOO_MANY_ARGUMENTS); } global->parlist[global->nargs++] = global->parmp; /* At start of new arg */ for (;; c = cget(global)) { /* Collect arg's bytes */ if (c == EOF_CHAR) { cerror(global, ERROR_EOF_IN_ARGUMENT); return(FPP_EOF_IN_MACRO); /* Sorry. */ } else if (c == '\\') { /* Quote next character */ charput(global, c); /* Save the \ for later */ charput(global, cget(global)); /* Save the next char. */ continue; /* And go get another */ } else if (type[c] == QUO) { /* Start of string? */ ret=scanstring(global, c, (ReturnCode (*)(struct Global *, int))charput); /* Scan it off */ if(ret) return(ret); continue; /* Go get next char */ } else if (c == '(') /* Worry about balance */ paren++; /* To know about commas */ else if (c == ')') { /* Other side too */ if (paren == 0) { /* At the end? */ unget(global); /* Look at it later */ break; /* Exit arg getter. */ } paren--; /* More to come. */ } else if (c == ',' && paren == 0) /* Comma delimits args */ break; else if (c == '\n') /* Newline inside arg? */ global->wrongline = TRUE; /* We'll need a #line */ charput(global, c); /* Store this one */ } /* Collect an argument */ charput(global, EOS); /* Terminate argument */ } /* Collect all args. */ return(FPP_OK); /* Normal return */ }
INLINE FILE_LOCAL ReturnCode cppmain(struct Global *global) { /* * Main process for cpp -- copies tokens from the current input * stream (main file, include file, or a macro) to the output * file. */ int c; /* Current character */ int counter; /* newlines and spaces */ ReturnCode ret; /* return code variable type */ long bracelevel = 0; long parenlevel = 0; long bracketlevel = 0; int fake = 0; #define MAX_FUNC_LENGTH 50 char tempfunc[MAX_FUNC_LENGTH + 1]; char tempfunc2[MAX_FUNC_LENGTH + 1]; char define = 0; /* probability of a function define phase in the program */ char prev = 0; /* previous type */ char go = 0; char include = 0; char initfunc = 0; /* Initialize for reading tokens */ global->tokenbsize = 50; global->tokenbuf = malloc(global->tokenbsize + 1); if(!global->tokenbuf) return(FPP_OUT_OF_MEMORY); global->functionname = malloc(global->tokenbsize + 1); if(!global->functionname) return(FPP_OUT_OF_MEMORY); global->functionname[0] = '\0'; if(global->showspace) { global->spacebuf = (char *)malloc(MAX_SPACE_SIZE); if(!global->spacebuf) return(FPP_OUT_OF_MEMORY); } if(global->showversion) Error(global, VERSION_TEXT); /* * Explicitly output a #line at the start of cpp output so * that lint (etc.) knows the name of the original source * file. If we don't do this explicitly, we may get * the name of the first #include file instead. */ if(global->linelines) /* if #line lines are wanted! */ sharp(global); /* * This loop is started "from the top" at the beginning of each line * wrongline is set TRUE in many places if it is necessary to write * a #line record. (But we don't write them when expanding macros.) * * The counter variable has two different uses: at * the start of a line, it counts the number of blank lines that * have been skipped over. These are then either output via * #line records or by outputting explicit blank lines. * When expanding tokens within a line, the counter remembers * whether a blank/tab has been output. These are dropped * at the end of the line, and replaced by a single blank * within lines. */ include = global->included; while(include--) { openinclude(global, global->include[include], TRUE); } for (;;) { counter = 0; /* Count empty lines */ for (;;) { /* For each line, ... */ global->comment = FALSE; /* No comment yet! */ global->chpos = 0; /* Count whitespaces */ while (type[(c = get(global))] == SPA) /* Skip leading blanks */ if(global->showspace) { if(global->chpos<MAX_SPACE_SIZE-1) /* we still have buffer to store this! */ global->spacebuf[global->chpos++]=(char)c; } if (c == '\n') { /* If line's all blank, */ if(global->comment) { /* A comment was output! */ Putchar(global, '\n'); } else ++counter; /* Do nothing now */ } else if (c == '#') { /* Is 1st non-space '#' */ global->keepcomments = FALSE; /* Don't pass comments */ ret = control(global, &counter); /* Yes, do a #command */ if(ret) return(ret); global->keepcomments = (global->cflag && compiling); } else if (c == EOF_CHAR) /* At end of file? */ break; else if (!compiling) { /* #ifdef false? */ skipnl(global); /* Skip to newline */ counter++; /* Count it, too. */ } else { break; /* Actual token */ } } if (c == EOF_CHAR) /* Exit process at */ break; /* End of file */ /* * If the loop didn't terminate because of end of file, we * know there is a token to compile. First, clean up after * absorbing newlines. counter has the number we skipped. */ if(global->linelines) { /* if #line lines are wanted! */ if ((global->wrongline && global->infile->fp != NULL) || counter > 4) sharp(global); /* Output # line number */ else { /* If just a few, stuff */ while (--counter >= 0) /* them out ourselves */ Putchar(global, (int)'\n'); } } if(global->showspace) { /* Show all whitespaces! */ global->spacebuf[global->chpos] = '\0'; Putstring(global, global->spacebuf); } /* * Process each token on this line. */ unget(global); /* Reread the char. */ for (;;) { /* For the whole line, */ do { /* Token concat. loop */ for (global->chpos = counter = 0; (type[(c = get(global))] == SPA);) { #if COMMENT_INVISIBLE if (c != COM_SEP) counter++; #else if(global->showspace && global->chpos < MAX_SPACE_SIZE-1) { global->spacebuf[global->chpos++]=(char)c; } counter++; /* Skip over blanks */ #endif } if (c == EOF_CHAR || c == '\n') break; /* Exit line loop */ else if (counter > 0) { /* If we got any spaces */ if(!global->showspace) /* We don't output all spaces */ Putchar(global, (int)' ');/* Output one space */ else { global->spacebuf[global->chpos] = '\0'; Putstring(global, global->spacebuf); /* Output all whitespaces */ } } if(ret=macroid(global, &c)) /* Grab the token */ return(ret); } while (type[c] == LET && catenate(global, &ret) && !ret); if(ret) /* If the loop was broken because of a fatal error! */ return(ret); if (c == EOF_CHAR || c == '\n') /* From macro exp error */ break; /* Exit line loop */ go++; switch (type[c]) { case LET: go =0; /* Quite ordinary token */ Putstring(global, global->tokenbuf); if(!define) { /* Copy the name */ strncpy(tempfunc, global->tokenbuf, MAX_FUNC_LENGTH); tempfunc[MAX_FUNC_LENGTH]=0; } /* fputs(global->tokenbuf, stdout); */ break; case DIG: /* Output a number */ case DOT: /* Dot may begin floats */ go = 0; ret=scannumber(global, c, (ReturnCode(*)(struct Global *, int))output); if(ret) return(ret); break; case QUO: /* char or string const */ go = 0; /* Copy it to output */ if(!global->webmode) { ret=scanstring(global, c, (ReturnCode(*)(struct Global *, int))output); if(ret) return(ret); break; } /* FALLTHROUGH */ default: /* Some other character */ define++; switch(c) { case '{': if(! bracelevel++ && define > 2) { /* * This is a starting brace. If there is a probability of a * function defining, we copy the `tempfunc' function name to * `global->functionname'. */ strcpy(global->functionname, tempfunc2); global->funcline = global->line; if(global->outputfunctions) { /* * Output the discovered function name to stderr! */ Error(global, "#> Function defined at line %d: %s <#\n", global->line, global->functionname); } if(global->initialfunc) { int a; for(a=0; a<global->excluded; a++) { /* check for excluded functions */ if(!strcmp(global->functionname, global->excludedinit[a])) break; } if(a==global->excluded) { expstuff(global, "__brace__", "{"); expstuff(global, "__init_func__", global->initialfunc); initfunc = TRUE; } } } break; case '}': go = 0; if( (--bracelevel == initfunc) && strcmp(global->infile->filename, "__init_func__") ) { /* we just stepped out of the function! */ global->functionname[0] = '\0'; global->funcline = 0; define = 1; if(initfunc) { Putchar(global, '}'); bracelevel--; initfunc=0; } } fake = 0; break; case ';': case ',': if(go == 2) { define = 1; fake = 0; go--; break; } break; case '(': if(! parenlevel++ && !bracelevel) { if(go == 2) { /* foobar(text) -> "(" is found. This can't be a function */ go--; define = 1; break; } if( define < 2 && prev == LET) { /* This is the first parenthesis on the ground brace level, and we did previously not have a probable function name */ strncpy(tempfunc2, global->tokenbuf, MAX_FUNC_LENGTH); tempfunc2[MAX_FUNC_LENGTH]=0; define++; } else { /* we have a fake start */ fake++; } } break; case ')': if(! --parenlevel && !bracelevel && define>1 && !fake) { /* * The starting parentheses level and * the starting brace level. * This might be the start of a function defining coming * up! */ define++; /* increase probability */ fake = 0; go = 1; } break; case '[': bracketlevel++; break; case ']': bracketlevel--; break; } define--; /* decrease function probability */ Putchar(global, c); /* Just output it */ break; } /* Switch ends */ prev = type[c]; } /* Line for loop */ if (c == '\n') { /* Compiling at EOL? */ Putchar(global, '\n'); /* Output newline, if */ if (global->infile->fp == NULL) /* Expanding a macro, */ global->wrongline = TRUE; /* Output # line later */ } } /* Continue until EOF */ if(global->showbalance) { if(bracketlevel) { cwarn(global, WARN_BRACKET_DEPTH, bracketlevel); } if(parenlevel) { cwarn(global, WARN_PAREN_DEPTH, parenlevel); } if(bracelevel) { cwarn(global, WARN_BRACE_DEPTH, bracelevel); } } if (global->wflag) { global->out = TRUE; /* enable output */ outdefines(global); /* Write out #defines */ } return(FPP_OK); }
static int field_encode_address(const char *name, char **value, int encoding, const char *charset) { int prefixlen = strlen(name) + 2, column = prefixlen, groupflag; int asciichars, specialchars, eightbitchars, reformat = 0, errflag = 0; size_t len; char *mp, *cp = NULL, *output = NULL; char *tmpbuf = NULL; size_t tmpbufsize = 0; struct mailname *mn; char errbuf[BUFSIZ]; /* * Because these are addresses, we need to handle them individually. * * Break them down and process them one by one. This means we have to * rewrite the whole header, but that's unavoidable. */ /* * The output headers always have to start with a space first; this * is just the way the API works right now. */ output = add(" ", output); for (groupflag = 0; (mp = getname(*value)); ) { if ((mn = getm(mp, NULL, 0, errbuf, sizeof(errbuf))) == NULL) { advise(NULL, "%s: %s", errbuf, mp); errflag++; continue; } reformat = 0; /* * We only care if the phrase (m_pers) or any trailing comment * (m_note) have 8-bit characters. If doing q-p, we also need * to encode anything marked as qspecial(). Unquote it first * so the specialchars count is right. */ if (! mn->m_pers) goto check_note; if ((len = strlen(mn->m_pers)) + 1 > tmpbufsize) { tmpbuf = mh_xrealloc(tmpbuf, tmpbufsize = len + 1); } unquote_string(mn->m_pers, tmpbuf); if (scanstring(tmpbuf, &asciichars, &eightbitchars, &specialchars)) { /* * If we have 8-bit characters, encode it. */ if (encoding == CE_UNKNOWN) encoding = pref_encoding(asciichars, specialchars, eightbitchars); /* * This is okay, because the output of unquote_string will be either * equal or shorter than the original. */ strcpy(mn->m_pers, tmpbuf); switch (encoding) { case CE_BASE64: if (field_encode_base64(NULL, &mn->m_pers, charset)) { errflag++; goto out; } break; case CE_QUOTED: if (field_encode_quoted(NULL, &mn->m_pers, charset, asciichars, eightbitchars + specialchars, 1)) { errflag++; goto out; } break; default: advise(NULL, "Internal error: unknown RFC-2047 encoding type"); errflag++; goto out; } reformat++; } check_note: /* * The "note" field is generally a comment at the end of the address, * at least as how it's implemented here. Notes are always surrounded * by parenthesis (since they're comments). Strip them out and * then put them back when we format the final field, but they do * not get encoded. */ if (! mn->m_note) goto do_reformat; if ((len = strlen(mn->m_note)) + 1 > tmpbufsize) { tmpbuf = mh_xrealloc(tmpbuf, tmpbufsize = len + 1); } if (mn->m_note[0] != '(' || mn->m_note[len - 1] != ')') { advise(NULL, "Internal error: Invalid note field \"%s\"", mn->m_note); errflag++; goto out; } strncpy(tmpbuf, mn->m_note + 1, len - 1); tmpbuf[len - 2] = '\0'; if (scanstring(tmpbuf, &asciichars, &eightbitchars, &specialchars)) { /* * If we have 8-bit characters, encode it. */ if (encoding == CE_UNKNOWN) encoding = pref_encoding(asciichars, specialchars, eightbitchars); switch (encoding) { case CE_BASE64: if (field_encode_base64(NULL, &tmpbuf, charset)) { errflag++; goto out; } break; case CE_QUOTED: if (field_encode_quoted(NULL, &tmpbuf, charset, asciichars, eightbitchars + specialchars, 1)) { errflag++; goto out; } break; default: advise(NULL, "Internal error: unknown RFC-2047 encoding type"); errflag++; goto out; } reformat++; /* * Make sure the size of tmpbuf is correct (it always gets * reallocated in the above functions). */ tmpbufsize = strlen(tmpbuf) + 1; /* * Put the note field back surrounded by parenthesis. */ mn->m_note = mh_xrealloc(mn->m_note, tmpbufsize + 2); snprintf(mn->m_note, tmpbufsize + 2, "(%s)", tmpbuf); } do_reformat: /* * So, some explanation is in order. * * We know we need to rewrite at least one address in the header, * otherwise we wouldn't be here. If we had to reformat this * particular address, then run it through adrformat(). Otherwise * we can use m_text directly. */ /* * If we were in a group but are no longer, make sure we add a * semicolon (which needs to be FIRST, as it needs to be at the end * of the last address). */ if (groupflag && ! mn->m_ingrp) { output = add(";", output); column += 1; } groupflag = mn->m_ingrp; if (mn->m_gname) { cp = add(mn->m_gname, NULL); } if (reformat) { cp = add(adrformat(mn), cp); } else { cp = add(mn->m_text, cp); } len = strlen(cp); /* * If we're not at the beginning of the line, add a command and * either a space or a newline. */ if (column != prefixlen) { if (len + column + 2 > OUTPUTLINELEN) { if ((size_t) (prefixlen + 3) < tmpbufsize) tmpbuf = mh_xrealloc(tmpbuf, tmpbufsize = prefixlen + 3); snprintf(tmpbuf, tmpbufsize, ",\n%*s", column = prefixlen, ""); output = add(tmpbuf, output); } else { output = add(", ", output); column += 2; } } /* * Finally add the address */ output = add(cp, output); column += len; free(cp); cp = NULL; } /* * Just in case we're at the end of a list */ if (groupflag) { output = add(";", output); } output = add("\n", output); free(*value); *value = output; output = NULL; out: if (tmpbuf) free(tmpbuf); if (output) free(output); return errflag > 0; }
boolean pathtofilespec ( bigstring bspath, ptrfilespec fs ) { // // 2010-01-24 creedon: fix for relative paths not working on mac, // bsfullpath was ending up with :: in it as well as // the full path to the application, see initfsdefault // function // // 2009-08-30 aradke: refactored mac version to make it easier to understand. // fixed bug where a bspath containing a non-existing volume name was accepted as valid, // e.g. filespec("foobar:"), thus deviating from previous behaviour. // // 2006-10-16 creedon: for Mac, FSRef-ized // // 5.0d8 dmb: clear fs first thing // // 2.1b2 dmb: use new fsdefault for building filespec. note that if bspath // isn't a partial path, the vref and dirid will be ignored. // // 2.1b2 dmb: added special case for empty string. also, added drive // number interpretation here. // // 1993-06-11 dmb: if FSMakeFSSpec returns fnfErr, the spec is cool (but // file doesn't exist) // // 1991-012-17 dmb: dont append path to default directory if it's a full // path // // 1991-07-05 dmb: use FSMakeFSSpec if it's available. since it only // returns noErr if the file exists, and we want to handle // non-existant files, we don't give up right away. // #ifdef MACVERSION FSRef fsr; bigstring bspathtmp, bsfullpath, bsfile, bsfolder; short ix = 1; boolean flvolume = false; #endif #ifdef WIN95VERSION bigstring bsfolder; #endif clearbytes ( fs, sizeof ( *fs ) ); if ( isemptystring ( bspath ) ) return ( true ); #ifdef MACVERSION // create cleaned-up full path representation of our input suitable for pathtosref copystring ( bspath, bspathtmp ); cleanendoffilename ( bspathtmp ); if ( scanstring ( ':', bspath, &ix ) && ( ix > 1 ) ) { // contains a colon but doesn't start with one, so it must be a full path if ( ix == stringlength ( bspath ) ) // the colon we found is the last char, so bspath is a volume name flvolume = true; copystring ( bspathtmp, bsfullpath ); } else { // it's a partial path, prefix with default directory (see initfsdefault) if ( ! filespectopath ( &fsdefault, bsfullpath ) ) // get path of default directory return ( false ); // delete first path separator if partial path begins with one because bsfullpath always ends with one if ( bspathtmp [ 1 ] == chpathseparator ) deletefirstchar ( bspathtmp ); pushstring ( bspathtmp, bsfullpath ); // append partial path } // now see if the full path resolves if ( pathtofsref ( bsfullpath, &fsr ) == noErr ) { return ( macmakefilespec ( &fsr, fs ) == noErr ); } // full path did not resolve but we actually only require the parent folder to exist if ( ! flvolume ) { // volumes don't have a parent folder filefrompath ( bsfullpath, bsfile ); folderfrompath ( bsfullpath, bsfolder ); if ( pathtofsref ( bsfolder, &fsr ) == noErr ) { clearfilespec ( fs ); fs->ref = fsr; bigstringtofsname ( bsfile, &fs->name ); return ( true ); } } return ( false ); #endif #ifdef WIN95VERSION copystring (bspath, fsname (fs)); folderfrompath (bspath, bsfolder); if ((isemptystring (bsfolder)) && (! fileisvolume(fs))) { filegetdefaultpath (fs); pushstring (bspath, fsname (fs)); } nullterminate (fsname (fs)); return (true); #endif } // pathtofilespec