回精華區
作者itoc (站上人數:802), 信區: plan
標題[功能] 台鐵時刻查詢
時間2006/05/21 Sun 12:17:12 Updated: 2006/05/21
: menu.c 適當的選單加上這二行

+ "bin/railway.so:main_railway", 0, - M_XMODE,
+ "Railway    ♂ 火車時刻 ♀",

: game/Makefile

SO =    ... railway.so

: game/railway.c 新增此程式

/*-------------------------------------------------------*/
/* railway.c    ( NTHU CS MapleBBS Ver 3.10 )            */
/*-------------------------------------------------------*/
/* target : 台鐵火車時刻表查詢                           */
/* create : 02/05/29                                     */
/* update :   /  /                                       */
/* author : lp@micro.ee.nthu.edu.tw                      */
/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw                 */
/*-------------------------------------------------------*/


#if 0
  1. 需要安裝 lynx、piconv、grep,且請檢查這三者在 http_conn()
     裡面的路徑是否正確。
  2. 程式雖然有轉車站的部分,但是目前沒有用。
#endif

#include "bbs.h"

#define mouts(x,y,s)    { move(x, y); outs(s); }

#define FORM_railway    "\"SBeginStation=%s&SBeginStationName=&SEndStation=%s&SEndStationName=&SClass=%s&SDateTime=%s&STime=&SearchType=0&SBeginCityCode=&SEndCityCode=&BStationIndex=&EStationIndex=\""

#define REF             "http://www.railway.gov.tw/"

#define RAILWAY_XPOS    1
#define RAILWAY_YPOS    0
#define MAX_SITE        212
#define SITE_PER_LINE   13      /* 每列秀 13 個站台 */

static char *siteid[MAX_SITE] = /* 車站站台 */
{
  "台東", "山里", "鹿野", "瑞源", "瑞和", "月美", "關山", "海端", "池上", "富里", "東竹", "東里", "安通",
  "玉里", "三民", "瑞穗", "富源", "大富", "光復", "萬榮", "鳳林", "南平", "溪口", "豐田", "壽豐", "平和",
  "志學", "吉安", "花蓮", "北埔", "景美", "新城", "崇德", "和仁", "和平", "漢本", "武塔", "南澳", "東澳",
  "永樂", "蘇澳","蘇澳新","新馬", "冬山", "羅東", "中里", "二結", "宜蘭", "四城", "礁溪", "頂埔", "頭城",
  "外澳", "龜山", "大溪", "大里", "石城", "福隆", "貢寮", "雙溪", "牡丹","三貂嶺","侯硐","瑞芳","四腳亭",
  "暖暖", "基隆", "三坑", "八堵", "七堵", "五堵", "汐止", "南港", "松山", "台北", "萬華", "板橋", "樹林",
  "山佳", "鶯歌", "桃園", "內壢", "中壢", "埔心", "楊梅", "富岡", "湖口", "新豐", "竹北", "新竹", "香山",
  "崎頂", "竹南", "談文", "大山", "後龍", "龍港","白沙屯","新埔", "通霄", "苑裡", "日南","大甲","台中港",
  "清水", "沙鹿", "龍井", "大肚", "追分", "造橋", "豐富", "苗栗", "南勢", "銅鑼", "三義", "泰安", "后里",
  "豐原", "潭子", "太原", "台中", "大慶", "烏日", "成功\","彰化", "花壇", "大村", "員林", "永靖", "社頭",
  "田中", "二水", "林內", "石榴", "斗六", "斗南", "石龜", "大林", "民雄", "嘉義", "水上", "南靖", "嘉北",
  "後壁", "新營", "柳營","林鳳營","隆田", "拔林", "善化", "新市", "永康", "大橋", "台南", "保安", "中洲",
  "大湖", "路竹", "岡山", "橋頭", "楠梓", "左營", "高雄", "鳳山", "後庄","九曲堂","六塊厝","屏東","歸來",
  "麟洛", "西勢", "竹田", "潮州", "崁頂", "南州", "鎮安", "林邊", "佳冬", "東海", "枋寮", "加祿", "內獅",
  "枋山", "古莊", "大武", "瀧溪", "多良", "金崙","太麻里","知本", "康樂", "大華", "十分", "望古", "嶺腳",
  "平溪", "菁桐", "竹中", "上員", "榮華", "竹東", "橫山","九讚頭","合興", "富貴", "內灣", "源泉", "濁水",
  "龍泉", "集集", "水里", "車埕"
};


