/*=gfunc prefix * * what: prefix lines with a string * general_use: * * exparg: prefix, string to insert at start of each line * exparg: text, multi-line block of text * * doc: * Prefix every line in the second string with the first string. * * For example, if the first string is "# " and the second contains: * @example * two * lines * @end example * @noindent * The result string will contain: * @example * # two * # lines * @end example =*/ SCM ag_scm_prefix(SCM prefix, SCM text) { char* pzPfx; char* pzText; char* pzDta; size_t out_size, rem_size; size_t pfx_size; char* pzRes; pzPfx = ag_scm2zchars(prefix, "prefix"); pzDta = \ pzText = ag_scm2zchars(text, "text"); pfx_size = strlen(pzPfx); out_size = pfx_size; for (;;) { switch (*(pzText++)) { case NUL: goto exit_count; case NL: out_size += pfx_size; /* FALLTHROUGH */ default: out_size++; } } exit_count:; pzText = pzDta; pzRes = pzDta = ag_scribble(rem_size = out_size); strcpy(pzDta, pzPfx); pzDta += pfx_size; rem_size -= pfx_size; pfx_size++; for (;;) { char ch = *(pzText++); switch (ch) { case NUL: if (rem_size != 0) AG_ABEND(PREFIX_FAIL); return AG_SCM_STR2SCM(pzRes, out_size); case NL: *pzDta = ch; strcpy(pzDta+1, pzPfx); pzDta += pfx_size; rem_size -= pfx_size; break; default: rem_size--; *(pzDta++) = ch; break; } } }
/** * Could not find the file or could not find the markers. * Either way, emit an empty enclosure. */ static SCM mk_empty_text(char const* pzStart, char const* pzEnd, SCM def) { size_t mlen = strlen(pzStart) + strlen(pzEnd) + 3; char* pzOut; if (! AG_SCM_STRING_P(def)) { pzOut = ag_scribble(mlen); sprintf(pzOut, LINE_CONCAT3_FMT+3, pzStart, pzEnd); } else { char const * pzDef = ag_scm2zchars(def, "dft extr str"); mlen += AG_SCM_STRLEN(def) + 1; pzOut = ag_scribble(mlen); sprintf(pzOut, LINE_CONCAT3_FMT, pzStart, pzDef, pzEnd); } return AG_SCM_STR02SCM(pzOut); }
/** * Replace marker text. * * Replace all occurrances of the marker text with the substitution text. * The result is stored in an automatically freed temporary buffer. * * @param src_str The source string * @param str_len The length of the string * @param match the SCM-ized marker string * @param repl the SCM-ized replacement string * @param ppz_res pointer to the result pointer * @param res_len pointer to result length */ static void do_substitution( char const * src_str, ssize_t str_len, SCM match, SCM repl, char ** ppz_res, ssize_t * res_len) { char* pzMatch = ag_scm2zchars(match, "match text"); char* rep_str = ag_scm2zchars(repl, "repl text"); int mark_len = AG_SCM_STRLEN(match); int repl_len = AG_SCM_STRLEN(repl); { int ct = sub_count(src_str, pzMatch); if (ct == 0) return; /* No substitutions -- no work. */ str_len += (repl_len - mark_len) * ct; } { char * dest = ag_scribble(str_len + 1); *ppz_res = dest; *res_len = str_len; for (;;) { char const * next = strstr(src_str, pzMatch); size_t len; if (next == NULL) break; len = next - src_str; if (len != 0) { memcpy(dest, src_str, len); dest += len; } memcpy(dest, rep_str, (size_t)repl_len); dest += repl_len; src_str = next + mark_len; } strcpy(dest, src_str); } }
/** * guts of the template file/line functions */ static SCM do_tpl_file_line(int line_delta, char const * fmt) { void * args[2] = { [0] = (void*)pCurTemplate->pzTplFile, [1] = (void*)((long)pCurMacro->lineNo + line_delta) }; char * buf = strrchr(args[0], DIRCH); if (buf != NULL) args[0] = buf + 1; { size_t sz = strlen(fmt) + strlen(args[0]) + 24; buf = ag_scribble(sz); } sprintfv(buf, fmt, (snv_constpointer*)args); return AG_SCM_STR02SCM(buf); }
/*=gfunc def_file_line * * what: get a definition file+line number * * exparg: ag-name, name of AutoGen value * exparg: msg-fmt, formatting for line message, optional * * doc: * Returns the file and line number of a AutoGen defined value, using * either the default format, "from %s line %d", or else the format you * supply. For example, if you want to insert a "C" language file-line * directive, you would supply the format "# %2$d \"%1$s\"", but that * is also already supplied with the scheme variable * @xref{SCM c-file-line-fmt}. You may use it thus: * * @example * (def-file-line "ag-def-name" c-file-line-fmt) * @end example * * It is also safe to use the formatting string, "%2$d". AutoGen uses * an argument vector version of printf: @xref{snprintfv}. =*/ SCM ag_scm_def_file_line(SCM obj, SCM fmt) { static char const zFmt[] = "from %s line %d"; char const * pzFmt = zFmt; char * buf; ag_bool x; tDefEntry * pE = findDefEntry(ag_scm2zchars(obj, "ag value"), &x); /* * IF we did not find the entry we are looking for * THEN return UNDEFINED */ if (pE == NULL) return SCM_UNDEFINED; if (AG_SCM_STRING_P(fmt)) pzFmt = ag_scm2zchars(fmt, "file/line format"); { void * args[2] = { (void*)pE->pzSrcFile, (void*)(long)pE->srcLineNum }; size_t maxlen; buf = strrchr(args[0], DIRCH); if (buf != NULL) args[0] = buf + 1; maxlen = strlen(args[0]) + strlen(pzFmt) + LOG10_2to32 + 1; buf = ag_scribble(maxlen); sprintfv(buf, pzFmt, (snv_constpointer*)args); } return AG_SCM_STR02SCM(buf); }
/*=gfunc hide_email * * what: convert eaddr to javascript * general_use: * * exparg: display, display text * exparg: eaddr, email address * * doc: Hides an email address as a java scriptlett. * The 'mailto:' tag and the email address are coded bytes * rather than plain text. They are also broken up. =*/ SCM ag_scm_hide_email(SCM display, SCM eaddr) { static char const zFmt[] = "&#%d;"; static char const zStrt[] = "<script language=\"JavaScript\" type=\"text/javascript\">\n" "<!--\n" "var one = 'ma';\n" "var two = 'ilt';\n" "document.write('<a href=\"' + one + two );\n" "document.write('o:"; static char const zEnd[] = "');\n" "document.write('\" >%s</a>');\n" "//-->\n</script>"; char* pzDisp = ag_scm2zchars(display, zFormat); char* pzEadr = ag_scm2zchars(eaddr, zFormat); size_t str_size = (strlen(pzEadr) * sizeof(zFmt)) + sizeof(zStrt) + sizeof(zEnd) + strlen(pzDisp); char* pzRes = ag_scribble(str_size); char* pzScan = pzRes; strcpy(pzScan, zStrt); pzScan += sizeof(zStrt) - 1; for (;;) { if (*pzEadr == NUL) break; pzScan += sprintf(pzScan, zFmt, *(pzEadr++)); } pzScan += sprintf(pzScan, zEnd, pzDisp); return AG_SCM_STR2SCM(pzRes, (size_t)(pzScan - pzRes)); }
/*=gfunc join * * what: join string list with separator * general_use: * exparg: separator, string to insert between entries * exparg: list, list of strings to join,, list * * doc: With the first argument as the separator string, * joins together an a-list of strings into one long string. * The list may contain nested lists, partly because you * cannot always control that. =*/ SCM ag_scm_join(SCM sep, SCM list) { int l_len, sv_l_len; SCM car; SCM alist = list; size_t sep_len; size_t str_len; char * pzRes; char const * pzSep; char * pzScan; if (! AG_SCM_STRING_P(sep)) return SCM_UNDEFINED; sv_l_len = l_len = scm_ilength(list); if (l_len == 0) return AG_SCM_STR02SCM(zNil); pzSep = AG_SCM_CHARS(sep); sep_len = AG_SCM_STRLEN(sep); str_len = 0; /* * Count up the lengths of all the strings to be joined. */ for (;;) { car = SCM_CAR(list); list = SCM_CDR(list); /* * This routine is listed as getting a list as the second * argument. That means that if someone builds a list and * hands it to us, it magically becomes a nested list. * This unravels that. */ if (! AG_SCM_STRING_P(car)) { if (car != SCM_UNDEFINED) car = ag_scm_join(sep, car); if (! AG_SCM_STRING_P(car)) return SCM_UNDEFINED; } str_len += AG_SCM_STRLEN(car); if (--l_len <= 0) break; str_len += sep_len; } l_len = sv_l_len; pzRes = pzScan = ag_scribble(str_len); /* * Now, copy each one into the output */ for (;;) { size_t cpy_len; car = SCM_CAR(alist); alist = SCM_CDR(alist); /* * This unravels nested lists. */ if (! AG_SCM_STRING_P(car)) car = ag_scm_join(sep, car); cpy_len = AG_SCM_STRLEN(car); memcpy((void*)pzScan, AG_SCM_CHARS(car), cpy_len); pzScan += cpy_len; /* * IF we reach zero, then do not insert a separation and bail out */ if (--l_len <= 0) break; memcpy((void*)pzScan, (void*)pzSep, sep_len); pzScan += sep_len; } return AG_SCM_STR2SCM(pzRes, str_len); }