/* * avrdude - A Downloader/Uploader for AVR device programmers * Copyright (C) 2000-2005 Brian S. Dean * Copyright (C) Joerg Wunsch * * 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, see . */ /* * Program an Atmel AVR device through one of the supported programmers * * For parallel port connected programmers, the pin definitions can be changed * via a config file. See the config file for instructions on how to add a * programmer definition. * */ // For AVRDUDE_FULL_VERSION and possibly others #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(WIN32) #include #endif #include "avrdude.h" #include "libavrdude.h" #include "config.h" #include "developer_opts.h" char *progname = "avrdude"; static const char *avrdude_message_type(int msglvl) { switch(msglvl) { case MSG_EXT_ERROR: return "OS error"; case MSG_ERROR: return "error"; case MSG_WARNING: return "warning"; case MSG_INFO: return "info"; case MSG_NOTICE: return "notice"; case MSG_NOTICE2: return "notice2"; case MSG_DEBUG: return "debug"; case MSG_TRACE: return "trace"; case MSG_TRACE2: return "trace2"; default: return "unknown msglvl"; } } /* * Core messaging routine for msg_xyz(), [pli]msg_xyz() and term_out() * See #define lines in avrdude.h of how it is normally called * * Named that way as there used to be a now gone different avrdude_message() */ int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int msgmode, int msglvl, const char *format, ...) { int rc = 0; va_list ap; static struct { // Memorise whether last print ended at beginning of line FILE *fp; int bol; // Are we at the beginning of a line for this fp stream? } bols[5 + 1]; // Cater for up to 5 different FILE pointers plus one catch-all size_t bi = 0; // bi is index to bols[] array for(bi = 0; bi < sizeof bols/sizeof *bols - 1; bi++) { // Note the -1, so bi is valid after loop if(!bols[bi].fp) { // First free space bols[bi].fp = fp; // Insert fp in first free space bols[bi].bol = 1; // Assume beginning of line on first use } if(bols[bi].fp == fp) break; } if(msglvl <= MSG_ERROR) // Serious error? Free progress bars (if any) report_progress(1, -1, NULL); if(msgmode & MSG2_FLUSH) { fflush(stdout); fflush(stderr); } // Reduce effective verbosity level by number of -q above one when printing to stderr if((fp == stderr? verblevel: verbose) >= msglvl) { if(msgmode & MSG2_LEFT_MARGIN && !bols[bi].bol) { fprintf(fp, "\n"); bols[bi].bol = 1; } // Keep vertical tab at start of format string as conditional new line if(*format == '\v') { format++; if(!bols[bi].bol) { fprintf(fp, "\n"); bols[bi].bol = 1; } } if(msgmode & (MSG2_PROGNAME | MSG2_TYPE)) { if(msgmode & MSG2_PROGNAME) { fprintf(fp, "%s", progname); bols[bi].bol = 0; } if(msgmode & MSG2_TYPE) { const char *mt = avrdude_message_type(msglvl); if(bols[bi].bol) fprintf(fp, "%c%s", msgmode & (MSG2_UCFIRST)? toupper(*mt & 0xff): *mt, mt + 1); else fprintf(fp, " %s", mt); bols[bi].bol = 0; } if(verblevel >= MSG_NOTICE2) { const char *bfname = strrchr(file, '/'); // Only print basename #if defined (WIN32) if(!bfname) bfname = strrchr(file, '\\'); #endif bfname = bfname? bfname + 1: file; if(msgmode & MSG2_FUNCTION) fprintf(fp, " %s()", func); if(msgmode & MSG2_FILELINE) fprintf(fp, " %s %d", bfname, lno); } fprintf(fp, ": "); } else if(msgmode & MSG2_INDENT1) { fprintf(fp, "%*s", (int) strlen(progname) + 1, ""); bols[bi].bol = 0; } else if(msgmode & MSG2_INDENT2) { fprintf(fp, "%*s", (int) strlen(progname) + 2, ""); bols[bi].bol = 0; } // Figure out whether this print will leave us at beginning of line // Determine required size first va_start(ap, format); rc = vsnprintf(NULL, 0, format, ap); va_end(ap); if(rc < 0) // Some errror? return 0; rc++; // Accommodate terminating nul char *p = mmt_malloc(rc); va_start(ap, format); rc = vsnprintf(p, rc, format, ap); va_end(ap); if(rc < 0) { mmt_free(p); return 0; } if(*p) { // Finally: print! if(bols[bi].bol && (msgmode & MSG2_UCFIRST)) fprintf(fp, "%c%s", toupper(*p & 0xff), p + 1); else fprintf(fp, "%s", p); bols[bi].bol = p[strlen(p) - 1] == '\n'; } mmt_free(p); } if(msgmode & MSG2_FLUSH) fflush(fp); return rc; } struct list_walk_cookie { FILE *f; const char *prefix; }; libavrdude_context *cx; // Context pointer, eventually the only global variable static LISTID updates = NULL; static LISTID extended_params = NULL; static LISTID additional_config_files = NULL; static PROGRAMMER *pgm; // Global options int verbose; // Verbose output int quell_progress; // Quell progress report and un-verbose output int ovsigck; // 1 = override sig check, 0 = don't const char *partdesc; // Part -p string const char *pgmid; // Programmer -c string static char usr_config[PATH_MAX]; // Per-user config file // Usage message static void usage(void) { char *home = getenv("HOME"); size_t l = home? strlen(home): 0; char *cfg = home && str_casestarts(usr_config, home)? mmt_sprintf("~/%s", usr_config + l + (usr_config[l] == '/')): mmt_sprintf("%s", usr_config); msg_error("Usage: %s {