static char *siteno[MAX_SITE] = /* 車站代碼 */
{
  "1632", "1631", "1630", "1629", "1628", "1627", "1626", "1625", "1624", "1623", "1622", "1621", "1620",
  "1619", "1617", "1616", "1614", "1613", "1612", "1611", "1610", "1609", "1608", "1607", "1606", "1605",
  "1604", "1602", "1715", "1714", "1713", "1712", "1711", "1710", "1709", "1708", "1706", "1705", "1704",
  "1703", "1827", "1826", "1825", "1824", "1823", "1822", "1821", "1820", "1819", "1818", "1817", "1816",
  "1815", "1814", "1813", "1812", "1811", "1810", "1809", "1808", "1807", "1806", "1805", "1804", "1803",
  "1802", "1001", "1029", "1002", "1003", "1004", "1005", "1006", "1007", "1008", "1009", "1011", "1012",
  "1013", "1014", "1015", "1016", "1017", "1018", "1019", "1020", "1021", "1022", "1023", "1025", "1026",
  "1027", "1028", "1102", "1104", "1105", "1106", "1107", "1108", "1109", "1110", "1111", "1112", "1113",
  "1114", "1115", "1116", "1117", "1118", "1302", "1304", "1305", "1307", "1308", "1310", "1314", "1315",
  "1317", "1318", "1323", "1319", "1322", "1320", "1321", "1120", "1202", "1240", "1203", "1204", "1205",
  "1206", "1207", "1208", "1209", "1210", "1211", "1212", "1213", "1214", "1215", "1217", "1218", "1241",
  "1219", "1220", "1221", "1222", "1223", "1224", "1225", "1226", "1227", "1239", "1228", "1229", "1230",
  "1231", "1232", "1233", "1234", "1235", "1236", "1238", "1402", "1403", "1404", "1405", "1406", "1407",
  "1408", "1409", "1410", "1411", "1412", "1413", "1414", "1415", "1416", "1417", "1418", "1502", "1503",
  "1504", "1507", "1508", "1510", "1511", "1512", "1514", "1516", "1517", "1903", "1904", "1905", "1906",
  "1907", "1908", "2203", "2204", "2211", "2205", "2206", "2207", "2208", "2209", "2210", "2702", "2703",
  "2704", "2705", "2706", "2707"
};


static int cx, cy;
static int fr_pos, to_pos, tr_pos;
static char fr_no[5], to_no[5], tr_no[4];       /* 起迄 代碼 */
static char typer[5];                           /* 對號/非對號 */


static void
outs_site(pos)
  int pos;
{
  char *site;

  site = siteid[pos];
  if (site[4] == '\0')
    prints(" %s ", site);
  else
    outs(site);
}


static void
outs_info(color, msg)
  int color;
  char *msg;             /* strlen(msg) == 14 */
{
  move(b_lines, 0);
  clrtoeol();
  move(b_lines, 30);     /* 置中 */
  prints("\033[%dm %s \033[m", color, msg);
}


static void
site_drawrow(x)          /* 重繪 x 列 */
  int x;
{
  int i;

  move(x + RAILWAY_XPOS, RAILWAY_YPOS);
  i = x * SITE_PER_LINE;
  x = (x + 1) * SITE_PER_LINE;
  if (x > MAX_SITE)
    x = MAX_SITE;
  for (; i < x; i++)
  {
    if (i == fr_pos)
      outs("\033[41m");
    else if (i == to_pos)
      outs("\033[44m");
    else if (i == tr_pos)
      outs("\033[42m");
    outs_site(i);
    if (i == fr_pos || i == to_pos || i == tr_pos)
      outs("\033[m");
  }
}


static void
site_show()
{
  int i;

  clear();
  move(0, 23);
  outs("\033[1;37;44m◎ 台鐵火車時刻表查詢系統 ◎\033[5;33m 測試版\033[m");

  for (i = 0; i < MAX_SITE; i++)
  {
    if (i % SITE_PER_LINE == 0)
      move(i / SITE_PER_LINE + RAILWAY_XPOS, RAILWAY_YPOS);
    outs_site(i);
  }

  move(b_lines - 4, 0);
  outs("啟程車站:         到達車站:");
  move(b_lines - 3, 0);
  outs("查詢時間:00:00 至 24:00 (內定, 無法改)");
  move(b_lines - 2, 0);
  outs("查詢車種:1)對號快車 2)非對號車 3)全部車種");

  cx = cy = 0;
  fr_pos = to_pos = tr_pos = -1;

}


