/* TODO maybe try not to use string port? */ static SgObject normalise_path(SgObject fullpath) { SgStringPort sp; SgObject out = Sg_InitStringOutputPort(&sp, SG_STRING_SIZE(fullpath)); int64_t pos = 0; int i = 0; while (i < SG_STRING_SIZE(fullpath)) { SgChar c = SG_STRING_VALUE_AT(fullpath, i++); if (c == '.') { if (i != SG_STRING_SIZE(fullpath)) { SgChar c2 = SG_STRING_VALUE_AT(fullpath, i++); if (c2 == '.') { if (SG_STRING_VALUE_AT(fullpath, i) == '/' || SG_STRING_SIZE(fullpath) == i) { if (pos-2 > 0) { SgObject tmp = Sg_GetStringFromStringPort(out); /* skip previous '.' and '/' */ pos = search_separator(tmp, pos-2); } else { pos = 1; /* root */ } if (pos <= 0) pos = 1; /* root */ Sg_SetPortPosition(out, pos, SG_BEGIN); if (pos == 1) i++; } else { /* ok just a file named '..?' or longer*/ Sg_PutcUnsafe(out, '.'); Sg_PutcUnsafe(out, '.'); pos += 2; for (; i < SG_STRING_SIZE(fullpath); i++) { SgChar c3 = SG_STRING_VALUE_AT(fullpath, i); if (c3 != '.') break; Sg_PutcUnsafe(out, c3); pos++; } } } else if (c2 != '/') { Sg_PutcUnsafe(out, '.'); Sg_PutcUnsafe(out, c2); pos += 2; } } } else { Sg_PutcUnsafe(out, c); pos++; } } return strip_trailing_slash(Sg_GetStringFromStringPort(out)); }
/* * Returns length of all starting parent references. */ static uint gp_file_name_prefix(const char *fname, uint flen, bool (*test)(const char *fname, uint flen)) { uint plen = gp_file_name_root(fname, flen), slen; const char *ip, *ipe; const char *item = fname; /* plen == flen could cause an indeterminizm. */ if (plen > 0) return 0; ip = fname + plen; ipe = fname + flen; for (; ip < ipe; ) { item = ip; slen = search_separator(&ip, ipe, item, 1); if (!(*test)(item, ip - item)) break; ip += slen; } return item - fname; }
/* * Combine a file name with a prefix. * Concatenates two paths and reduce parent references and current * directory references from the concatenation when possible. * The trailing zero byte is being added. * * Returns "gp_combine_success" if OK and sets '*blen' to the length of * the combined string. If the combined string is too small for the buffer * length passed in (as defined by the initial value of *blen), then the * "gp_combine_small_buffer" code is returned. * * Also tolerates/skips leading IODevice specifiers such as %os% or %rom% * When there is a leading '%' in the 'fname' no other processing is done. * * Examples : * "/gs/lib" + "../Resource/CMap/H" --> "/gs/Resource/CMap/H" * "C:/gs/lib" + "../Resource/CMap/H" --> "C:/gs/Resource/CMap/H" * "hard disk:gs:lib" + "::Resource:CMap:H" --> * "hard disk:gs:Resource:CMap:H" * "DUA1:[GHOSTSCRIPT.LIB" + "-.RESOURCE.CMAP]H" --> * "DUA1:[GHOSTSCRIPT.RESOURCE.CMAP]H" * "\\server\share/a/b///c/../d.e/./" + "../x.e/././/../../y.z/v.v" --> * "\\server\share/a/y.z/v.v" * "%rom%lib/" + "gs_init.ps" --> "%rom%lib/gs_init.ps * "" + "%rom%lib/gs_init.ps" --> "%rom%lib/gs_init.ps" */ gp_file_name_combine_result gp_file_name_combine_generic(const char *prefix, uint plen, const char *fname, uint flen, bool no_sibling, char *buffer, uint *blen) { /* * THIS CODE IS SHARED FOR MULTIPLE PLATFORMS. * PLEASE DON'T CHANGE IT FOR A SPECIFIC PLATFORM. * Change gp_file_name_combine instead. */ char *bp = buffer, *bpe = buffer + *blen; const char *ip, *ipe; uint slen; uint infix_type = 0; /* 0=none, 1=current, 2=parent. */ uint infix_len = 0; uint rlen = gp_file_name_root(fname, flen); /* We need a special handling of infixes only immediately after a drive. */ if ( flen > 0 && fname[0] == '%') { /* IoDevice -- just return the fname as-is since this */ /* function only handles the default file system */ /* NOTE: %os% will subvert the normal processing of prefix and fname */ ip = fname; *blen = flen; if (!append(&bp, bpe, &ip, flen)) return gp_combine_small_buffer; return gp_combine_success; } if (rlen != 0) { /* 'fname' is absolute, ignore the prefix. */ ip = fname; ipe = fname + flen; } else { /* Concatenate with prefix. */ ip = prefix; ipe = prefix + plen; rlen = gp_file_name_root(prefix, plen); } if (!append(&bp, bpe, &ip, rlen)) return gp_combine_small_buffer; slen = gs_file_name_check_separator(bp, buffer - bp, bp); /* Backward search. */ if (rlen != 0 && slen == 0) { /* Patch it against names like "c:dir" on Windows. */ const char *sep = gp_file_name_directory_separator(); slen = strlen(sep); if (!append(&bp, bpe, &sep, slen)) return gp_combine_small_buffer; rlen += slen; } for (;;) { const char *item = ip; uint ilen; slen = search_separator(&ip, ipe, item, 1); ilen = ip - item; if (ilen == 0 && !gp_file_name_is_empty_item_meanful()) { ip += slen; slen = 0; } else if (gp_file_name_is_current(item, ilen)) { /* Skip the reference to 'current', except the starting one. * We keep the starting 'current' for platforms, which * require relative paths to start with it. */ if (bp == buffer) { if (!append(&bp, bpe, &item, ilen)) return gp_combine_small_buffer; infix_type = 1; infix_len = ilen; } else { ip += slen; slen = 0; } } else if (!gp_file_name_is_parent(item, ilen)) { if (!append(&bp, bpe, &item, ilen)) return gp_combine_small_buffer; /* The 'item' pointer is now broken; it may be restored using 'ilen'. */ } else if (bp == buffer + rlen + infix_len) { /* Input is a parent and the output only contains a root and an infix. */ if (rlen != 0) return gp_combine_cant_handle; switch (infix_type) { case 1: /* Replace the infix with parent. */ bp = buffer + rlen; /* Drop the old infix, if any. */ infix_len = 0; /* Falls through. */ case 0: /* We have no infix, start with parent. */ if ((no_sibling && ipe == fname + flen && flen != 0) || !gp_file_name_is_partent_allowed()) return gp_combine_cant_handle; /* Falls through. */ case 2: /* Append one more parent - falls through. */ DO_NOTHING; } if (!append(&bp, bpe, &item, ilen)) return gp_combine_small_buffer; infix_type = 2; infix_len += ilen; /* Recompute the separator length. We cannot use the old slen on Mac OS. */ slen = gs_file_name_check_separator(ip, ipe - ip, ip); } else { /* Input is a parent and the output continues after infix. */ /* Unappend the last separator and the last item. */ uint slen1 = gs_file_name_check_separator(bp, buffer + rlen - bp, bp); /* Backward search. */ char *bie = bp - slen1; bp = bie; DISCARD(search_separator((const char **)&bp, buffer + rlen, bp, -1)); /* The cast above quiets a gcc warning. We believe it's a bug in the compiler. */ /* Skip the input with separator. We cannot use slen on Mac OS. */ ip += gs_file_name_check_separator(ip, ipe - ip, ip); if (no_sibling) { const char *p = ip; DISCARD(search_separator(&p, ipe, ip, 1)); if (p - ip != bie - bp || memcmp(ip, bp, p - ip)) return gp_combine_cant_handle; } slen = 0; } if (slen) { if (bp == buffer + rlen + infix_len) infix_len += slen; if (!append(&bp, bpe, &ip, slen)) return gp_combine_small_buffer; } if (ip == ipe) { if (ipe == fname + flen) { /* All done. * Note that the case (prefix + plen == fname && flen == 0) * falls here without appending a separator. */ const char *zero=""; if (bp == buffer) { /* Must not return empty path. */ const char *current = gp_file_name_current(); int clen = strlen(current); if (!append(&bp, bpe, ¤t, clen)) return gp_combine_small_buffer; } *blen = bp - buffer; if (!append(&bp, bpe, &zero, 1)) return gp_combine_small_buffer; return gp_combine_success; } else { /* ipe == prefix + plen */ /* Switch to fname. */ ip = fname; ipe = fname + flen; if (slen == 0) { /* Insert a separator. */ const char *sep; slen = search_separator(&ip, ipe, fname, 1); sep = (slen != 0 ? gp_file_name_directory_separator() : gp_file_name_separator()); slen = strlen(sep); if (bp == buffer + rlen + infix_len) infix_len += slen; if (!append(&bp, bpe, &sep, slen)) return gp_combine_small_buffer; ip = fname; /* Switch to fname. */ } } } } }
static void scan_script( void ) { inputcb * cb; mac_entry * me; char * p; char * pt; int toklen; int k; bool cwfound; cb = input_cbs; p = scan_start + 1; scan_restart = scan_start; if( (*p == '*') || !strnicmp( p, "cm ", 3 ) ) { scan_start = scan_stop + 1; // .cm +++ ignore comment up to EOL return; // .* +++ ignore comment up to EOL } if( *p == SCR_char && *(p+1) == SCR_char ) { pt = token_buf; *pt++ = SCR_char; // special for ...label *pt++ = SCR_char; *pt = '\0'; me = NULL; scan_start = p + 2; toklen = 2; } else { if( *p == '\'' ) { // .' p++; ProcFlags.CW_sep_ignore = 1; } else { if( CW_sep_char == '\0') { ProcFlags.CW_sep_ignore = 1;// No separator char no split } else{ ProcFlags.CW_sep_ignore = 0; } if( *p == SCR_char ) { // .. p++; ProcFlags.macro_ignore = 1; me = NULL; } else { ProcFlags.macro_ignore = 0; } } if( ProcFlags.literal ) { // no macro or split line if literal ProcFlags.CW_sep_ignore = 1; ProcFlags.macro_ignore = 1; } if( !ProcFlags.CW_sep_ignore ) { // scan line for CW_sep_char char * pchar; pchar = search_separator( buff2, CW_sep_char ); if( pchar != NULL ) { if( *(pchar + 1) != '\0' ) { // only split if more follows split_input( buff2, pchar + 1, false );// ignore CW_sep_char } *pchar= '\0'; // delete CW_sep_char buff2_lg = strlen( buff2 ); // new length of first part } } scan_start = p; pt = token_buf; while( *p && is_macro_char( *p ) ) { // end of controlword *pt++ = tolower( *p++ ); // copy lowercase to TokenBuf } *pt = '\0'; toklen = pt - token_buf; if( *p && (*p != ' ') || toklen == 0 ) {// no valid script controlword / macro // if( !ProcFlags.literal ) { // TBD // cw_err(); // } scan_start = scan_restart; // treat as text return; } if( toklen >= MAC_NAME_LENGTH ) { *(token_buf + MAC_NAME_LENGTH) = '\0'; } if( !ProcFlags.macro_ignore ) { me = find_macro( macro_dict, token_buf ); } else { me = NULL; } } if( me != NULL ) { // macro found if( GlobalFlags.firstpass && cb->fmflags & II_research ) { if( cb->fmflags & II_macro ) { printf_research( "L%d %c%s macro found in macro %s(%d)\n\n", inc_level, SCR_char, token_buf, cb->s.m->mac->name, cb->s.m->lineno ); } else { printf_research( "L%d %c%s macro found in file %s(%d)\n\n", inc_level, SCR_char, token_buf, cb->s.f->filename, cb->s.f->lineno ); } add_SCR_tag_research( token_buf ); } add_macro_cb_entry( me, NULL ); inc_inc_level(); add_macro_parms( p ); scan_restart = scan_stop + 1; } else { // try script controlword cwfound = false; if( cb->fmflags & II_research && GlobalFlags.firstpass ) { if( cb->fmflags & II_macro ) { printf_research( "L%d %c%s CW found in macro %s(%d)\n\n", inc_level, SCR_char, token_buf, cb->s.m->mac->name, cb->s.m->lineno ); } else { printf_research( "L%d %c%s CW found in file %s(%d)\n\n", inc_level, SCR_char, token_buf, cb->s.f->filename, cb->s.f->lineno ); } add_SCR_tag_research( token_buf ); } if( toklen == SCR_KW_LENGTH ) { for( k = 0; k < SCR_TAGMAX; ++k ) { if( !strcmp( scr_tags[k].tagname, token_buf ) ) { #if 0 if( !ProcFlags.fb_document_done && scr_tags[k].cwflags & cw_o_t ) { /***************************************************/ /* if this is the first cw which produces output */ /* set page geometry and margins from layout */ /***************************************************/ do_layout_end_processing(); } #endif if( !ProcFlags.layout && (scr_tags[k].cwflags & cw_o_t) ) { /********************************************************/ /* this is the first control word which produces output */ /* start the document, the layout is done */ /* start_doc_sect() calls do_layout_end_processing() */ /********************************************************/ start_doc_sect(); } if( ProcFlags.literal ) { // .li active if( !strcmp( token_buf, "li" ) ) { // .li scan_start = p; // found, process scr_tags[k].tagproc(); } } else { scan_start = p; // script controlword found, process if( scr_tags[k].cwflags & cw_break ) { scr_process_break();// output incomplete line, if any } scr_tags[k].tagproc(); } cwfound = true; break; } } } if( !cwfound ) { cw_err(); // unrecognized control word } } scan_start = scan_restart; }