/*------------------------------------------------------------------------- * Copyright (c) 2000-2003 Kenneth W. Sodemann (stuffle@mac.com) *------------------------------------------------------------------------- * tex_utils * * Synopsis: * A collection of utilities for created TeX files out of problem reports. * * $Id: tex_utils.c,v 1.1 2003/03/09 20:59:11 stuffle Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA *------------------------------------------------------------------------- */ #include #include #include #include #include #include #include "audit_trail.h" #include "error_chks.h" #include "gstr_utils.h" #define TEX_HEADER "\ \\batchmode \n\ \\font\\prtitle = cmb10 scaled \\magstep 4 \n\ \\font\\prsection = cmb10 scaled \\magstep 3 \n\ \\font\\prtext = cmr10 " #define TEX_END "\\bye" #define BLANK_LINE "\n" #define ITEM1 "\\item{} %s\n" #define ITEM2 "\\item{} %s: %s\n" #define PAR "\\par\n" #define PARINDENT20 "\\parindent = 20 pt\n" #define PARINDENT0_PARSKIP5 "\\parindent = 0 pt \\parskip = 5 pt\n" #define PARSKIP0 "\\parskip = 0 pt\n" #define PRSECTION "\\prsection %s\n" #define PRTEXT0 "\\prtext\n" #define PRTEXT1 "\\prtext\n%s\n" #define PRTITLE "\\prtitle PR \\#%d: %s\n" #define NOINDENT "\\noindent\n" #define NONE "$<$none$>$" #define VFILL_EJECT "\\vfill \\eject\n" #define VSKIP20 "\\vskip 20 pt\n" #define TEX_BS "$\\backslash$" #define TEX_BS_LEN 11 #define TEX_OPEN_BRACKET "$\\{$" #define TEX_OPEN_BRACKET_LEN 4 #define TEX_CLOSE_BRACKET "$\\}$" #define TEX_CLOSE_BRACKET_LEN 4 #define TEX_TILDA "\\~{}" #define TEX_TILDA_LEN 4 #define TEX_UNDERBAR "\\_{}" #define TEX_UNDERBAR_LEN 4 #define TEX_ARROW "\\^{}" #define TEX_ARROW_LEN 4 #define TEX_LT "$<$" #define TEX_LT_LEN 3 #define TEX_GT "$>$" #define TEX_GT_LEN 3 #define PR_NUM_POS 0 #define PR_TITLE_POS 1 #define PR_DESCR_POS 2 #define PR_FIX_POS 3 #define PROJ_NAME_POS 4 #define SUBMITTER_NAME_POS 5 #define RESPONSIBLE_NAME_POS 6 #define TYPE_NAME_POS 7 #define SEVR_NAME_POS 8 #define STAT_NAME_POS 9 #define MAIN_SQL "\ SELECT pr.problem_num, pr.title, pr.descr, pr.fix, proj.name, \ p1.last_name || ', ' || p1.first_name || '(' || p1.login_id || ')', \ p2.last_name || ', ' || p2.first_name || '(' || p2.login_id || ')', \ pt.name, sevr.name, stat.name \ FROM problem_report pr, \ person p1, \ person p2, \ project proj, \ problem_type pt, \ severity sevr, \ status stat \ WHERE sevr.severity_num = pr.severity_num \ AND stat.status_num = pr.status_num \ AND pt.type_num = pr.type_num \ AND p1.login_id = pr.submitter_id \ AND p2.login_id = pr.responsible_id \ AND proj.project_num = pr.project_num \ AND pr.problem_num in (%s) \ UNION \ SELECT pr.problem_num, pr.title, pr.descr, pr.fix, proj.name, \ p1.last_name || ', ' || p1.first_name || '(' || p1.login_id || ')', \ '', pt.name, sevr.name, stat.name \ FROM problem_report pr, \ person p1, \ project proj, \ problem_type pt, \ severity sevr, \ status stat \ WHERE sevr.severity_num = pr.severity_num \ AND stat.status_num = pr.status_num \ AND pt.type_num = pr.type_num \ AND p1.login_id = pr.submitter_id \ AND pr.responsible_id is NULL \ AND proj.project_num = pr.project_num \ AND pr.problem_num in (%s) \ ORDER BY 1 " /* * fix_tex_string * * Fix the string for use with tex. Escape out any characters that need * it, and double up any '\n' characters. (read the tutorial some more, * and think about what the best way to do this is going to be). */ void fix_tex_string (GString *str) { gboolean prev_space = FALSE; /* was previous char a space? */ gint i = 0; while (i < str->len) { switch (str->str[i]) { case '%' : case '&' : case '$' : case '#' : g_string_insert_char (str, '\\', i); i += 2; prev_space = FALSE; break; case '\\' : g_string_delete_char (str, i); g_string_insert_str (str, TEX_BS, i); i += TEX_BS_LEN; prev_space = FALSE; break; case '{' : g_string_delete_char (str, i); g_string_insert_str (str, TEX_OPEN_BRACKET, i); i += TEX_OPEN_BRACKET_LEN; prev_space = FALSE; break; case '}' : g_string_delete_char (str, i); g_string_insert_str (str, TEX_CLOSE_BRACKET, i); i += TEX_CLOSE_BRACKET_LEN; prev_space = FALSE; break; case '<' : g_string_delete_char (str, i); g_string_insert_str (str, TEX_LT, i); i += TEX_LT_LEN; prev_space = FALSE; break; case '>' : g_string_delete_char (str, i); g_string_insert_str (str, TEX_GT, i); i += TEX_GT_LEN; prev_space = FALSE; break; case '~' : g_string_delete_char (str, i); g_string_insert_str (str, TEX_TILDA, i); i += TEX_TILDA_LEN; prev_space = FALSE; break; case '_' : g_string_delete_char (str, i); g_string_insert_str (str, TEX_UNDERBAR, i); i += TEX_UNDERBAR_LEN; prev_space = FALSE; break; case '^' : g_string_delete_char (str, i); g_string_insert_str (str, TEX_ARROW, i); i += TEX_ARROW_LEN; prev_space = FALSE; break; case '\n' : g_string_insert_char (str, '\n', i); i += 2; prev_space = FALSE; break; case ' ' : /* * If the previous character was also a space, replace this * space with non-breaking space. */ if (prev_space) { g_string_delete_char (str, i); g_string_insert_char (str, '~', i); } i += 1; prev_space = TRUE; break; default: i += 1; prev_space = FALSE; } /* switch */ } /* while */ } /* * create_main_sql_str * * Create the main sql string given the problem numbers in the list. * * Return NULL if the list is empty. */ GString* create_main_sql_str (GList *list) { GString *tmp = NULL; GString *list_str = NULL; GString *q_str = NULL; GList *iter; if (!list) { return NULL; } list_str = g_string_new (""); tmp = g_string_new (""); iter = g_list_first (list); while (iter) { g_string_sprintf (tmp, "%d, ", GPOINTER_TO_INT (iter->data)); list_str = g_string_append (list_str, tmp->str); iter = iter->next; } /* * Chop off the last ", ". */ list_str = g_string_truncate (list_str, list_str->len - 2); q_str = g_string_new (""); g_string_sprintf (q_str, MAIN_SQL, list_str->str, list_str->str); g_string_free (tmp, TRUE); g_string_free (list_str, TRUE); return q_str; } /* * write_tex_audit_trail * * Write the audit trail for the current problem report out to the tex * file. */ gboolean write_tex_audit_trail (FILE *fp, PGconn *conn, gint pk_num) { GString *query_str = NULL; GString *curr_str = NULL; PGresult *res; gboolean rtn_val = TRUE; gint i, n; query_str = g_string_new (""); curr_str = g_string_new (""); g_string_sprintf (query_str, PR_SUBMIT_DATE_QUERY, pk_num); res = PQexec (conn, query_str->str); rtn_val = chk_sql_error (res, _("Get submit date")); assert (PQntuples (res) == 1); if (rtn_val) { fprintf (fp, "%s\n", PQgetvalue (res, 0, 0)); fprintf (fp, PARSKIP0); g_string_sprintf (query_str, SELECT_AUDIT_TRAIL, pk_num, pk_num); PQclear (res); res = PQexec (conn, query_str->str); rtn_val = chk_sql_error (res, _("Get audit trail data")); if (rtn_val) { n = PQntuples (res); for (i = 0; i < n; i++) { g_string_sprintf (curr_str, PQgetvalue (res, i, 0)); fix_tex_string (curr_str); fprintf (fp, ITEM1, curr_str->str); } /* end for loop */ } /* end if (rtn_val) 2 */ } /* end if (rtn_val) 1 */ PQclear (res); g_string_free (query_str, TRUE); g_string_free (curr_str, TRUE); return rtn_val; } /* * write_tex_file * * Master function that writes the data out to the tex file. This * function performs as follows: * write the "header" section of the file * loop through the query results * get the audit trail for each record * write each record * end loop * write the "closing" section of the file * * Returns TRUE upon success, FALSE on any failure. */ gboolean write_tex_file (FILE *fp, PGconn *conn, PGresult *res) { gint i, n; gint num; GString *tmp_str; tmp_str = g_string_new (""); fprintf (fp, TEX_HEADER); n = PQntuples (res); assert (n > 0); for (i = 0; i < n; i++) { fprintf (fp, BLANK_LINE); fprintf (fp, PARINDENT0_PARSKIP5); num = atoi (PQgetvalue (res, i, PR_NUM_POS)); tmp_str = g_string_assign (tmp_str, PQgetvalue (res, i, PR_TITLE_POS)); fix_tex_string (tmp_str); fprintf (fp, PRTITLE, num, tmp_str->str); fprintf (fp, PAR); fprintf (fp, BLANK_LINE); fprintf (fp, VSKIP20); fprintf (fp, PARINDENT20); fprintf (fp, NOINDENT); fprintf (fp, PRSECTION, "General Information:"); fprintf (fp, PRTEXT0); tmp_str = g_string_assign (tmp_str, PQgetvalue (res, i, PROJ_NAME_POS)); fix_tex_string (tmp_str); fprintf (fp, ITEM2, "Project", tmp_str->str); fprintf (fp, PARSKIP0); tmp_str = g_string_assign (tmp_str, PQgetvalue (res, i, SUBMITTER_NAME_POS)); fix_tex_string (tmp_str); fprintf (fp, ITEM2, "Submitter", tmp_str->str); tmp_str = g_string_assign (tmp_str, PQgetvalue (res, i, RESPONSIBLE_NAME_POS)); fix_tex_string (tmp_str); fprintf (fp, ITEM2, "Responsible", tmp_str->str); tmp_str = g_string_assign (tmp_str, PQgetvalue (res, i, TYPE_NAME_POS)); fix_tex_string (tmp_str); fprintf (fp, ITEM2, "Problem Type", tmp_str->str); tmp_str = g_string_assign (tmp_str, PQgetvalue (res, i, SEVR_NAME_POS)); fix_tex_string (tmp_str); fprintf (fp, ITEM2, "Problem Severity", tmp_str->str); tmp_str = g_string_assign (tmp_str, PQgetvalue (res, i, STAT_NAME_POS)); fix_tex_string (tmp_str); fprintf (fp, ITEM2, "Status", tmp_str->str); fprintf (fp, PAR); fprintf (fp, BLANK_LINE); fprintf (fp, PARINDENT0_PARSKIP5); fprintf (fp, VSKIP20); fprintf (fp, PRSECTION, "Description"); fprintf (fp, PAR); tmp_str = g_string_assign (tmp_str, PQgetvalue (res, i, PR_DESCR_POS)); fix_tex_string (tmp_str); fprintf (fp, PRTEXT1, tmp_str->str); fprintf (fp, PAR); fprintf (fp, BLANK_LINE); fprintf (fp, VSKIP20); fprintf (fp, PRSECTION, "Fix Description"); fprintf (fp, PAR); tmp_str = g_string_assign (tmp_str, PQgetvalue (res, i, PR_FIX_POS)); fix_tex_string (tmp_str); fprintf (fp, PRTEXT1, tmp_str->str); fprintf (fp, PAR); fprintf (fp, BLANK_LINE); fprintf (fp, VSKIP20); fprintf (fp, PRSECTION, "Audit Trail"); fprintf (fp, PAR); fprintf (fp, PRTEXT0); write_tex_audit_trail (fp, conn, num); fprintf (fp, VFILL_EJECT); } fprintf (fp, BLANK_LINE); fprintf (fp, TEX_END); g_string_free (tmp_str, TRUE); return TRUE; }