static int              /* 1:成功 */
site_choose(flag)
  int flag;             /* 1:選起站  2:選迄站  4: 選轉站 */
{
  int pos;

  /* 這幾格沒有站台 */
  if (cx == MAX_SITE / SITE_PER_LINE && cy >= MAX_SITE % SITE_PER_LINE)
    return 0;

  pos = cx * SITE_PER_LINE + cy;

  if (flag == 1)
  {
    fr_pos = pos;
    strcpy(fr_no, siteno[fr_pos]);
    move(b_lines - 4, 10);
    prints("%-6s", siteid[fr_pos]);
  }
  else if (flag == 4)
  {
    if (fr_pos == pos)
      return 0;
    to_pos = pos;
    strcpy(to_no, siteno[to_pos]);
    move(b_lines - 4, 29);
    outs(siteid[to_pos]);
  }
  else /* if (flag == 2) */
  {
    if (fr_pos == pos || to_pos == pos)
      return 0;
    tr_pos = pos;
    strcpy(tr_no, siteno[tr_pos]);
    move(b_lines - 4, 48);
    outs(siteid[tr_pos]);
  }

  site_drawrow(cx);
  return 1;       /* 選下一個 */
}


static int              /* 1: 已決定起迄站 */
site_menu(flag)         /* 目前在選 1:起 4:迄 2:轉 站 */
  int flag;
{
  for (;;)
  {
    /* itoc.031209: 若遇到三個字的站名,又偵測全形時,那麼會多跳一次,暫時不管了 :p */
    move(cx + RAILWAY_XPOS, cy * 6 + RAILWAY_YPOS + 2);
    switch (vkey())
    {
    case KEY_RIGHT:
      cy++;
      if (cy > 12)
        cy = 0;
      break;

    case KEY_LEFT:
      cy--;
      if (cy < 0)
        cy = 12;
      break;

    case KEY_DOWN:
      cx++;
      if (cx > 16)
        cx = 0;
      break;

    case KEY_UP:
      cx--;
      if (cx < 0)
        cx = 16;
      break;

    case KEY_ENTER:
    case ' ':
      if (site_choose(flag))
        return 1;
      break;

    case 'q':
      return 0;
    }
  }
}


static void
rail_query()
{
  char ans[3], *msg;

  outs_info(45, "請選擇查詢車種");

  switch (vget(b_lines - 2, 0, "查詢車種:1)對號快車 2)非對號車 3)全部車種:[3] ", ans, 3, DOECHO))
  {
  case '1':
    strcpy(typer, "0");
    msg = "1)對號快車";
    break;

  case '2':
    strcpy(typer, "1");
    msg = "2)非對號車";
    break;

  default:
    strcpy(typer, "2");
    msg = "3)全部車種";
    break;
  }

  move(b_lines - 2, 10);
  outs(msg);
  clrtoeol();

  refresh();        /* 再次 vget() 會出現前面的控制碼,要 refresh */
}


static char
Tcolor(str)        /* 依車次來決定顏色 */
  char *str;
{
  if (!strncmp(str, "自強", 4))
    return '1';
  if (!strncmp(str, "莒光", 4))
    return '6';
  if (!strncmp(str, "復興", 4))
    return '4';
  return '0';
}


