/*------------------------------------------------------------------------- * Copyright (c) 1999-2003 Kenneth W. Sodemann (stuffle@mac.com) *------------------------------------------------------------------------- * tex_pr * * Synopsis: * Routines to handle creating a tex file from problem reports. * * $Id: tex_pr.c,v 1.12 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 * *------------------------------------------------------------------------- */ #ifdef HAVE_CONFIG_H # include #endif /* * Only compile this stuff if printing is actually supported. */ #ifdef PRINTING_SUPPORTED #include #include #include #include #include #include #include #include #include #include "error_chks.h" #include "print_prog_dlg.h" #include "tex_utils.h" #include "util.h" /* * Buffer size for buffers used to read the data piped back from the * forked processes. */ #define BUFF_SIZE 80 /* * cleanup_files * * Delete all of the working files from the printing process. I really * do not care about errors at this point, since there is not a heck of * a lot I can do about them. If one occurs, just log it. */ void cleanup_files (const gchar *infn) { GString *tmp_str; tmp_str = g_string_new (infn); tmp_str = g_string_append (tmp_str, ".tex"); if (unlink (tmp_str->str) == -1) { syslog (LOG_WARNING, _("Failure deleting %s: %m"), tmp_str->str); } tmp_str = g_string_assign (tmp_str, infn); tmp_str = g_string_append (tmp_str, ".log"); if (unlink (tmp_str->str) == -1) { syslog (LOG_WARNING, _("Failure deleting %s: %m"), tmp_str->str); } tmp_str = g_string_assign (tmp_str, infn); tmp_str = g_string_append (tmp_str, ".dvi"); if (unlink (tmp_str->str) == -1) { syslog (LOG_WARNING, _("Failure deleting %s: %m"), tmp_str->str); } } /* * get_file_path * * Given a full file name, get the path to the file (full file name without * the file name part). * * The returned value needs to be free'ed with g_string_free. */ static GString* get_file_path (const gchar *str) { GString *tmp_str = g_string_new (str); gint i = strlen (str); while (i >= 0 && !(tmp_str->str[i] == '/' || tmp_str->str[i] == '\\')) { i--; } tmp_str = g_string_truncate (tmp_str, i + 1); return tmp_str; } GString* create_tex_file (PGconn *conn, GList *list, GtkWidget *msg_win) { GString *fn_base = NULL; GString *fn = NULL; GString *query_str = NULL; PGresult *res; char *tempfn = NULL; FILE *fp; gboolean in_error = FALSE; /* * Create a unique file name, and open the file. Remember to save off * the file's base name so we can return it. */ tempfn = tempnam (NULL, "preps"); fn_base = g_string_new (tempfn); fn = g_string_new (tempfn); fn = g_string_append (fn, ".tex"); fp = fopen (fn->str, "w"); /* * If the open worked, then proceed on writting the file. */ in_error = (fp == NULL); if (!in_error) { /* * It worked. Here is what we need to do: * Build the query string * Execute the query * Build the tex file. * free and NULL file name base * end if */ query_str = create_main_sql_str (list); in_error = (query_str == NULL); if (!in_error) { if (msg_win) { print_prog_dlg_output_message (msg_win, _("Fetching problem reports to print...\n"), FALSE); } res = PQexec (conn, query_str->str); in_error = !chk_sql_error (res, _("Getting problems to be printed")); if (!in_error) { if (msg_win) { print_prog_dlg_output_message (msg_win, _("Typsetting problem reports...\n"), FALSE); } in_error = !write_tex_file (fp, conn, res); } PQclear (res); } g_string_free (query_str, TRUE); } /* * if we had any problems, free up the file name base string, and set * it to return NULL. */ if (in_error) { g_string_free (fn_base, TRUE); fn_base = NULL; } free (tempfn); fclose (fp); return fn_base; } /* * This one is pretty simple. Just open the log file, and dump the contents * to the text widget. Since this is very non-essential, any errors get * logged to the syslog, but nothing more. */ void dump_tex_log (const gchar *infn, GtkWidget *text) { GString *log_fn; FILE *log_file; gchar buffer [BUFF_SIZE]; log_fn = g_string_new (infn); if (!log_fn) { syslog (LOG_WARNING, _("Error allocating TeX log file name: %m")); return; } log_fn = g_string_append (log_fn, ".log"); log_file = fopen (log_fn->str, "r"); if (log_file) { while (fgets (buffer, BUFF_SIZE, log_file)) { print_prog_dlg_output_message (text, buffer, FALSE); } fclose (log_file); } else { syslog (LOG_WARNING, _("Error opening TeX log file: %m")); } return; } gboolean tex_to_dvi (const gchar *infn, GtkWidget *msg_win) { GString *path = NULL; GString *err_str = NULL; int fork_result; gboolean in_error = FALSE; int pipe_files[2]; int fd; int bytes_read; int child_status; gchar buffer[BUFF_SIZE]; if (pipe (pipe_files) != -1) { fork_result = fork(); switch (fork_result) { case -1: /* error case */ in_error = TRUE; err_str = g_string_new (""); g_string_printf (err_str, _("Failed to create child for TeX: %s\n"), g_strerror (errno)); print_prog_dlg_output_message (msg_win, err_str->str, TRUE); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); break; case 0: /* * in the child * * First CD over to where-ever we created the TeX file. TeX * likes to create the .dvi file in the current directory. */ path = get_file_path (infn); if (chdir (path->str) == -1) { err_str = g_string_new (""); g_string_printf (err_str, _("Cannot change directory to %s : %s\n"), path->str, g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } g_string_free (path, TRUE); /* * If we managed to CD correctly, attempt to fire off TeX, * but first make it such that stdout will be the write end * of the comm pipe. */ if (close (1) == -1) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to close stdout: %s\n"), g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } fd = dup (pipe_files[WRITE_PIPE]); if (fd != 1) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to dup stdout: rtn: %d msg: %s\n"), fd, g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); /* * If we get here, both pipes should be closed and stdout * should be the write end of the pipe. We should finally * be ready to fire off TeX. */ if (execl (TEX_PATH, "tex", infn, NULL) == -1) { err_str = g_string_new (""); g_string_printf (err_str, _("Error starting TeX (%s) : %s\n"), TEX_PATH, g_strerror (errno)); write (fd, err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); _exit (-1); } break; default: /* * Close the write pipe, and read the read pipe until we * are all done. */ close (pipe_files[WRITE_PIPE]); bytes_read = read (pipe_files[READ_PIPE], buffer, BUFF_SIZE - 1); while (bytes_read) { if (msg_win) { buffer[bytes_read] = '\000'; print_prog_dlg_output_message (msg_win, buffer, FALSE); } bytes_read = read (pipe_files[READ_PIPE], buffer, BUFF_SIZE); } close (pipe_files[READ_PIPE]); wait (&child_status); in_error = (child_status != 0); } } else { /* * We failed to open the communications pipe. Let the user know this. */ in_error = TRUE; err_str = g_string_new (""); g_string_printf (err_str, _("Failed to open communications pipe: %s\n"), g_strerror (errno)); print_prog_dlg_output_message (msg_win, err_str->str, TRUE); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); } return !in_error; } gboolean dvi_to_ps (const gchar *infn, const gchar *outfn, GtkWidget *msg_win) { gboolean in_error = FALSE; int fork_result; int child_status; int pipe_files[2]; int fd; GString *err_str = NULL; gchar buffer[BUFF_SIZE]; gint bytes_read; if (pipe (pipe_files) != -1) { fork_result = fork (); switch (fork_result) { case -1: /* error condition */ in_error = TRUE; err_str = g_string_new (""); g_string_printf (err_str, _("Failed to create child for dvips: %s\n"), g_strerror (errno)); print_prog_dlg_output_message (msg_win, err_str->str, TRUE); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); break; case 0: /* * We are in the child. Close dup the write pipe as stdout, * and execute dvips to create the output postscript file. */ if (close (1) == -1) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to close stdout: %s\n"), g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } fd = dup (pipe_files[WRITE_PIPE]); if (fd != 1) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to dup stdout: rtn: %d err: %s\n"), fd, g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } if (close (2) == -1) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to close stderr: %s\n"), g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } fd = dup (pipe_files[WRITE_PIPE]); if (fd != 2) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to dup stderr: rtn: %d err: %s\n"), fd, g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); /* * If we are here, both the READ and WRITE parts of this * end of the pipe should be closed, with the WRITE pipe * being duped as stdout. */ if (execl (DVIPS_PATH, "dvips", "-o", outfn, infn, NULL) == -1) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to exec dvips (%s) : %s\n"), DVIPS_PATH, g_strerror (errno)); write (fd, err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); _exit (-1); } break; default: close (pipe_files[WRITE_PIPE]); bytes_read = read (pipe_files[READ_PIPE], buffer, BUFF_SIZE - 1); while (bytes_read) { if (msg_win) { buffer[bytes_read] = '\000'; print_prog_dlg_output_message (msg_win, buffer, FALSE); } bytes_read = read (pipe_files[READ_PIPE], buffer, BUFF_SIZE); } close (pipe_files[READ_PIPE]); wait (&child_status); in_error = (child_status != 0); if (in_error) { print_prog_dlg_output_message (msg_win, _("Process completed with errors.\n"), TRUE); } else { if (msg_win) { print_prog_dlg_output_message (msg_win, _("Done...\n"), FALSE); } } } /* end switch */ } else { in_error = TRUE; err_str = g_string_new (""); g_string_printf (err_str, _("Failed to open communications pipe: %s\n"), g_strerror (errno)); print_prog_dlg_output_message (msg_win, err_str->str, TRUE); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); } return !in_error; } gboolean dvi_to_printer (const gchar *infn, const gchar *prn, GtkWidget *msg_win) { gboolean in_error = FALSE; int fork_result; int child_status; int pipe_files[2]; int fd; GString *err_str = NULL; gchar buffer[BUFF_SIZE]; gint bytes_read; if (pipe (pipe_files) != -1) { fork_result = fork (); switch (fork_result) { case -1: /* error condition */ in_error = TRUE; err_str = g_string_new (""); g_string_printf (err_str, _("Failed to create child for dvips: %s\n"), g_strerror (errno)); print_prog_dlg_output_message (msg_win, err_str->str, TRUE); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); break; case 0: /* * We are in the child. Close dup the write pipe as stdout * and stderr. Execute dvips to create the output postscript * file. */ if (close (1) == -1) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to close stdout: %s\n"), g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } fd = dup (pipe_files[WRITE_PIPE]); if (fd != 1) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to dup stdout: rtn: %d err: %s\n"), fd, g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } if (close (2) == -1) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to close stderr: %s\n"), g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } fd = dup (pipe_files[WRITE_PIPE]); if (fd != 2) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to dup stderr: rtn: %d err: %s\n"), fd, g_strerror (errno)); write (pipe_files[WRITE_PIPE], err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); _exit (-1); } close (pipe_files[READ_PIPE]); close (pipe_files[WRITE_PIPE]); /* * If we are here, both the READ and WRITE parts of this * end of the pipe should be closed, with the WRITE pipe * being duped as stdout. */ if (execl (DVIPS_PATH, "dvips", "-P", prn, infn, NULL) == -1) { err_str = g_string_new (""); g_string_printf (err_str, _("Failed to exec dvips (%s) : %s\n"), DVIPS_PATH, g_strerror (errno)); write (fd, err_str->str, err_str->len); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); _exit (-1); } break; default: close (pipe_files[WRITE_PIPE]); bytes_read = read (pipe_files[READ_PIPE], buffer, BUFF_SIZE - 1); while (bytes_read) { if (msg_win) { buffer[bytes_read] = '\000'; print_prog_dlg_output_message (msg_win, buffer, FALSE); } bytes_read = read (pipe_files[READ_PIPE], buffer, BUFF_SIZE); } close (pipe_files[READ_PIPE]); wait (&child_status); in_error = (child_status != 0); if (in_error) { print_prog_dlg_output_message (msg_win, _("Process completed with errors.\n"), TRUE); } else { if (msg_win) { print_prog_dlg_output_message (msg_win, "Done...\n", FALSE); } } } /* end switch */ } /* end pipes OK */ else { in_error = TRUE; err_str = g_string_new (""); g_string_printf (err_str, _("Failed to open communications pipe: %s\n"), g_strerror (errno)); print_prog_dlg_output_message (msg_win, err_str->str, TRUE); syslog (LOG_WARNING, err_str->str); g_string_free (err_str, TRUE); } return !in_error; } #endif