static void
html_parser(src, dst)
  char *src, *dst;
{
  FILE *fpr, *fpw;
  char data[256];
  char *result;
  int line_num;
  int tcount;         /* 總共有幾班次 */
  struct stat st;

  if ((!stat(src, &st) && !st.st_size) || !(fpr = fopen(src, "r")))
    return;

  fpw = fopen(dst, "w");

  line_num = 0;
  while (fgets(data, sizeof(data), fpr))
  {
    if (++line_num >= 6)
    {
      fprintf(fpw, "%s", data);
      break;
    }
  }

  line_num++;
  fprintf(fpw, "\n"
    "┌───┬──┬─┬───────┬─────┬─────┬──┬─────┐\n"
    "│ 乘坐 │車次│山│始發站->終點站│登車車站  │下車車站  │全票│行駛時間  │\n"
    "│ 車種 │編號│海│              │開車時間  │到達時間  │價錢│          │");

  while (fgets(data, sizeof(data), fpr))
  {
    if (++line_num >= 30)
      break;
  }

  tcount = 0;
  while (1)
  {
    if (!fgets(data, sizeof(data), fpr) || !(result = strtok(data, " ")))
      break;

    fprintf(fpw, "\n├───┼──┼─┼───────┼─────┼─────┼──┼─────┤");

    /* 車型,6 bytes */
    fprintf(fpw, "\n│\033[1;4%c;37m%6.6s\033[m", Tcolor(result), result);        /* 冷氣柴客會超過 6 bytes */

    /* 車次代碼,4 bytes */
    if (!(result = strtok(NULL, " ")))
      break;
    fprintf(fpw, "│%4.4s", result);        /* 冷氣柴客會超過 4 bytes */

    /* 山線或海線或空的,2 bytes */
    if (!fgets(data, sizeof(data), fpr) || !(result = strtok(data, "\n")))
      break;
    fprintf(fpw, "│%2s", result + 37);

    /* 啟程站、到達站,6 bytes */
    if (!fgets(data, sizeof(data), fpr) || !(result = strtok(data, "\n")))
      break;
    fprintf(fpw, "│%14s", result + 31);

    /* 開車時間 */
    if (!fgets(data, sizeof(data), fpr) || !(result = strtok(data, "\n")))
      break;
    fprintf(fpw, "│%8s  ", result + 32);

    /* 到達時間 */
    if (!fgets(data, sizeof(data), fpr) || !(result = strtok(data, "\n")))
      break;
    fprintf(fpw, "│%8s  ", result + 32);

    /* 全票價格 3 bytes */
    if (!fgets(data, sizeof(data), fpr) || !(result = strtok(data, "\n")))
      break;
    fprintf(fpw, "│%4s", result + 34);

    /* 行駛時間 */
    if (!fgets(data, sizeof(data), fpr) || !(result = strtok(data, "\n")) || !(result = strtok( result, " ")))
      break;
    fprintf(fpw, "│%10s│", result);

    /* 跳過備註 */
    if (!fgets(data, sizeof(data), fpr))
      break;

    tcount++;
  }                 /* end of while */


  fprintf(fpw,  "\n└───┴──┴─┴───────┴─────┴─────┴──┴─────┘\n\n\n\n");

  if (!tcount)
    fprintf(fpw, "\n\n抱歉!沒有您欲搭乘的班車");

  fclose(fpr);
  fclose(fpw);
}


static int
http_conn(s)
  char *s;
{
  char src[30], dst[30];
  char cmd[768];

  mouts(b_lines - 1, 0, "連接伺服器中,請稍候...");
    refresh();

  sprintf(src, "tmp/%s.rail", cuser.userid);
  sprintf(cmd, "/usr/local/bin/lynx -display_charset=utf-8 -nolist -dump  "
    "http://new.twtraffic.com.tw/twrail/nonscript_search_result.aspx?%s | "
    "/usr/local/bin/piconv -f utf8 -t big5 | /usr/bin/grep -v '圖示' > %s",
    s, src);
  system(cmd);

  sprintf(dst, "tmp/%s.way", cuser.userid);
  html_parser(src, dst);

  /* show message that return from the web server */


  if (more(dst, (char *) -1) >= 0)
  {
    if (vans("您要將查詢結果寄回信箱嗎?[N] ") == 'y')
      mail_self(dst, cuser.userid, "[備 忘 錄] 火車時刻查詢結果", MAIL_READ);
  }
  unlink(dst);
  unlink(src);

  return 0;
}



static void
railway(delay)
  int delay;
{
  char atrn[512];
  char day[20];
  struct tm *ptime;
  time_t now;

  time(&now);
  now += 86400 * delay;
  ptime = localtime(&now);
  sprintf(day, "%02d/%d/%d",
    (ptime->tm_year - 11 ) % 100 , ptime->tm_mon + 1, ptime->tm_mday);

  sprintf(atrn, FORM_railway, fr_no, to_no, typer, day);
  http_conn(atrn);
}


int
main_railway()
{
  int ch;

  site_show();

  outs_info(41, "請選擇啟程車站");
  if (!site_menu(1))
    return 0;

  outs_info(44, "請選擇到達車站");
  if (!site_menu(4))
    return 0;

  rail_query();  /* 決定對號/非對號 */

  ch = vans("查詢 0)今天 1)明天 2)後天 3456789)天後的時刻表 Q)離開?[0] ");
  if (ch == 'q')
  {
    vmsg("hmm.....不想查囉...^o^");
    return 0;
  }
  if (ch < '0' || ch > '9')
    ch = 0;
  else
    ch -= '0';

  railway(ch);

  return 0;
}

--
□ 本文章由 itocitoc.Dorm11.NCTU.edu.tw 發表
精華選讀←離開[主題上]主題下(k)上篇(j)下篇S/a搜尋 G串列 TAB精華 ↑↓捲 Pg/Space翻